Error capture
Capture exceptions and unhandled rejections as $error events on the same pipeline as the rest of your traffic. Server-side capture is documented per-language on each SDK page; this page covers the browser-side opt-in and the wire shape that's common to all SDKs.
Paste to your agent
Browser capture
The browser SDK exposes captureError() for manual capture and an init option for automatic capture of uncaught exceptions and unhandled promise rejections.
import { captureError } from "@clamp-sh/analytics"
try {
riskyOperation()
} catch (err) {
captureError(err, { feature: "checkout", retry: 1 })
}To auto-capture every uncaught exception and unhandled rejection:
import { init } from "@clamp-sh/analytics"
init("proj_xxx", { captureErrors: true })The error-capture machinery lives in a separate chunk that lazy-loads on first use, so users who never enable it pay zero bytes for it.
Server-side capture
Each server SDK exposes its own captureError-style method. See the per-language page for the exact import and signature:
- Node / Edge — Cloudflare Workers, Vercel Edge, Deno Deploy, Bun
- Python — Django, FastAPI, Flask, Celery
- PHP — Laravel, Symfony, WordPress
- Go — net/http, gin, echo
- Ruby — Rails, Sinatra, Sidekiq
Event shape
Each captured error is a $error event with structured properties. Standard event fields (url, browser, OS, device_type, country, anonymous_id, session_id) are auto-populated by ingest the same way as any other event, so errors can be sliced by any traffic dimension.
{
"name": "$error",
"properties": {
"error.message": "Cannot read property 'foo' of undefined",
"error.type": "TypeError",
"error.stack": "TypeError: ...\n at checkout.js:42:18\n ...",
"error.handled": false,
"error.fingerprint": "<server-computed sha256 prefix>"
},
"url": "https://app.example.com/checkout",
"browser": "Safari",
"os": "iOS",
"device_type": "mobile",
"country": "DE",
"anonymous_id": "anon_xxx",
"session_id": "ses_yyy",
"timestamp": "2026-05-01T12:34:56Z"
}Fingerprint is computed server-side at ingest as a sha256 of the normalized error message plus the first stack frame (file:line). It groups the same bug across occurrences regardless of which session or SDK reported it. No source-map resolution today; production stacks are stored verbatim.
Length caps: error.stack up to 16KB, error.context up to 4KB, error.message up to 1KB. Other event property strings stay capped at 512 chars. Rate limit (browser only): up to 5 occurrences of the same message per session, then dropped. Server-side fingerprinting still groups across sessions.
Reading errors via MCP
Four MCP tools cover the questions an agent typically asks once errors are flowing.
errors.list
Recent error events with full context. One row per occurrence, newest first. Filter by message, fingerprint, browser, OS, device type, country, or handled flag.
errors.groups
Errors deduplicated by fingerprint, with count, users_affected, first_seen, and last_seen per group. Sort by count (default), users_affected, first_seen, or last_seen.
errors.timeline
Error count over time, hourly or daily buckets. Optionally scoped to one fingerprint to chart a single bug's rate.
errors.context
Breadcrumbs leading to one error: the events from the same session, before the error timestamp, in chronological order.
See MCP tools for full parameter details.
Plan
$error is a custom event, which requires a Pro or Growth plan to land in your charts. The browser SDK still installs the listeners on the free plan, but the events are dropped at ingest. See pricing for the per-plan event quotas.