TrackID.dev

API Documentation

Build powerful music applications with TrackID.dev's free API. No registration required, unlimited usage.

Quick Start

Get started with basic API usage, examples, and key concepts.

Continue reading below

APIAPI Reference

Detailed endpoint documentation, schemas, and advanced features.

View Reference →

DEVDeveloper Guide

Step-by-step tutorial for building music apps with code examples.

Start Building →

CASECase Study

See how we identified 47 tracks in a techno mix with 94.2% accuracy.

Read Study →

Try Live Demo

Test the API interactively with your own YouTube URLs.

Try Now →

HELPCommunity

Join GitHub discussions, contribute, and get developer support.

Join GitHub →

Quick Start

Get started with TrackID.dev API in under 5 minutes. No API keys needed.

// 1. Submit a URL for analysis
const response = await fetch('https://trackid.dev/api/analyze', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ url: 'https://youtu.be/your-video-id' })
});

const { jobId } = await response.json();

// 2. Check processing status
const statusResponse = await fetch(`https://trackid.dev/api/job/${jobId}`);
const jobStatus = await statusResponse.json();

// 3. Get results when completed
if (jobStatus.status === 'completed') {
  console.log('Tracks:', jobStatus.tracks);
}

Base URL

https://trackid.dev/api

All API requests should be made to this base URL

Authentication

✅ No Authentication Required

TrackID.dev API is completely free and open. No API keys, no registration, no limits.

Rate Limiting

10 requests per 15 minutes per IP address to ensure fair usage.

API Endpoints

POST/api/analyze

Submit a YouTube URL for track identification

Request Body:

{
  "url": "https://youtu.be/VIDEO_ID"
}

Response:

{
  "jobId": "job_1640995200000_abc123",
  "status": "queued", 
  "message": "Processing job created successfully",
  "estimatedTime": 300
}

Supported URLs:

  • https://youtube.com/watch?v=VIDEO_ID
  • https://youtu.be/VIDEO_ID
  • https://youtube.com/embed/VIDEO_ID
GET/api/job/{jobId}

Check the status and get results of a processing job

Response (Processing):

{
  "id": "job_1640995200000_abc123",
  "status": "fingerprinting",
  "progress": 60,
  "currentStep": "Generating audio fingerprints...",
  "estimatedTimeRemaining": 120,
  "youtubeUrl": "https://youtu.be/VIDEO_ID",
  "createdAt": "2025-12-23T08:00:00.000Z",
  "updatedAt": "2025-12-23T08:02:30.000Z"
}

Response (Completed):

{
  "id": "job_1640995200000_abc123",
  "status": "completed",
  "progress": 100,
  "currentStep": "Analysis complete!",
  "tracks": [
    {
      "id": "track_1",
      "timestamp": 0,
      "duration": 180,
      "artist": "Pendulum",
      "title": "Propane Nightmares", 
      "confidence": 0.89,
      "acoustidId": "pendulum_propane_123",
      "youtubeUrl": "https://youtube.com/watch?v=example"
    }
  ]
}

Job Status Values:

  • queued - Job is waiting to be processed
  • downloading - Downloading audio from YouTube
  • segmenting - Splitting audio into segments
  • fingerprinting - Generating audio fingerprints
  • matching - Identifying tracks with AcoustID
  • completed - Processing finished successfully
  • failed - Processing failed with error
GET/api/health

Check API service health and status

Response:

{
  "status": "ok",
  "timestamp": "2025-12-23T08:00:00.000Z",
  "version": "1.0.0",
  "uptime": 3600
}

Error Handling

TrackID.dev API uses conventional HTTP response codes to indicate success or failure.

400Bad Request
{
  "error": "Invalid YouTube URL format"
}
429Rate Limited
{
  "error": "Rate limit exceeded. Try again later."
}
500Server Error
{
  "error": "Internal server error"
}

💻 Code Examples

JavaScript / Node.js

async function identifyTracks(youtubeUrl) {
  try {
    // Start analysis
    const response = await fetch('https://trackid.dev/api/analyze', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ url: youtubeUrl })
    });
    
    if (!response.ok) throw new Error('Failed to start analysis');
    
    const { jobId } = await response.json();
    console.log('Job started:', jobId);
    
    // Poll for completion
    let job;
    do {
      await new Promise(resolve => setTimeout(resolve, 5000)); // Wait 5s
      
      const statusResponse = await fetch(`https://trackid.dev/api/job/${jobId}`);
      job = await statusResponse.json();
      
      console.log(`Progress: ${job.progress}% - ${job.currentStep}`);
    } while (job.status !== 'completed' && job.status !== 'failed');
    
    if (job.status === 'completed') {
      console.log('Found tracks:', job.tracks);
      return job.tracks;
    } else {
      throw new Error('Processing failed');
    }
    
  } catch (error) {
    console.error('Error:', error.message);
    throw error;
  }
}

// Usage
identifyTracks('https://youtu.be/LlIBWVxZLpc')
  .then(tracks => console.log('Success!', tracks))
  .catch(error => console.error('Failed:', error));

Python

import requests
import time
import json

def identify_tracks(youtube_url):
    """Identify tracks in a YouTube video using TrackID.dev API"""
    
    # Start analysis
    response = requests.post('https://trackid.dev/api/analyze', 
                           json={'url': youtube_url})
    response.raise_for_status()
    
    job_id = response.json()['jobId']
    print(f"Job started: {job_id}")
    
    # Poll for completion
    while True:
        time.sleep(5)  # Wait 5 seconds
        
        status_response = requests.get(f'https://trackid.dev/api/job/{job_id}')
        status_response.raise_for_status()
        
        job = status_response.json()
        print(f"Progress: {job['progress']}% - {job['currentStep']}")
        
        if job['status'] == 'completed':
            print(f"Found {len(job['tracks'])} tracks")
            return job['tracks']
        elif job['status'] == 'failed':
            raise Exception(f"Processing failed: {job.get('error', 'Unknown error')}")

# Usage
try:
    tracks = identify_tracks('https://youtu.be/LlIBWVxZLpc')
    for track in tracks:
        if track.get('artist') and track.get('title'):
            print(f"{track['timestamp']}s - {track['artist']} - {track['title']}")
except Exception as e:
    print(f"Error: {e}")

cURL

# Start analysis
curl -X POST https://trackid.dev/api/analyze \
  -H "Content-Type: application/json" \
  -d '{"url": "https://youtu.be/LlIBWVxZLpc"}'

# Response: {"jobId": "job_123", "status": "queued", ...}

# Check status (replace job_123 with actual jobId)
curl https://trackid.dev/api/job/job_123

# Response: {"status": "completed", "tracks": [...], ...}

Best Practices

✅ Do

  • • Poll job status every 5-10 seconds
  • • Handle rate limiting gracefully
  • • Check for both 'completed' and 'failed' status
  • • Validate YouTube URLs before submission
  • • Cache results to avoid reprocessing
  • • Use HTTPS for all API calls

❌ Don't

  • • Poll more frequently than every 3 seconds
  • • Submit the same URL multiple times
  • • Ignore rate limiting responses
  • • Assume processing always succeeds
  • • Submit non-YouTube URLs
  • • Block UI while waiting for results

📊 Track Object Schema

{
  "id": "string",           // Unique track identifier
  "timestamp": 0,           // Start time in seconds
  "duration": 180,          // Track length in seconds
  "artist": "Artist Name",  // Track artist (empty if unknown)
  "title": "Track Title",   // Track title (empty if unknown)
  "confidence": 0.89,       // Confidence score (0.0-1.0)
  "acoustidId": "string",   // AcoustID identifier (if available)
  "youtubeUrl": "string",   // YouTube URL for track (if available)
  "isUnknown": false        // True if track couldn't be identified
}

🆘 Support & Community

Need help? Join our developer community or contribute to the project.