SkillAgentSearch skills...

Odesli.js

A lightweight Node.js wrapper for the Odesli (Songlink) API – easily retrieve smart music links, metadata, and sharing info across all major streaming platforms.

Install / Use

/learn @MattrAus/Odesli.js
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

odesli.js

npm version npm license CI Test Coverage Bundle Size Downloads TypeScript

A Node.js client for the Odesli API (formerly song.link/album.link) that helps you find links to music across multiple streaming platforms.

📋 Table of Contents

Features

  • 🔗 Cross-platform links: Get links for music across Spotify, Apple Music, YouTube Music, and more
  • 🎵 Song & Album support: Works with both individual tracks and full albums
  • 🌍 Multi-country support: Specify country codes for region-specific results
  • 🔑 API Key support: Optional API key for higher rate limits
  • 📦 TypeScript support: Full TypeScript definitions included
  • Lightweight: Minimal dependencies, fast performance
  • 🛡️ Robust error handling: Comprehensive error messages and validation
  • 🧪 Fully tested: 100% test coverage with comprehensive test suite

Installation

From npm

npm install odesli.js

Quick Start

CommonJS (require):

const Odesli = require('odesli.js');

// Initialize without API key (10 requests/minute limit)
const odesli = new Odesli();

// Or with API key for higher limits
// const odesli = new Odesli({
//   apiKey: 'your-api-key-here',
//   version: 'v1-alpha.1', // optional, defaults to v1-alpha.1
// });

// You can also disable the metrics collector if you don't need it
// const odesliLight = new Odesli({ metrics: false });

// Fetch a song by URL (this is the actual working example)
(async () => {
  try {
    const song = await odesli.fetch(
      'https://open.spotify.com/track/4Km5HrUvYTaSUfiSGPJeQR'
    );
    console.log(`🎵 ${song.title} by ${song.artist.join(', ')}`);
    console.log(`🔗 Song.link: ${song.pageUrl}`);
  } catch (error) {
    console.error('❌ Error:', error.message);
  }
})();

ESM (import):

import Odesli from 'odesli.js';

// Initialize without API key (10 requests/minute limit)
const odesli = new Odesli();

// Or with API key for higher limits
// const odesli = new Odesli({
//   apiKey: 'your-api-key-here',
//   version: 'v1-alpha.1', // optional, defaults to v1-alpha.1
// });

// You can also disable the metrics collector if you don't need it
// const odesliLight = new Odesli({ metrics: false });

// Fetch a song by URL (this is the actual working example)
try {
  const song = await odesli.fetch(
    'https://open.spotify.com/track/4Km5HrUvYTaSUfiSGPJeQR'
  );
  console.log(`🎵 ${song.title} by ${song.artist.join(', ')}`);
  console.log(`🔗 Song.link: ${song.pageUrl}`);
} catch (error) {
  console.error('❌ Error:', error.message);
}

API Key

An API key is optional but recommended for production use. Without an API key, you're limited to 10 requests per minute.

To get an API key, email developers@song.link.

Usage

Basic Usage

CommonJS (require):

const Odesli = require('odesli.js');

// Initialize without API key (10 requests/minute limit)
const odesli = new Odesli();

// Or with API key for higher limits
// const odesli = new Odesli({
//   apiKey: 'your-api-key-here',
// });

(async () => {
  // Fetch a song by URL
  const song = await odesli.fetch(
    'https://open.spotify.com/track/4Km5HrUvYTaSUfiSGPJeQR'
  );
  console.log(`${song.title} by ${song.artist.join(', ')}`);

  // Fetch multiple songs at once
  const urls = [
    'https://open.spotify.com/track/4Km5HrUvYTaSUfiSGPJeQR',
    'https://open.spotify.com/track/0V3wPSX9ygBnCm8psDIegu',
  ];
  const songs = await odesli.fetch(urls);
  songs.forEach(song => console.log(song.title));
})();

ESM (import):

import Odesli from 'odesli.js';

// Initialize without API key (10 requests/minute limit)
const odesli = new Odesli();

// Or with API key for higher limits
// const odesli = new Odesli({
//   apiKey: 'your-api-key-here',
// });

// Fetch a song by URL
const song = await odesli.fetch(
  'https://open.spotify.com/track/4Km5HrUvYTaSUfiSGPJeQR'
);
console.log(`${song.title} by ${song.artist.join(', ')}`);

// Fetch multiple songs at once
const urls = [
  'https://open.spotify.com/track/4Km5HrUvYTaSUfiSGPJeQR',
  'https://open.spotify.com/track/0V3wPSX9ygBnCm8psDIegu',
];
const songs = await odesli.fetch(urls);
songs.forEach(song => console.log(song.title));

Advanced Usage

CommonJS (require):

const Odesli = require('odesli.js');

// Initialize with custom options
const odesli = new Odesli({
  apiKey: 'your-api-key-here',
  version: 'v1-alpha.1',
  cache: true,
  timeout: 10000,
  maxRetries: 3,
  retryDelay: 1000,
  headers: { 'User-Agent': 'MyApp/1.0' },
  validateParams: true,
  logger: (message, level) => console.log(`[${level}] ${message}`),
});

(async () => {
  // Fetch with options
  const song = await odesli.fetch('https://open.spotify.com/track/123', {
    country: 'GB',
    skipCache: false,
    timeout: 5000,
  });

  // Batch fetch with concurrency control
  const urls = [
    'https://open.spotify.com/track/123',
    'https://music.apple.com/us/album/test/456?i=789',
    'https://www.youtube.com/watch?v=abc123',
  ];

  const songs = await odesli.fetch(urls, {
    country: 'US',
    concurrency: 3,
    skipCache: true,
  });

  // Handle errors in batch results
  songs.forEach((song, index) => {
    if (song.error) {
      console.log(`Song ${index + 1}: Error - ${song.error}`);
    } else {
      console.log(`Song ${index + 1}: ${song.title}`);
    }
  });
})();

ESM (import):

import Odesli from 'odesli.js';

// Initialize with custom options
const odesli = new Odesli({
  apiKey: 'your-api-key-here',
  version: 'v1-alpha.1',
  cache: true,
  timeout: 10000,
  maxRetries: 3,
  retryDelay: 1000,
  headers: { 'User-Agent': 'MyApp/1.0' },
  validateParams: true,
  logger: (message, level) => console.log(`[${level}] ${message}`),
});

// Fetch with options
const song = await odesli.fetch(
  'https://open.spotify.com/track/4Km5HrUvYTaSUfiSGPJeQR',
  {
    country: 'GB',
    skipCache: false,
    timeout: 5000,
  }
);

// Batch fetch with concurrency control
const urls = [
  'https://open.spotify.com/track/4Km5HrUvYTaSUfiSGPJeQR',
  'https://open.spotify.com/track/0V3wPSX9ygBnCm8psDIegu',
  'https://open.spotify.com/track/3n3Ppam7vgaVa1iaRUc9Lp',
];

const songs = await odesli.fetch(urls, {
  country: 'US',
  concurrency: 3,
  skipCache: true,
});

// Handle errors in batch results
songs.forEach((song, index) => {
  if (song.error) {
    console.log(`Song ${index + 1}: Error - ${song.error}`);
  } else {
    console.log(`Song ${index + 1}: ${song.title}`);
  }
});

Response Format

All methods return a response object with the following structure:

{
  entityUniqueId: "SPOTIFY_SONG::4Km5HrUvYTaSUfiSGPJeQR",
  title: "Bad and Boujee",
  artist: ["Migos"],
  type: "song",
  thumbnail: "https://i.scdn.co/image/...",
  userCountry: "US",
  pageUrl: "https://song.link/i/4Km5HrUvYTaSUfiSGPJeQR",
  linksByPlatform: {
    spotify: {
      entityUniqueId: "SPOTIFY_SONG::4Km5HrUvYTaSUfiSGPJeQR",
      url: "https://open.spotify.com/track/4Km5HrUvYTaSUfiSGPJeQR",
      nativeAppUriMobile: "spotify://track/4Km5HrUvYTaSUfiSGPJeQR",
      nativeAppUriDesktop: "spotify://track/4Km5HrUvYTaSUfiSGPJeQR"
    },
    appleMusic: {
      // ... similar structure
    }
    // ... other platforms
  },
  entitiesByUniqueId: {
    "SPOTIFY_SONG::4Km5HrUvYTaSUfiSGPJeQR": {
      id: "4Km5HrUvYTaSUfiSGPJeQR",
      type: "song",
      title: "Bad and Boujee",
      artistName: ["Migos"],
      thumbnailUrl: "https://i.scdn.co/image/...",
      apiProvider: "spotify",
      platforms: ["spotify"]
    }
    // ... other entities
  }
}

Supported Platforms

  • Spotify
  • Apple Music
  • iTunes
  • YouTube Music
  • YouTube
  • Google Play Music
  • Pandora
  • Deezer
  • Tidal
  • Amazon Music
  • SoundCloud
  • Napster
  • Yandex Music
  • Spinrilla

TypeScript Support

This package includes full TypeScript definitions with strict country code validation:

CommonJS (require):

const Odesli = require('odesli.js');

const odesli = new Odesli({ apiKey: 'your-key' });

(async () => {
  // Get all valid country codes and names for UI dropdowns
  const countryOptions = Odesli.getCountryOptions();
  console.log('Top 3 countries:', countr
View on GitHub
GitHub Stars5
CategoryDevelopment
Updated3mo ago
Forks1

Languages

JavaScript

Security Score

87/100

Audited on Dec 21, 2025

No findings