---
type: explanation
title: Proof of work
summary: Why Caputchin makes the browser do a little computation before issuing a token, and how that raises the cost of abuse.
---

Every verification asks the visitor's browser to solve a small computational puzzle before Caputchin issues a token. That puzzle is the proof of work.

## How it works

Caputchin hands the browser a challenge and asks it to find a number (a nonce) that, when hashed together with the challenge, produces a hash beginning with a required count of leading zeros. There is no shortcut: the browser has to try nonce after nonce until one happens to work. Finding a valid nonce takes many attempts; checking one is a single hash. So the work is hard to do but cheap to verify, and Caputchin confirms the answer clears the required difficulty.

## Content-Security-Policy

The solver runs in a Web Worker, which the widget creates from a `blob:` URL, so the embedding page's Content-Security-Policy must allow `blob:` for workers (`worker-src blob:`, or `child-src` / `default-src` as the fallback chain). This part is required: there is no main-thread fallback, so a policy that blocks the worker blocks verification. Separately, the solver compiles a WebAssembly routine for speed, which needs `'wasm-unsafe-eval'` in `script-src`. That part is optional: without it the same solver runs slower in pure JavaScript inside the Worker. See [game sandboxing](/docs/understanding-caputchin/game-sandboxing#the-csp-you-set-on-your-own-page) for the complete host-page policy.

## Why it deters abuse

The point is not to make any single solve impossible. It is to make abuse at scale uneconomic.

A real visitor solves one puzzle in a fraction of a second and never notices. A bot that wants to fire thousands of requests pays that compute cost thousands of times over. If clearing the challenge costs more than the spam is worth, the attack stops making financial sense. Proof of work shifts the goal from "unbreakable" to "not worth it."

## The knobs

Two settings on a key's [Security](/docs/site-keys/security) page tune the cost:

- **Difficulty** sets how many leading zeros the hash must have, which raises the cost of each solve.
- **Challenges per request** multiplies that cost by asking for several solves at once.

## An honest limit

No challenge is unbreakable; given enough money, anything can be solved. Proof of work accepts that and competes on cost instead. It also only proves that *effort* was spent, not that a real browser spent it, which is why Caputchin pairs it with [instrumentation](/docs/understanding-caputchin/instrumentation) to check the environment too.
