Skip to main content

What are Extractors?

Extractors are modular components in Discord Player that handle fetching metadata and streaming audio from various sources. Each extractor is responsible for:
  • Validating queries - Determining if a query belongs to their service
  • Extracting metadata - Fetching track information (title, author, duration, etc.)
  • Streaming audio - Providing playable audio streams
  • Bridging - Converting metadata from one source to a streamable format from another
Extractors use a priority system where higher priority extractors are executed first. The default priority is 1, but you can customize it when creating custom extractors.

How Extractors Work

Execution Flow

When you search for a track, Discord Player:
  1. Runs all registered extractors sorted by priority (highest first)
  2. Validates the query against each extractor using validate()
  3. Handles the query with the first matching extractor using handle()
  4. Returns track metadata as Track objects
  5. Streams audio when needed using stream()

Bridging System

Some extractors (like Spotify and Apple Music) only provide metadata, not audio streams. Discord Player uses a bridging system to automatically find streamable versions:
// Spotify extractor returns metadata only
const spotifyTrack = await player.search('https://open.spotify.com/track/...');

// When streaming, Discord Player automatically bridges to another extractor
// For example, it might search YouTube or SoundCloud for the same song
Extractors that support bridging implement the bridge() method:
public async bridge(
  track: Track,
  sourceExtractor: BaseExtractor | null,
): Promise<ExtractorStreamable | null> {
  // Search for the track on this extractor's platform
  const query = sourceExtractor?.createBridgeQuery(track) ?? 
    `${track.author} - ${track.title}`;
  
  const result = await this.handle(query, { type: QueryType.SEARCH });
  
  if (!result.tracks.length) return null;
  
  return this.stream(result.tracks[0]);
}

Loading Extractors

Load Default Extractors

import { Player } from 'discord-player';
import { DefaultExtractors } from '@discord-player/extractor';

const player = new Player(client);

// Load all default extractors
await player.extractors.loadMulti(DefaultExtractors);

Load Specific Extractors

import { SpotifyExtractor, SoundCloudExtractor } from '@discord-player/extractor';

// Load only Spotify and SoundCloud
await player.extractors.loadMulti([
  SpotifyExtractor,
  SoundCloudExtractor
]);

Load with Options

await player.extractors.loadMulti(
  [SpotifyExtractor, SoundCloudExtractor],
  {
    'com.discord-player.spotifyextractor': {
      clientId: 'your-client-id',
      clientSecret: 'your-client-secret'
    },
    'com.discord-player.soundcloudextractor': {
      clientId: 'your-soundcloud-client-id'
    }
  }
);

Managing Extractors

Register Individual Extractor

import { SpotifyExtractor } from '@discord-player/extractor';

const extractor = await player.extractors.register(
  SpotifyExtractor,
  {
    clientId: 'your-client-id',
    clientSecret: 'your-client-secret'
  }
);

Unregister Extractor

// By identifier
await player.extractors.unregister('com.discord-player.spotifyextractor');

// By instance
await player.extractors.unregister(extractor);

Check Extractor Status

// Check if registered
if (player.extractors.isRegistered('com.discord-player.spotifyextractor')) {
  console.log('Spotify extractor is registered');
}

// Get extractor instance
const spotify = player.extractors.get('com.discord-player.spotifyextractor');

// Check if enabled/disabled
if (player.extractors.isEnabled('com.discord-player.spotifyextractor')) {
  console.log('Spotify extractor is enabled');
}

// Get count of registered extractors
console.log(`${player.extractors.size} extractors registered`);

Block Extractors

You can prevent specific extractors from executing:
const player = new Player(client, {
  blockExtractors: [
    'com.discord-player.spotifyextractor',
    'com.discord-player.applemusicextractor'
  ]
});

Extractor Events

Listen to extractor lifecycle events:
// Extractor registered
player.extractors.on('registered', (context, extractor) => {
  console.log(`Registered: ${extractor.identifier}`);
});

// Extractor activated
player.extractors.on('activate', (context, extractor) => {
  console.log(`Activated: ${extractor.identifier}`);
});

// Extractor deactivated
player.extractors.on('deactivate', (context, extractor) => {
  console.log(`Deactivated: ${extractor.identifier}`);
});

// Extractor unregistered
player.extractors.on('unregistered', (context, extractor) => {
  console.log(`Unregistered: ${extractor.identifier}`);
});

// Extractor error
player.extractors.on('error', (context, extractor, error) => {
  console.error(`Error in ${extractor.identifier}:`, error);
});

Protocols

Extractors can define custom protocols for search shortcuts:
// SoundCloud: scsearch
await player.search('scsearch:alan walker faded');

// Spotify: spsearch
await player.search('spsearch:imagine dragons');

// Apple Music: amsearch
await player.search('amsearch:taylor swift');
Protocols are defined in each extractor’s protocols property and are automatically registered during activation.

Query Types

Discord Player uses query types to route queries to the appropriate extractor:
Query TypeDescriptionExample
SPOTIFY_SONGSpotify trackhttps://open.spotify.com/track/...
SPOTIFY_PLAYLISTSpotify playlisthttps://open.spotify.com/playlist/...
SPOTIFY_ALBUMSpotify albumhttps://open.spotify.com/album/...
SPOTIFY_SEARCHSpotify searchspsearch:query
SOUNDCLOUD_TRACKSoundCloud trackhttps://soundcloud.com/...
SOUNDCLOUD_PLAYLISTSoundCloud playlistSoundCloud set URL
SOUNDCLOUD_SEARCHSoundCloud searchscsearch:query
APPLE_MUSIC_SONGApple Music songhttps://music.apple.com/...
APPLE_MUSIC_ALBUMApple Music albumApple Music album URL
APPLE_MUSIC_PLAYLISTApple Music playlistApple Music playlist URL
VIMEOVimeo videohttps://vimeo.com/...
REVERBNATIONReverbnation trackhttps://reverbnation.com/...
ARBITRARYDirect URLAny direct audio URL
FILELocal file/path/to/file.mp3
AUTOAuto-detectLet Discord Player detect

Best Practices

Load extractors once

Load extractors during bot initialization, not on every command.

Use loadMulti for batches

Use loadMulti() instead of multiple register() calls for better performance.

Handle extractor errors

Listen to the error event to catch and log extractor failures.

Set appropriate priorities

Custom extractors should have priorities based on their reliability and speed.

Next Steps

Default Extractors

Learn about built-in extractors and their configuration

Custom Extractors

Create your own extractors for custom sources

Build docs developers (and LLMs) love