Overview
A breadcrumb is a small, timestamped record of something that happened before an error — a console log, a click, a network request, a navigation. They're kept in a rolling in-memory trail on the client and attached to the next captured exception, giving you the sequence of events that led up to a failure instead of just the failure itself.
Breadcrumbs only travel with exceptions. Logs, traces, and spans don't carry a breadcrumb trail — there's nothing "leading up to" a log call the same way there is for a crash.
Adding breadcrumbs manually
ts
Buglapse.addBreadcrumb({
type: 'checkout',
level: 'info',
message: 'Applied promo code SUMMER10',
data: { code: 'SUMMER10', discount: 0.1 },
})
try {
await chargeCard(order)
} catch (error) {
Buglapse.captureException(error) // ships with the breadcrumb above already in its trail
}Only message is required:
type— a free-form string used to pick an icon/renderer on the dashboard (see Viewing breadcrumbs on the dashboard). Defaults to"debug"if omitted.level—log|info|warn|error|debug|success. Defaults to"debug". Drives the color of the breadcrumb's marker, independent oftype.data— an optional object of structured detail (a payload, a response body, form values). Shown collapsed under the breadcrumb on the dashboard, expandable as raw JSON.timestamp— stamped automatically (new Date().toISOString()) when you calladdBreadcrumb(); there's no reason to set it yourself.
Breadcrumbs are global to the client, not scoped to a single captureException() call — anything added anywhere in your app keeps accumulating in the same trail until the next exception ships it.
Automatic breadcrumbs
Rather than instrumenting addBreadcrumb() calls by hand throughout your app, BreadcrumbsIntegration records the same kind of trail automatically: console calls, DOM clicks/keypresses, fetch/XHR requests, and SPA navigations (history.pushState/popstate) each show up as a breadcrumb with no code changes needed. It's opt-in — enable it via integrations: [breadcrumbsIntegration()] in init(), or toggle it on from the project's Settings → Loader Script tab if you're on the CDN embed. Each source (console/DOM/fetch/ XHR/history) can be turned off independently; see BreadcrumbsIntegration for the config shape.
Manual addBreadcrumb() calls and the integration's automatic ones land in the same trail and interleave by time — you don't need to choose one or the other.
Trail limit
The trail keeps at most the 50 most recent breadcrumbs (MAX_BREADCRUMBS); once it's full, the oldest breadcrumb is dropped as a new one is added. An exception captured after a long-running session only ships the last 50 breadcrumbs leading up to it, not the full session history.
Viewing breadcrumbs on the dashboard
An exception's (or an issue's) detail page renders its breadcrumb trail chronologically above the stack trace. Every row's marker is colored by level (error red, warn amber, success emerald, info blue, log/debug neutral) regardless of type — type only picks which component renders the row and how it reads data. Matching is exact on type first, then falls back to the prefix before the first ./- (so a custom "cart.added" type falls through to the prefix cart, which itself has no dedicated component and lands on the generic row below).
console— title is "Console{level}" (e.g. "Console warn"). The subtitle readsdata.args: an array of the raw arguments passed to the console call, joined with spaces (non-stringsJSON.stringify'd individually). Ifdata.argsisn't an array, it falls back tomessage. No expandable data section.interaction(and the legacyui.click/ui.keypresstype) — the title is humanized fromdata.kind("click"→ "Click","keypress"→ "Keyboard", anything else just capitalized); with nodata.kind, it's derived from aui.*type instead, or "Interaction" if neither is present. The subtitle isdata.target— the ancestor-path element description (button.icon-button > svg "Submit"-style string) — falling back tomessage. No expandable data section.navigation— title is fixed to "Navigation". The subtitle readsdata.from/data.to:"{from} → {to}"when both are present, justtowhen there's nofrom, ormessageif neither field exists.fetch/xhr/http— title is "Fetch"/"XHR"/"HTTP" to match the type (default "HTTP" for anything else routed here). The response status (data.status) is shown next to the title, colored red whenlevelis"error"and emerald otherwise. The subtitle joinsdata.method+data.url, falling back tomessageif neither is set. Any other keys left indatabeyondmethod/url/statusare shown in a collapsed "Data" section as raw JSON — the section only appears if there's something left over.- Anything else falls back to a generic row: the title is the type capitalized, and the subtitle is always
message. Its icon is picked by an exact match ontypeagainst a small fixed set (log,exception,error,nav,request,form,checkout,cart,query,searcheach get their own icon; anything unrecognized gets a generic info icon) — this lookup is exact, not prefix-based, so"cart.added"still gets the generic icon even though"cart"would match. If the breadcrumb carriesdata(and it's not an empty array), it's shown as a collapsed "Data" section — expand it to see the raw JSON rather than a flattened key/value list, since breadcrumb data can be arbitrarily shaped.