Skip to main content
The voice tracking module records when members join and leave voice channels, calculates session durations, and persists everything to PostgreSQL. Sessions that are open when the bot restarts are preserved through a periodic flush mechanism.

How sessions work

Every voice state change fires the voiceStateUpdate handler:
  • Join — opens a new session row in voice_sessions with left_at = NULL.
  • Leave — closes the open session, writing left_at and duration_seconds.
  • Move — closes the old-channel session and opens a new one for the new channel.
  • Mute / deafen / stream — no session change.
Session state is mirrored in memory for fast access. The database write happens before the in-memory update, so a crash between the two can leave a stale in-memory entry that is harmlessly overwritten on the next join.

Configuration

Voice tracking is configured at the guild level under the voice key. Defaults are applied when the key is absent.
config.json
{
  "voice": {
    "enabled": false,
    "xpPerMinute": 2,
    "dailyXpCap": 120,
    "logChannel": null
  }
}
FieldDefaultDescription
enabledfalseEnable voice session tracking
xpPerMinute2XP awarded per minute in voice (if reputation is also enabled)
dailyXpCap120Maximum XP from voice per day
logChannelnullChannel ID for voice join/leave log messages
Join and leave events are always tracked (to close open sessions) even when enabled is false. This prevents orphaned in-memory sessions if the feature is toggled off while members are already in voice.

Periodic flush

Every 5 minutes, the bot writes the current duration_seconds of all open sessions to the database without closing them. This is a heartbeat that limits data loss to at most 5 minutes if the process crashes while members are in voice.

Leaderboard periods

The voice leaderboard supports three time windows:
PeriodSQL filter
weekSessions started in the last 7 days
monthSessions started in the last 30 days
allAll completed sessions

Commands

Shows voice activity for yourself or another member:
  • Total time in voice (formatted as 1h 30m, 45m, or 30s)
  • Number of completed sessions
  • Favourite voice channel
OptionRequiredDescription
userNoMember to look up. Defaults to yourself
Available to all members.
Ranks the top 10 members by total voice time. Supports three time windows:
ChoiceValueDescription
This weekweekDefault — sessions from the last 7 days
This monthmonthSessions from the last 30 days
All timeallAll completed sessions
Available to all members.
Exports raw voice session data as a CSV file attachment (up to 5,000 rows). The CSV includes columns: id, user_id, channel_id, joined_at, left_at, duration_seconds.
OptionRequiredDescription
periodNoTime range to export: week, month, or all (default: all)
Permission: Requires the Manage Server Discord permission.

Duration formatting

Durations are formatted as follows:
DurationDisplay
Less than 60 seconds30s
Minutes only45m
Hours only2h
Hours and minutes1h 30m

Database schema

Sessions are stored in the voice_sessions table:
ColumnTypeDescription
idserialPrimary key
guild_idtextGuild snowflake
user_idtextUser snowflake
channel_idtextVoice channel snowflake
joined_attimestamptzSession start time
left_attimestamptzSession end time (NULL while open)
duration_secondsintegerComputed duration on close (updated by periodic flush for open sessions)

Build docs developers (and LLMs) love