Platform
Hosting & deploysPush to a branch, get a live linkDatabaseReal Postgres, one per appSign-inEmail and Google, users includedFile storageUploads, photos and documentsPaymentsCheckout and plans, same projectAI gatewayEvery model, with a hard spend cap
Solutions
Moving an app overFrom Lovable, Bolt, Replit or v0Your first real appNever shipped anything beforeSide project → businessWhen people start paying youPricing$20/month plus prepaid credits
Resources
DocsGuides written for people who are newFor AI agentsClaude Code, Cursor, MCP, JSON CLIChangelogWhat shipped, most recent firstComponentsPaste-ready UI for sign-in and moreSupportA person answers, not a queue botRefer a friendBoth of you get credits Start for $20
Open in ChatGPT Open in Claude Last updated 2026-09-24

Error tracking

Exceptions from the browser SDK or a raw POST become grouped issues — with an inbox, alert emails and suggest-fix hints.

Every thrown error becomes an issue: a group of identical occurrences built from a fingerprint of the error name, the message with numbers stripped, and the first in-app stack frame. user 12345 failed and user 9 failed are the same issue. The console Errors page is the inbox; the count, last-seen time and a kept ring of recent samples tell you whether it is noise or a fire.

From the browser: cx.js

The cx.js snippet — the same one that powers analytics — captures window.onerror and unhandled rejections on its own, and exposes manual capture:

window.cx.errors.captureException(err, { path: "/checkout", extra: { plan: "pro" } });
window.cx.errors.captureMessage("Checkout abandoned twice", { extra: { cart: cartId } });
window.cx.errors.flush(); // force the queued batch out now

Calls queue client-side and post in batches — flushed every 2 seconds, at 10 queued events, and on pagehide. The script only runs in same-origin mode: it posts to /camplax/v1/errors/i on your own domain, and the Camplax runtime attaches the project's ingest key before forwarding. The cak_live_ key never appears in your pages.

From a server: POST /v1/errors/i

Send a batch directly when you are not using cx.js:

curl -X POST https://camplax.dev/v1/errors/i \
  -H "Authorization: Bearer $CAMPLAX_ANALYTICS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "batch": [
      {
        "name": "TypeError",
        "message": "Cannot read properties of undefined",
        "stack": "TypeError: …\n    at createOrder (app/api/orders.ts:12:3)",
        "path": "/api/orders",
        "gitSha": "9f2ac1b",
        "environment": "production"
      }
    ]
  }'
  • Batch limits: 1–20 events, body at most 64 KB.
  • Event fields: name (≤200 chars, default Error), message (required, ≤2000), stack (≤8192), path, distinctId, userId, sessionId, deployId, gitSha, environment, extra (a property bag), timestamp, runtime (browser or node).
  • A 202 returns { "ingested": n }. Stacks and extra are scrubbed for lines that look like secrets before they are stored.
  • Rate limits: 30 requests/minute per key + IP and 200/minute per key; a 429 carries Retry-After.

The environment is stamped server-side, never trusted from the body. With an Origin header it is resolved from your domains; without one, deployId then gitSha are matched against this project's deploys. Only proven production events can trigger alert email — a browser claiming environment: "production" does not get to page anyone.

The inbox

Issues carry a status: unresolved, resolved or ignored. Resolve and ignore are one click in the console (or a POST); a fresh occurrence on a resolved issue reopens it as a regression and bumps a regression counter. Each issue also shows a short doctor suggestion — a first-thing-to-check hint generated from the message and stack, not a diagnosis.

EndpointWhat it does
GET /v1/projects/:slug/errors?status=&environment=List issues (default unresolved), sorted by count
GET /v1/projects/:slug/errors/:groupIdOne issue with stack, recent samples and the suggestion
POST /v1/projects/:slug/errors/:groupId/resolve · /ignore · /reopenChange status
GET · PATCH /v1/projects/:slug/errors/settingsPause collection, manage ingest origins

Setting paused makes ingest accept-and-drop: POST /v1/errors/i answers 204 and nothing is stored.

Alert emails

New production issues and regressions email your alert recipients — the same recipient list uptime alerts use, so there is one "who gets paged" list per project. A given issue can send at most one email every 6 hours; ignored issues never send.

EndpointWhat it does
GET · PATCH /v1/projects/:slug/error-alertsRead or toggle alert email ({ "enabled": false })
POST /v1/projects/:slug/error-alerts/testSend a real test alert (one per 15 minutes)

Restrict who can send

Because the ingest key is public by design, you can narrow it by origin. Under error settings, ingestOrigins is a list of up to 20 hostnames (docs.example.com) allowed to POST events — your widget hosts are already allowed. A browser POST whose Origin is not on the list gets 403 origin_not_allowed; server-to-server posts without an Origin are unaffected.

Caps

  • 50,000 production and 5,000 preview occurrences per project per month.
  • 2,000 open groups per project per environment — past that, new fingerprints are dropped (existing groups still count occurrences).
  • Over-cap ingest answers 429 { "error": "errors_capped" }, so your SDK call fails cleanly instead of silently filling a queue.
© 2026 Camplax $20 / month · credits stop at zero
Ask about Camplax