GuidesDEEZER
Deezer API from JavaScript
Prefix https://proxy.cors.dev/ to any api.deezer.com URL and your page can read it: free, no signup, no key, 600 requests per minute per client IP, JSON up to 1 MiB. Deezer's public endpoints for search, artists, albums, tracks, charts and radio need no key either, but they send no Access-Control-Allow-Origin header, so a direct fetch() fails with a CORS error. The 30-second preview MP3s are the exception: Deezer's CDN serves them with Access-Control-Allow-Origin: *, so they play without any proxy.
Why your Deezer fetch() fails
api.deezer.com answers without an Access-Control-Allow-Origin header. The request reaches Deezer and the JSON comes back, but the browser refuses to hand it to your script and logs a blocked-by-CORS-policy error. The proxy fetches the same URL and returns it with the header added. The Axios CORS error guide uses api.deezer.com as its example too.
Search tracks, artists and albums
/search returns tracks, /search/artist artists and /search/album albums. Each track carries nested artist and album objects, duration in seconds and a preview URL. A page holds 25 results by default and up to 100 with limit.
async function deezer(path) {
const response = await fetch(`https://proxy.cors.dev/https://api.deezer.com${path}`, { credentials: 'omit' });
if (!response.ok) {
throw new Error(`Deezer request failed: ${response.headers.get('X-Cors-Error') ?? response.status}`);
}
// Deezer reports errors with HTTP 200 and an error object
const data = await response.json();
if (data.error) throw new Error(`Deezer error ${data.error.code ?? ''}: ${data.error.message}`);
return data;
}
const results = await deezer(`/search?q=${encodeURIComponent('daft punk')}&limit=10`);
const tracks = results.data.map((track) => ({
id: track.id,
title: track.title,
artist: track.artist.name,
album: track.album.title,
cover: track.album.cover_medium,
seconds: track.duration,
preview: track.preview,
}));
console.log(results.total, tracks[0]);Deezer documents field filters inside q, such as artist:"..." and track:"...". In our tests a single track:"one more time" filter worked with 283 results, but artist:"daft punk" returned 0 and every combination, like artist:"eminem" track:"lose yourself", returned 0 too. The plain query eminem lose yourself put the right track first, so start with plain text. order=RANKING and order=DURATION_DESC did not change the order either.
Deezer API endpoints and response sizes
| Path | Returns | Size |
|---|---|---|
| /search?q=daft%20punk | 25 of 177 tracks, with next | 53 KB |
| /search?q=daft%20punk&limit=3 | 3 tracks | 6.4 KB |
| /search/artist?q=eminem&limit=1 | 1 artist | 866 B |
| /search/album?q=discovery&limit=3 | 3 albums | 4.8 KB |
| /artist/27 | Daft Punk: 38 albums, 5,223,222 fans | 879 B |
| /artist/27/top?limit=5 | 5 of 100 top tracks | 16 KB |
| /artist/27/albums?limit=5 | 5 of 38 albums | 4.5 KB |
| /artist/27/related?limit=5 | 5 similar artists | 3.9 KB |
| /album/302127 | Discovery with its 14 tracks | 23 KB |
| /track/3135556 | Harder, Better, Faster, Stronger with ISRC and preview | 4.9 KB |
| /chart | 10 each of tracks, albums, artists, playlists, podcasts | 72 KB |
| /chart/0/tracks?limit=500 | 300 chart tracks | 632 KB |
| /playlist/3155776842 | Top Worldwide, 100 tracks | 162 KB |
| /genre | Genre list | 15 KB |
| /radio | 93 to 152 stations, by country | 65 to 105 KB |
Apple's iTunes Search API is the keyless option that needs no proxy at all: https://itunes.apple.com/search?term=daft+punk&entity=song&limit=3 sent Access-Control-Allow-Origin: * and returned 3 songs with previewUrl in 4.6 KB.
Artists, albums, charts and radio
- Artist:
/artist/IDhasnb_album,nb_fanand picture URLs; add/top,/albumsor/relatedfor top tracks, the discography or similar artists. - Album and track:
/album/IDincludesrelease_dateand the full track list;/track/IDaddsisrc,gainand thepreviewURL. - Charts:
/chartreturns 10 each of tracks, albums, artists, playlists and podcasts;/chart/0/tracksgives 10 by default and 300 with a highlimit. - Genres and radio:
/genrelists genre IDs,/genre/ID/artiststhe artists in one, and/radiothe radio stations.
Charts, genres and radio depend on the IP that calls Deezer. /infos reported country_iso FR when our test server called directly and DE through the proxy, and /radio listed 303 stations directly against 93 to 152 through the proxy on the same day. Expect the proxy location, not your visitor country.
Pagination with index, limit and next
List endpoints take index (an offset) and limit and return total plus a next URL while more remain. limit=500 on search still gave 100 items and a next link at index=100. next is an absolute api.deezer.com URL, so turn it back into a path before you fetch it, or the browser calls Deezer directly and hits the CORS error again.
async function deezerAll(path, max = 500) {
const items = [];
let next = new URL(path, 'https://api.deezer.com');
while (next && items.length < max) {
const page = await deezer(next.pathname + next.search);
items.push(...page.data);
next = page.next ? new URL(page.next) : null;
}
return items.slice(0, max);
}
const albums = await deezerAll('/artist/27/albums?limit=25');
console.log(albums.length, albums.map((album) => album.title));Daft Punk's 38 albums came back in 2 requests of 25.
Play the 30-second previews
Every track has a preview field with a signed MP3 on cdnt-preview.dzcdn.net. The one we checked was 479,827 bytes, 30 seconds at 128 kbps, served as audio/mpeg with Access-Control-Allow-Origin: *. An audio element plays it, and even fetch() can read it, with no proxy. Through the free tier it fails: binary audio returns 502 with X-Cors-Error: unsupported_response.
// Markup: <ol id="tracks"></ol>
const list = document.querySelector('#tracks');
list.replaceChildren(
...tracks.map((track) => {
const item = document.createElement('li');
const cover = document.createElement('img');
const audio = document.createElement('audio');
cover.src = track.cover;
cover.alt = '';
cover.width = 56;
cover.height = 56;
// The MP3 streams straight from Deezer's CDN, which allows any origin
audio.controls = true;
audio.preload = 'none';
if (track.preview) audio.src = track.preview;
item.append(cover, `${track.artist}: ${track.title} `, audio);
return item;
}),
);The link expires. The exp= value in its hdnea parameter is a Unix time 900 seconds after the API call, and an expired or edited link returns 403. Request the track again for a fresh URL instead of storing previews.
Errors arrive as HTTP 200
Deezer reports most errors with status 200 and an error object, so response.ok is not enough. The deezer() helper above checks data.error.
| Request | error.type | code | message |
|---|---|---|---|
| /artist/999999999 | DataException | 800 | no data |
| /search?q= | ParameterException | 500 | empty parameter |
| /user/me without a token | OAuthException | 200 | An active access token must be used... |
| Too many requests | Exception | 4 | Quota limit exceeded |
Deezer's developer support documents a limit of 50 requests per 5 seconds per IP. When we fired 120 requests at once directly, 62 came back with code 4; later bursts of the same size passed, so enforcement varies. A few large bursts through the proxy also drew 403 Access Denied pages from Deezer's edge. Retry code 4 and 403 after a short wait. Through the proxy Deezer sees the proxy's address, which other proxy users share.
JSONP versus the proxy
Deezer still answers output=jsonp&callback=NAME with text/javascript, and its developer FAQ suggests JSONP to avoid CORS errors. JSONP is GET-only, runs Deezer's response as a script in your page, hides HTTP status codes, and the next links keep the callback parameters. A proxied fetch() returns plain JSON you can await, check and cache.
Free tier limits for Deezer calls
- Size: 1 MiB per decoded response; the largest call here, 300 chart tracks, was 632 KB.
- Rate: 600 requests per minute per client IP on cors.dev; Deezer's own limit of 50 per 5 seconds is lower.
- Keys: calls with an
access_tokenin the URL return 400 on the free tier; Pro forwards keys in the URL. - Text only: JSON passes; images and MP3s return 502
unsupported_response, butimgandaudiotags load both straight from Deezer's CDN.
Good questions.
Does the Deezer API support CORS?
No. api.deezer.com sends no Access-Control-Allow-Origin header, so fetch() from a web page is blocked. Route the call through https://proxy.cors.dev/ or your own server. The preview MP3s on cdnt-preview.dzcdn.net are the exception; they allow any origin.
Do I need an API key for the Deezer API?
Not for public data: search, artists, albums, tracks, charts, playlists, genres and radio are open. Only user endpoints such as /user/me need an OAuth access token; without one Deezer returns an OAuthException with HTTP 200.
What is the Deezer API rate limit?
50 requests per 5 seconds per IP, according to Deezer developer support. Going over returns HTTP 200 with error code 4, Quota limit exceeded. cors.dev adds its own free-tier limit of 600 requests per minute per client IP.
How do I get more than 25 results from the Deezer API?
Set limit, up to 100 per page, then follow the next URL or raise index. A search for daft punk reported a total of 177 and returned them in pages of up to 100.
How do I play Deezer previews in the browser?
Set the track's preview URL as the src of an audio element; no proxy needed. The link is signed and expires 15 minutes after the API call, then returns 403, so fetch the track again for a fresh one.
Does Deezer JSONP still work?
Yes, output=jsonp&callback=name still returns text/javascript. A proxied fetch() is easier to work with: real JSON, real status codes and an X-Cors-Error header when the proxy fails.
Is the Deezer API free?
Yes. Deezer has no paid API plan, and the public endpoints need no key. Previews stop at 30 seconds, which Deezer's developer FAQ calls a legal restriction.