Install for your stack
Pick your language or framework and copy the install and config steps that connect it to Unhandled.
Unhandled stores standard OpenTelemetry data, so every stack connects the same way: something in your process exports OTLP over HTTP with the three headers taken from your DSN. What differs is how much of that is done for you.
The full agent. One installer writes the config, registers the provider and middleware, and traces routes, Lucid queries, mail, queue jobs and Ace commands.
Express, Fastify, Hono, NestJS, Next.js or plain Node.js get an Unhandled SDK that starts OpenTelemetry, reads UNHANDLED_DSN and the environment, and adds route names and error reports for that framework.
The browser SDK in your layout, the Vite plugin for releases and source maps, and Cloudflare Workers Observability or @unhandled/node for the server.
Your language's standard OpenTelemetry SDK. You set four OTEL_* variables and keep your instrumentation portable.
Setup
The snippets use a sample DSN and the production environment. In the app, Setup instructions on a service row shows the same steps with that service's endpoint and id filled in, and a new service shows them with its full DSN. There you also pick the environment. The last step follows it: development runs the dev server, and staging or production builds the app and starts the built server. /docs/install?stack=<id> opens a stack directly.
AdonisJS has two options. Unhandled agent installs @unhandled/agent-adonisjs. Already using @adonisjs/otel keeps the official package and only sets its exporter variables, as described in Keep @adonisjs/otel.
Unhandled SDKs
OpenTelemetry SDKs
Coding agents
Already on Sentry
Spring Boot, Quarkus and any JVM app through the OpenTelemetry Java agent. Guide
- 1
Download the Java agent
bashcurl -L -o opentelemetry-javaagent.jar https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar - 2
Point the exporter at Unhandled
dotenvOTEL_SERVICE_NAME=orders-api OTEL_EXPORTER_OTLP_ENDPOINT=https://ingest.example.com OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf OTEL_EXPORTER_OTLP_HEADERS=x-api-key=uh_live_7Hq2xR9vLp3sKd8mWn4tYb6c,x-unhandled-service-id=0b6f3c1e-8d2a-4f7b-9c5e-2a1d4e6f8b3c,x-unhandled-env=productionThe exporter appends /v1/traces, /v1/logs and /v1/metrics to the endpoint. Change x-unhandled-env per deployment.
- 3
Start the JVM with the agent
bashjava -javaagent:./opentelemetry-javaagent.jar -jar app.jar
Set up with an AI agent
Set up with an AI agent gives you a prompt for Claude Code, Cursor, Codex or any agent that edits files and runs commands. Paste it in the project's root. The prompt carries the DSN, the environment and the OTEL_* variables, and tells the agent to:
- Detect the stack from the project's manifest files.
- Install the matching Unhandled package, or the official OpenTelemetry SDK for other languages.
- Set
UNHANDLED_DSNandAPP_ENVin the env file the app loads. - Hook up error reporting and set
user.idfrom the signed-in user. - Start the app for the chosen environment and send one request.
- Confirm the request arrived.
For the last step, connect the MCP server first. The agent then calls list_traces for the service and environment and finds its own request. Without it, the agent asks you to check Last seen on the service.
The DSN and the headers
A DSN such as https://uh_live_…@ingest.example.com/0b6f3c1e-… holds everything a sender needs. The Unhandled SDKs read it from UNHANDLED_DSN. OpenTelemetry SDKs need it split into parts:
| From the DSN | OpenTelemetry setting |
|---|---|
The origin, https://ingest.example.com | OTEL_EXPORTER_OTLP_ENDPOINT |
| The username, the API key | x-api-key in OTEL_EXPORTER_OTLP_HEADERS |
| The path, the service id | x-unhandled-service-id in OTEL_EXPORTER_OTLP_HEADERS |
| Your deployment's environment | x-unhandled-env in OTEL_EXPORTER_OTLP_HEADERS |
The exporters append /v1/traces, /v1/logs and /v1/metrics to the endpoint. Any OpenTelemetry SDK is the full wire contract.
What each stack fills in
Traces, logs, metrics, issues, requests, queries and external calls work from any SDK that follows the OpenTelemetry semantic conventions. A few pages depend on spans that only some instrumentations produce:
| Page | Needs | Who creates it |
|---|---|---|
| Emails | Spans with email.system | The AdonisJS agent, for @adonisjs/mail. Other stacks add them by hand. |
| Commands | A root span marked unhandled.entry_point=cli, or an INTERNAL span with process.executable.name | The AdonisJS agent, for Ace commands. Other stacks follow the OpenTelemetry CLI conventions. |
| Users | user.id or enduser.id on request spans | Your auth middleware, in any stack. |
| System metrics | Runtime and host metrics | Node.js SDKs report the event loop and V8 heap. Other runtimes report CPU and memory. |
Check the data
Send a few requests, then open Settings, Services. The service shows events, a Last seen time and a badge with the language and SDK it reports.