DisGoLink can be integrated with any Go Discord library. This guide covers general integration patterns and specific notes for popular libraries.
Compatibility Overview
DisGoLink requires github.com/disgoorg/snowflake/v2.ID types. Most Discord libraries use either:
String-based IDs (DiscordGo, Arikawa) - Require conversion
uint64-based IDs (Disgord) - May require conversion depending on version
Snowflake IDs (DisGo) - No conversion needed ✓
Snowflake Type Compatibility : You’ll need to convert between your library’s ID type and snowflake.ID (uint64). This is usually straightforward with snowflake.Parse() or snowflake.MustParse().
General Integration Pattern
Regardless of your Discord library, you need to:
Install dependencies
Create DisGoLink client with your bot’s application ID
Forward voice events from Discord to DisGoLink
Convert ID types between your library and DisGoLink
Manage players through the DisGoLink API
Core Requirements
Required Intents
Your Discord bot must have these gateway intents enabled:
// Exact syntax depends on your library
Guilds // To receive guild events
GuildVoiceStates // CRITICAL: To receive voice events
Required Event Handlers
You must implement and register these two handlers:
OnVoiceStateUpdate
Fired when your bot joins, moves, or leaves a voice channel.
func ( b * Bot ) onVoiceStateUpdate ( event VoiceStateUpdateEvent ) {
// Only handle events for your bot
if event . UserID != b . BotUserID {
return
}
// Convert your library's ID types to snowflake.ID
guildID := convertToSnowflake ( event . GuildID )
// ChannelID is nil when bot disconnects
var channelID * snowflake . ID
if event . ChannelID != "" { // Or however your library represents "no channel"
id := convertToSnowflake ( event . ChannelID )
channelID = & id
}
// Forward to DisGoLink
b . Lavalink . OnVoiceStateUpdate (
context . TODO (),
guildID ,
channelID ,
event . SessionID , // Usually already a string
)
}
OnVoiceServerUpdate
Fired when Discord provides voice server connection details.
func ( b * Bot ) onVoiceServerUpdate ( event VoiceServerUpdateEvent ) {
// Convert guild ID to snowflake
guildID := convertToSnowflake ( event . GuildID )
// Forward to DisGoLink
b . Lavalink . OnVoiceServerUpdate (
context . TODO (),
guildID ,
event . Token ,
event . Endpoint ,
)
}
ID Conversion Helpers
String-based IDs
Most libraries (DiscordGo, Arikawa) use strings:
import " github.com/disgoorg/snowflake/v2 "
// String to snowflake.ID
func stringToSnowflake ( id string ) ( snowflake . ID , error ) {
return snowflake . Parse ( id )
}
// Panic version (use only when ID is guaranteed valid)
func mustStringToSnowflake ( id string ) snowflake . ID {
return snowflake . MustParse ( id )
}
// snowflake.ID to string
func snowflakeToString ( id snowflake . ID ) string {
return id . String ()
}
// Usage example
guildIDString := "123456789012345678"
guildID , err := stringToSnowflake ( guildIDString )
if err != nil {
// Handle invalid ID
}
uint64-based IDs
Some libraries use raw uint64:
import " github.com/disgoorg/snowflake/v2 "
// uint64 to snowflake.ID (direct cast)
func uint64ToSnowflake ( id uint64 ) snowflake . ID {
return snowflake . ID ( id )
}
// snowflake.ID to uint64 (direct cast)
func snowflakeToUint64 ( id snowflake . ID ) uint64 {
return uint64 ( id )
}
Library-Specific Examples
Arikawa
Arikawa uses discord.Snowflake (which is a string wrapper).
import (
" github.com/diamondburned/arikawa/v3/discord "
" github.com/diamondburned/arikawa/v3/state "
" github.com/disgoorg/snowflake/v2 "
" github.com/disgoorg/disgolink/v3/disgolink "
)
type Bot struct {
State * state . State
Lavalink disgolink . Client
}
// Convert Arikawa's discord.Snowflake to snowflake.ID
func arikawaToSnowflake ( id discord . Snowflake ) snowflake . ID {
return snowflake . MustParse ( id . String ())
}
// Initialize
func NewBot ( token string ) ( * Bot , error ) {
s := state . New ( "Bot " + token )
// Add intents
s . AddIntents ( gateway . IntentGuilds | gateway . IntentGuildVoiceStates )
b := & Bot {
State : s ,
}
// Create DisGoLink client
me , _ := s . Me ()
b . Lavalink = disgolink . New ( arikawaToSnowflake ( me . ID ))
// Register handlers
s . AddHandler ( b . onVoiceStateUpdate )
s . AddHandler ( b . onVoiceServerUpdate )
return b , s . Open ( context . TODO ())
}
func ( b * Bot ) onVoiceStateUpdate ( e * gateway . VoiceStateUpdateEvent ) {
me , _ := b . State . Me ()
if e . UserID != me . ID {
return
}
var channelID * snowflake . ID
if e . ChannelID . IsValid () {
id := arikawaToSnowflake ( e . ChannelID )
channelID = & id
}
b . Lavalink . OnVoiceStateUpdate (
context . TODO (),
arikawaToSnowflake ( e . GuildID ),
channelID ,
e . SessionID ,
)
}
func ( b * Bot ) onVoiceServerUpdate ( e * gateway . VoiceServerUpdateEvent ) {
b . Lavalink . OnVoiceServerUpdate (
context . TODO (),
arikawaToSnowflake ( e . GuildID ),
e . Token ,
e . Endpoint ,
)
}
Disgord
Disgord uses disgord.Snowflake (uint64 wrapper).
import (
" github.com/andersfylling/disgord "
" github.com/disgoorg/snowflake/v2 "
" github.com/disgoorg/disgolink/v3/disgolink "
)
type Bot struct {
Client * disgord . Client
Lavalink disgolink . Client
}
// Convert Disgord's snowflake to DisGoLink's snowflake
func disgordToSnowflake ( id disgord . Snowflake ) snowflake . ID {
return snowflake . ID ( uint64 ( id ))
}
func NewBot ( token string ) * Bot {
client := disgord . New ( disgord . Config {
BotToken : token ,
Intents : disgord . IntentGuilds | disgord . IntentGuildVoiceStates ,
})
b := & Bot {
Client : client ,
}
// Create DisGoLink client
myself , _ := client . CurrentUser (). Get ()
b . Lavalink = disgolink . New ( disgordToSnowflake ( myself . ID ))
// Register handlers
client . Gateway (). VoiceStateUpdate ( b . onVoiceStateUpdate )
client . Gateway (). VoiceServerUpdate ( b . onVoiceServerUpdate )
return b
}
func ( b * Bot ) onVoiceStateUpdate ( s disgord . Session , evt * disgord . VoiceStateUpdate ) {
myself , _ := b . Client . CurrentUser (). Get ()
if evt . UserID != myself . ID {
return
}
var channelID * snowflake . ID
if ! evt . ChannelID . IsZero () {
id := disgordToSnowflake ( evt . ChannelID )
channelID = & id
}
b . Lavalink . OnVoiceStateUpdate (
context . TODO (),
disgordToSnowflake ( evt . GuildID ),
channelID ,
evt . SessionID ,
)
}
func ( b * Bot ) onVoiceServerUpdate ( s disgord . Session , evt * disgord . VoiceServerUpdate ) {
b . Lavalink . OnVoiceServerUpdate (
context . TODO (),
disgordToSnowflake ( evt . GuildID ),
evt . Token ,
evt . Endpoint ,
)
}
Basic Usage Pattern
Once you’ve set up the integration, using DisGoLink is the same regardless of your Discord library:
// Create DisGoLink client
lavalink := disgolink . New ( botApplicationID )
// Add Lavalink node
node , err := lavalink . AddNode ( ctx , disgolink . NodeConfig {
Name : "main-node" ,
Address : "localhost:2333" ,
Password : "youshallnotpass" ,
Secure : false ,
})
// Get or create player for a guild
player := lavalink . Player ( guildID )
// Load a track
node . LoadTracksHandler ( ctx , "ytsearch:never gonna give you up" ,
disgolink . NewResultHandler (
func ( track lavalink . Track ) {
// Play the track
player . Update ( ctx , lavalink . WithTrack ( track ))
},
func ( playlist lavalink . Playlist ) {
// Handle playlist
},
func ( tracks [] lavalink . Track ) {
// Handle search results
},
func () {
// No matches
},
func ( err error ) {
// Error
},
),
)
// Control playback
player . Update ( ctx , lavalink . WithPaused ( true ))
player . Update ( ctx , lavalink . WithVolume ( 80 ))
player . Update ( ctx , lavalink . WithPosition ( lavalink . Duration ( 30000 )))
Troubleshooting
Voice Connection Not Working
Check intents : Ensure GuildVoiceStates intent is enabled
Verify event handlers : Both OnVoiceStateUpdate and OnVoiceServerUpdate must be registered
Check ID filtering : Make sure you’re only handling events for your bot’s user ID
Validate conversions : Ensure ID conversions don’t produce invalid snowflakes
Type Conversion Errors
// BAD - Can panic
id := snowflake . MustParse ( possiblyInvalidString )
// GOOD - Handle errors
id , err := snowflake . Parse ( possiblyInvalidString )
if err != nil {
log . Printf ( "Invalid ID: %v " , err )
return
}
Common Mistakes
Not filtering voice events (handling all users instead of just the bot)
Missing the GuildVoiceStates intent
Incorrect nil handling for channelID when bot disconnects
Not converting IDs before passing to DisGoLink
Need Help?
If your Discord library isn’t listed here:
Find how to listen to VOICE_STATE_UPDATE and VOICE_SERVER_UPDATE events
Determine your library’s ID type and create conversion functions
Follow the general integration pattern above
Check the DisGo example as a reference
Next Steps
Player Guide Learn about player management and controls
Track Loading Load tracks from various sources