Discord Player provides a comprehensive event system to monitor and respond to playback changes, errors, and queue updates.
Event System Overview
Events are emitted through the player.events emitter:
player . events . on ( 'playerStart' , ( queue , track ) => {
console . log ( `Now playing: ${ track . title } ` );
});
Player Events
Global player-level events:
debug
Emitted when debug information is available:
player . on ( 'debug' , ( message ) => {
console . log ( '[Debug]' , message );
});
error
Emitted for player-level errors:
player . on ( 'error' , ( error ) => {
console . error ( '[Player Error]' , error );
});
voiceStateUpdate
Emitted when voice states change:
player . on ( 'voiceStateUpdate' , ( queue , oldState , newState ) => {
console . log ( `Voice state changed in ${ queue . guild . name } ` );
});
Queue Events
Events specific to guild queues, accessed via player.events:
Playback Events
playerStart
Emitted when a track starts playing:
player . events . on ( 'playerStart' , ( queue , track ) => {
queue . metadata . channel . send ( `Now playing: ** ${ track . title } **` );
});
Parameters:
queue: GuildQueue - The queue
track: Track - The track that started
playerFinish
Emitted when a track finishes playing:
player . events . on ( 'playerFinish' , ( queue , track ) => {
console . log ( `Finished playing: ${ track . title } ` );
});
Parameters:
queue: GuildQueue - The queue
track: Track - The track that finished
playerSkip
Emitted when a track is skipped:
player . events . on ( 'playerSkip' , ( queue , track , reason , description ) => {
console . log ( `Skipped ${ track . title } : ${ description } ` );
});
Parameters:
queue: GuildQueue - The queue
track: Track - The skipped track
reason: TrackSkipReason - Skip reason enum
description: string - Human-readable description
Skip Reasons:
enum TrackSkipReason {
NoStream = 'ERR_NO_STREAM' ,
Manual = 'MANUAL' ,
SEEK_OVER_THRESHOLD = 'SEEK_OVER_THRESHOLD' ,
Jump = 'JUMPED_TO_ANOTHER_TRACK' ,
SkipTo = 'SKIP_TO_ANOTHER_TRACK' ,
HistoryNext = 'HISTORY_NEXT_TRACK'
}
playerPause
Emitted when playback is paused:
player . events . on ( 'playerPause' , ( queue ) => {
console . log ( 'Playback paused' );
});
playerResume
Emitted when playback is resumed:
player . events . on ( 'playerResume' , ( queue ) => {
console . log ( 'Playback resumed' );
});
playerTrigger
Emitted when the audio player is triggered:
player . events . on ( 'playerTrigger' , ( queue , track , reason ) => {
console . log ( `Player triggered: ${ reason } ` );
});
Parameters:
queue: GuildQueue - The queue
track: Track - The current track
reason: 'filters' | 'normal' - Trigger reason
playerError
Emitted when an error occurs during playback:
player . events . on ( 'playerError' , ( queue , error , track ) => {
console . error ( `Error playing ${ track . title } : ${ error . message } ` );
queue . metadata . channel . send ( 'An error occurred during playback!' );
});
Parameters:
queue: GuildQueue - The queue
error: Error - The error object
track: Track - The track that caused the error
Queue Management Events
audioTrackAdd
Emitted when a single track is added:
player . events . on ( 'audioTrackAdd' , ( queue , track ) => {
queue . metadata . channel . send ( `Added ${ track . title } to the queue` );
});
audioTracksAdd
Emitted when multiple tracks are added:
player . events . on ( 'audioTracksAdd' , ( queue , tracks ) => {
queue . metadata . channel . send ( `Added ${ tracks . length } tracks to the queue` );
});
audioTrackRemove
Emitted when a track is removed:
player . events . on ( 'audioTrackRemove' , ( queue , track ) => {
console . log ( `Removed ${ track . title } ` );
});
audioTracksRemove
Emitted when multiple tracks are removed:
player . events . on ( 'audioTracksRemove' , ( queue , tracks ) => {
console . log ( `Removed ${ tracks . length } tracks` );
});
Connection Events
connection
Emitted when a voice connection is established:
player . events . on ( 'connection' , ( queue ) => {
console . log ( `Connected to ${ queue . channel . name } ` );
});
connectionDestroyed
Emitted when a voice connection is destroyed:
player . events . on ( 'connectionDestroyed' , ( queue ) => {
console . log ( 'Connection destroyed' );
});
disconnect
Emitted when the bot is disconnected:
player . events . on ( 'disconnect' , ( queue ) => {
console . log ( 'Disconnected from voice channel' );
});
Queue State Events
emptyQueue
Emitted when the queue becomes empty:
player . events . on ( 'emptyQueue' , ( queue ) => {
queue . metadata . channel . send ( 'Queue finished!' );
});
emptyChannel
Emitted when the voice channel becomes empty:
player . events . on ( 'emptyChannel' , ( queue ) => {
console . log ( 'Voice channel is empty' );
});
channelPopulate
Emitted when users join an empty voice channel:
player . events . on ( 'channelPopulate' , ( queue ) => {
console . log ( 'Channel has users again!' );
});
Queue Lifecycle Events
queueCreate
Emitted when a queue is created:
player . events . on ( 'queueCreate' , ( queue ) => {
console . log ( `Queue created for ${ queue . guild . name } ` );
});
queueDelete
Emitted when a queue is deleted:
player . events . on ( 'queueDelete' , ( queue ) => {
console . log ( `Queue deleted for ${ queue . guild . name } ` );
});
Filter Events
volumeChange
Emitted when volume changes:
player . events . on ( 'volumeChange' , ( queue , oldVolume , newVolume ) => {
console . log ( `Volume: ${ oldVolume } % → ${ newVolume } %` );
});
equalizerUpdate
Emitted when equalizer is updated:
player . events . on ( 'equalizerUpdate' , ( queue , oldEQ , newEQ ) => {
console . log ( 'Equalizer updated' );
});
biquadFiltersUpdate
Emitted when biquad filters are updated:
player . events . on ( 'biquadFiltersUpdate' , ( queue , oldFilters , newFilters ) => {
console . log ( 'Biquad filters updated' );
});
audioFiltersUpdate
Emitted when FFmpeg audio filters are updated:
player . events . on ( 'audioFiltersUpdate' , ( queue , oldFilters , newFilters ) => {
console . log ( `Filters: ${ newFilters . join ( ', ' ) } ` );
});
dspUpdate
Emitted when DSP filters are updated:
player . events . on ( 'dspUpdate' , ( queue , oldFilters , newFilters ) => {
console . log ( 'DSP filters updated' );
});
sampleRateUpdate
Emitted when sample rate changes:
player . events . on ( 'sampleRateUpdate' , ( queue , oldRate , newRate ) => {
console . log ( `Sample rate: ${ oldRate } Hz → ${ newRate } Hz` );
});
sampleRateFilterUpdate
Emitted when a named sample rate filter is updated:
player . events . on ( 'sampleRateFilterUpdate' , ( queue , oldFilter , newFilter ) => {
console . log ( `Sample rate filter: ${ newFilter } ` );
});
reverbUpdate
Emitted when reverb filter is updated:
player . events . on ( 'reverbUpdate' , ( queue , oldReverb , newReverb ) => {
console . log ( 'Reverb updated' );
});
compressorUpdate
Emitted when compressor filter is updated:
player . events . on ( 'compressorUpdate' , ( queue , oldCompressor , newCompressor ) => {
console . log ( 'Compressor updated' );
});
playerSeek
Emitted when seeking is performed:
player . events . on ( 'playerSeek' , ( queue , parameters ) => {
console . log ( `Seeked to ${ parameters . seekTarget } ms` );
});
Advanced Events
willPlayTrack
Emitted before playing a track (can modify stream config):
player . events . on ( 'willPlayTrack' , ( queue , track , config , done ) => {
// Modify config if needed
console . log ( `About to play: ${ track . title } ` );
done (); // Must call done() to continue
});
Parameters:
queue: GuildQueue - The queue
track: Track - Track about to play
config: StreamConfig - Stream configuration
done: () => void - Callback to continue playback
You must call done() to allow playback to continue when using this event.
willAutoPlay
Emitted when autoplay is about to add a track:
player . events . on ( 'willAutoPlay' , ( queue , tracks , done ) => {
// Select which track to play
const track = tracks [ 0 ];
done ( track ); // or done(null) to cancel
});
Parameters:
queue: GuildQueue - The queue
tracks: Track[] - Suggested tracks
done: (track: Track | null) => void - Callback with selected track
debug
Emitted for queue-specific debug information:
player . events . on ( 'debug' , ( queue , message ) => {
console . log ( `[ ${ queue . guild . name } ] ${ message } ` );
});
error
Emitted for queue-specific errors:
player . events . on ( 'error' , ( queue , error ) => {
console . error ( `[ ${ queue . guild . name } ] Error: ${ error . message } ` );
});
voiceStateUpdate
Emitted for voice state updates in the queue:
player . events . on ( 'voiceStateUpdate' , ( queue , oldState , newState ) => {
// Custom voice state handling
});
Consuming this event may disable the default voice state handler unless Player.lockVoiceStateHandler() is called.
Event Constants
Use the GuildQueueEvent enum for type-safe event names:
import { GuildQueueEvent } from 'discord-player' ;
player . events . on ( GuildQueueEvent . PlayerStart , ( queue , track ) => {
console . log ( `Playing: ${ track . title } ` );
});
player . events . on ( GuildQueueEvent . AudioTrackAdd , ( queue , track ) => {
console . log ( `Added: ${ track . title } ` );
});
Example: Complete Event Handler
import { Player , GuildQueueEvent } from 'discord-player' ;
const player = new Player ( client );
// Track all playback events
player . events . on ( GuildQueueEvent . PlayerStart , ( queue , track ) => {
queue . metadata . channel . send (
`Now playing: ** ${ track . title } ** [ ${ track . duration } ]`
);
});
player . events . on ( GuildQueueEvent . AudioTrackAdd , ( queue , track ) => {
queue . metadata . channel . send (
`Added ** ${ track . title } ** to the queue`
);
});
player . events . on ( GuildQueueEvent . EmptyQueue , ( queue ) => {
queue . metadata . channel . send ( 'Queue finished!' );
});
player . events . on ( GuildQueueEvent . EmptyChannel , ( queue ) => {
queue . metadata . channel . send ( 'Everyone left, pausing playback...' );
});
// Error handling
player . events . on ( GuildQueueEvent . Error , ( queue , error ) => {
console . error ( `[ ${ queue . guild . name } ] Queue error:` , error );
queue . metadata . channel . send ( 'An error occurred!' );
});
player . events . on ( GuildQueueEvent . PlayerError , ( queue , error , track ) => {
console . error ( `[ ${ queue . guild . name } ] Player error:` , error );
queue . metadata . channel . send ( `Error playing ${ track . title } ` );
});
// Filter changes
player . events . on ( GuildQueueEvent . AudioFiltersUpdate , ( queue , oldFilters , newFilters ) => {
if ( newFilters . length > 0 ) {
queue . metadata . channel . send ( `Applied filters: ${ newFilters . join ( ', ' ) } ` );
} else {
queue . metadata . channel . send ( 'Filters cleared' );
}
});
// Connection events
player . events . on ( GuildQueueEvent . Connection , ( queue ) => {
console . log ( `Connected to ${ queue . channel . name } ` );
});
player . events . on ( GuildQueueEvent . Disconnect , ( queue ) => {
console . log ( `Disconnected from ${ queue . guild . name } ` );
});
Best Practices
Always listen to error events to prevent unhandled errors: player . events . on ( 'error' , ( queue , error ) => {
console . error ( 'Queue error:' , error );
});
player . events . on ( 'playerError' , ( queue , error , track ) => {
console . error ( 'Player error:' , error );
queue . node . skip (); // Skip problematic track
});
Store channel references in queue metadata for easy access in events: const queue = player . nodes . create ( guild , {
metadata: { channel: interaction . channel }
});
player . events . on ( 'playerStart' , ( queue , track ) => {
queue . metadata . channel . send ( `Now playing: ${ track . title } ` );
});
Use type-safe event constants and proper typing: import { GuildQueueEvent , GuildQueue , Track } from 'discord-player' ;
player . events . on (
GuildQueueEvent . PlayerStart ,
( queue : GuildQueue , track : Track ) => {
// Full type safety
}
);
See Also
Player - Learn about the Player class
GuildQueue - Queue management
Hooks - React-like hooks for accessing queue data