Skip to content
camada
Menu

Quickstart

Flask 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

from camada.flask import init_app
init_app(app)   # wraps app.wsgi_app, so camada answers before routing
  • Wraps the WSGI app rather than registering a before_request hook: the beacon and challenge endpoints answer before routing.

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.flask import script_tag
return f"<head>{script_tag()}</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.flask import track
track("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.