Skip to main content
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 MethodBreadcrumb Level
console.loginfo
console.debugdebug
console.infoinfo
console.warnwarning
console.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

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.
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,
  }
}

Performance Considerations

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');
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>
If certain integrations create too much noise:
Proliferate.init({
  breadcrumbs: {
    console: false,  // Disable if you log too much
  },
});
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.