Breadcrumbs
Structured trail of events that live on scopes and are applied to error events to show what happened before an issue.
Breadcrumbs create a trail of events that happened prior to an issue. They live on scopes and are applied to error events at capture time, giving users context about what led to a problem.
Unlike traditional logs, breadcrumbs are structured — they carry a type, category, severity level, and arbitrary data. They are stored in a ring buffer with a configurable maximum size, keeping only the most recent entries.
Related specs:
- Scopes — scope propagation and forking
- Breadcrumbs Interface — wire format reference
On the event, breadcrumbs appear as either a wrapped or flat array. SDKs SHOULD use the wrapped format:
{
"breadcrumbs": {
"values": [
{
"timestamp": "2016-04-20T20:55:53.845Z",
"message": "Started",
"category": "log"
},
{
"timestamp": "2016-04-20T20:55:53.847Z",
"type": "navigation",
"data": { "from": "/login", "to": "/dashboard" }
}
]
}
}
{
"breadcrumbs": {
"values": [
{
"timestamp": "2016-04-20T20:55:53.845Z",
"message": "Started",
"category": "log"
},
{
"timestamp": "2016-04-20T20:55:53.847Z",
"type": "navigation",
"data": { "from": "/login", "to": "/dashboard" }
}
]
}
}
Entries are ordered oldest to newest. The last entry is the last event before the captured error occurred.
Breadcrumbs MUST be stored in a ring buffer on the scope. When a breadcrumb is added and the total count exceeds the max_breadcrumbs limit, the SDK MUST remove the oldest breadcrumb.
The max_breadcrumbs limit is a Client option. SDKs SHOULD default to 100.
If the SDK is disabled (no active client), breadcrumbs SHOULD NOT be recorded.
Breadcrumbs live on scopes and follow the same scope data application rules as other scope data. When an event is captured, breadcrumbs from the global, isolation, and current scopes are merged.
The top-level Sentry.addBreadcrumb() MUST write to the isolation scope. This ensures breadcrumbs are shared across all events within the same request/tab/session.
When merging breadcrumbs from multiple scopes at capture time, the SDK SHOULD sort them by insertion order and then reapply the max_breadcrumbs limit.
When a scope is forked (via withScope() or starting a new span), the forked scope receives a copy of the parent's breadcrumbs. Breadcrumbs added to the forked scope do not propagate back to the parent — this follows copy-on-write semantics.
SDKs SHOULD automatically record breadcrumbs for common events via default integrations:
- HTTP requests:
type: "http",category: "http". Added after the request finishes. Level:info(2xx-3xx),warning(4xx),error(5xx). Data SHOULD includeurl,http.request.method,http.response.status_code. HTTP requests matching the configured DSN MUST be excluded. - UI events:
type: "default",category: "ui.click"(or similarui.*). Button clicks, touch events, etc. - System events: Low battery, low storage, airplane mode, memory warnings, device orientation changes.
- Console/log messages:
type: "default",category: "console". - Navigation:
type: "navigation", withdata.fromanddata.to.
| Method | Description |
|---|---|
scope.addBreadcrumb(breadcrumb) | Add a breadcrumb to the scope. Enforces the ring buffer limit. |
scope.clearBreadcrumbs() | Remove all breadcrumbs from the scope. |
scope.clear() | Remove all data from the scope, including breadcrumbs. |
| Function | Target Scope | Description |
|---|---|---|
Sentry.addBreadcrumb(breadcrumb) | Isolation scope | Convenience function. The breadcrumb passes through the before_breadcrumb hook before being added. |
| Option | Type | Default | Description |
|---|---|---|---|
max_breadcrumbs | int | 100 | Maximum number of breadcrumbs per scope. |
before_breadcrumb | callback | — | Hook to modify or discard breadcrumbs before recording. |
// Manual breadcrumb
Sentry.addBreadcrumb({
category: "auth",
message: "User logged in",
level: "info",
});
// Navigation breadcrumb
Sentry.addBreadcrumb({
type: "navigation",
data: {
from: "/login",
to: "/dashboard",
},
});
// HTTP breadcrumb (typically added automatically by integrations)
Sentry.addBreadcrumb({
type: "http",
category: "xhr",
data: {
url: "https://api.example.com/users",
method: "GET",
status_code: 200,
reason: "OK",
},
});
// Manual breadcrumb
Sentry.addBreadcrumb({
category: "auth",
message: "User logged in",
level: "info",
});
// Navigation breadcrumb
Sentry.addBreadcrumb({
type: "navigation",
data: {
from: "/login",
to: "/dashboard",
},
});
// HTTP breadcrumb (typically added automatically by integrations)
Sentry.addBreadcrumb({
type: "http",
category: "xhr",
data: {
url: "https://api.example.com/users",
method: "GET",
status_code: 200,
reason: "OK",
},
});
import sentry_sdk
# Manual breadcrumb
sentry_sdk.add_breadcrumb(
category="auth",
message="User logged in",
level="info",
)
# Breadcrumb on a specific scope
with sentry_sdk.new_scope() as scope:
scope.add_breadcrumb(
category="db",
message="SELECT * FROM users",
level="info",
)
sentry_sdk.capture_exception(error)
import sentry_sdk
# Manual breadcrumb
sentry_sdk.add_breadcrumb(
category="auth",
message="User logged in",
level="info",
)
# Breadcrumb on a specific scope
with sentry_sdk.new_scope() as scope:
scope.add_breadcrumb(
category="db",
message="SELECT * FROM users",
level="info",
)
sentry_sdk.capture_exception(error)
| Version | Date | Summary |
|---|---|---|
1.1.0 | 2024-02-14 | Breadcrumbs written via top-level API now go to isolation scope (three-scope model) |
1.0.0 | 2020-05-04 | Initial spec — breadcrumb structure, types, ring buffer, before_breadcrumb hook |
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").