Skip to main content
Autter Runtime captures errors and usage from your frontend and backend. Compatible server releases also capture structured logs and operation outcomes. This guide sets up capture and checks stored data; follow Operation logging for the new logging APIs and required deployments.
Prefer to have an AI coding agent set this up for you? See AI agent skills — npx skills add Autter-dev/autter-skills --all, then tell your agent “install Autter Runtime in this project.”

Concepts

Two kinds of keys — never mix them up: Two ways to send browser events:
  • Relay (recommended, including static sites) — the browser posts to a same-origin route on your server, Worker, or edge function, which forwards with your server key. Allow the relay in connect-src (usually 'self') and check the actual browser request. See Stack integrations for the serverless relay.
  • Direct (lossy fallback for pure-static only) — the browser posts straight to the ingester with a publishable client key. Ad-blockers silently drop these cross-origin requests.
What is never sent: cookies, DOM content, form values, request/response bodies, headers, emails, full URLs with query strings. Use a Runtime ingest key, not an Autter CLI/PAT or MCP token. Keep the key value in your environment; your coding agent only needs its variable name. Custom log context is application-authored: do not include sensitive data, even though the SDK and ingester redact it.
1

Run the ingester

For a local try-out, clone the repo and start ClickHouse plus the ingester with Docker Compose:
There’s no key step. The local Compose setup accepts the built-in key autter_rt_local_dev_only, but only from your own machine. A deployed ingester never accepts it. Point your app at it and check the connection:
verify goes through key, network, ingester, storage, auth, ingest, stored, trace, release and logs, and stops at the first step that fails with what to do. Its test event never opens an issue. Run it first whenever events don’t show up. See Is my data arriving?.For real deployments, see Self-hosting or use Autter’s hosted ingester at otlp.autter.dev: set AUTTER_ENDPOINT=https://otlp.autter.dev and your repository’s server key, then run the same two commands.
2

Instrument your backend

Create instrument.cjs — it must load before your app:
Reuse your existing SDK initialization if you already have one. The example opts into bounded, local slow-request trace retention. Set GIT_SHA to the deployed commit SHA. See Endpoint regressions for metric requirements and retention limits.This records HTTP request metrics and captures crashes and unhandled promise rejections. A rejection from a promise started during a request keeps that request’s route and request id.On Express, add request ids and the error hook to your app:
With @autter/runtime-node 1.10.0 or later, the error behind every Express 5xx is recorded with its type, message, stack, route and request id even without autterErrorHandler(). That holds in every router, including routers with their own error handler. The handler adds coded errors that end in a 4xx, and it never reports an error twice, so one app.use(autterErrorHandler()) at app level is enough. On older versions it is required: without it a thrown error shows up only as GET /route returned 500, with no stack. Fastify and Koa need their hooks (autterFastifyErrors, autterKoa); see Integrations.For handled errors:
A run that returns normally but did not do its job (a declined payment) is not an exception. Declare it so it becomes an issue:
Test it without an ingester: @autter/runtime-node/testing keeps every record in memory.
Then check the real path: npx @autter/runtime-node verify --service payments-api. If your app has no key, or the ingester refuses it, the SDK prints one line saying so at startup or on the first refusal.
3

Add server operation diagnostics

Node/Next.js SDK and ingester 1.4.0+ are required (compatibility table). npx @autter/runtime-node doctor shows whether operation logging is active for your installed SDK and ingester, and verify checks that a log record is stored.Once supported, add logging options to the existing initialization and wrap meaningful checkout/job boundaries with withRuntimeOperation. Record measured steps, bounded nested context, and explicit business outcomes. Use runtimeLogger.info/warn/error for diagnostics, while keeping exception or declared failed-outcome capture for issues.Follow the checkout example. A callback that returns normally defaults to success, so declare a failed payment result explicitly. Preserve existing loggers and await flushing at the end of short-lived jobs. If support is pending, continue basic capture and report that gap.
4

Instrument your frontend

Add a relay route to your backend (the key stays server-side):
Then initialize the tracker in your frontend entry point:
No backend? See the direct setup and full walkthrough in Installation.
5

See your own events

verify proves the path; it is safe in production because its test event never opens an issue or counts as a request. To see your app’s own events locally, trigger an error, wait a few seconds (server errors arrive within 2 s, request counts within 60 s; see arrival times), then query ClickHouse. In production, inspect existing traffic instead:
With the local Compose setup: docker compose exec clickhouse clickhouse-client --password dev.When operation logging is enabled, verify it separately:
These queries are for your local development database. In the platform, open the intended repository’s Runtime → Logs, inspect the captured IDs, and confirm the failed issue’s Operation evidence. Logs and traces may arrive separately; refresh or rerun analysis for later evidence. An unavailable source differs from an available source with no matching rows. See logging verification.

Production checklist

  • Server keys only in backend env vars; client keys only where a relay is genuinely impossible.
  • Client keys have allowedOrigins set to your exact app origins.
  • release is wired to your git SHA in both frontend and backend — it powers regression detection (“broke in release X”).
  • Keep trace sampling at ~1% (traceSampleRate) — errors are always captured regardless (what is sampled).
  • npx @autter/runtime-node verify passes from where the app runs (CI or the deployed host), with the production endpoint and key.
  • Confirm the logging SDK release and ingester/platform deployment separately; redeploy the application after upgrading.
  • Declare business outcomes, preserve existing loggers, and check buffered/dropped records and flush failures. Logs are best-effort diagnostics.
  • Check export volume after enabling retainTracesAboveMs. The platform rollout does not enable this option in existing applications.
  • The relay route keeps its built-in per-IP rate limit, or your WAF covers it (perIpRateLimit: false).
  • Direct browser ingest: your CSP includes connect-src https://your-ingester…, and you accept that ad-blockers may drop some events (the relay avoids this).
  • The ingester’s /healthz is wired to your load balancer health check.

Installation

Install the right package for your stack, including Next.js.

Stack integrations

Per-stack setup for React, Node, Next.js, Go, Rust, and any OpenTelemetry SDK.