This bot verifies new members through a Discord button, an 8-character hexadecimal code, Google Forms, Google Sheets, moderator slash commands, and a small Discord-authenticated dashboard.
- A user joins and receives your existing
Unverifiedrole. - The user clicks a verification button in Discord.
- The bot DMs them your Google Form link, a random 8-character hexadecimal code, and their Discord user ID.
- The user enters the code and Discord user ID in the Google Form within 5 minutes.
- Google Forms writes the response to Google Sheets, including the collected email address.
- The bot checks the sheet, confirms the email domain is allowed, removes
Unverified, addsVerified, and DMs the user. - Moderators can manually verify or reject users through slash commands or the web dashboard.
Use Node.js 20 or newer.
npm installIn the Discord Developer Portal:
- Create an application and bot.
- Enable the
SERVER MEMBERS INTENT. - Copy the bot token, client ID, and client secret into
.env. - Add this OAuth2 redirect URL:
http://localhost:3000/auth/discord/callback
Use your deployed URL later if you host the dashboard publicly.
Invite it with these scopes:
bot
applications.commands
Recommended permissions:
Manage Roles
Send Messages
Read Message History
Use Slash Commands
The bot role must be above the Unverified and Verified roles in Discord's role list.
Create a Google Form with:
- A short-answer field for the verification code.
- A short-answer field for the Discord user ID.
- Any record-only fields you need, such as name and DOB.
- Email collection enabled.
Link the form to a Google Sheet.
Create a Google Cloud service account, enable the Google Sheets API, and share the response sheet with the service account email as a viewer. Put the service account email and private key in .env.
The bot expects these sheet headers by default:
Verification Code
Email Address
Discord User ID
You can change those names with SHEETS_CODE_HEADER, SHEETS_EMAIL_HEADER, and SHEETS_DISCORD_ID_HEADER.
Copy the example file:
cp .env.example .envFill every value in .env. Keep .env private.
npm run register:commandsnpm startThe dashboard will run at:
http://localhost:3000
/verification-panelposts the public button users click to start verification./verify-user user:<member> reason:<optional>manually verifies a member./reject-verification user:<member> reason:<optional>rejects a member./verification-status user:<member>shows the stored verification status.
Commands are moderator-only by Discord permission and by role checks inside the bot.
Open the dashboard URL, sign in with Discord, and use the action panel to:
- Manually verify a Discord user ID.
- Reject a Discord user ID.
- Re-check pending users against Google Sheets.
Access requires either:
- A role listed in
MODERATOR_ROLE_IDS, or - A Discord user ID listed in
DASHBOARD_ALLOWED_USER_IDS.
- Verification codes expire after 5 minutes by default.
- Local state stores Discord IDs, generated codes, status, timestamps, and sheet row references. It does not store form names, DOBs, or full email addresses.
- The Google Sheet remains the source of truth for submitted form data.
- If a user has DMs disabled, they will see a Discord message asking them to enable DMs and try again.