Breadcrumbs are a trail of events that occurred before an error, helping you understand what the user was doing when something went wrong.
What Are Breadcrumbs?
When an error occurs, Proliferate captures the last 100 events (by default) that led up to it:
Error: Cannot read property 'id' of null
────────────────────────────────────────────
Breadcrumbs (12):
14:23:45.100 navigation Navigated to /dashboard
14:23:45.500 fetch GET /api/user (200, 150ms)
14:23:46.200 click Clicked on button#load-data "Load Data"
14:23:46.300 fetch GET /api/projects (200, 230ms)
14:23:47.100 click Clicked on a.project-link "Project Alpha"
14:23:47.150 navigation Navigated to /projects/123
14:23:47.500 fetch GET /api/projects/123 (200, 180ms)
14:23:48.000 click Clicked on button#edit "Edit"
14:23:48.100 fetch GET /api/projects/123/settings (500, 450ms) ⚠️
14:23:48.200 console Error loading settings (error)
14:23:48.300 [ERROR OCCURRED HERE]
Automatic Integrations
The SDK automatically captures breadcrumbs from common browser APIs:
All fetch() calls are recorded with method, URL, status, and duration: await fetch ( '/api/users' );
// Breadcrumb: "GET /api/users" (200, 150ms)
await fetch ( '/api/orders' , { method: 'POST' });
// Breadcrumb: "POST /api/orders" (201, 230ms)
Recorded data: HTTP method, URL, status code, duration in milliseconds, error message (if request failed)
XMLHttpRequest calls are captured similarly: const xhr = new XMLHttpRequest ();
xhr . open ( 'GET' , '/api/data' );
xhr . send ();
// Breadcrumb: "GET /api/data" (200, 180ms)
Console methods are captured as breadcrumbs: console . log ( 'User clicked submit' );
// Breadcrumb: "User clicked submit" (info)
console . warn ( 'Form validation failed' );
// Breadcrumb: "Form validation failed" (warning)
console . error ( 'API returned error' );
// Breadcrumb: "API returned error" (error)
Console Method Breadcrumb Level console.loginfoconsole.debugdebugconsole.infoinfoconsole.warnwarningconsole.errorerror
Click events are recorded with element information: // User clicks a button
// Breadcrumb: "Clicked on button#submit-order 'Place Order'"
// User clicks a link
// Breadcrumb: "Clicked on a.nav-link 'Dashboard'"
Recorded data: Element tag and ID/class, text content (truncated to 30 characters), aria-label if present, data-testid if present
URL changes are tracked: // User navigates
// Breadcrumb: "Navigated to /dashboard"
// Browser back button
// Breadcrumb: "Navigated to /home"
// History API
history . pushState ({}, '' , '/new-page' );
// Breadcrumb: "Navigated to /new-page"
Configuration
Enabling/Disabling Integrations
Proliferate . init ({
endpoint: 'https://api.proliferate.com/api/v1/errors' ,
apiKey: 'pk_your_api_key' ,
breadcrumbs: {
fetch: true , // Capture fetch requests (default: true)
xhr: true , // Capture XHR requests (default: true)
console: true , // Capture console output (default: true)
click: true , // Capture user clicks (default: true)
navigation: true , // Capture URL changes (default: true)
},
});
Maximum Breadcrumbs
Proliferate . init ({
breadcrumbs: {
maxBreadcrumbs: 100 , // Default: 100
},
});
When the limit is reached, the oldest breadcrumbs are discarded.
Breadcrumb Structure
Each breadcrumb contains:
{
timestamp : 1703500000123 , // Unix milliseconds
category : 'fetch' , // fetch, xhr, console, click, navigation, custom
message : 'GET /api/users' , // Human-readable description
level : 'info' , // debug, info, warning, error
data : { // Category-specific data
method : 'GET' ,
url : '/api/users' ,
status_code : 200 ,
duration_ms : 150 ,
}
}
Automatic breadcrumbs are designed for minimal overhead:
Non-blocking: Integrations don’t slow down the original operations
Lightweight data: Only essential information is captured
Memory bounded: Limited by maxBreadcrumbs
Passive listeners: Click handlers use passive event listeners
Best Practices
Avoid excessive console output that could flood breadcrumbs: // Bad - creates 1000 breadcrumbs
items . forEach ( item => console . log ( 'Processing:' , item . id ));
// Good - one summary breadcrumb
console . log ( 'Processing' , items . length , 'items' );
Use Meaningful Click Targets
Add identifiable attributes to interactive elements: <!-- Good - clear breadcrumb -->
< button id = "checkout-btn" data-testid = "checkout" > Complete Purchase </ button >
<!-- Less useful - generic breadcrumb -->
< div >< span > Click here </ span ></ div >
Disable Noisy Integrations
If certain integrations create too much noise: Proliferate . init ({
breadcrumbs: {
console: false , // Disable if you log too much
},
});
Supplement with Custom Breadcrumbs
Automatic breadcrumbs capture what happened, but custom breadcrumbs can capture why: Proliferate . addBreadcrumb ( 'custom' , 'User started checkout flow' , 'info' , {
cart_items: 3 ,
cart_total: 99.99 ,
});
See Custom Breadcrumbs for more.