projects
← All projects

Discord Voice State Snapshot

A Discord server-moderation bot that keeps an accurate, queryable ledger of who was in which voice channel and when, including across the bot's own restarts and outages, which Discord's event model makes hard to reconstruct. Built with Python and PostgreSQL.

2024-present
  • Python
  • discord.py
  • PostgreSQL
  • SQLAlchemy
  • Alembic
  • Docker Compose

Overview

A Discord server-moderation bot that records every voice-channel join and leave into PostgreSQL as an append-only ledger. It answers questions about the history through slash commands: who’s in voice now, a channel’s log over any window, one member’s sessions, and the exact intervals a given set of members shared a channel.

Usage

Voice events / monthServers with ≥1 event / month100k200k300k100200294k192k238Jan ’25Apr ’25Jul ’25Oct ’25Jan ’26Apr ’26Jun ’26
Recorded voice activity, January 2025 to June 2026
View data as table
MonthVoice events / monthServers with ≥1 event / month
Jan ’2512,21310
Feb ’2513,45313
Mar ’2512,97915
Apr ’2522,53029
May ’2524,02732
Jun ’2530,09939
Jul ’2534,59147
Aug ’2532,13452
Sep ’2557,69370
Oct ’2565,13063
Nov ’2586,38687
Dec ’25119,189107
Jan ’26115,880145
Feb ’26122,739138
Mar ’26138,187192
Apr ’26293,970193
May ’26200,811207
Jun ’26191,516238

1,616,622 events across 435 servers as of early July 2026. It was shared with a handful of friends at the start and spread to the rest on its own, without any advertising.

How it works

8:00pm
How to use this
  • Move people in and out of voice with the name buttons. Each move appends one immutable row to the ledger on the right. Nothing is ever overwritten.
  • Run the bot's real commands in the console below the timeline. Every answer is computed from the ledger, the same way the running bot's SQL does it.
  • Press play to let the clock run, or leave it paused and place events by hand.
  • Take the bot offline, move people around, then bring it back: reality drifts from the ledger during the gap, and reconciliation heals it with UNKNOWN_ rows dated to the last heartbeat, never to the restart.
  • Load an example to start from a ready-made scene, then query or extend it.
🔊 General
/channel: 🔊 General
Event ledger · voice_events
Move people in and out of voice. Each move appends an immutable row to the ledger. Then run the bot's real slash commands against it: point-in-time state, channel and member logs, and the sweep-line query for when a set of members shared the channel. Take the bot offline and reality drifts from the ledger; bring it back and reconciliation fills the gap with explicitly-marked UNKNOWN_ events.