Thisbefine
Guides

Error Tracking

Catch errors before your users tweet about them

Error Tracking

Catch crashes before users report them. Get stack traces, breadcrumbs, and affected user counts.

Setup

app/layout.tsx
<Analytics
  apiKey="tif_xxx"
  config={{
    errors: {
      enabled: true,
    },
  }}
/>

That's it. Unhandled errors now get captured automatically.

Full Config

<Analytics
  apiKey="tif_xxx"
  config={{
    errors: {
      enabled: true,
      captureConsoleErrors: false,
      captureNetworkErrors: true,
      maxBreadcrumbs: 25,
      beforeSend: (payload) => payload,
    },
  }}
/>
OptionDefaultDescription
enabledtrueCapture unhandled exceptions
captureConsoleErrorsfalseTreat console.error() as errors
captureNetworkErrorsfalseCatch failed fetch/XHR
maxBreadcrumbs25Breadcrumbs to keep
beforeSend-Filter/modify errors, return null to drop

Automatic Capture

Error TypeCaptured
Uncaught exceptionsYes
Unhandled promise rejectionsYes
window.onerror eventsYes
console.error()If captureConsoleErrors: true
Failed fetch/XHRIf captureNetworkErrors: true

Manual Capture

import { useCaptureException } from '@thisbefine/analytics/next';

const MyComponent = () => {
  const captureException = useCaptureException();

  const handleSubmit = async (data) => {
    try {
      await submitForm(data);
    } catch (error) {
      captureException(error as Error, { component: 'ContactForm' });
      toast.error('Something went wrong.');
    }
  };

  return <form>{/* form */}</form>;
};
try {
  await riskyOperation();
} catch (error) {
  getAnalytics()?.captureException(error as Error, { operation: 'riskyOperation' });
}

Capture Messages

Report errors without an Error object:

getAnalytics()?.captureMessage('API rate limit approaching', 'warning', { usage: 950, limit: 1000 });
getAnalytics()?.captureMessage('Payment failed', 'error', { orderId: 'ord_123' });
getAnalytics()?.captureMessage('Database connection lost', 'fatal', { attempts: 5 });

Trail of events leading up to an error.

Automatic Breadcrumbs

TypeCaptured
clickUser clicks
navigationPage changes
consoleconsole.error (if enabled)
networkFailed requests (if enabled)

Manual Breadcrumbs

getAnalytics()?.addBreadcrumb({
  type: 'custom',
  message: 'User started checkout',
  data: { cartItems: 3, cartTotal: 149.97 },
});

Fingerprinting

Similar errors are grouped by fingerprint (message + top stack frame). Same fingerprint = same group.

Filtering

Filter noise with beforeSend:

<Analytics
  apiKey="tif_xxx"
  config={{
    errors: {
      enabled: true,
      beforeSend: (payload) => {
        if (payload.stack?.includes('chrome-extension://')) return null;
        if (payload.message.includes('ResizeObserver loop')) return null;
        if (payload.stack?.includes('gtag')) return null;
        return payload;
      },
    },
  }}
/>

You can also enrich errors:

beforeSend: (payload) => {
  payload.context = { ...payload.context, buildId: process.env.NEXT_PUBLIC_BUILD_ID };
  payload.message = payload.message.replace(/email=\S+/g, 'email=[REDACTED]');
  return payload;
}

React Error Boundaries

components/error-boundary.tsx
'use client';

import { Component, ReactNode } from 'react';
import { getAnalytics } from '@thisbefine/analytics';

interface Props { children: ReactNode; fallback: ReactNode; }
interface State { hasError: boolean; }

export class ErrorBoundary extends Component<Props, State> {
  state = { hasError: false };

  static getDerivedStateFromError() {
    return { hasError: true };
  }

  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
    getAnalytics()?.captureException(error, { componentStack: errorInfo.componentStack });
  }

  render() {
    return this.state.hasError ? this.props.fallback : this.props.children;
  }
}
<ErrorBoundary fallback={<div>Something broke.</div>}>
  <MyComponent />
</ErrorBoundary>

Best Practices

Don't log sensitive data: Never include passwords or tokens in error context.

Add useful context: Include component name, user action, relevant IDs.

Use breadcrumbs for critical flows: Add breadcrumbs before/after important operations so you can trace what happened.

On this page