LaraBug

Data Filtering & Security

Every LaraBug SDK ships with a built-in DataFilter that runs over every event before it leaves the browser. It's designed to be a safe default: you can install the SDK into a production app without first auditing every console.log or setContext call in your codebase.

This page explains what the filter does, how to extend it, and how to verify it's working.

The default blacklist

The filter matches object keys case-insensitively via substring. Any key containing one of these patterns has its value replaced with [FILTERED]:

password, passwd, secret, token, auth, authorization,
cookie, session, api_key, apikey, access_key,
access_token, refresh_token, private_key,
credit_card, card_number, cardnumber, cvv, cvc,
iban, ssn, social_security

So a request body like { user: 'alice', password: 'hunter2', totp_token: '123456' } becomes { user: 'alice', password: '[FILTERED]', totp_token: '[FILTERED]' } — both password (exact match) and totp_token (substring match on token) get scrubbed.

URL query-string filtering

URLs are scrubbed separately. Any query parameter whose name matches this list has its value replaced:

token, access_token, refresh_token, api_key, apikey,
auth, authorization, password, secret, code, signature, sig

So https://example.com/reset?token=abc&email=user@example.com becomes https://example.com/reset?token=%5BFILTERED%5D&email=user@example.com. Your email stays; the reset token gets masked.

URL filtering applies to:

  • The request.url on every captured event
  • Fetch/XHR breadcrumb URLs
  • Navigation breadcrumb URLs (including document.referrer)
  • URLs mentioned inside log message strings

Extending the blacklist

Pass extra patterns in your init() options:

LaraBug.init({
  dsn: '...',
  blacklist: [
    'patient_id',
    'medical_record',
    'internal_flag',
  ],
  urlBlacklist: [
    'oauth_verifier',
  ],
});

Your additions are merged with the defaults. Both are matched case-insensitively.

To replace the defaults entirely rather than merging, use the DataFilter class directly and pass replaceDefaults: true. Most apps should never need this — the defaults are sensible and removing them is almost always a mistake.

What's NOT scrubbed

The filter operates on keys, not values. A string like "My password is hunter2" won't be detected — there's no key to match. Two implications:

  1. Don't log free-text secrets. If your app has a debugging statement like console.log('User input:', rawFormData.toString()) and that input happened to contain a password, the filter can't help.
  2. Use structured data. Prefer console.log('User input:', { email, password }) over concatenated strings. Then the filter catches the password key.

The beforeSend hook is your escape valve for anything the built-in filter can't handle:

LaraBug.init({
  dsn: '...',
  beforeSend: (event) => {
    // Custom scrubbing of free-text fields
    if (event.message?.includes('password is')) {
      event.message = event.message.replace(/password is \S+/gi, 'password is [FILTERED]');
    }
    return event;
  },
});

Rate limiting and circuit breaking

The filter handles privacy. The rate limiter handles performance:

  • Dedupe — identical events inside a 5-second window are dropped. A render loop throwing the same error 60 times a second becomes a single event.
  • Per-minute cap — 100 events/minute/client by default. Anything above that is dropped.
  • Circuit breaker — after 5 consecutive transport failures, the SDK pauses for 60 seconds before retrying.
  • Retry-After / X-LaraBug-Disable-Capture — the SDK honors both headers. If our ingest responds with Retry-After: 30, the SDK sleeps for 30 seconds before the next attempt.

These knobs are configurable:

LaraBug.init({
  dsn: '...',
  maxEventsPerMinute: 50,
  dedupeWindowMs: 10000,
});

The defaults are tuned for typical production traffic. Only lower them if you're seeing bursts; only raise them if you're seeing legitimate events dropped.

Verifying it works

Open your browser's devtools network tab, filter for requests to www.larabug.com, and trigger a test error. Inspect the outgoing payload and confirm:

  • No password / token / auth values appear in plain text
  • URL query strings with access_token=... are replaced with access_token=%5BFILTERED%5D
  • Your custom blacklist entries from init() are taking effect

If you see something leaking that shouldn't, add it to blacklist or handle it in beforeSend — and let us know so we can consider adding it to the default list.