Abrova
☰ Docs menu · Next.js SDK

Next.js SDK

Error tracking, crash detection, breadcrumbs, and React integration for Next.js apps using App Router or Pages Router.

Next.js 0.1.8Next.js 12+React 17+Node 16+Last updated: 27 Oct 2026
Error Tracking

Automatic capture of uncaught errors, promise rejections, and React errors

Crash Detection

Browser tab crash and unresponsiveness detection

Breadcrumbs

Track user actions and events for error context

Source Maps

Automatic source map support for readable stack traces

Next.js Optimized

Built for App Router and Pages Router

React Integration

Error boundaries, hooks, and components

Universal

Works in browser and Node.js (API routes, server components)

Rich Context

Navigation tracking, user sessions, custom metadata

Configurable

Sampling, filtering, and hooks

Installation#

Packages come from Abrova Center. Two steps:

1. Add the Abrova registry to .npmrc in your project root (npm, yarn and pnpm all read it):

# .npmrc
@abrova-trace:registry=https://center.abrova.ir/api/packages/abrova/npm/

2. Install the package:

bash
npm install @abrova-trace/nextjs-sdk
# or
yarn add @abrova-trace/nextjs-sdk
# or
pnpm add @abrova-trace/nextjs-sdk

Quick Start#

App Router (Next.js 13+)

Create app/providers.tsx:

tsx
'use client';

import { useEffect } from 'react';
import { AbrovaTrace } from '@abrova-trace/nextjs-sdk';
import { useAbrovaTraceNavigation } from '@abrova-trace/nextjs-sdk/react';

export function Providers({ children }: { children: React.ReactNode }) {
  useEffect(() => {
    AbrovaTrace.init({
      apiKey: 'ab_live_your_api_key',
      environment: process.env.NODE_ENV,
      release: process.env.NEXT_PUBLIC_APP_VERSION,
      debug: process.env.NODE_ENV === 'development',
    });
  }, []);

  // Track navigation
  useAbrovaTraceNavigation();

  return <>{children}</>;
}

useAbrovaTraceNavigation() reads useSearchParams(). If next build complains about a missing Suspense boundary, call it from a small component wrapped in <Suspense> instead (see the NavigationTracker in Navigation Tracking below).

Update app/layout.tsx:

tsx
import { Providers } from './providers';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}

Pages Router (Next.js 12 and earlier)

Update pages/_app.tsx:

tsx
import { useEffect } from 'react';
import type { AppProps } from 'next/app';
import { AbrovaTrace } from '@abrova-trace/nextjs-sdk';
import { useAbrovaTracePagesRouter } from '@abrova-trace/nextjs-sdk/react';

function MyApp({ Component, pageProps }: AppProps) {
  useEffect(() => {
    AbrovaTrace.init({
      apiKey: 'ab_live_your_api_key',
      environment: process.env.NODE_ENV,
      release: process.env.NEXT_PUBLIC_APP_VERSION,
    });
  }, []);

  // Track navigation
  useAbrovaTracePagesRouter();

  return <Component {...pageProps} />;
}

export default MyApp;

Error Boundary#

Wrap your components with the error boundary to automatically catch and report React errors:

Basic Usage

tsx
import { ErrorBoundary } from '@abrova-trace/nextjs-sdk/react';

export default function Page() {
  return (
    <ErrorBoundary fallback={<div>Something went wrong!</div>}>
      <YourComponent />
    </ErrorBoundary>
  );
}

With Reset Function

tsx
<ErrorBoundary
  fallback={(error, errorInfo, resetError) => (
    <div>
      <h1>Error: {error.message}</h1>
      <button onClick={resetError}>Try again</button>
    </div>
  )}
>
  <YourComponent />
</ErrorBoundary>

With Error Handler

tsx
<ErrorBoundary
  onError={(error, errorInfo) => {
    console.log('Error occurred:', error);
    // Custom error handling
  }}
>
  <YourComponent />
</ErrorBoundary>

Default Fallback

Without a fallback, the boundary renders a built-in panel: a "Something went wrong" heading, a short message, and a Try again button that resets the boundary. Since 0.1.8 the error message, stack trace and component stack are no longer shown in production: they appear in a collapsible "Error details" block only when showErrorDetails is true, and it defaults to process.env.NODE_ENV !== 'production' (shown in development, hidden in production builds). A custom fallback is rendered as you wrote it and is not affected by showErrorDetails.

tsx
<ErrorBoundary
  fallbackMessage="We could not load this section."
  showErrorDetails={false}
>
  <YourComponent />
</ErrorBoundary>

Props

OptionTypeRequiredDescription
childrenReactNodeYesThe components to protect
fallbackReactNode | functionNoCustom UI shown after an error: an element, or a function (error, errorInfo, resetError) that returns one. Replaces the default fallback
onErrorfunctionNoCalled with (error, errorInfo) after the error has been reported
showDefaultFallbackbooleanNoRender the built-in fallback when no fallback is given (default: true). With false, nothing is rendered
fallbackMessagestringNoMessage in the built-in fallback (default: "An unexpected error occurred. Our team has been notified.")
showErrorDetailsbooleanNoShow the error message and stack trace in the built-in fallback (default: true in development, false in production)

Manual Error Capture#

Using Hooks

tsx
import { useAbrovaTrace } from '@abrova-trace/nextjs-sdk/react';

function MyComponent() {
  const { captureException, captureMessage, setUserId } = useAbrovaTrace();

  const handleClick = async () => {
    try {
      await riskyOperation();
    } catch (error) {
      captureException(error as Error, 'Failed to complete operation', {
        userId: user.id,
        action: 'button_click',
      });
    }
  };

  return <button onClick={handleClick}>Click me</button>;
}

Direct API Usage

typescript
import { AbrovaTrace } from '@abrova-trace/nextjs-sdk';

// Capture exception
try {
  throw new Error('Something broke');
} catch (error) {
  AbrovaTrace.getInstance()?.captureException(error as Error, 'Custom context', {
    userId: '123',
    customData: 'value',
  });
}

// Capture a message (level: 'debug' | 'info' | 'warning' | 'error')
AbrovaTrace.getInstance()?.captureMessage(
  'User completed checkout',
  'info',
  { orderId: '456' }
);
Where messages show up.

Messages appear in the Console under Abrova Trace → Messages, with their level, platform, extra data and breadcrumbs. They never create an issue. Levels: 'debug', 'info' (default), 'warning', 'error'. Use messages for things your app reports on purpose ("checkout started", "sync finished"); for high-volume diagnostics use Logs.

Breadcrumbs track user actions and provide context for errors. Navigation changes (once you use a navigation hook) and console.error / console.warn calls are recorded automatically.

Manual Breadcrumbs

typescript
import { BreadcrumbService, BreadcrumbType } from '@abrova-trace/nextjs-sdk';

// Generic breadcrumb
BreadcrumbService.add('User action', BreadcrumbType.User, { button: 'submit' });

// Specific types
BreadcrumbService.addUser('Clicked checkout button');
BreadcrumbService.addHttp('POST', '/api/orders', 200);
BreadcrumbService.addState('Cart updated', { items: 3 });
BreadcrumbService.addNavigation('/cart', '/checkout');

Using Hooks

tsx
import { useBreadcrumbs } from '@abrova-trace/nextjs-sdk/react';

function Component() {
  const { addBreadcrumb, addHttp, addState } = useBreadcrumbs();

  const handleSubmit = async (data) => {
    addBreadcrumb('Form submitted', { formName: 'contact' });

    const response = await fetch('/api/contact', {
      method: 'POST',
      body: JSON.stringify(data),
    });

    addHttp('POST', '/api/contact', response.status);
  };

  return <form onSubmit={handleSubmit}>...</form>;
}

Crash Detection#

The SDK detects browser tab crashes and unresponsiveness using a localStorage-based heartbeat system.

  • Tab Crashes — Detects browser tab crashes
  • Unresponsive Tabs — Detects frozen/hung tabs
  • Force-Close — Detects force-close scenarios
  • Post-Mortem — Reporting on next launch

How It Works

  1. App starts — Crash marker created in localStorage
  2. Heartbeat runs every 5 seconds
  3. App closes normally — Marker removed
  4. App crashes — Marker remains
  5. Next session — Crash detected and reported

API Routes & Server Components#

The init() call in Providers / _app.tsx runs in the browser only, so on the server AbrovaTrace.getInstance() returns null until you initialize the SDK there too. Create a small server helper (init() returns the existing instance if one is already set up):

typescript
// lib/abrova-trace-server.ts
import { AbrovaTrace } from '@abrova-trace/nextjs-sdk';

export const trace =
  AbrovaTrace.getInstance() ??
  AbrovaTrace.init({
    apiKey: process.env.ABROVA_TRACE_API_KEY!,
    environment: process.env.NODE_ENV,
  });

API Routes

typescript
// pages/api/example.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import { trace } from '@/lib/abrova-trace-server';

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  try {
    // Your API logic
  } catch (error) {
    trace.captureException(error as Error, 'API Error', {
      endpoint: '/api/example',
      method: req.method,
    });
    res.status(500).json({ error: 'Internal Server Error' });
  }
}

Server Components (App Router)

tsx
// app/page.tsx
import { trace } from '@/lib/abrova-trace-server';

export default async function Page() {
  try {
    const data = await fetchData();
    return <div>{data}</div>;
  } catch (error) {
    trace.captureException(error as Error, 'Server Component Error');
    return <div>Error loading data</div>;
  }
}

Source Maps#

Enable production source maps for readable stack traces in your next.config.js:

javascript
// next.config.js
module.exports = {
  productionBrowserSourceMaps: true,
};

After building your app, upload the .map files with the Abrova Trace CLI, using the same release you pass to AbrovaTrace.init():

bash
npx @abrova-trace/cli sourcemaps upload .next/static --release 1.0.0 --project YOUR_PROJECT_ID --token ab_pat_xxx

Configuration Options#

typescript
AbrovaTrace.init({
apiKey: 'ab_live_your_api_key',           // Required
environment: 'production',              // Default: 'production'
release: '1.0.0',                       // Optional
captureUncaughtErrors: true,            // Default: true
enabled: true,                          // Default: true
debug: false,                           // Default: false
timeout: 10,                            // Default: 10 seconds
enableServerSide: true,                 // Default: true
enableClientSide: true,                 // Default: true
enableCrashDetection: true,             // Default: true
maxBreadcrumbs: 20,                     // Default: 20
sampleRate: 1.0,                        // 0.0 to 1.0
tags: { team: 'frontend' },            // Custom tags
ignoreErrors: ['ResizeObserver loop limit exceeded'],
ignoreUrls: [/chrome-extension:\/\//],   // matched against the stack trace
beforeSend: (error) => error,           // Filter/modify errors
});
OptionTypeRequiredDescription
apiKeystringYesYour project API Key
environmentstringNoEnvironment name (default: "production")
releasestringNoApp version identifier
captureUncaughtErrorsbooleanNoCatch uncaught errors automatically (default: true)
enabledbooleanNoEnable/disable SDK (default: true)
debugbooleanNoEnable debug logging (default: false)
timeoutnumberNoHTTP request timeout in seconds (default: 10)
enableServerSidebooleanNoCapture uncaught errors and unhandled rejections automatically on the server (default: true)
enableClientSidebooleanNoCapture uncaught errors and unhandled rejections automatically in the browser (default: true)
enableCrashDetectionbooleanNoEnable crash detection (default: true)
maxBreadcrumbsnumberNoMax breadcrumbs to keep (default: 20)
sampleRatenumberNoSample rate for errors and messages, 0.0-1.0 (default: 1.0)
tagsobjectNoCustom tags to attach to all errors
ignoreErrorsarrayNoError messages to ignore (strings or RegExp)
ignoreUrlsarrayNoStrings or RegExp matched against the error stack trace; a match drops the error
beforeSendfunctionNoHook to modify/filter errors before sending; return null or false to drop the error
apiUrlstringNoBase URL of the Trace API (default: "https://trace.abrova.ir"). Set it only for self-hosted

User Identification#

typescript
import { AbrovaTrace } from '@abrova-trace/nextjs-sdk';

// Set user ID after authentication
AbrovaTrace.getInstance()?.setUserId('user-123');

// Get user ID
const userId = AbrovaTrace.getInstance()?.getUserId();

App Router (Next.js 13+)

tsx
'use client';

import { useAbrovaTraceNavigation } from '@abrova-trace/nextjs-sdk/react';

export function NavigationTracker() {
  useAbrovaTraceNavigation();
  return null;
}

Pages Router

tsx
import { useAbrovaTracePagesRouter } from '@abrova-trace/nextjs-sdk/react';

function MyApp({ Component, pageProps }) {
  useAbrovaTracePagesRouter();
  return <Component {...pageProps} />;
}

Manual Tracking

typescript
import { RouterIntegration } from '@abrova-trace/nextjs-sdk';

RouterIntegration.setCurrentRoute('/custom-route');

Context & Tags#

Attach persistent metadata to every error and message. Tags are categorical filters; extras are richer per-event payloads. (Logs, spans and Web Vitals do not carry them.)

Global extras

typescript
const sdk = AbrovaTrace.getInstance();

sdk?.setExtra('organizationId', 'org-123');
sdk?.setExtra('feature', 'checkout-v2');

sdk?.setExtras({
  organizationId: 'org-123',
  feature: 'checkout-v2',
  experiment: 'new-flow',
});

const orgId = sdk?.getExtra('organizationId');
const allExtras = sdk?.getExtras();

sdk?.clearExtras();

Tags

typescript
const sdk = AbrovaTrace.getInstance();

sdk?.setTag('team', 'payments');
sdk?.setTag('region', 'us-east');

sdk?.setTags({ team: 'payments', version: '2.1' });

const team = sdk?.getTag('team');
const allTags = sdk?.getTags();

sdk?.clearTags();

Session ID

A unique session ID is auto-generated when the SDK initializes (16 random hex bytes) and attached to every error and message for session grouping in Abrova Console:

typescript
const sessionId = AbrovaTrace.getInstance()?.getSessionId();

Web Vitals#

Track Core Web Vitals using Google's official web-vitals library (browser only). Metrics show up in Abrova Console under Abrova Trace → Performance alongside HTTP spans.

typescript
const sdk = AbrovaTrace.getInstance();

sdk?.enableWebVitals({
  reportAllChanges: false, // Only report final values (default)
  batchInterval: 5000,     // Send 5 s after the last metric (default); also sent when the page is hidden
});

Tracked metrics:

OptionTypeRequiredDescription
LCP--Largest Contentful Paint
CLS--Cumulative Layout Shift
INP--Interaction to Next Paint
TTFB--Time to First Byte
FCP--First Contentful Paint

Web Vitals events automatically include device type (mobile/tablet/desktop), connection type, page URL, and route information.

TypeScript#

The SDK is written in TypeScript and ships with full type definitions. Import the types when you need explicit annotations on config objects or event payloads:

typescript
import type {
  AbrovaTraceConfig,
  AbrovaTraceError,
  Breadcrumb,
} from '@abrova-trace/nextjs-sdk';

import type {
  PerformanceSpan,
  WebVitalsData,
  LogEntry,
  LogLevel,
  LogServiceConfig,
} from '@abrova-trace/nextjs-sdk';

Logging#

Structured server-side logging that works in App Router, Pages Router, and API Routes. Logging uses a dedicated LogService instance — create one in lib/logger.ts and import it from anywhere:

typescript
import { LogService } from '@abrova-trace/nextjs-sdk';

export const logger = new LogService({
  apiKey: process.env.ABROVA_TRACE_API_KEY!,
  sourceId: 'nextjs-app',
  platform: 'nextjs',
  environment: process.env.NODE_ENV,
});

logger.log('Users fetched', 'info', { count: 42 });

You can also log through the SDK instance, which reuses the init() config: AbrovaTrace.getInstance()?.info('Users fetched', { count: 42 }) (see the Logging table in the API Reference below). Logs are separate from captureMessage(): they are batched and appear under Abrova Trace → Logs.

See Next.js SDK Logging for the full pipeline — App Router, Pages Router, API Routes, log levels, and request middleware.

API Reference#

AbrovaTrace — Initialization & lifecycle

OptionTypeRequiredDescription
init(config)--Initialize SDK
getInstance()--Get the singleton SDK instance
close()--Cleanup SDK, flush pending data

Error capture

OptionTypeRequiredDescription
captureException(error, message?, extra?, level?, callback?)--Capture an error / exception
captureMessage(message, level?, extra?, callback?)--Send a message to Abrova Trace → Messages (not an issue)

User & session

OptionTypeRequiredDescription
setUserId(userId)--Set the current user identifier
getUserId()--Get the current user identifier
getSessionId()--Get the auto-generated session ID

Global context (extras)

OptionTypeRequiredDescription
setExtra(key, value)--Set a single extra
setExtras(extras)--Set multiple extras at once
getExtra(key)--Get a single extra value
getExtras()--Get all extras
clearExtras()--Clear all extras

Tags

OptionTypeRequiredDescription
setTag(key, value)--Set a single tag
setTags(tags)--Set multiple tags at once
getTag(key)--Get a single tag value
getTags()--Get all tags
clearTags()--Clear all tags

Performance monitoring

OptionTypeRequiredDescription
enablePerformanceTracking(options?)--Turn on performance reporting; in the browser this also tracks every fetch call. Options: batchSize (default: 5), flushInterval in ms (default: 5000)
enableWebVitals(options?)--Turn on Web Vitals tracking
reportPerformanceSpan(span)--Report a single span
reportPerformanceSpanBatch(spans)--Report multiple spans at once
trackOperation(operation, fn, options?)--Time and report an async operation
createPerformanceFetch()--Build a fetch wrapper that reports a span per request. It reports only after enablePerformanceTracking(), trackOperation() or reportPerformanceSpan() has been called
flushPerformance()--Flush buffered performance data immediately

Logging

OptionTypeRequiredDescription
enableLogging(options?)--Turn on the log pipeline
log(message, level?, metadata?)--Log at an explicit level
trace(message, metadata?)--Log at trace level
logDebug(message, metadata?)--Log at debug level
info(message, metadata?)--Log at info level
warn(message, metadata?)--Log at warn level
logError(message, metadata?)--Log at error level
fatal(message, metadata?)--Log at fatal level
flushLogs()--Flush buffered logs immediately
pendingLogCount--Number of logs still in the buffer

BreadcrumbService

OptionTypeRequiredDescription
add(message, type, data?, level?)--Add a generic breadcrumb
addNavigation(from, to, data?)--Add a navigation breadcrumb
addUser(action, data?)--Add a user-action breadcrumb
addHttp(method, url, status?, data?)--Add an HTTP breadcrumb
addState(message, data?)--Add a state-change breadcrumb
getAll()--Get all breadcrumbs
clear()--Clear all breadcrumbs

RouterIntegration

OptionTypeRequiredDescription
trackAppRouterNavigation(pathname, searchParams?)--Track App Router navigation manually
initializePagesRouter(router)--Initialize Pages Router tracking
setCurrentRoute(route)--Override the current route
getCurrentRoute()--Get the current route
getNavigationContext()--Get the active navigation context

CrashDetector

OptionTypeRequiredDescription
enable()--Turn on crash detection
disable()--Turn off crash detection
didCrashLastSession()--True if the previous session ended in a crash
getCrashReport()--Get details of the previous crash

React hooks

OptionTypeRequiredDescription
useAbrovaTrace()--Returns { captureException, captureMessage, setUserId, setExtra, setExtras, setTag, setTags }
useAbrovaTraceNavigation()--Track App Router navigation automatically
useAbrovaTracePagesRouter()--Track Pages Router navigation automatically
useBreadcrumbs()--Returns { addBreadcrumb, addNavigation, addHttp, addState }

React components

OptionTypeRequiredDescription
ErrorBoundary--React error boundary with automatic error reporting (alias: AbrovaTraceErrorBoundary)

Best Practices#

Initialize Early

Initialize AbrovaTrace as early as possible in your app lifecycle to catch all errors

Set User ID

Set user ID after authentication to associate errors with users

Use Error Boundaries

Wrap major sections of your app with error boundaries for automatic React error capture

Add Context to Errors

Include user IDs, amounts, and relevant data when capturing errors

Use Breadcrumbs

Add breadcrumbs for important user actions to provide error context

Environment-Specific Config

Use different configs for production vs development (debug mode, sample rate)

Cleanup on Unmount

Call AbrovaTrace.getInstance()?.close() when cleaning up for proper crash detection

Was this page helpful?
Report a problem