Home Global Coverage Pricing Docs MCP Compare SDK Blog Changelog Status Contact Get API Key →
Spotify killed audio_features — Nov 2024 ⚡ Now on RapidAPI →

The audio_features replacement  ·  BPM · Key · Energy · Mood · Genre

Maintained. Most advanced. 42 fields. One call.

The maintained Spotify audio_features replacement — full analysis from just a track name, in one call:

View Docs OpenAPI →

£0.17 per 1k  ·  941+ genres  ·  12+ language families  ·  Auto-enrichment + dashboard

No account required  ·  No ISRC needed  ·  886k+ tracks instant  ·  J-Pop · K-Pop · Mandopop · Bollywood · MPB · Afrobeats  ·  Free tier — no card

Fields per track
42 data points
⚡ AI-Native via MCP →
Hosted connector — no install, no key
Missing data?
Auto-enriched + dashboard
~30ms Cached response (p95 < 100ms)
42 Fields per track
886k+ Pre-analysed & growing daily · rest backfilled in ~15s
£0.17 Per 1k requests on Pro
Try it live

One field. One curl.
Real audio features.

Type any song. We'll call /lookup against a public demo key and render the response below. No signup, no card, no email.

try:

Public demo key. Per-IP rate-limited via nginx; capped monthly quota. For real usage, grab your own free key — no card, instant by email.


Why this API

Built for developers,
not musicologists.

No ID hunting. No 30-second waits. Send a name, get data. Here's what makes it different.

01
886k+ Tracks Pre-Analysed & Growing · Rest Backfilled in ~15s

Multi-source fallback chain (own catalog + AcousticBrainz + Million Song Dataset + FMA) returns audio features in under 300ms. If we don't have it, Intelligent Backfill fetches the preview from iTunes, runs full Essentia analysis, ingests it, and notifies you when it's ready — any commercial release on iTunes typically resolves in ~15 seconds (always under a minute). Per-track emails for normal use; bulk catalog work rolls into a single daily digest. No upload. No waitlist. Name-based lookup — no ISRC required.

02
Native AI Integration via MCP

The only music metadata API with an MCP server. Add one line to Claude, Cursor, or Windsurf and your AI can query BPM, key, mood, and genre directly — no code required. See setup →

03
High-Fidelity Remix Support

We don't just guess. We analyze the specific audio of remixes, edits, and club mixes — not just the original release — for significantly higher BPM precision.

04
941+ Genres · 12+ Language Families

Standard APIs ship a fixed 100-genre taxonomy. Our catalog carries 941 distinct genres across 12+ language families — Amapiano, Mandopop, Cantopop, Bollywood, Tamil, Telugu, Punjabi, MPB, Sertanejo, Pagode, Baile Funk, Reggaeton, Bachata, Khaleeji, Turkish Pop, French Chanson, Hyperpop, Phonk, UK Drill and more. 96% of all catalog tracks carry a genre tag. See global coverage →

05
Developer-First Concurrency

Audio analysis (/analyze, /identify) runs through per-tier concurrency lanes — Hobbyist 2, Starter 3, Pro 6, Enterprise 8 simultaneous. Catalog /lookup has a generous per-key concurrency cap (6 simultaneous in-flight on Free, 10 on paid — excess parallel calls get an instant 429 with Retry-After: 2) — typically 25–40ms with keep-alive, p95 under 100ms.

06
Fast Cached Responses

Catalog lookups return in ~25–40ms with keep-alive (p95 under 100ms) — results are pre-computed once and served from an in-memory cache. Lookups never trigger live analysis; they just fetch a row. Consistent latency at any scale.

07
Bulk Endpoint — 50 Tracks, 1 Request

POST /bulk resolves up to 50 tracks in a single round-trip — by name or ISRC (exact-match, ideal when your candidates already carry ISRCs from Chartmetric or Spotify), looked up in parallel server-side, so one HTTP call replaces fifty. It's quota-only (no per-minute rate cap), so it scales with your plan's monthly allowance — perfect for playlist enrichment, data pipelines, and recommendation engines.


Global Coverage

Built for the whole world. Not just the Anglosphere.

Spotify's audio_features ML model was trained English-default. AudD recognises mostly Western commercial releases. We mirror what charts in every region we ingest from — Apple Music storefronts across 45 countries, Deezer genre charts, region-specific feeds, plus customer-driven backfill for the long tail. Below: track counts in the catalog right now, by language family.

🇧🇷 Brazil / Portugal Brazilian & Lusophone 6,500+ tracks in catalog
MPBSertanejoPagodeBaile FunkBossa NovaSambaForróAxé
🌍 Africa Afrobeats & African 12,900+ tracks in catalog
AfrobeatsAmapianoAfro HouseAfro-PopAfro-FusionHighlifeBongo-FlavaGqomMaskandi
🇮🇳 South Asia Indian & Subcontinental 3,000+ tracks in catalog
BollywoodTamilTeluguPunjabiMalayalamIndian PopIndian ClassicalBhangra
🇫🇷 France French & Francophone 1,200+ tracks in catalog
French PopFrench ChansonChansonVariété Française
🌍 Middle East & North Africa Arabic & MENA 750+ tracks in catalog
Arabic PopKhaleejiEgyptian PopNorth AfricanLevantineIsraeli
🌏 Southeast Asia Thai · Filipino · SEA 150+ tracks in catalog
T-PopThai PopOPMPinoy PopIndo Pop

Same JSON shape, same 42 fields, in every language. No region flag in the request, no special endpoint, no extra cost. Send artist=BLACKPINK&track=Pink Venom or artist=Bad Bunny&track=Tití Me Preguntó — same response shape. UTF-8 in, BPM/key/energy/genre out. Diacritics, kana, hangul, hanzi, Cyrillic and Arabic are matched via NFKD normalisation; the catalog uses native scripts where Apple Music does. Missing a track? Intelligent Backfill fetches and analyses it in ~15 seconds (always under a minute) — works the same for Tokyo indie as for Tennessee country.


Catalog Coverage

941+ genres.
All pre-analyzed.

From Amapiano to Zydeco, Mandopop to Hyperpop — 941 distinct genres live in the catalog right now, 96% of all tracks carry one. Standard APIs ship a fixed 100-genre taxonomy; we mirror what the catalog actually contains. Click any tag to search the live catalog — results return below.

60s Classics 70s Disco 70s Soul 80s Hip Hop 80s Synthpop 90s Eurodance 90s Pop 90s RnB 2000s Pop 2010s EDM 2010s Indie Afrobeats Afro-Beat Afro House Afropop Afro-Fusion Alternative Alternative Rock Amapiano Ambient Americana Anime Arabic Arabic Pop Bachata Baile Funk Bass Bedroom Pop Big Band Bluegrass Blues Bollywood Bongo-Flava Bossa Nova Brazilian Breakbeat Britpop Cantopop Celtic Chinese Hip-Hop Chinese Rock Christmas Cinematic Classic Rock Classical Classical Crossover Classical Piano Corridos Tumbados Country Country Blues Cumbia Dance Dancehall Darkwave Death Metal Deep House Disco Downtempo Dream Pop Drill Drum & Bass Dubstep East Coast Rap EDM Egyptian Pop Electronic Electropop Emo Eurovision Flamenco Folk Folk-Rock Forró French Chanson French Pop Funk Fusion Future Bass Garage German Folk German Pop Glam Rock Gospel Gqom Grime Grunge Gym Music Happy / Upbeat Happy Hardcore Hard Rock Hardcore Hardstyle Heavy Metal Highlife Hip Hop Honky Tonk House Hyperpop IDM Indian Classical Indian Pop Indie Electronic Indie Folk Indie Pop Indie Rock Industrial Israeli J-Pop Jazz Jazz Fusion Jersey Club Jungle K-Pop Khaleeji Korean Hip-Hop Korean Indie Korean Rock Kuduro Latin Latin Jazz Latin Pop Latin Rap Latin Urban Liquid DnB Lo-Fi Lounge Lovers Rock Malayalam Mandopop Maskandi Math Rock Melodic Techno Merengue Metal Metalcore Modern Dancehall Motown MPB Música Mexicana Música Tropical Neo Soul New Age New Wave North African Nu Metal Old School Rap Orchestral Original Pilipino Music Outlaw Country Pagode Phonk Pop Pop in Spanish Pop Latino Pop Punk Pop Rap Pop Rock Post-Punk Post-Rock Praise & Worship Progressive Rock Psytrance Punjabi Punk Punk Rock R&B R&B/Soul Recession Pop Reggae Reggaeton Regional Mexican Roots Reggae Romantic Running Music Sad Songs Salsa Samba Sertanejo Shoegaze Singer-Songwriter Ska Smooth Jazz Soft Rock Soul Soundtrack Southern Rock Spoken Word Summer Hits Surf Synthpop Synthwave Tamil Tech House Techno Teen Pop Telugu T-Pop Thai Pop Thrash Metal TikTok Viral Top 100 AU Top 100 Global Top 100 UK Top 100 USA Top 50 Canada Top 50 Ireland Trance Trap Trip Hop Turkish Hip-Hop Turkish Pop UK Bass UK Drill UK Garage UK Hip-Hop Underground Rap Urbano Latino Vaporwave Video Game Music Vocal Jazz West Coast Rap Workout Worldwide + 718 more · growing nightly

All 42 fields

Every field you need.
Nothing you don't.

BPM, key, mood, energy, genre, ISRC and 30 more — all pre-computed, all returned in a single API call.

Field Description Coverage
bpm + bpm_confidence Tempo in BPM with per-track confidence score ✅ 100%
bpm_alt Half-time / double-time corrected BPM — populated when our heuristic suggests Essentia locked onto the wrong beat grid (e.g. Blinding Lights returns 85 with bpm_alt=170). Null when no correction is warranted. ✅ when warranted
key + key_int + mode + key_confidence Musical key (human-readable e.g. C#-Minor) plus Spotify-shaped numeric form: key_int = pitch class 0–11, mode = 0 minor / 1 major, plus confidence ✅ 100%
camelot + open_key Camelot wheel notation (e.g. 8A) and Open Key (e.g. 1m) for harmonic mixing ✅ 100%
energy 0–1 normalised RMS energy ✅ 100%
loudness_db LUFS-style dB reading ✅ 100%
time_signature Integer beats per bar ✅ 100%
danceability Tempo + beat strength + regularity ✅ 100%
valence Musical positivity — scale + tempo + brightness + energy ✅ 100%
acousticness Spectral-flatness estimate — approximate; calibrate per use-case ✅ 100%
instrumentalness MFCC vocal-formant estimate — approximate; calibrate per use-case ✅ 100%
liveness Noise-floor / room-ambience proxy — approximate; calibrate per use-case ✅ 100%
speechiness Zero-crossing-rate estimate — approximate; calibrate per use-case ✅ 100%
mood MIREX-style label: happy, calm, sad, tense, energetic, melancholic, neutral ✅ 100%
mood_vector 5-axis probabilities: happy, sad, aggressive, relaxed, party ◯ AB-only
representative_segment_start Highest-energy 30s window — 0.0 for 30-second previews (most of the catalog); non-zero only on full-length uploads ✅ 100%
onset_rate Onset events per second — higher = more rhythmic / percussive ◯ AB-only
dynamic_complexity Loudness variation across the track (dB) — higher = wider dynamic range ◯ AB-only
tuning_frequency Estimated A4 reference in Hz — modern recordings cluster near 440 ◯ AB-only
average_loudness Normalised average loudness [0–1] — perceptual-loudness reference ◯ AB-only
mbid MusicBrainz recording ID for cross-referencing other databases ◔ ~6%
isrc International Standard Recording Code ◑ ~75%
is_remix + remixer + mix_name + remix_of_isrc Remix labelling parsed from the title — is_remix (true/false), the remixer credit when attributable, the mix_name version label (e.g. Extended Mix, Alesso Remix), and remix_of_isrc — the ISRC of the original recording a remix is based on, so you can jump straight to the source. Populated for catalog remix/version rows; null on fallback layers. ◔ remix rows
genre Genre tag — primarily iTunes, then AcousticBrainz and Last.fm ◕ ~96%
feature_source Provenance label for the row: essentia_preview (analysed from a 30s preview by this pipeline — bpm/key/meter via Essentia, loudness via librosa, valence/energy/danceability via librosa-derived heuristics), acousticbrainz (MBID-matched, July 2022 dump), fma, msd, or user_upload. See the migration thresholds guide for per-field numerical implications when comparing to Spotify. ✅ 100%
album_name + release_date Album or single title and ISO 8601 release date ◕ ~99%
duration_ms Full track length in milliseconds ◕ ~99%
explicit Boolean explicit flag from catalog ◕ ~97% rising
source + first_ingested_at Which chart/source first surfaced this track and when ✅ 100%

Coverage snapshot — 2026-07-17. Percentages measured against our 886,691-track own catalog. populated on every catalog row. ≥80% — fills via our MusicBrainz enrichment pass. 50–80%. <50% — fills gradually via MusicBrainz resolution at lookup time plus Deezer enrichment on chart-source ingests. AB-matched only — populated where the track's MusicBrainz ID exists in the AcousticBrainz July-2022 dump (a partial slice of the current catalog; the MBID-bearing share has been diluted as the catalog has grown from 50k → 886k+ via on-demand backfill). These are research-grade descriptors with no active backfill path — the AB-matched slice is frozen, so its share of the catalog gradually declines as the catalog grows. The low-coverage fields above are different: they keep rising over time via MusicBrainz resolution at lookup time plus Deezer enrichment on chart-source ingests.

Pricing

Simple, honest pricing.

No per-request billing surprises. Pay monthly, cancel anytime. Free keys are instant — paid plans activate immediately on checkout.

🌍 Prices are shown in your local currency and charged in that currency at checkout — switch any time with the currency selector at the bottom-left.

Billing Save 15%
Free
£0 /month
Forever-free — first 1,000 requests / month

Build a proof of concept. No card required.

  • 1,000 requests/month
  • On-demand track fetches — no daily cap
  • /analyze + /lookup + /bulk
  • ~20 bulk batches/month (50 tracks each)
  • 50 req/min rate limit
  • 1 concurrent analysis
  • Usage dashboard
  • Email support
Starter
£39 /month
£0.26 per 1,000 requests
Billed annually

Ship your integration. Enough headroom for a live product.

  • 150,000 requests/month
  • On-demand track fetches — no daily cap
  • /analyze + /lookup + /bulk
  • ~3,000 bulk batches/month (50 tracks each)
  • 600 req/min rate limit
  • 3 concurrent analyses
  • Usage dashboard
  • Email support
Start building
Professional
£129 /month
£0.17 per 1,000 requests
Billed annually

High-volume apps, teams, and production workloads.

  • 750,000 requests/month
  • On-demand track fetches — no daily cap
  • /analyze + /lookup + /bulk
  • ~15,000 bulk batches/month (50 tracks each)
  • 600 req/min rate limit
  • 6 concurrent analyses
  • Usage dashboard
  • Priority email support
Go Professional
Enterprise
Custom
Custom volume pricing — talk to us

Unlimited volume, dedicated infrastructure, and full catalog licensing.

  • Unlimited requests
  • Dedicated API instance
  • SLA available on request
  • Full catalog data license
  • Dedicated support
  • Priority backfill — your missing tracks jump the analysis queue
Talk to us

Cost calculator

How much would 15,000 requests / month cost?

Drag the slider. We compare what you'd pay on FreqBlog versus the closest commercial alternatives at the same monthly volume.

Comparison rates pulled from each provider's published pricing in 2026: AudD ($5/1k → $3.60/1k volume tier), MusicAPI.com (€189/12k → €890/120k tiers, ~€7.40–€15.75 per 1k), Cyanite (custom pricing — listed at indicative $0.01/track). Currency conversion via open.er-api.com.


Limits

Limits & rate limits.

Three independent limits per plan — all visible on your dashboard, and every limit response tells you how long to wait.

Plan Requests / month Rate limit*
Free1,00050 / min
Hobbyist15,000300 / min
Starter150,000600 / min
Pro750,000600 / min

*The per-minute rate limit applies to the upload endpoints /analyze and /identify. Lookup endpoints (/lookup, /bpm, /key, /bulk, /v1/audio-features) are quota-only. Monthly quota resets on the 1st; /identify costs 2 requests per call.

Free-tier on-demand. Every free /lookup for a track that isn’t in the catalogue yet gets analysed on demand and added to the catalogue — we email you when it’s ready. There’s no daily cap; you’re bounded only by your monthly quota (1,000 lookups/mo on Free). Upgrade for a higher quota.
Response Meaning What to do
200Found — full data returned.
202Not in the catalogue yet — queued for on-demand analysis (~15s, occasionally up to a minute under load). This is a success, not an error.Add ?wait=N (up to 25s) to /lookup to hold the request and get the track back inline (200) in the same call — otherwise retry shortly (honours Retry-After), or wait for the email / dashboard notice when ready.
404No match anywhere (and no title to ingest from).Check spelling, or try ?isrc= / ?mbid=.
422A required parameter is missing or malformed — e.g. no track, bpm, or ids supplied.Add the parameter the endpoint expects; the detail field names it.
429A limit hit — per-minute rate, monthly quota, or the per-key /lookup concurrency cap.Honour the Retry-After header and back off; if it's the monthly quota, upgrade or wait for the 1st.
401Missing or invalid API key.Send X-Api-Key or ?key=; check the key email (incl. spam).
413Upload over the 15 MB /analyze / /identify limit.Trim to a ~30s clip or lower the bitrate.
415Unsupported / unreadable audio file.Use MP3/WAV/OGG/FLAC/AAC–M4A; re-export if corrupt.
503Genuine service unavailability — not normal back-pressure. Slow batches no longer 503: /bulk, /bulk-csv & /v1/audio-features all return a 200 with partial results (uncharged).Check the status page; retry shortly.

Audio fingerprinting

Upload audio.
Know what it is.

Send any clip, get back the title, artist, MusicBrainz ID and ISRC of the recording it represents — plus the full 42-field FreqBlog audio analysis when the track is already in our catalog. Powered by Chromaprint fingerprinting and the AcoustID open dataset of 60M+ recordings.

🎙️
Same input shape as /analyze

Multipart upload, MP3 / WAV / FLAC / AAC / OGG, max 15 MB. Returns within ~2 seconds for a 60-second clip. Audio is held in /dev/shm (RAM tmpfs) for fingerprinting and unlinked the moment Chromaprint returns — no audio is written to durable storage.

🔗
Catalog hit = full features for free

When the matched MBID resolves to a track in our catalog, the response carries the full audio_features object — BPM, key, mood, valence, danceability, AcousticBrainz descriptors. No second round-trip needed.

💸
Audio fingerprinting included

/identify charges 2 quota requests (vs 1 for the rest), so on Pro that's £0.34 per 1,000 identifications. AudD's lowest tier is $5/1k. Same Chromaprint fingerprinting, same AcoustID dataset.

🧱
Same concurrency lanes as /analyze

CPU-bound work runs through the per-tier semaphores already protecting /analyze — Free 1, Hobbyist 2, Starter 3, Pro 6, Enterprise 8 concurrent. No surprise contention with your other endpoints.

$ curl -F "[email protected]" \
       -H "X-Api-Key: sk_live_..." \
       https://api.freqblog.com/identify

{ "matched": true,
  "score": 0.94,
  "mbid": "5b11f4ce-a62d-471e-81fc-a69a8278c7da",
  "isrc": "CAUM71900002",
  "track_name": "Blinding Lights",
  "artist_name": "The Weeknd",
  "in_catalog": true,
  "audio_features": { "bpm": 85.39, "bpm_alt": 170.78, "key": "F-Minor", "camelot": "4A", "mood": "tense", ... }
}

When the recording isn't in our catalog yet, audio_features is null — call /lookup with the returned name + artist to queue an on-demand analysis — add ?wait=N (up to 25s) to get the features back in the same call.


Recommendation engine

One call.
Acoustically similar tracks.

Pass a track id, get the 10 most acoustically similar tracks in the catalog. Cosine similarity over an 18-feature audio embedding — BPM, key, energy, loudness, danceability, valence, mood and AcousticBrainz descriptors. No model to host. No vector DB to manage.

Sub-millisecond ranking

A single matrix multiply over the entire audio-feature index returns ranked recommendations faster than your network round-trip. No vector DB, no ANN tuning, no infrastructure to babysit.

🎯
Honest data, not fake matches

Per-feature z-score normalisation runs over real values only, so a track with 8 real features doesn't get false-matched to one with only 2. Tracks with too few real features are filtered from results entirely.

🎚️
Cross-artist filter, free

exclude_same_artist=true drops other tracks by the seed's artist — ideal for "more like this, but different" radio feeds and discovery lanes.

🛰️
The Spotify /recommendations replacement

Spotify removed /v1/recommendations and related-artists in Nov 2024 — we shipped both back. /recommendations blends up to 5 seed tracks into one centroid and returns nearest tracks re-ranked by genre affinity; /related-artists derives an artist graph from the same index — no editorial listening data needed.

💸
A fraction of Cyanite's price

Cyanite charges enterprise rates for similarity tagging. We return cosine similarity over a fully transparent 18-feature embedding for the same £0.17 per 1,000 requests as everything else.

$ curl https://api.freqblog.com/similar?track_id=1488408568&limit=3 \
       -H "X-Api-Key: sk_live_..."

{ "seed": { "track_name": "Blinding Lights", "artist_name": "The Weeknd" },
  "count": 3,
  "results": [
    { "score": 0.94, "track": { "track_name": "Don't Start Now", "artist_name": "Dua Lipa" } },
    { "score": 0.91, "track": { "track_name": "Levitating",    "artist_name": "Dua Lipa" } },
    { "score": 0.89, "track": { "track_name": "Save Your Tears", "artist_name": "The Weeknd"  } }
  ]
}

Pass any itunes_track_id from a /lookup, /search, or /bpm response. Counts as one quota request regardless of result count.


DJ-ready exports

Skip Mixed In Key.
Just call /export.

Generate a Pioneer Rekordbox XML, M3U, or plain-text cuesheet from any list of catalog ids — with BPM, Camelot key, and a hot cue at the chorus already baked in. Pair with /radio to build a harmonic playlist in one chained call.

🎚️
/radio — Harmonic playlist generator

Greedy walk over the similarity index that respects Camelot wheel adjacency and BPM continuity. Pass a seed and get a 30-track playlist that flows like a real DJ set, no ML model to host.

📁
/export/rekordbox — Pioneer XML

Full Rekordbox 1.0.0 XML with AverageBpm, Tonality, and a POSITION_MARK cue at the highest-energy 30-second window — that's your "Chorus" hot cue out of the box.

📝
/export/m3u + /export/cuesheet

Extended M3U for Serato / Traktor / Engine DJ / VirtualDJ, or a paste-friendly plain-text cuesheet for chats and notebooks. Same data, three formats, one quota request.

📈
/charts/<country> — Live national charts

Real-time top-songs feeds for 45 countries, sourced from Apple Music RSS and cross-referenced against the catalog so you can pipe a chart directly into /lookup, /similar, or your /export chain. Cached 12 hours.

🎛️
Harmonic Set Builder — we score the flow, not just the fields

Other APIs hand you raw key and BPM and leave the mixing to you. We score the transition itself. /transition rates any two tracks 0–100 on Camelot-wheel key fit, octave-aware BPM proximity (half/double-time counts) and energy smoothness, with a plain-English reason. /next-track ranks a seed’s sonic neighbours by that score. POST /setlist orders a whole crate (2–100 tracks) into a peak_time / warmup / cooldown energy arc and hands back a flow_score — then chain into /export/rekordbox to drop the set straight into your decks.

# 1. Generate a 20-track harmonic playlist from a seed
$ curl "https://api.freqblog.com/radio?seed_track_id=1488408568&n=20" \
       -H "X-Api-Key: sk_live_..."

# 2. Pipe its track ids straight into a Rekordbox XML download
$ curl "https://api.freqblog.com/export/rekordbox?track_ids=$IDS" \
       -H "X-Api-Key: sk_live_..."  -o playlist.xml

# 3. Drag playlist.xml into Rekordbox → ready to mix.
# Each TRACK already has BPM, Tonality (Camelot key) and a Chorus cue point.
# Score how cleanly one track mixes into another
$ curl "https://api.freqblog.com/transition?from_track_id=1488408568&to_track_id=1871990263" \
       -H "X-Api-Key: sk_live_..."

{ "score": 99,
  "components": { "harmonic": 100, "tempo": 96, "energy": 99 },
  "reason": "4A→4A same key, 85→85 BPM (-0.44), energy -0.004" }

# Order a crate into a peak-time set, then export it to Rekordbox
$ curl -X POST "https://api.freqblog.com/setlist" \
       -H "X-Api-Key: sk_live_..." -H "Content-Type: application/json" \
       -d '{"track_ids": ["1488408568","1871990263","1527115454"], "arc": "peak_time"}'

$ curl "https://api.freqblog.com/export/rekordbox?track_ids=$ORDERED_IDS" \
       -H "X-Api-Key: sk_live_..."  -o set.xml

Quota: /radio and /transition cost 1 request each, /next-track counts as 3 and /setlist as 5 — charged only on a served result. Track audio is referenced via a synthetic freqblog://<id> location — relink to your local library after import using your DJ software's built-in tools.


Auto-Enrichment

Incomplete data?
We'll fill it in automatically.

Missing genre, release date, or ISRC? The API queues a background job to enrich the track. Your search returns instantly — the data arrives via email and dashboard.

Intelligent Data Merge

On every incomplete track, the worker intelligently enriches and merges results by field authority. Searches return instantly — enrichment happens in the background.

📧
Email Notifications

Get an email when a track you searched for is enriched. The notification includes the track name, artist, and which fields were populated. Above the per-day cap (5 free / 20 paid), notifications roll up into a single end-of-day digest — bulk catalog work won't flood your inbox.

📊
Dashboard Visibility

See all your enriched tracks via the API. Query /backfill/notifications to list completed backfills with timestamps and updated fields.

🔄
Non-Blocking

The backfill job runs in the background — your search response is instant. Backfill jobs use exponential backoff and rate limiting, so they never hammer external APIs or impact response times.

How it works: Search /lookup for a track with missing fields (e.g., genre is null). The API returns the partial result instantly and queues a background job. The worker enriches the track, updates the database, and logs a notification. Per-track emails arrive within ~2 minutes; on a heavy catalog pass they roll up into a single end-of-day summary instead, so a big backfill never spams your inbox. Query /backfill/notifications anytime to see completed enrichments.

📖 Full guide: For API endpoints, integration examples, and troubleshooting, check the API documentation.


Under the hood

Academic-grade analysis.
Production-grade speed.

The core fields — BPM, key, energy and loudness — come from peer-reviewed signal-processing libraries (MTG-Essentia, librosa) used in academic music research. The perceptual descriptors (mood, valence and the timbral estimates) are lighter signal-analysis heuristics — useful, but calibrate before you rely on them. Audio is processed in memory and never written to disk.

MTG-Essentia · RhythmExtractor2013
BPM Detection

Beat-tracking algorithm from the Music Technology Group at Universitat Pompeu Fabra. Returns a track-level confidence score alongside the BPM — so you know how reliable each result is. Time signature is inferred from the detected beat grid (defaults to 4/4 when beats are too sparse).

bpm bpm_confidence time_signature
MTG-Essentia · KeyExtractor
Key Detection

Chromagram-based key estimation using the HPCP (Harmonic Pitch Class Profile) algorithm. Returns human-readable key names (e.g. "A-Minor") with a 0–1 confidence score.

key key_confidence mode camelot open_key
Librosa · RMS + amplitude_to_db
Energy & Loudness

Root Mean Square energy normalised to 0–1, plus mean loudness in dBFS — the standard digital full-scale reference.

energy loudness_db
Librosa · Spectral + MFCC analysis
Descriptors & Mood

Six audio descriptors computed via spectral flatness, zero-crossing rate, MFCC vocal formants, dynamic-range ratio, and tempo analysis. The four timbral estimates (acousticness, instrumentalness, liveness, speechiness) are coarse approximations — calibrate per use-case. Mood is derived from the MIREX four-quadrant model — valence vs. energy.

danceability valence mood acousticness instrumentalness liveness speechiness
Signal Processing · ID Lookup
Segment Detection & Identifiers

On full-length uploads, a sliding window finds the highest-energy 30-second segment — pinpointing the chorus or drop. For the 30-second previews that make up most of the catalog it returns 0.0 (the preview is already the clip). Cross-references recording databases for MBID and ISRC codes used in rights tracking.

representative_segment_start mbid isrc
Public Music APIs · Catalog Data
Track Metadata

Release metadata captured at ingest time — no extra lookup required. Every catalog track includes album, release date, full track length, and explicit flag alongside the audio features.

album_name release_date duration_ms explicit source first_ingested_at
MTG-Essentia · Public Music Classifiers
Multi-Source Fallback

When a track isn't in our live catalog, we look it up in curated datasets of pre-analyzed tracks. Returns mood, mood_vector (5-axis dimensional scores), genre, acousticness, and instrumentalness alongside BPM and key. These fields are also backfilled for catalog tracks when a match is found; they are null when no match exists.

mood mood_vector genre acousticness instrumentalness
Creative Commons · Public Datasets
Valence & Creative Commons

13,000+ Creative Commons tracks from public archives — used to compute valence and other emotional descriptors not derivable purely from local signal analysis. Acts as enrichment for any result missing valence, and as a standalone fallback for indie/CC catalog.

valence danceability energy acousticness instrumentalness liveness speechiness
Academic Research · Public Archives
1M-Track Historic Catalog Fallback

1 million tracks from 1955–2011 with full audio features including tempo, key, mode, loudness, energy, and danceability. Ideal for classic rock, jazz, pop, and historic catalog not covered by the live ingest. Matched by artist + title name lookup.

bpm key mode loudness_db energy danceability

Zero-footprint pipeline — uploaded audio is processed in memory and discarded the moment analysis completes. Nothing is written to disk and no audio is retained.


AI Integration

The only music API
your AI can use natively.

Paste one URL into Claude, Cursor, or Windsurf — zero install, no API key — and your AI looks up BPM, key, mood, and genre as a first-class tool. No code required. Prefer a local server with the full 23-tool set? The music-metadata-mcp npm package has you covered too.

1 · Try it free

Paste the hosted connector URL. No key, no install — shared monthly cap. Start ↓

2 · Your own quota

Free key + the npm package — 1,000 req/mo, no card, full 23 tools. Get a key

3 · Build on the API

Direct HTTP / SDK from £0.17 / 1,000 — webhooks, bulk CSV, SLAs. See pricing →

New · Hosted One-click connector — nothing to install

In Claude, open Settings → Connectors → Add custom connector and paste the URL below. No npm, no API key — it works in Claude (web, desktop & mobile), Cursor and Windsurf.

Connector URL
https://mcp.freqblog.com/mcp

Cursor — {"mcpServers":{"freqblog-music":{"url":"https://mcp.freqblog.com/mcp"}}}
Windsurf — same, but the field is serverUrl.

Or run it locally — npm package, your own key, full 23 tools

Claude Desktop
~/.claude/claude_desktop_config.json
JSON
{
  "mcpServers": {
    "music-metadata": {
      "command": "npx",
      "args": ["music-metadata-mcp", "--api-key=sk_live_YOUR_KEY"]
    }
  }
}
Cursor / Windsurf
.cursor/mcp.json  or  .windsurf/mcp.json
JSON
{
  "mcpServers": {
    "music-metadata": {
      "command": "npx",
      "args": ["music-metadata-mcp", "--api-key=sk_live_YOUR_KEY"]
    }
  }
}

Once connected, your AI can answer questions like:

"What's the BPM and key of Blinding Lights by The Weeknd?"
"Find me 10 tracks in A-Minor around 128 BPM"
"What's the mood and genre of Come to Daddy by Aphex Twin?"
"Build me a harmonic playlist starting in 8A, 126 BPM"

Hosted connector — 12 tools

get_audio_features get_audio_features_batch search_catalog find_tracks_by_bpm find_tracks_by_key find_compatible_keys

The hosted connector exposes 12 tools — the core six (audio features, batch, search, BPM & key discovery, harmonic keys) plus transition scoring, next-track, setlist & recommendations — zero install. The music-metadata-mcp npm package (npx or npm i -g) adds the full 23-tool set: harmonic radio, DJ export, country charts, lyrics, waveforms & more.

Connector reference — what each tool does

get_audio_features — Audio features for one track: BPM, key (name + Camelot + Open Key), energy, danceability, valence, acousticness, instrumentalness, mood, genre, time signature & more. Identify by name+artist, ISRC, MusicBrainz ID, or Spotify ID. Read-only.
get_audio_features_batch — The same features for up to 50 tracks in one call — ideal for analysing a whole playlist. Read-only.
search_catalog — Full-text search by track / artist / album to resolve a fuzzy or partial name into a concrete track before looking up features. Read-only.
find_tracks_by_bpm — Find catalog tracks near a target tempo (± tolerance), each with full features — for DJ sets and workout playlists. Read-only.
find_tracks_by_key — Find tracks in a given musical key (Camelot, Open Key, or key name) for harmonic, key-locked playlists. Read-only.
find_compatible_keys — Given a Camelot key, return the harmonically compatible keys for mixing (same key, relative major/minor, adjacent ±1, and optionally ±7 energy boost/drop). Pure music theory, no quota. Read-only.

Setup

  1. In Claude, open Settings → Connectors → Add custom connector and paste https://mcp.freqblog.com/mcp (include the /mcp path). No account or API key.
  2. Enable the connector, then ask a music question (see the examples above) — Claude calls the tools automatically. In Cursor/Windsurf, add the same URL under mcpServers.

Troubleshooting

No tools appear / it won't connect. Paste the full URL including the /mcp path, and add it as a custom / remote connector (not a local one). It's authless — no key is required.
A lookup says “queued” or returns null fields. The track wasn't in the catalog yet, so an on-demand analysis was queued — retry in ~15s (up to a minute under load). For fuzzy names, call search_catalog first.
Track not found. Add the artist, or pass an isrc, mbid, or spotify_id for an exact match.
BPM looks like half what I expected. bpm is the raw value (e.g. 85 for “Blinding Lights”); the perceptual tempo (~171) is in bpm_alt. This is by design.
“Usage cap” / HTTP 429. The shared free hosted-connector cap for the month was reached; it resets next month. For your own quota and the full 23 tools, grab a free key and the music-metadata-mcp npm package.

Still stuck? Email [email protected].


Enterprise checkboxes

Webhooks. SDKs.
Bulk CSV. Signed.

The boring infra-team checklist that often blocks production. Webhooks signed with HMAC-SHA256, single-file Python and Node SDKs, bulk CSV enrichment, and a plain-language Security & Data Handling page covering GDPR posture, subprocessors and DPA contact.

🪝
Backfill webhooks — signed

Configure an HTTPS callback via POST /me/webhook and we'll POST a JSON event when your on-demand ingests (ingest.completed/.failed) and backfills finish — so a pipeline is pushed the result (with a result_url) instead of polling. Each request is signed with a timestamp-bound X-FreqBlog-Signature: sha256=… — reject anything else.

🐍
Single-file Python SDK

~200 lines. httpx only. curl -O https://freqblog.com/sdk/freqblog.py and you're done. Includes a one-line verify_webhook() helper.

🟩
Single-file Node SDK

~150 lines. Zero dependencies on Node 18+ (uses native fetch). CJS + ESM. Same verifyWebhook() contract as the Python.

📊
/bulk-csv — CSV in, CSV out

POST a CSV with artist,title columns; get the same CSV back with 26 audio-feature columns appended. Up to 500 rows per call. No new schema to learn — just enrich whatever CSV you already have.

SDK & webhook docs → Security & data handling →

BPM API Reference

Simple REST API. One header.

All requests authenticated with a single header. Interactive OpenAPI docs at /docs.

Base URL https://api.freqblog.com
Auth Header X-Api-Key: <your_key>
Response application/json
All requests require: X-Api-Key: your_key_hereRequest your free key to get started.
POST
/analyze
Upload audio file (MP3, WAV, OGG, FLAC, AAC/M4A — max 15MB). Returns full analysis. Use for tracks not yet in the catalog.
POST
/identify New
Upload audio (any format ffmpeg can decode, max 15 MB) and identify the recording via Chromaprint + AcoustID. Returns track name, artist, MBID, ISRC, score, and full audio features when the matched recording is in our catalog. Counts as 2 quota requests.
GET
/lookup?track=<name>&artist=<name>
Name-based catalog search. Returns instantly for pre-analyzed tracks. If not in catalog, falls through an intelligent multi-source fallback chain. Case-insensitive. Artist is optional but improves accuracy.
GET
/bpm?bpm=128&tolerance=2&limit=10
Find tracks by BPM. Returns catalog tracks within ±tolerance of the target BPM, ordered by proximity then popularity. No audio upload needed.
GET
/key?q=8A&limit=10
Find tracks by musical key. Accepts Camelot (8A), Open Key (1m), or key name (A-Minor). Results ordered by popularity. No audio upload needed.
GET
/search?q=<text>&limit=10 New
Full-text search across track name, artist name, and album name. SQLite FTS5-backed; each whitespace-separated token is matched as a prefix. Returns lightweight track stubs (no audio features) ordered by relevance, then popularity.
GET
/artist/tracks?artist=<name>&limit=20&offset=0 New
List catalog tracks for an artist (case-insensitive exact match on artist name). Paginated via limit + offset.
GET
/genres New
List every genre in the catalog with track counts. Useful for filter UIs and discovery dashboards. Sorted by count descending.
GET
/genres/<name>/tracks?limit=20&offset=0 New
List tracks tagged with a given genre (case-insensitive). Paginated.
GET
/key/<camelot>/compatible?extended=true New
Pure-logic helper — return harmonically compatible keys for an input Camelot value (e.g. 8A). Always includes same, relative, adjacent_up, adjacent_down; with extended=true also energy_boost (+7) and energy_drop (-7). No quota, no auth.
GET
/track/<id>/embedding New
Project a track's audio features into an 18-dimensional numeric vector — for similarity search, clustering, or feeding into your own ML model. Returns embedding, embedding_mask (which positions are real vs filler), and fields (positional field names). Pass an itunes_track_id from any /search or /lookup response.
GET
/track/<id>/artwork?size=300|600|1200 New
302-redirect to a cover-art image. Resolution order: iTunes Lookup API for numeric catalog ids, then Cover Art Archive via the track's MusicBrainz release MBIDs. Sizes: 100, 200, 250, 300, 500, 600, 1000, 1200 (closest snap). Hits are cached 30 days; misses too.
GET
/track/<id>/lyrics New
Synced + plain lyrics for a catalog track via the open LRClib dataset. Synced lyrics come back parsed as [{ms, text}] — no LRC math client-side. Cached 30 days per (track, artist).
GET
/track/<id>/waveform.svg?w=600&h=80 New
SVG waveform render of the track's 30-second iTunes preview. 120 RMS-bucketed bars, themable via CSS currentColor. Sizes 120×20 to 2400×400. Buckets cached 90 days — subsequent renders take ~1 ms.
GET
/similar?track_id=<id>&limit=10&exclude_same_artist=false New
Recommendation engine. Cosine similarity over the 18-feature embedding across the entire catalog. Returns ranked {track, score} pairs. Pass exclude_same_artist=true for cross-artist discovery feeds. Tracks with too few real features (< 6) are filtered from both seeds and candidates.
GET
/tag?track=<name>&artist=<name> New
Compact, honestly-labelled tags for a track — energy, danceability, valence, acousticness, instrumentalness, mood and a broad genre — resolved by name, isrc, mbid, spotify_id or catalog track_id. A tag-shaped projection of /lookup (no upload, no new compute). Every tag carries a confidence (measured / derived / model-estimated / catalog-genre) and a provenance, so you know exactly what’s measured vs estimated. Counts as 1 quota request.
GET
/recommendations?seed_tracks=<id1,id2,…>&limit=20&exclude_seed_artists=false New
The Spotify /v1/recommendations replacement. Blends 1–5 seed track ids into a feature-space centroid and returns the nearest catalog tracks re-ranked by genre affinity — so a feature-close cross-genre track doesn’t outrank same-genre picks. Each result carries the raw audio-feature cosine score (genre drives the order, so the list isn’t strictly score-descending). Optional exclude_seed_artists=true. Counts as 2 quota requests.
GET
/related-artists?artist=<name>&limit=20 New
The Spotify related-artists replacement. Derives an artist graph from the similarity index: the seed artist’s track-vector centroid → nearest tracks → aggregated by artist, each scored on its top-3 track sims (so a prolific catalogue can’t dominate) plus a same-genre lift and cross-genre penalty. Returns related artists with score, match_count and a sample_track_id. Counts as 2 quota requests.
GET
/charts/<country>?type=most-played&limit=50 New
Live national music chart for any of 45 supported countries (ISO alpha-2). Sourced from Apple Music RSS, cached 12 hours per country/limit. Each entry is cross-referenced against the catalog so in_catalog=true entries carry a full TrackStub.
GET
/radio?seed_track_id=<id>&n=20&max_key_distance=2&bpm_drift=8 New
Harmonic + BPM-continuity playlist generator. Greedy walk over the similarity index that respects Camelot wheel adjacency and per-step BPM drift. Returns the playlist in play order — pipe straight into /export/rekordbox for a ready-to-mix XML.
GET
/transition?from_track_id=<id>&to_track_id=<id> New
Score how cleanly two catalog tracks mix (0–100): Camelot-wheel key compatibility + octave-aware BPM proximity (half/double-time counts as a match) + energy smoothness. Returns score, the harmonic/tempo/energy components and a plain-English reason. Counts as 1 quota request.
GET
/next-track?seed_track_id=<id>&n=10&min_score=0&exclude_same_artist=false New
The seed’s sonic neighbours re-ranked by transition score — each suggestion carries its score, components and reason. Tune with min_score, bpm_drift and max_key_distance. Counts as 3 quota requests.
POST
/setlist New
Order a crate into a beat-matched set. POST {"track_ids": […], "arc": "peak_time"} (2–100 ids; arc = peak_time/warmup/cooldown/flat). Returns the play order, per-step transition scores and an overall flow_score — pipe the ordered ids into /export/rekordbox. Counts as 5 quota requests.
GET
/export/<format>?track_ids=id1,id2,… New
Generate a DJ-ready playlist file. Formats: rekordbox (Pioneer XML 1.0.0 with hot cues), m3u (Extended M3U8 for Serato/Traktor/Engine DJ/VirtualDJ), or cuesheet (plain text). Up to 200 tracks per call.
POST
/bulk-csv (multipart, field=file) New
Upload a CSV with artist,title columns and receive an enriched CSV with all 26 audio-feature columns appended. Up to 500 rows per request. Each row counts as one quota request.
GET
/me/webhook New
Get / set / clear an HTTPS webhook URL for completion events (ingest.completed, ingest.failed, backfill.completed). POST {"url": "https://..."} to set (public https only), DELETE to clear. Each fired webhook carries X-FreqBlog-Timestamp + a timestamp-bound X-FreqBlog-Signature: sha256=<hex>; verify with the SDK helper.
GET
/health
Service health check. No auth required.
GET
/docs
Interactive OpenAPI documentation (Swagger UI). No auth required.

Example response — /lookup or /analyze

JSON Response
{
  "track_name": "Blinding Lights",
  "artist_name": "The Weeknd",
  "album_name": "Blinding Lights - Single",  // catalog metadata
  "itunes_track_id": "1488408568",
  "isrc": "USUMV2403154",
  "mbid": "1227659f-a933-4549-8fc4-d839b4cd3d45",
  "is_remix": false,             // true for a third-party remix; then remixer + mix_name populate
  "remixer": null,               // e.g. "Alesso" on a remix
  "mix_name": null,              // e.g. "Extended Mix" / "Alesso Remix"
  "remix_of_isrc": null,        // on a remix: the ISRC of the original it's based on
  "release_date": "2019-11-29",
  "duration_ms": 201570,          // track duration in milliseconds
  "explicit": false,
  "source": "itunes_search",      // source identifier
  "first_ingested_at": "2026-04-05 07:39:31",
  // ── tempo · key · loudness — the precise, deterministic fields ──
  "bpm": 85.39,                  // raw detected tempo (never auto-doubled)
  "bpm_alt": 170.78,             // half/double-time candidate — use when the genre runs faster
  "bpm_confidence": 3.6127,      // higher = more confident; typical range 0–10
  "key": "F-Minor",
  "key_confidence": 0.9124,      // 0–1
  "mode": 0,                      // 0 = minor, 1 = major
  "key_int": 5,                   // pitch class 0–11
  "camelot": "4A",               // harmonic mixing notation (Camelot wheel)
  "open_key": "9m",              // Open Key notation (Serato / Mixed In Key)
  "loudness_db": -10.96,         // dBFS integrated loudness
  "time_signature": 4,
  "mood": "tense",                // happy · calm · sad · tense · energetic · melancholic · neutral
  "genre": "synthwave",
  // ── feel — useful, but approximate; calibrate to your use-case ──
  "energy": 1.0,                 // 0–1 normalised RMS
  "danceability": 0.7036,        // 0–1
  "valence": 0.4224,             // 0–1; high = happy/euphoric
  // acousticness, instrumentalness, liveness, speechiness also returned — coarse perceptual estimates; see the field guide before relying on them
  "mood_vector": null,            // 5-axis probabilities — populated when AB low-level present
  "representative_segment_start": 0.0,  // seconds into track; highest-energy 30s window
  "onset_rate": null,             // onset events per second (AB low-level)
  "dynamic_complexity": null,    // loudness variation, dB (AB low-level)
  "tuning_frequency": null,     // A4 reference, Hz (AB low-level)
  "average_loudness": null,     // normalised loudness (AB low-level)
  "feature_source": "essentia_preview",  // where the audio features came from
  "backfill_status": null,         // 'queued' if missing fields are being enriched
  "backfill_notification_id": null
}

Multi-source fallback response (track not in live catalog)

Automatically resolved via an intelligent multi-source fallback chain. Fields populated vary by which source matched.

JSON /lookup fallback
{
  "track_name": "Windowlicker",
  "artist_name": "Aphex Twin",
  "bpm": 136.0,
  "key": "F-Minor",
  "camelot": "4A",
  "open_key": "9m",
  "danceability": 0.8142,
  "acousticness": 0.0312,       // spectral analysis
  "instrumentalness": 0.9821,   // vocal-detection score
  "mood": "energetic",            // derived from valence + energy
  "mood_vector": {"happy": 0.18, "sad": 0.21, "aggressive": 0.64, "relaxed": 0.11, "party": 0.88},
  "onset_rate": 3.42,
  "dynamic_complexity": 4.18,
  "tuning_frequency": 439.6,
  "average_loudness": 0.812,
  "genre": "electronic",          // genre classification
  "mbid": "b10bbbfc-cf9e-42e0-be17-e2c3e1d2600d",
  "isrc": "GBAAN9800112",
  "feature_source": "acousticbrainz"
}
Code Examples

Integrate in minutes.

Pick your language and drop it straight into your project.

★ Spotify-shape — host-swap, same response structure (values may need threshold-tuning)

curl /v1/audio-features/{id}
curl "https://api.freqblog.com/v1/audio-features/0VjIjW4GlUZAMYd2vXMi3b" \
  -H "X-Api-Key: your_key_here"

# Returns Spotify's exact AudioFeaturesObject shape.
# {id} auto-detects: 22-char Spotify ID or 12-char ISRC (hyphens optional).
# NOTE: a raw Spotify ID only resolves tracks we've already mapped to one
#       (a minority of the catalog) — for full coverage use the ISRC, or
#       look up by name: GET /lookup?track=...&artist=...
# Batch: GET /v1/audio-features?ids=id1,id2,...   (up to 100)

Name-based lookup (instant for chart tracks)

curl /lookup
curl "https://api.freqblog.com/lookup?track=Blinding+Lights&artist=The+Weeknd" \
  -H "X-Api-Key: your_key_here"

Find tracks by BPM

curl /bpm
curl "https://api.freqblog.com/bpm?bpm=128&tolerance=2&limit=10" \
  -H "X-Api-Key: your_key_here"

Find tracks by key (Camelot, Open Key, or name)

curl /key
curl "https://api.freqblog.com/key?q=8A&limit=10" \
  -H "X-Api-Key: your_key_here"

# Also accepts: ?q=1m (Open Key) or ?q=A-Minor (key name)

Upload for analysis (tracks not in catalog)

curl /analyze
curl -X POST "https://api.freqblog.com/analyze" \
  -H "X-Api-Key: your_key_here" \
  -F "[email protected]"

★ Spotify-shape — host-swap, same response structure (values may need threshold-tuning)

Python /v1/audio-features/{id}
import requests

API_KEY    = "your_key_here"
spotify_id = "0VjIjW4GlUZAMYd2vXMi3b"  # or an ISRC like "USUM71900001"

resp = requests.get(
    f"https://api.freqblog.com/v1/audio-features/{spotify_id}",
    headers={"X-Api-Key": API_KEY}
)
data = resp.json()
print(f"tempo={data['tempo']} key={data['key']} mode={data['mode']}")

# {id} auto-detects 22-char Spotify ID or 12-char ISRC. Same AudioFeaturesObject shape.
# A raw Spotify ID only resolves tracks already mapped to one (a minority of the
# catalog) — prefer the ISRC, or look up by name: GET /lookup?track=...&artist=...
# Batch:   GET /v1/audio-features?ids=id1,id2,...   (up to 100; returns {"audio_features": [...]})

Name-based lookup

Python /lookup
import requests

API_KEY = "your_key_here"
BASE    = "https://api.freqblog.com"
headers = {"X-Api-Key": API_KEY}

resp = requests.get(
    f"{BASE}/lookup",
    params={"track": "Blinding Lights", "artist": "The Weeknd"},
    headers=headers
)
data = resp.json()
print(f"BPM: {data['bpm']} (confidence: {data['bpm_confidence']:.2f})")
print(f"Key: {data['key']} (confidence: {data['key_confidence']:.0%})")

Upload for analysis

Python /analyze
with open("track.mp3", "rb") as f:
    resp = requests.post(
        f"{BASE}/analyze",
        headers=headers,
        files={"file": f}
    )
print(resp.json())

★ Spotify-shape — host-swap, same response structure (values may need threshold-tuning)

JavaScript /v1/audio-features/{id}
const API_KEY   = 'your_key_here';
const spotifyId = '0VjIjW4GlUZAMYd2vXMi3b';  // or an ISRC like 'USUM71900001'

const res  = await fetch(`https://api.freqblog.com/v1/audio-features/${spotifyId}`, {
  headers: { 'X-Api-Key': API_KEY }
});
const data = await res.json();
console.log(`tempo=${data.tempo} key=${data.key} mode=${data.mode}`);

// {id} auto-detects 22-char Spotify ID or 12-char ISRC. Same AudioFeaturesObject shape.
// A raw Spotify ID only resolves tracks already mapped to one (a minority of the
// catalog) — prefer the ISRC, or look up by name: GET /lookup?track=...&artist=...
// Batch: GET /v1/audio-features?ids=id1,id2,...   (up to 100; returns {audio_features:[...]})

Name-based lookup

JavaScript /lookup
const API_KEY = 'your_key_here';
const BASE    = 'https://api.freqblog.com';

const params = new URLSearchParams({
  track: 'Blinding Lights', artist: 'The Weeknd'
});
const res  = await fetch(`${BASE}/lookup?${params}`, {
  headers: { 'X-Api-Key': API_KEY }
});
const data = await res.json();
console.log(`BPM: ${data.bpm}, Key: ${data.key}`);

Upload for analysis

JavaScript /analyze
const form = new FormData();
form.append('file', fileInput.files[0]);

const res = await fetch(`${BASE}/analyze`, {
  method: 'POST',
  headers: { 'X-Api-Key': API_KEY },
  body: form
});
console.log(await res.json());
Ready to plug this in?
Free key — 1,000 requests/month, no card required. Arrives in your inbox instantly.

FAQ

Questions,
answered.

Quick-start answers first, then the errors developers hit most often.

Is this a replacement for Spotify's Audio Features API?
Yes — it's a shape-compatible drop-in for Spotify's deprecated audio-features endpoint: GET /v1/audio-features/{id} accepts an ISRC or a Spotify track ID and returns BPM, key, energy, valence, danceability and more in the same JSON shape. One caveat: a raw Spotify ID only resolves if we've already mapped that track to a Spotify ID — today a minority of the catalog (~2.4%). It is not a universal Spotify-ID reverse lookup, and we can't resolve an unknown Spotify ID server-side. For reliable results, look up by name (GET /lookup?track=…&artist=… — searches the full catalog and queues an on-demand fetch on a miss) or by ISRC (GET /v1/audio-features/<ISRC>). Values are derived with MTG-Essentia rather than Spotify's models, so they're directionally compatible — re-tune any hard thresholds (see our field-by-field guide).
How do I get BPM and key from just a track name?
Send GET /lookup?track=…&artist=… — no audio file or ISRC required. The API resolves the track from its 886,691 pre-analysed catalog and returns BPM (with a half-time/double-time bpm_alt), key, Camelot, Open Key and 30+ other fields, typically in 25–40ms.
Can I look up audio features by ISRC, MusicBrainz ID, or Spotify ID?
Yes. Use /lookup?isrc=…, /lookup?mbid=… (a MusicBrainz recording ID — the precise key when no ISRC exists, e.g. pre-1986 vinyl, or when a name match is ambiguous), or /lookup?spotify_id=…. The Spotify-shaped /v1/audio-features/{id} accepts an ISRC or a Spotify ID too. Note that a raw Spotify ID only resolves when we've already mapped that track to a Spotify ID (a minority of the catalog) — it isn't a universal Spotify-ID reverse lookup. For the widest coverage, look up by name (/lookup?track=…&artist=…) or, if your own Spotify integration already gives you the ISRC (external_ids.isrc), pass that — /lookup?isrc=… or /v1/audio-features/<ISRC>.
Can I use it without an API key — or add it to Claude / Cursor / Windsurf?
Yes. The hosted MCP connector needs no API key and nothing to install — in Claude, open Settings → Connectors → Add custom connector and paste https://mcp.freqblog.com/mcp (Cursor uses a "url" entry, Windsurf "serverUrl"). See the connector setup. It's a free, shared service with a monthly cap; when the cap is reached you get a clear in-chat message to grab your own free key — 1,000 requests/month, no card — for a dedicated quota plus the full 23-tool set. For direct HTTP or SDK calls you do need a key: grab one free.
Can I use this through RapidAPI?
Yes — the Music Metadata API is listed on the RapidAPI marketplace. If your team already manages its APIs there, you can subscribe, get a key, and call the same endpoints (/lookup, /bulk, /v1/audio-features and the rest) through RapidAPI's gateway, billed on your RapidAPI account — coverage, fields and name-based lookups are identical to calling us directly. Prefer to onboard with us instead? The free tier and direct API keys work exactly as before — RapidAPI is simply a second way in for teams that standardise on it.
What makes this different from other music metadata APIs?
Three things: it works by track name — no Spotify ID or audio upload needed, it returns the widest field set (42 fields including mood, Camelot and the AcousticBrainz low-level descriptors), and it has intelligent backfill — a track that isn't already in the catalog is analysed on demand in ~15s (usually under a minute) rather than returning nothing. See the full comparison.
How do I build a harmonic DJ set, or score a transition, via the API?
Three endpoints work on the catalog’s key/BPM/energy to give you set flow, not just raw fields. GET /transition?from_track_id=&to_track_id= scores how cleanly two tracks mix (0–100) from Camelot-wheel key fit, octave-aware BPM proximity (half/double-time counts as a match) and energy smoothness, and returns a plain-English reason like 11B→11B same key, 118→117 BPM (-0.29), energy +0.12. GET /next-track?seed_track_id=&n=10 returns the seed’s sonic neighbours re-ranked by that transition score (tune with min_score, exclude_same_artist, bpm_drift, max_key_distance). POST /setlist takes {"track_ids":[…],"arc":"peak_time"} (2–100 ids; arc = peak_time/warmup/cooldown/flat) and orders the crate into a beat-matched set with per-step scores and an overall flow_score. Chain the ordered ids into GET /export/rekordbox?track_ids=… to drop the set straight into Rekordbox or Serato. Track ids are the catalog itunes_track_id values from /search or any /lookup response. Quota: /transition 1 request, /next-track 3, /setlist 5 — charged only on a served result.
Does /radio respect the Camelot wheel, or just BPM?
Both — /radio walks the similarity index while keeping each step within your max_key_distance on the Camelot wheel and within your bpm_drift. (We fixed a latent bug on 25 June 2026 where it had been reading key data from un-enriched rows, so its harmonic filter was effectively inert and it matched on BPM continuity alone; harmonic adjacency is now genuinely applied.) For finer control over how individual transitions are scored, or to order an existing crate rather than generate a fresh playlist, use the Harmonic Set Builder endpoints (/transition, /next-track, /setlist) above.
How do I get track recommendations or related artists now Spotify's /recommendations endpoint is gone?
Two endpoints replace the ones Spotify removed in November 2024 (GET /v1/recommendations and GET /v1/artists/{id}/related-artists) — same auth and monthly quota as /lookup, charged only on a served result. GET /recommendations?seed_tracks=&limit=20 takes 1–5 catalog track ids, blends them into one feature-space centroid, returns the nearest catalog tracks and re-ranks them by genre affinity — so a feature-close but cross-genre track doesn’t outrank your same-genre picks. Each result carries the raw audio-feature cosine score; because genre drives the order, the list isn’t strictly score-descending. Add exclude_seed_artists=true to drop the seeds’ own artists. Costs 2 quota requests. GET /related-artists?artist=&limit=20 derives an artist graph from the same similarity index (there’s no editorial listening graph behind it, just as there wasn’t behind Spotify’s): the seed artist’s track-vector centroid → nearest catalog tracks → aggregated by artist, each scored on its top-3 track sims (so a prolific back-catalogue can’t dominate) with a same-genre lift and a cross-genre penalty. It returns related artists with a score, match_count and a sample_track_id, and costs 2 quota requests. Both are built on our own audio-feature index and catalogue genre data — not ListenBrainz or any third-party graph. seed_tracks and sample_track_id are the catalog itunes_track_id values from /search or any /lookup response.
How do I auto-tag a track’s mood, energy and genre?
Call GET /tag with the track — by name (track + artist), isrc, mbid, spotify_id or a catalog track_id — and you get a compact tag array: energy, danceability, valence, acousticness, instrumentalness, a mood label and a broad genre. It’s a tag-shaped projection of the same analysis /lookup already returns — no audio upload, no new compute — so it costs just 1 request, charged only on a served result. What sets it apart from opaque taggers (e.g. Cyanite) is that every tag tells you how we know it: a confidence of measured (our Essentia analysis, provenance: essentia), derived (a MIREX-quadrant mood from measured valence + energy), model-estimated (an AcousticBrainz mood-model probability, raw value in value) or catalog-genre (a broad catalogue tag). Numeric tags carry their [0,1] value; the mood category and genre are label-only (value: null). Example: /tag?track=Blinding Lights&artist=The Weeknd → measured high-energy (1.0), very-danceable and acoustic, a derived mood of tense, and a catalog-genre of synthwave. The broad, reliable coverage is the measured tags — available for the full analysed catalogue and for any track you look up by name (fetched and analysed on demand on a miss). You can also tag by mbid or isrc against 7.5M+ AcousticBrainz recordings when you supply that identifier. For the full numeric feature set use /lookup; for the nearest-sounding tracks use /similar.
/lookup returned 202 — what now?
A 202 means the track wasn't in the catalog so we've queued an on-demand ingest — we fetch the preview, run full Essentia analysis, and add it to the catalog automatically. Typically ready in ~15 seconds (occasionally up to a minute under load). Watch progress in the dashboard's Recent Activity panel, or just retry the same /lookup call shortly — or skip the 202 next time by adding ?wait=N (up to 25s) to /lookup to hold the request and get the track back inline (200) in the same call. Looking up by ISRC (?isrc=…) or Spotify ID (?spotify_id=…) returns 404 instead — those identifier paths can't fall back to a name+artist search. If we've already tried a ?track= lookup and the track isn't on any streaming source we can analyse, repeat calls return 404 with terminal: true, outcome: "unavailable", a reason (not_on_streaming or no_preview_audio) and a Retry-After header (currently 7 days) rather than another 202 — so automated clients can stop polling a verdict that won't change yet (see "Why does a track come back 'not available'?" below). If a track truly can't be found (e.g. SoundCloud-only, no commercial preview anywhere), upload the audio file directly via POST /analyze — MP3, WAV, OGG, FLAC, and AAC/M4A up to 15 MB.
Why does a track come back “not available”? What can’t you analyse?
Audio features are computed from a track’s commercial streaming preview audio (Apple Music / Deezer). If a track has no streaming release we can reach — CD-only or event-only releases, unreleased or bootleg material, or catalogue that’s been pulled from streaming (common for some underground indie, idol, and pre-1980s recordings) — there’s no audio for us to analyse, so a repeat ?track= lookup returns 404 with outcome: "unavailable" and reason: "not_on_streaming" (or "no_preview_audio" when a match exists but carries no preview clip). This isn’t an error or a matching gap on our side — the recording simply isn’t on a streaming service we can pull audio from, and no metadata provider can supply audio features without the audio. Everything with a commercial streaming release resolves in ~15 s (usually under a minute) via Intelligent Backfill. If you have the audio file yourself, you can still analyse it directly via POST /analyze (MP3, WAV, OGG, FLAC, AAC/M4A up to 15 MB).
401 Unauthorized on every request
Two auth forms work: the header X-Api-Key: your_key_here (preferred for production code) or the URL param ?key=your_key_here (convenient for quick browser/curl tests). Bearer tokens are not accepted. Key must be active; if you just signed up, check your inbox (including spam) for the key email. Test with curl "https://api.freqblog.com/lookup?track=Test" -H "X-Api-Key: your_key_here" or paste https://api.freqblog.com/lookup?track=Test&key=your_key_here straight into a browser.
Can I call the API from browser JavaScript?
No — this is a server-side API. Your key is a secret credential (it counts against your quota and, on paid plans, your bill), so it must never sit in front-end code where anyone can read it straight from the page source. Cross-origin browser requests are intentionally not allowed: a preflight OPTIONS from a non-allowlisted origin is rejected, so a key embedded in client-side JavaScript can’t be scraped and abused. Call the API from your backend instead — curl, an SDK, any server-to-server request (none of which use CORS, so none are affected) — or, if you’re building a browser app, proxy the requests through your own server so the key stays server-side. This is the same reason Stripe and other secret-key APIs don’t allow their keys to be used directly from the browser.
429 Too Many Requests
Up to three limits apply — a 429 means you've hit one of them, not that anything is broken. (1) A per-minute rate limit (50/min Free • 300/min Hobbyist • 600/min Starter • 600/min Pro • 600/min Enterprise) applies to the CPU-bound endpoints — /analyze and /identify — only. /lookup, /bulk, /bpm, and /key are not rate-limited per-minute — they're bounded by your monthly quota and a per-key concurrency cap (point 4 below). (2) A monthly quota (1,000 / 15,000 / 150,000 / 750,000 requests for Free / Hobbyist / Starter / Pro) resets on the 1st of each month. (3) A per-key concurrency limit on /lookup — up to 6 requests in flight at once on Free (10 on paid); fire more in parallel and the extras get an instant 429 with Retry-After: 2 — pace your fan-out or use /bulk to resolve up to 50 tracks in one call. This is normal back-pressure, not an outage. Every 429 carries a Retry-After header, so back off for that many seconds; the per-minute-limited endpoints also return standard RateLimit-Limit/-Remaining/-Reset headers so you can pace before you hit the wall. Note that /identify costs 2 quota requests per call (an upstream AcoustID lookup is included); batch endpoints — /bulk, /v1/audio-features?ids= and /bulk-csv — charge 1 per track or row in the batch; every other endpoint is 1 per call. If you're hitting the monthly cap regularly, consider upgrading your plan.
Slow batches: partial results, never a wholesale failure
Batch endpoints resolve every track in parallel but stop at a 25-second server time-box — a batch packed with tracks not in the catalogue yet (each triggers a slower on-demand resolution) can run past it. This is not an outage, and anything unresolved is never charged against your quota. All three batch endpoints return a 200 with partial results. /bulk and /v1/audio-features?ids= hand back the tracks that finished and return the slow ones as null (or found:false with backfill_status:"processing" on /bulk). /bulk-csv behaves the same way — a slow file comes back as a partial CSV where resolved rows are enriched and any the deadline cut off carry found="processing" (also uncharged), with X-Bulk-Complete, X-Bulk-Rows-Processed and X-Bulk-Rows-Pending headers so you can spot a partial without scanning rows. Just re-submit the unfinished items to collect them. Either way the practical fix is smaller batches — ~15 tracks per /bulk call, ~25 IDs per /v1/audio-features?ids= call, or split a large /bulk-csv file into chunks. If every request fails (not just the miss-heavy ones), check the status page.
413 Payload Too Large on /analyze
The file size limit is 15MB. Trim the audio to a representative 30-second clip, or re-encode at a lower bitrate (128kbps MP3 is more than sufficient for accurate BPM and key detection). The API analyzes the full audio you send — longer files do not improve accuracy.
415 Unsupported Media Type on /analyze or /identify
The file isn't a recognised audio type. We accept MP3, WAV, OGG, FLAC and AAC/M4A (the response names the type we detected). If your file is one of those, it's most likely corrupt or truncated — re-export it and try again. Note these endpoints take the raw audio as a multipart/form-data file upload, not a URL or JSON — sending those returns 415.
cached: false — response is slow (3–5 seconds)
This is expected on the first analysis of a new track. The audio is being processed by Essentia in real time. Once analyzed, the result is cached permanently — all future lookups for that track return in ~25–40ms (p95 under 100ms). If you are regularly analyzing the same tracks, they will be fast after the first request.
From the Blog

Guides & Engineering Notes

All posts →
Migration

Spotify Audio Features Is Dead — Here's What to Use Instead

An honest comparison of every alternative since Spotify deprecated audio_features, with migration code.

Engineering

Why Music Metadata Matching Is Harder Than It Looks

Three real failure modes — Unicode drift, search blind spots, naive result-picking — and how to fix each.

Guide

AcousticBrainz Alternative in 2026

What you lost when AcousticBrainz shut down, what's still usable from the dump, and how to build on it.

Attribution & Legal

Open Data & Open Source

This API is built using open-source signal processing libraries and public music databases released under permissive licenses. Audio analysis is powered by established music-information-retrieval research.

This API is not affiliated with, endorsed by, or sponsored by Spotify, Apple, or any other music platform. Artist and track names appear only as metadata and remain the property of their respective owners. No audio is stored or retained.