A feature-rich Discord bot for easily generating and hosting quizzes with up to hundreds of users playing along.
- Generate endless quizzes: Create a spreadsheet anywhere, upload it to Quiz Unlocked, and randomly generate quizzes using all the info contained in it. You can also manually write a quiz or a question bank.
- Engaging real-time competition: your Discord community plays along together in a real time trivia game with dynamic updating embeds, a customizable hint system, and extra points for speed.
- Leaderboards, stats, and study modes: participants can check their weekly/monthly/yearly/overall ranking and save study materials to practice and improve their performance.
- Admin controls: lock down any commands to require "Manage Server" permissions.
- Sophisticated architecture: Built with strictly-typed TypeScript, Discord.js v14, and Prisma ORM. Database persistence with PostgreSQL. Hundreds of unit and integration tests with vitest.
Want advanced role support, Google sheets integration, or a web editor? Join the waitlist for Quiz Unlocked Pro
Quiz Unlocked Free Open Source can be hosted on your own computer or server.
- Node.js 18.0.0 or higher
- npm or yarn
- PostgreSQL
- your own Discord bot token (from Discord Developer Portal)
Don't know how to self-host? You can still add Quiz Unlocked to your Discord server for free
When setting up your Discord bot, you'll need to configure the following OAuth2 scopes and permissions:
bot- Required for bot functionalityapplications.commands- Required for slash commands
The bot requires the following Gateway Intents to be enabled in your Discord application:
Server Members Intent- Required to access member information for leaderboards and user management
The bot requires the following permissions:
General Permissions:
Send Messages- To send quiz questions and responsesUse Slash Commands- To respond to slash command interactionsEmbed Links- To send rich embeds for leaderboards and quiz informationAttach Files- To potentially send quiz results or images
When creating your bot invite URL, include these scopes and permissions:
https://discord.com/api/oauth2/authorize?client_id=YOUR_CLIENT_ID&permissions=8&scope=bot%20applications.commands-
Clone the repository
git clone <repository-url> cd discord-quiz-bot
-
Install dependencies
npm install
-
Set up environment variables
cp env.example .env
Edit
.envand add your Discord bot token and other configuration:DISCORD_TOKEN=your_discord_bot_token_here DISCORD_CLIENT_ID=your_discord_client_id_here DISCORD_DEV_GUILD_ID=your_guild_id_here DATABASE_URL="postgresql://username:password@host:5432/database_name"
-
Set up the database
Development:
npm run db:deploy:dev
npm run devFor PostgreSQL (Production):
npm run db:deploy
npm run build
npm startNotes:
- The
startcommand automatically deploys Discord slash commands and then starts the bot - Ensure your
DATABASE_URLis a valid PostgreSQL connection string
/quiz start <quiz_name>- Start a new quiz session/quiz stop- Stop the current quiz/quiz status- Check current quiz status/quiz upload [title] [file]- Upload a CSV file to create a custom quiz/quiz template- Get a CSV template for creating custom quizzes/quiz create- Create a new quiz with interactive form/quiz edit <quiz_id>- Edit an existing quiz/quiz delete <quiz_id>- Delete a specific quiz
/leaderboard- View leaderboard/stats- View your own performance stats/user stats @username- View another user's performance stats
/admin delete everything- Delete all the data in the database/admin delete userdata @username- Delete all data by one user
/botowner status- Check bot and database status
The bot supports creating custom quizzes by uploading CSV files. This feature allows users to easily create quizzes from existing question banks or spreadsheets.
The CSV file should have the following columns:
| Column | Type | Required | Description |
|---|---|---|---|
questionText |
string | Yes | The question text |
options |
JSON array | Yes | Array of answer options (e.g., ["Option A","Option B","Option C","Option D"]) |
correctAnswer |
integer | Yes | 0-based index of the correct answer |
points |
integer | No | Points for this question (1-100, default: 10) |
timeLimit |
integer | No | Time limit in seconds (10-300, default: 30) |
questionText,options,correctAnswer,points,timeLimit
"What is the capital of Poland?","[""Warsaw"",""Krakow"",""Gdansk"",""Wroclaw""]",0,10,30
"What is the Polish word for 'hello'?","[""Cześć"",""Dzień dobry"",""Do widzenia"",""Dziękuję""]",0,10,30
"What is 2 + 2 in Polish?","[""Dwa"",""Trzy"",""Cztery"",""Pięć""]",2,5,15
- File size: Maximum 25MB
- File type: Must be CSV format
- Questions: Maximum 100 questions per quiz
- Options: Must be valid JSON array with at least 2 options
- Correct answer: Must be a valid index within the options array
- Points: Must be between 1-100 (optional, default: 10)
- Time limit: Must be between 10-300 seconds (optional, default: 30)
app/
├── commands/ # Slash command handlers
├── events/ # Discord event handlers
├── services/ # Business logic services
├── types/ # TypeScript type definitions
├── utils/ # Utility functions
└── index.ts # Main entry point
data/
docs/
prisma/
public/
scripts/
tests/npm run dev- Start development server with hot reloadnpm run build- Build the projectnpm run start- Start production servernpm run lint- Run ESLintnpm run lint:fix- Fix ESLint errorsnpm run format- Format code with Prettiernpm test- Run testsnpm run db:generate- Generate Prisma clientnpm run db:push- Push schema to databasenpm run db:studio- Open Prisma Studionpm run deploy-commands- (Re)deploy bot commands to your configured dev servernpm run deploy-commands -- --guildId=1234567890- (Re)deploy bot commands to the given servernpm run reset-commands- Clear all registered Discord commands (global and server-specific)npm run reset-commands -- --guildId=1234567890- Clear commands for a specific server
This project uses:
- TypeScript with strict mode enabled
- ESLint for code linting
- Prettier for code formatting
- vitest for testing
- Husky for git hooks
The project uses Prisma as the ORM with PostgreSQL as the database. The schema is defined in prisma/schema.prisma.
| Variable | Description | Required |
|---|---|---|
DISCORD_TOKEN |
Discord bot token | Yes |
DISCORD_CLIENT_ID |
Discord application client ID | Yes |
DISCORD_GUILD_ID |
Discord guild ID (for development) | No |
DATABASE_URL |
Database connection string | Yes |
NODE_ENV |
Environment (development/production) | No |
LOG_LEVEL |
Logging level | No |
| Variable | Description | Default |
|---|---|---|
DEFAULT_QUESTION_TIMEOUT |
Default question time limit (seconds) | 30 |
DEFAULT_QUIZ_TIMEOUT |
Default quiz time limit (seconds) | 300 |
POINTS_PER_CORRECT_ANSWER |
Base points for correct answer | 10 |
SPEED_BONUS_MULTIPLIER |
Speed bonus multiplier | 0.1 |
STREAK_BONUS_MULTIPLIER |
Streak bonus multiplier | 0.05 |
This application uses PostgreSQL for both development and production environments, with a single schema file (prisma/schema.prisma).
| Variable | Description | PostgreSQL Example |
|---|---|---|
DATABASE_URL |
Connection string | "postgresql://user:pass@host:5432/db" |
| Script | Purpose | Use Case |
|--------|---------|-------------|----------|
| npm run db:migrate:deploy | Apply migrations | Recommended for production |
| npm run db:deploy | Generate client + deploy | Production setup |
| npm run db:studio | Open Prisma Studio | Database browsing |
Development Workflow (Prisma Best Practice):
- Make changes to
prisma/schema.prisma - Run
npm run db:migrate --name describe_your_change - Test your changes
- Commit both schema and migration files
Production Workflow (Prisma Best Practice):
- Deploy migrations:
npm run db:migrate:deploy - This should be part of your CI/CD pipeline
- Never run
migrate devin production
If you encounter duplicate commands or deployment issues, use the reset script to clear all registered commands:
# Clear all commands (global and configured guild commands)
npm run reset-commands
# Clear commands for a specific guild
npm run reset-commands -- --guildId=YOUR_GUILD_IDNote:
- Global command changes may take up to 1 hour to propagate
- After resetting, redeploy your commands with
npm run deploy-commands - This is useful when switching between development and production deployments
This error occurs when the database schema hasn't been initialized. Solution:
# Run database setup before starting the bot
npm run db:deploy
npm run build
npm startError: "connection to server failed" or database connection errors
Solutions:
- Verify your
DATABASE_URLformat:postgresql://username:password@host:port/database - Ensure the PostgreSQL database exists and is accessible
- Check firewall settings and network connectivity
- Verify database credentials and permissions
Environment Setup:
- ✅ Environment variables set (
.envfile or environment)DATABASE_URLwith valid PostgreSQL connection stringDISCORD_TOKENandDISCORD_CLIENT_IDsetNODE_ENV=production(recommended)
- ✅ Dependencies installed (
npm install) - ✅ Database initialized (
npm run db:deploy) - ✅ Project built (
npm run build) - ✅ Bot started (
npm start) - automatically deploys commands
Database Support:
- ✅ Development & Production: PostgreSQL with migrations -
schema.prisma
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
If you encounter any issues or have questions, please open an issue on GitHub.