Raccoon Docs

Browser monitoring

Measure Core Web Vitals and catch frontend errors in any web app, with readable stack traces and links to the backend request each error followed.

raccoon-nodejs/browser measures each page load's Core Web Vitals (LCP, INP, CLS, FCP and TTFB) and reports uncaught errors and rejected promises. It adds about 3 KB and works with any frontend: Next.js, Vite, React, Vue or plain JavaScript. The backend doesn't need to be a Node.js app.

Install#

npm install raccoon-nodejs

Copy the environment's browser key (rcb_...) from Settings → Environments. It can only send page views and errors, so it's safe to put in your frontend code.

import { init, setUser, captureException } from 'raccoon-nodejs/browser';

init({ url: 'https://raccoon.watch', key: 'rcb_...', release: '1.4.2' });
setUser({ id: 42, name: 'Ada' });
  • In Next.js 15.3 or later, put the init() call in instrumentation-client.ts, next to instrumentation.ts.
  • With Vite or another bundler, call it once in the entry file, before the app renders.

What it measures#

Vitals are sent when the tab is hidden. Navigations inside a single-page app count as page views without vitals. The Frontend page shows the 75th percentile of each vital per route, rated good, needs improvement or poor with Google's thresholds.

Raccoon groups paths into routes itself, so /users/42 becomes /users/:id. To name routes yourself, pass a function:

init({ url: 'https://raccoon.watch', key: 'rcb_...', route: () => '/users/[id]' });

Errors show up under Exceptions and become issues, like backend errors. Their execution source is "browser".

Source maps#

Production bundles are minified, so a browser error points at something like /assets/index-3f2a.js:1:48210. Upload your source maps after each build, and Raccoon shows the original file, line and code instead. The same error then also stays in one issue across deploys, even though bundle file names change.

  1. Turn on source maps for the browser build: productionBrowserSourceMaps: true in next.config, or build: { sourcemap: true } in vite.config.

  2. After the build, with RACCOON_URL and RACCOON_TOKEN set (the environment token, not the browser key), upload them:

    npx raccoon-nodejs sourcemaps .next/static --delete   # Next.js
    npx raccoon-nodejs sourcemaps dist --delete           # Vite
    

Each map is stored under the path its bundle is served from: the directory's contents go under --url-prefix, which defaults to /_next/static for .next/static and / otherwise. --delete removes the maps after uploading so your server doesn't publish your source code. --release labels the upload. Raccoon keeps maps for 31 days.

Errors that arrived before their map was uploaded keep their minified frames.

Errors linked to backend requests#

The script adds a W3C traceparent header to the page's fetch and XMLHttpRequest calls to its own origin. A backend that uses raccoon-nodejs or another OpenTelemetry SDK continues that trace, so its request in Raccoon gets the same trace id.

When an error follows a request, the error's occurrence links to that request, with its queries, logs and timing. The linked request is the last one that failed in the previous 30 seconds, or else the last one that finished in the previous 10 seconds.

For an API on another origin, list it, and allow the traceparent header in that API's CORS settings:

init({
    url: 'https://raccoon.watch',
    key: 'rcb_...',
    tracePropagationTargets: ['https://api.example.com'],
});

Laravel backends start their own trace for each request, so errors don't link to Laravel requests.

Options and API#

Option What it does
url Raccoon's URL.
key The environment's browser key.
release Your app's version, shown as the deploy.
route A function that returns the current route's name.
tracePropagationTargets Other origins that get a traceparent header.

setUser({ id, name }) attaches the signed-in user to later page views and errors, and setUser(null) clears it. captureException(error) reports an error you caught yourself. Pass { handled: false } for errors the user saw.

A page load sends at most 20 errors, so a render loop can't use up your event allowance.