Skip to content
camada
Menu

Quickstart

Django quickstart

Package camada, on PyPI.

1. Install

pip install camada

2. Environment

The key is printed once when you create a project in the app. Set these as environment variables: export them in the shell that starts your app, or add them in your host's settings. Python reads no .env file on its own.

shell
export CAMADA_KEY=<ingest_token>.<snap_token>
export CAMADA_INGEST_URL=http://localhost:8787   # dev only; defaults to production ingest

3. Wire it in

# settings.py
MIDDLEWARE = ["camada.django.CamadaMiddleware", *MIDDLEWARE]
  • Put it first, so blocked requests never reach the rest of the stack.
  • Sync and async stacks alike; the matched route pattern rides the event.

4. Add the beacon to HTML pages

Optional but recommended. The beacon cuts false positives by showing which sessions are real browsers. Use the helper.

from camada.django import script_tag
return f"<head>{script_tag(request)}</head>…"

5. Send app outcomes

Login failures, signups and checkout declines are the signals no edge position sees. The identifier is HMAC-hashed in your process. How they catch credential stuffing.

from camada.django import track
track(request, "login_failed", user=email)

Runtime

What it does per request

  1. Refreshes the snapshot off-path on a daemon thread (30 s poll with ETag, gzip on the wire). A cold start fails open.
  2. Resolves the client IP per your trusted-proxy setting. Raw X-Forwarded-For is never trusted without it.
  3. Your ordered custom rules first, then allow, block, challenge. A block gets a 403 with x-block-reason before your app runs; a challenge serves the proof-of-work page on a page load, and an API call reaches your app with an x-camada-challenge: 1 response header. The event still ships.
  4. Serves /_cam/b.js (the beacon, first-party) and relays /_cam/fp posts onto the event batch with the resolved client IP.
  5. Sets x-rid and the _sfp session cookie, and when the response is done ships one batched, redacted event.

Limits

Caveats at this position

  • Enforcement at this position covers IP, path, user-agent and request-header conditions. ASN, country and TLS-fingerprint entries fail open in-app.
  • WSGI loses the wire's header order; the analyst knows this tap cannot see it and never scores its absence.
  • Every worker process polls its own snapshot (about 5 MB each) — the server's poll_seconds keeps the cadence honest. Under gunicorn --preload the threads restart after the fork.
  • CAMADA_SERVERLESS=1 switches to lazy refresh with no poll thread.

Kill switch: CAMADA_DISABLED=1, checked per request. All other variables are listed in the docs index; the package's options and deployment notes are on the Python page.