---
type: explanation
title: Gaming anti-cheat
summary: How the game is more than a challenge. A layered anti-cheat system that sets every round up on the server, runs it sandboxed in the browser, and re-verifies it by deterministic replay.
---

The game a visitor plays for a few seconds is the part you see. Underneath it is the anti-cheat system that makes the game count as proof of a human. Caputchin borrows the playbook competitive multiplayer games use against cheaters: the server is authoritative over every round, the game runs in a locked-down sandbox, and the outcome is re-derived by replaying the player's inputs. The game can be played, not faked.

This is the third verification gate, stacked with [proof of work](/docs/understanding-caputchin/proof-of-work) and [instrumentation](/docs/understanding-caputchin/instrumentation). It is configured per key on the [Security](/docs/site-keys/security) page.

## The lifecycle

A round moves through three phases: set up on the server before play, run sandboxed in the browser during play, and re-verified on the server after play.

```mermaid
sequenceDiagram
    participant V as Visitor browser
    participant S as Caputchin server
    participant G as Sandboxed game iframe
    participant R as Replay isolate
    V->>S: Request a challenge
    S->>V: Signed single-use ticket (server picks the game and seed)
    V->>G: Mount the game in an isolated iframe
    Note over G: No network, no reach into your page
    G->>V: Record the player's inputs as a trace
    V->>S: Submit the ticket and the trace
    S->>R: Re-run the trace under the same seed
    Note over R: Sealed, no network, time-bounded
    R->>S: Verdict and score
    S->>V: Signed token, only if the replay confirms the play
```

## Before the round: server-authoritative setup

Everything that decides what the round *is* happens on the server, never in the browser. This is the "never trust the client" principle from multiplayer anti-cheat: the client sends intent, the server decides reality.

- **A signed, single-use ticket** mints the round. It is short-lived and can only be spent once. A captured ticket cannot be replayed into a second pass.
- **The game and its random seed are chosen server-side** and carried in the ticket. The browser cannot pick an easier game or a friendlier seed, because it never makes that choice.
- **A different game from the eligible pool each time.** A solver never knows which game it will face, so it cannot pre-train on a single static target. Operators can narrow the rotation, but the server always picks from the allowed set. The pool itself only contains games that passed an index-time conformance check. See [build a marketplace game](/docs/marketplace-game-development/build-a-marketplace-game).

## During the round: a sandboxed game

The game runs in the visitor's browser, but inside a boundary that protects both the visitor's site and the integrity of the round.

`<caputchin-game>` mounts each game in an isolated iframe with no same-origin access, so the game has an opaque origin and cannot reach the host page's cookies, storage, DOM, or same-origin network. Its inline content-security-policy pins the script to exactly the game's bundle and blocks outbound network calls, and the bundle is checked against a known hash before it runs (a mismatch fails closed). The host page's own security policy is untouched. The precise sandbox and policy shape is documented in [how Caputchin sandboxes games](/docs/understanding-caputchin/game-sandboxing).

The takeaway: the game is untrusted-by-default and contained. It cannot exfiltrate anything, and it cannot tamper with the page it is embedded in.

## After the round: deterministic replay

When the visitor finishes, the browser submits the recorded input trace. The server does not take the browser's word for the result. It re-runs the trace.

- **The round is re-simulated on the server** under the same server-derived seed, in a sealed isolate with no network access and a hard time budget. This is the same property deterministic lockstep relies on in strategy games: identical seed plus identical inputs reproduce identical play. A trace that did not really clear the game does not reproduce a passing outcome.
- **Pass or fail is taken from that replay**, never from a number the browser reported. A client cannot claim a score it did not earn.
- **A signed token is issued only if the replay confirms the play.** That token is itself single-use when your backend later confirms it at verification time.

## What Caputchin does not do

Most game and interactive CAPTCHAs lean on behavioral signals: mouse-path entropy, tap timing, device telemetry fed to a classifier that guesses bot-versus-human. Caputchin deliberately does not. It collects no behavioral profile of the player. Instead of guessing *how* the inputs were produced, it re-derives *whether* they actually clear the game from first principles. This is both a privacy stance and a security one: there is no behavioral model to fool, only physics to reproduce.

## An honest limit

**The gate is only as strong as the game.** The anti-cheat machinery proves a round was genuinely played and not faked, but it cannot make an easy game hard. A trivial game (a static board, the winning move readable in the DOM, "click the red dot to pass") is cheap for a script to solve, and the deterministic replay will faithfully confirm those scripted inputs win, because they do. Resistance to bots comes from the game itself being hard to solve programmatically: fast, sensory, split-second reactions, with no solution sitting in the DOM. The anti-cheat layer guarantees the play was real; the game's design decides whether real play was hard to automate. Choose and build games with that in mind, see [build a marketplace game](/docs/marketplace-game-development/build-a-marketplace-game).

Pass or fail is decided by each game's own logic; the server faithfully re-runs that logic but does not second-guess what a given game considers a win. Gaming anti-cheat is strongest composed with [proof of work](/docs/understanding-caputchin/proof-of-work), [instrumentation](/docs/understanding-caputchin/instrumentation), and the rest of a key's [security settings](/docs/site-keys/security).
