You need to track who changed a role permission or channel override in your Discord server. Manual review of the audit log is slow and unreliable for large servers. Discord provides a REST API endpoint that lets bots poll the audit log programmatically. This article explains how to set up a bot that uses the Get Guild Audit Log endpoint to capture permission changes automatically.
Key Takeaways: Building a Bot to Poll Audit Log for Permission Changes
- Get Guild Audit Log endpoint (GET /guilds/{guild.id}/audit-logs): Returns a list of audit log entries that include action type, target, user, and changes.
- Action type 24 (MEMBER_ROLE_UPDATE) and 31 (CHANNEL_OVERWRITE_UPDATE): Filter for these specific action types to capture permission modifications.
- Bot with ‘view_audit_log’ permission: The bot must have this permission in the server to access the audit log endpoint.
How the Discord Audit Log Endpoint Works for Permission Auditing
The Discord Audit Log API allows bots to retrieve a server’s audit log entries. Each entry contains an action type, the user who performed the action, the target object (role, channel, or member), and a changes array that lists what was modified. For permission changes, the relevant action types are 24 for member role updates, 31 for channel overwrite updates, 3 for role create, 4 for role delete, 5 for role update (includes permission bitfield changes), and 10 for channel update (includes permission overwrites).
The endpoint is rate-limited. Bots can make 10 requests per 60 seconds per server. Each request returns up to 100 entries. To capture all changes, you must poll the endpoint repeatedly and store the last processed entry ID to avoid duplicates.
Prerequisites for Using the Audit Log Endpoint
Before writing code, ensure your bot has the following:
- The
view_audit_logpermission (bitwise value 0x80) in the target server. - A bot token with the
botscope and theguildsintent enabled. - Access to the server ID where you want to audit permission changes.
Steps to Build a Bot That Polls Audit Log for Permission Changes
The following steps use Python with the discord.py library version 2.3 or later. You can adapt the logic to other languages and libraries.
- Install discord.py and set up the bot client
Runpip install discord.py. Create a bot client with theintents.default()andintents.guilds = True. ReplaceYOUR_BOT_TOKENwith your actual token. - Define the audit log action type constants
Import theAuditLogActionenum from discord.py. The constants you need areAuditLogAction.member_role_update(24),AuditLogAction.channel_overwrite_update(31),AuditLogAction.role_update(5), andAuditLogAction.channel_update(10). - Create a polling function that fetches audit log entries
Define an async function that callsguild.audit_logs(limit=100, after=last_entry_id). Theafterparameter ensures you only get new entries since the last poll. Storelast_entry_idin a file or database. - Filter entries by action type and extract change details
Loop through the returned entries. For each entry, checkentry.actionagainst the relevant action types. If it matches, extractentry.user(the moderator),entry.target(the role or channel), andentry.changes(a list ofAuditLogChangeobjects). Each change hasbeforeandaftervalues. - Parse the changes array to identify permission modifications
For role updates, the changes includepermissions(a bitfield). Comparebefore.valueandafter.valueusing bitwise operations to determine which permission bits were added or removed. For channel overwrites, the changes includeallowanddenybitfields for the overwrite target. - Log or send the audit data to a designated channel
Format the extracted data into a readable message. Use an embed with fields for user, target, action type, and changed permissions. Send the embed to a private logging channel usingchannel.send(embed=embed). - Run the polling loop on a timer
Usetasks.loop(seconds=10)from discord.py to run the polling function every 10 seconds. This respects the rate limit while keeping the audit log relatively up to date.
Common Issues and Limitations When Polling the Audit Log
Bot Does Not See Recent Audit Log Entries
The audit log endpoint only returns entries that the bot has permission to see. If the bot lacks the view_audit_log permission on a specific channel or role, it may not see entries related to that object. Grant the bot the Administrator permission temporarily for testing, then reduce to the minimum required permissions.
Rate Limits Cause Missed Entries
If your poll interval is longer than 10 seconds, you might miss entries if many changes happen in a short burst. The audit log endpoint has a 10-request-per-minute limit per server. Set your poll interval to 6 seconds or longer to stay under the limit. If you need near-real-time auditing, consider using Discord’s Gateway events instead of polling.
Change Objects Contain Opaque Bitfields
The before and after values for permission changes are integers representing bitfields. You must decode these using Discord’s permission flag constants. In discord.py, use Permissions(before.value) to convert to a readable Permissions object. Then compare the Permissions objects to list added and removed permissions.
Entry IDs Are Not Sequential Across Restarts
If your bot restarts, the stored last_entry_id might be stale. The audit log endpoint returns entries in reverse chronological order. Always use the after parameter with the ID of the last entry you successfully processed. If you lose the stored ID, start from the current time and accept that you may miss entries from the downtime.
| Item | Polling via REST API | Gateway Events (GUILD_AUDIT_LOG_ENTRY_CREATE) |
|---|---|---|
| Real-time delivery | No, polled every N seconds | Yes, pushed immediately |
| Rate limit | 10 requests per 60 seconds per server | No rate limit on event receipt |
| Implementation complexity | Low, simple HTTP requests | Medium, requires intent and event handler |
| Data completeness | May miss entries between polls | Complete if connection is stable |
| Permission requirement | view_audit_log | view_audit_log |
The table above compares the two main methods for capturing audit log data. For most permission auditing needs, polling is sufficient and easier to implement. Use the Gateway event approach only if you require sub-second notification of changes.
You can now build a bot that polls the Discord audit log endpoint to track permission changes in your server. Start by implementing the polling loop with a 10-second interval and storing the last processed entry ID in a persistent database. For advanced auditing, consider combining the polling approach with a background task that also listens for the GUILD_AUDIT_LOG_ENTRY_CREATE Gateway event to reduce latency. Always test your bot in a small server before deploying to production to ensure the permission filtering logic works correctly.