# Cap Standalone

Cap Standalone is the recommended way to self-host Cap's backend. It runs on Bun and keeps idle memory usage around 50 MB. It ships with built-in support for instrumentation challenges, which significantly raise the bar for bots, a siteverify API compatible with reCAPTCHA, and a web dashboard for managing multiple site keys.

We recommend using [Docker](https://docs.docker.com/get-docker/) to run Cap Standalone.

## Installation

Create a `docker-compose.yml` file:

```yaml
services:
  cap:
    image: tiago2/cap:latest
    container_name: cap
    ports:
      - "3000:3000"
    environment:
      ADMIN_KEY: your_secret_password
      REDIS_URL: redis://valkey:6379
    depends_on:
      valkey:
        condition: service_healthy
    restart: unless-stopped

valkey:
    image: valkey/valkey:9-alpine
    container_name: cap-valkey
    volumes:
      - valkey-data:/data
    command: valkey-server --save 60 1 --loglevel warning --maxmemory-policy noeviction
    healthcheck:
      test: ["CMD", "valkey-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 5
    restart: unless-stopped

volumes:
  valkey-data:
```

### Tips

- `ADMIN_KEY` is your dashboard's login. We recommend making it at least 32 characters
- Change `3000:3000` if that port is already in use on your host.
- If the dashboard is unreachable, try adding `network_mode: "host"` under the `cap` service.

Start the container:

```bash
docker compose up -d
```

Open `http://localhost:3000` (or your server's IP/domain on port 3000) to access the dashboard. Log in with your admin key, create a site key, and note down both the **site key** and its **secret key**, you'll need both.

Instrumentation challenges are enabled by default when creating new site keys. We recommend keeping them on, as they significantly raise the bar for bots. You can also enable headless browser detection for additional protection.

Your Cap Standalone instance must be publicly reachable from the internet so the widget can communicate with it. If you're using a reverse proxy, review the [options guide](https://trycap.dev/guide/standalone/options.html) to configure rate-limiting correctly.

## Usage

### Client-side

Point the widget at your instance by setting the `data-cap-api-endpoint` attribute:

```
https://<instance_url>/<site_key>/
```

- `<instance_url>` — the public URL of your Cap Standalone instance
- `<site_key>` — the site key from your dashboard

Example:

```html
<cap-widget data-cap-api-endpoint="https://cap.example.com/d9256640cb53/"></cap-widget>
```

We recommend reading our [widget documentation](https://trycap.dev/guide/widget.html) for more details and example snippets for multiple frameworks.

### Server-side

Once a user completes the CAPTCHA, your backend must verify the token before trusting it. Send a `POST` request to your instance's `/siteverify` endpoint with the following JSON body:

```bash
curl "https://<instance_url>/<site_key>/siteverify" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{ "secret": "<key_secret>", "response": "<captcha_token>" }'
```

Where `<key_secret>` is the secret key from your dashboard ( **not** the dashboard admin key), and `<captcha_token>` is the challenge token generated by the widget.

A successful verification returns:

```json
{ "success": true }
```
