Platform
Hosting & deploysPush to a branch, get a live linkDatabaseReal Postgres, one per appSign-inEmail and Google, users includedFile storageUploads, photos and documentsAI gatewayEvery model, with a hard spend cap
Resources
DocsGuides written for people who are newFor AI agentsClaude Code, Cursor, MCP, JSON CLICompareCamplax beside the stack it replacesPricingFrom $25/month plus prepaid creditsSupportA person answers, not a queue botPoliciesTerms, privacy and how we handle data Get started
Open in ChatGPT Open in Claude Last updated 2026-10-08

Feature flags

Flags per project — percentage rollouts, property targeting, per-environment switches, a user allowlist and JSON payloads — evaluated over one public endpoint.

A feature flag is a named switch with a rollout. Your app asks one endpoint which flags are on for this user, and the answer is a map of booleans — plus, for a flag that is on, an optional JSON payload. No SDK to install, no local state to sync.

A flag

Each flag has a key (new_checkout — lowercase, 2–64 characters), an on/off switch, and four kinds of targeting, applied in this order:

  1. Environments — production, preview, or both. A flag that is off for production returns false there no matter what else says.
  2. Allowed user ids — up to 100 ids that always get the flag, ahead of everything below.
  3. Rules (match) — up to 20 property rules, all of which must hold: plan is one of pro, team, seats is at least 5, email ends with @acme.com. No rules means everybody.
  4. Rollout percent — 0 to 100 of the people the rules let through. Users are bucketed deterministically on a hash of the project, the flag and the user's id, so the same person always lands on the same side of a rollout, and adding a rule never reshuffles who is in.

A project can hold 50 flags. Create them in the console under Analytics → Flags and open Targeting on a flag to edit its rules, share and payload — or use the session API at GET/POST /v1/projects/<slug>/flags, PATCH/DELETE /flags/:id.

Rules

A rule is { "property", "op", "value" }. Property names are letters, digits, _ and . (up to 64 characters).

opValueHolds when the property…
eq · neqstring, number or booleanequals / does not equal it (numbers compare as numbers)
in · not_inlist of 1–50 of thoseis / is not one of them
contains · starts_with · ends_withstringcontains / starts / ends with it, ignoring case
gt · gte · lt · ltenumberis more / at least / less / at most
exists · not_existsnonewas sent / was not sent

userId and distinctId are targetable too, and always mean the ids the request carried — a property named userId cannot stand in for them. A rule on a property the request did not send does not hold (except not_exists).

Properties come from your app, so targeting on them is a product decision — who sees the new checkout — never an access control. Anything that must be enforced belongs in your server code.

Payloads

A flag can carry any JSON value up to 4 KB — a headline, a price, a list of enabled plans. It is returned only while the flag is on for that caller, never for a flag that evaluated off.

Evaluating

Without properties, a GET:

GET /v1/flags/i?userId=user_123&distinctId=anon_abc
x-camplax-analytics-key: cak_live_…

With properties for rules, a POST (body up to 8 KB, at most 50 scalar properties):

POST /v1/flags/i
x-camplax-analytics-key: cak_live_…
content-type: application/json

{ "userId": "user_123", "distinctId": "anon_abc", "properties": { "plan": "pro", "seats": 8 } }

Both answer:

{ "flags": { "new_checkout": true, "beta_nav": false }, "payloads": { "new_checkout": { "headline": "Faster checkout" } }, "ttlSec": 30 }

From a browser, send the project's public ingest key (cak_live_…) as x-camplax-analytics-key — the same key analytics and errors use. It is publishable, so it is safe in a page. On a Camplax app the page can also call its own /camplax/v1/flags/i (GET or POST), which adds the key for you.

From your server, send the app's own token instead: Authorization: Bearer $CAMPLAX_PROJECT_TOKEN. Camplax injects it into every environment, so there is nothing to set, and it names the environment it belongs to — a preview's server always gets preview flags.

Pass userId when the user is signed in — evaluation prefers it, so signing in does not rebucket a person. Anonymous visitors are bucketed on distinctId. Send both when you have both.

What the endpoint guarantees: the environment is decided by Camplax, never by the caller — from the server's token, or from the address of the page that called (<slug>.camplax.app or a live custom domain is production, a branch--slug.camplax.app preview is preview). A call that proves neither — a server sending only the ingest key, with no token — gets 400 environment_unproven rather than a guess. Flags are not secrets, though: the ingest key is public, and a script that sets a page's Origin header itself reads what that page would. That is why targeting is never access control. The allowlist and the rules are never returned. The response is cacheable for ttlSec (30s). It is rate-limited to 120 evaluations per minute per key and IP.

From the SDK

import { createCamplax } from "@camplax/sdk";

// On your server there is nothing to pass — it reads what Camplax injects.
// In a browser, add analyticsKey: "<your public ingest key>".
const cx = createCamplax({
  flags: { getProperties: () => ({ plan: user.plan, seats: team.seats }) },
});

if (await cx.flags.get("new_checkout")) {
  const copy = await cx.flags.payload<{ headline: string }>("new_checkout");
}

With getProperties the SDK sends a POST; without it, a GET. Different properties are a different answer, so they are part of the SDK's 30-second cache key. On a server the SDK also sends CAMPLAX_PROJECT_TOKEN from the environment, so it reads the flags of the environment it runs in.

From cx.js

If your app already serves the analytics snippet, booleans are one call away — cx.js fetches /v1/flags/i for you and caches for the TTL:

if (await window.cx.flags.get("new_checkout")) { /* … */ }
const all = await window.cx.flags.all();

cx.js does not send properties or read payloads yet; use the SDK for a flag with rules.

What flags are not

They are not experiments: there is no variant split beyond on/off, no holdout and no significance maths. And a payload is configuration for a feature, not a place for secrets — anyone who gets the flag gets the payload.

Camplax

Hosting, database, sign-in and storage in one project. One login, one bill.

Platform
More
Legal
Company
© 2026 Camplax From $25 / month · credits stop at zero