Instrumentation (Experimental)
Distributed tracing for Better Auth
OpenTelemetry instrumentation is experimental and may change in future releases. The API and span structure are subject to change.
Better Auth is instrumented through OpenTelemetry for distributed tracing. Spans are emitted for endpoints, hooks, database operations and the plugin lifecycle. The goal of this instrumentation is to provide better insights into the behavior of your Better Auth instance, helping you debug issues and optimize performance.
Setup
Better Auth uses the OpenTelemetry API to create spans. For traces to be collected and exported, at minimum, you must configure a TracerProvider and a SpanExporter in your application.
For setup instructions, see the official OpenTelemetry documentation:
- Node.js getting started – Core setup for Node.js apps
Supported Spans
The following spans are supported by Better Auth:
Endpoint Spans
| Span Name | Description | When Emitted |
|---|---|---|
{METHOD} {route} | Parent span for an auth endpoint | Every auth API call (e.g. GET /get-session) |
handler {route} | Span around the endpoint handler execution | Inside each endpoint, wrapping the handler |
Attributes:
http.route- The route template (low cardinality)better_auth.operation_id- The operation identifier (e.ggetSession)
The following global hooks are supported:
| Span Name | Description | When Emitted |
|---|---|---|
hook before {route} {source} | Before-hook for an auth endpoint | When a before hook runs for the route |
hook after {route} {source} | After-hook for an auth endpoint | When an after hook runs for the route |
- Attributes:
better_auth.hook.type- The hook type (e.g.beforeorafter)better_auth.context- Execution context:"user"for global hooks,"plugin:{pluginId}"for plugin-registered hookshttp.route- The route template (low cardinality)better_auth.operation_id- The operation identifier (e.ggetSession)
Middlewares are also supported:
| Span Name | Description | When Emitted |
|---|---|---|
onRequest {pluginId} | Plugin onRequest hook | Before request handling |
onResponse {pluginId} | Plugin onResponse hook | After response is produced |
middleware {route} {pluginId} | Plugin middleware execution | When middleware runs for a route |
Attributes:
better_auth.hook.type- The hook type:"onRequest","onResponse", or"middleware"better_auth.context- Execution context:"plugin:{pluginId}"(e.g.plugin:bearer,plugin:test-plugin)http.route- The route template (low cardinality) on middleware spans onlyhttp.response.status_code- The HTTP response status code (onResponse only)
Database Spans
| Span Name | Description | When Emitted |
|---|---|---|
db {operation} {model} | Span for a database operation | All adapter operations (create, findOne, etc.) |
- Operations:
create,findOne,findMany,update,updateMany,delete,deleteMany,count - Models: Core models include
user,account,session,verification, plus plugin-defined models (e.g.organization,rateLimit). - Attributes:
db.operation.name- The database operation name (e.g.create)db.collection.name- The database collection/model name (e.g.user)
Additionally, when defined, the following spans are also emitted for database hooks:
| Span Name | Description | When Emitted |
|---|---|---|
db {operation}.before {model} | Before-hook for a create/update/delete | When a databaseHooks before hook runs |
db {operation}.after {model} | After-hook for a create/update/delete | When a databaseHooks after hook runs |
- Operations:
create,update,updateMany,delete(used for both single delete anddeleteManycalls) - Attributes:
better_auth.hook.type- The hook type (e.g.create.before,create.after,update.before)better_auth.context- Execution context:"user"or"plugin:{pluginId}"db.collection.name- The database collection/model name (e.g.user)