A free and open-source music recognition backend built with Node.js and TypeScript.
Instead of relying on a single provider, this project combines multiple recognition services into one unified pipeline to achieve reliable results while keeping API costs low.
Note
This backend handles the core heavy lifting of downloading, extraction, transcoding, and service fallback. It is perfect for integration with custom web apps, desktop components, or mobile frontends.
- 🎼 Audio fingerprinting using Chromaprint (fpcalc)
- 🔍 Song identification through AcoustID
- 📚 Metadata enrichment using MusicBrainz
- 🎧 Automatic fallback to Shazam RapidAPI when open databases cannot confidently identify a track
- 📦 Unified response format regardless of the recognition source
- 🚀 REST API built with Express
- 🔒 Fully typed with TypeScript
The backend includes several production-oriented reliability mechanisms:
- 🔄 Automatic YouTube session cookie validation and refresh via Heartbeat
- ❤️ Health-check endpoint designed for uptime monitors (e.g. UptimeRobot)
- 🔑 Multi-key failover for RapidAPI
- 💾 Binary auto-management across Windows and Linux
- 📈 Memory usage logging for long-running deployments
⚠️ Graceful API fallback when providers are temporarily unavailable
When deploying to serverless or cloud platforms like Render, YouTube often flags or blocks requests coming from data center IP ranges. To bypass this, the backend uses YouTube session cookies. However, these cookies expire or become invalid over time.
The /api/keep-alive heartbeat endpoint acts as a proactive mechanism to solve this. Triggered by a remote cron/uptime monitor, it systematically verifies and refreshes your session cookies before real user requests hit the backend.
Heartbeat Request Triggered
│
▼
Download small test audio (via yt-dlp)
│
▼
Is Cookie Valid?
│
┌───────┴───────┐
│ │
Yes No
│ │
│ ▼
│ Refresh Cookies
│ │
└───────┬───────┘
│
▼
Success Response
Important
Local Testing vs Deployed Render Requests: Local testing (DO NOT need cookie validation), as your domestic residential IP is usually trusted by YouTube. This feature exists strictly to ensure that requests deployed on cloud instances (like Render) remain valid and are not rejected or rate-limited by YouTube's data center blocks.
URL Input (YouTube / Instagram / etc.)
│
▼
yt-dlp (extract audio)
│
▼
FFmpeg (MP3 conversion + normalization: 128kbps)
│
▼
Audio File
│
▼
Chromaprint (fpcalc)
│
▼
AcoustID
│
│
▼
MusicBrainz
├─────────────── Score ≥ 0.95 ───────────────┐
│ │
▼ ▼
Shazam API Return Result (MusicBrainz)
│
▼
Return Results (Shazam API + MusicBrainz)
If AcoustID confidence is low or no match:
│
▼
Shazam API
│
▼
Return Result (Shazam API (if any) + MusicBrainz (if any))
The backend is designed to support multiple candidate results when confidence is uncertain.
- Node.js
- TypeScript
- Express
- Axios
- Multer
- Chromaprint (fpcalc)
- AcoustID
- MusicBrainz
- Shazam API (fallback)
- FFmpeg & FFprobe
This project is tailored to work out-of-the-box on Render.
Render Build Command:
mkdir -p bin/linux && \
curl -L [https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp](https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp) -o bin/linux/yt-dlp && \
curl -L [https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-linux64-gpl.tar.xz](https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-linux64-gpl.tar.xz) | tar -xJ --wildcards --strip-components=2 -C bin/linux/ '*/bin/ffmpeg' '*/bin/ffprobe' && \
curl -L [https://github.com/acoustid/chromaprint/releases/download/v1.5.1/chromaprint-fpcalc-1.5.1-linux-x86_64.tar.gz](https://github.com/acoustid/chromaprint/releases/download/v1.5.1/chromaprint-fpcalc-1.5.1-linux-x86_64.tar.gz) | tar -xz --strip-components=1 -C bin/linux/ chromaprint-fpcalc-1.5.1-linux-x86_64/fpcalc && \
chmod +x bin/linux/* && \
npm install && \
npm run build
Render Start Command:
npm run start
src/
│
├── routes/
│ ├── heartbeat.ts
│ ├── urlRecognize.ts
│ └── recognize.ts
│
├── services/
│ ├── acoustid.ts
│ ├── chromaprint.ts
│ ├── downloader.ts
│ ├── executableManager.ts
│ ├── memoryLogger.ts
│ ├── musicbrainz.ts
│ ├── normalizer.ts
│ ├── recognition.ts
│ └── shazam.ts
│
├── config.ts
└── index.ts
git clone [https://github.com/Henrycoding-design/Music-Detector-Backend.git](https://github.com/Henrycoding-design/Music-Detector-Backend.git)
cd Music-Detector-Backend
npm install
Create a .env file in the root directory:
ACOUSTID_API_KEY=your_key
RAPIDAPI_KEY=your_key
RAPIDAPI_KEYS=your_key1,your_key2
RAPIDAPI_HOST=shazam.p.rapidapi.com
HEARTBEAT_SECRET=your_heartbeat_secret
Note
You can provide either RAPIDAPI_KEYS (comma-separated for horizontal scale and failover rotation) or a traditional singular RAPIDAPI_KEY. The system prioritizes multi-keys first and fallbacks to the singular variant.
HEARTBEAT_SECRET is used to make sure the request is coming from an authorized client, preventing random requests from accidentally triggering your yt-dlp download and cookie refreshing loop. Skip if you do not use the /api/keep-alive endpoint.
The system automatically handles production binaries via the Render build script. For local development, ensure the platform-appropriate executable files are placed in the bin/ directory:
bin/
linux/
ffmpeg
ffprobe
fpcalc
yt-dlp
windows/
ffmpeg.exe
ffprobe.exe
fpcalc.exe
yt-dlp.exe
Run the local development server (with hot-reloading via ts-node-dev):
npm run dev
Build the TypeScript project into native JavaScript:
npm run build
Run the production compiled build:
npm start
Triggers the heartbeat check to test and refresh deployment session cookies using a light test audio stream. This endpoint is typically targeted by external cron jobs or uptime checkers like UptimeRobot.
- Query Parameters or JSON body fields:
token: The secret key matching your configuredHEARTBEAT_SECRETenv variable.url: A reliable fallback YouTube URL used to perform the diagnostic audio chunk fetch.
Example Monitor Configuration (e.g., UptimeRobot HEAD/GET):
[https://music-detector-backend.onrender.com/api/keep-alive?token=MusicFinderBackendHearbeatSecret&url=https://www.youtube.com/watch?v=1kehqCLudyg](https://music-detector-backend.onrender.com/api/keep-alive?token=MusicFinderBackendHearbeatSecret&url=https://www.youtube.com/watch?v=1kehqCLudyg)
Upload a raw audio file binary using multipart/form-data.
- Field Name:
file
Example Usage:
curl -X POST \
-F "file=@song.mp3" \
http://localhost:3000/recognize
Send a public media link (YouTube, Instagram, TikTok, etc.) to trigger stream parsing.
- Headers:
Content-Type: application/json
Example Request:
curl -X POST http://localhost:3000/urlRecognize \
-H "Content-Type: application/json" \
-d '{
"url": "[https://www.youtube.com/watch?v=dQw4w9WgXcQ](https://www.youtube.com/watch?v=dQw4w9WgXcQ)"
}'
{
"success": true,
"result": [
{
"confidence": 0.97204643,
"recording": {
"id": "1e141b98-eed4-4312-9f72-4efc61ed24df",
"title": "Love Story",
"artist": "Taylor Swift",
"duration": 234
},
"album": "Fearless",
"releaseDate": "2008-11-11",
"isrc": "USCJY0803276",
"genres": [],
"cover": null,
"shazamUrl": null
}
]
}
The backend optimization follows a confidence-based routing flow:
- High-confidence AcoustID match (≥ 0.95): Drops execution immediately and relies purely on AcoustID + MusicBrainz open-source layers (0 API cost).
- Low-confidence or no AcoustID match: Falls back cleanly to Shazam RapidAPI endpoints to handle noisy/microphone audio samples.
Warning
Do not intentionally trim or slice the original file length on ingestion. Slicing structural intervals can break continuous wave patterns that AcoustID requires to produce high confidence fingerprint matches.
- Chromaprint integration
- AcoustID integration
- MusicBrainz integration
- Shazam fallback
- Unified recognition pipeline
- yt-dlp integration
- FFmpeg preprocessing
- Multi-key failover fallback mechanism for Shazam RapidAPI
- Added Memory Logger for a one-off snapshot of current RAM usage to console
- Automated Cookie Keep-Alive validation flow
Contributions, issues, and feature requests are welcome! Feel free to check the issues page.
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature) - Commit your Changes (
git commit -m 'Add some AmazingFeature') - Push to the Branch (
git push origin feature/AmazingFeature) - Open a Pull Request
Distributed under the MIT License. See LICENSE for more information.
This project is built upon the work of excellent open-source and public services: