Self-hosted service
Ralex91/Razzia avatar
Ralex91/Razzia

Razzia: a self-hosted quiz server for small events, with a WebSocket protocol for custom buzzers

A self-hosted, open-source quiz platform for smaller events.

1,017 stars44 forksTypeScriptMIT

At a glance

What is it?
Razzia is a TypeScript quiz platform you run on your own machine, configured through a mounted config folder. The interesting part is not the quiz UI, it is the documented WebSocket protocol that lets you build your own client, including a physical buzzer.
Who is it for?
Adopt Razzia if you run quizzes for a room-sized group and want the game state on your own hardware, especially if you intend to build a custom client against docs/websocket-protocol.md. Do not adopt it if you need hosted accounts, remote participants, or an audit trail of who answered what.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem Razzia solves: quiz night without a third-party account

Most quiz tools assume a hosted service. You create an account, the question set lives on someone else's server, and the event depends on that provider staying up and keeping its free tier. Razzia inverts this. The README describes it as "a straightforward and open-source quiz platform, allowing users to host it on their own server for smaller events." The scope word is smaller. This is not a product for a thousand-player tournament; it is for a room, a projector, and a set of phones.

The README also carries an explicit disclaimer that the project is independent and not affiliated with, endorsed by, or sponsored by any third-party quiz platform, and that any resemblance is incidental. That sentence exists because the genre has an obvious incumbent, and the author wants the boundary drawn clearly. Read it as a signal about intent: Razzia is not trying to be a drop-in clone with an import path from a commercial service. It is a separate thing you run yourself.

Who is it for, concretely? Someone with a server or even a laptop, a Docker runtime, and an audience small enough that one process on port 3000 can serve every player. The manager interface and the player interface are the same web app, separated by a password.

Architecture visible from the repository: one process, one config volume, one WebSocket surface

The stack is TypeScript with React, per the repository topics and primary language. The deployment unit is a single container listening on port 3000. There is no database mentioned anywhere in the README. Instead, persistence is a mounted directory: the Docker example uses -v ./config:/app/config, and the README explains that this lets you edit configuration files on the host, keep settings across container updates, and back up quizzes by copying a folder.

That is the whole data flow as documented. Quizzes and game settings live as files under config. The manager loads them, starts a game, and players connect to the same origin. The README's play instructions are numbered and short: open the manager interface at http://localhost:3000/manager, enter the manager password from config/game.json, share the game URL and room code, wait for players, click start.

The room code is the join mechanism. It is generated per game rather than configured, which is why the instructions say to share the game URL and the room code together. Nothing in the supplied material describes how room codes are generated or how long they live, so treat that as an open question if you plan to run back-to-back sessions.

The third surface is the one worth paying attention to. docs/websocket-protocol.md is listed in the documentation index with the note that it exists so you can "build a custom client (e.g. an ESP32 physical buzzer)." A documented wire protocol is a deliberate design choice: it means the browser client is one implementation among possible ones, not the only way in.

Getting it running: docker compose up, or Node 24 with pnpm

Two paths are documented. The Docker path is marked recommended. The repository ships a compose file, referenced in the README as /compose.yml, and the command is:

docker compose up -d

If you prefer a bare container, the README gives this example:

docker run -d -p 3000:3000 -v ./config:/app/config ralex91/razzia:latest

The same image is published to the GitHub Container Registry, so ghcr.io/ralex91/razzia:latest works as an alternative to Docker Hub. The README states the config folder is created automatically on first run, with an example quiz inside. The app then answers at http://localhost:3000.

The non-Docker path requires Node.js 24 or higher and pnpm 10.16 or higher. Clone the repository, run pnpm install, then either pnpm dev for development or pnpm build followed by pnpm start for production. Note the version floors: Node 24 is a recent major, so a long-term-support box on an older release will not satisfy the prerequisite as written.

Configuration is a single required step. In config/game.json you set managerPassword. The README is emphatic that the value must be changed from the default string PASSWORD, because otherwise manager access is blocked. That is a fail-closed default, and it is the right call: shipping a working default password would be worse. But it also means a fresh deployment looks broken until you edit the file. If your manager page rejects you on first boot, check that file before anything else.

Three further documents are listed for operational work: docs/configuration.md for the manager password, docs/quiz.md for creating and structuring quizzes, and docs/reverse-proxy.md for running behind Traefik, Nginx, or Caddy. The supplied material does not reproduce their contents, so the exact quiz file schema is not something I can state here.

The WebSocket protocol is the reason to pick Razzia over a hosted quiz site

Every quiz platform has a question screen and a scoreboard. The differentiator in this repository is that the transport is documented as a public interface. The README points at docs/websocket-protocol.md and names the motivating use case: an ESP32 physical buzzer. That is a specific, non-trivial target. It implies the protocol is simple enough to implement on a microcontroller, and that the author expects people to write clients the project does not ship.

For an event organiser this changes what is possible. A buzzer built from a cheap board removes the latency question of who tapped a phone screen first, because the input device is dedicated hardware on the local network rather than a browser tab competing for attention. It also means you are not limited to phones as the player device.

I cannot verify the protocol's shape from the supplied material. The README lists the document but does not summarise message types, authentication, or reconnection behaviour. Before committing to a custom client, read that file directly. If it turns out to be a thin description of the browser client's own messages rather than a stable contract, the ESP32 use case becomes a reverse-engineering exercise. That is the single most important thing to check, and it is checkable in a few minutes.

Where Razzia is the wrong tool

The most obvious limitation is stated by the project itself: smaller events. Nothing in the README describes scaling, load testing, or multi-instance deployment. The architecture as documented is one container, one config directory, one port. There is no mention of a shared datastore, so running two replicas behind a load balancer would give you two independent game states unless the underlying design says otherwise, and the supplied material gives no reason to think it does.

Remote participation is a second gap. The play instructions assume players join a shared URL and a room code. There is no account system, no lobby moderation, and no described mechanism for keeping a room private beyond the code itself. If your event involves strangers, or if you need to remove a disruptive player mid-game, the documentation does not describe how.

File-based persistence is a trade-off, not a flaw. It makes backup a folder copy and makes quizzes diffable and version-controllable, which is genuinely pleasant. It also means concurrent edits to the same file have no coordination layer, and there is no query surface for post-event analysis. If you want to know which question the room found hardest, you would be reading raw files, and the README does not describe an export or reporting feature.

Finally, the manager password is a single shared secret in a JSON file. There is no mention of user accounts, roles, or per-manager credentials. For a club night that is proportionate. For anything where multiple people need differentiated access, it is not.

How it differs from Kahoot, and from running slides yourself

The realistic comparison is a hosted quiz service of the Kahoot type. The difference is not features, it is where the state lives and who can change the rules. A hosted service gives you accounts, question banks in a web editor, and a player base that already has the app. It also gives you a dependency: your event runs at the provider's discretion, on the provider's schedule, over whatever the venue's uplink happens to be. Razzia's entire value proposition is removing that dependency. The trade is that you now own the server, the updates, and the backup.

The second comparison is a slide deck with hand raising, which is what most small events actually use. A deck has zero setup cost and no failure mode beyond the laptop dying. Razzia adds automatic scoring, a room code join flow, and the WebSocket surface for custom input devices. If your quiz is six questions for twelve people, the deck wins on effort. If you are running a recurring event and want scores computed for you, Razzia is the smaller jump.

A third option worth naming is writing your own. The repository is TypeScript and the protocol is documented, so a determined team could build a bespoke client. The reason not to is the manager interface, the quiz file format, and the join flow, all of which already exist here under MIT. Building your own only makes sense if your requirements diverge sharply from a room-sized, self-hosted quiz.

Maintenance, upgrades and the MIT licence

Razzia is MIT licensed. In practical terms that means you can run it, modify it, and ship it inside a commercial event without a copyleft obligation on your own code. It does not mean the project owes you support, and it does not remove the attribution requirement. I am not giving legal advice; read the LICENSE file in the repository if the terms matter to your situation.

The release cadence visible in the supplied material shows 3.0.0 in May 2026, then 3.0.1 and 3.1.0 both in July 2026, with the last push to the default branch in September 2026. A patch release on the same day as the minor suggests the 3.1.0 line needed a quick fix, which is normal and not alarming. It does mean you should read the release notes for 3.1.0 before jumping from 3.0.x rather than assuming a smooth upgrade.

Upgrade cost is low by design. Because state lives in a mounted config directory rather than inside the container, updating is a matter of pulling a new image tag and restarting. The README explicitly lists keeping your settings when updating the container as a benefit of the volume mount. The one thing to re-check after any upgrade is config/game.json, since the manager password is read from there and a schema change would show up as a locked manager page rather than an error message.

There is no migration tooling mentioned, and no versioned config schema. If a future release changes the quiz file format, the supplied material gives no indication of how that would be handled. Keep the config folder in version control so you can diff it after an upgrade.

Editorial conclusion

Adopt Razzia if you run quizzes for a room-sized group and want the game state on your own hardware, especially if you intend to build a custom client against docs/websocket-protocol.md. Do not adopt it if you need hosted accounts, remote participants, or an audit trail of who answered what. Before your first event, open config/game.json and confirm managerPassword is no longer the literal string PASSWORD, because the README states manager access is blocked while that default remains.

Official sources

  1. Issues
  2. License: MIT
  3. Ralex91/Razzia on GitHub
  4. README
  5. Releases
Community notes

Community notes