Configuration - Next.js

3 min read Updated: 11.09.2026

Environment variables

The integration has no config file of its own - everything is read from the environment when initRay() runs.

VariableDefaultMeaning
RAY_TOKEN, RAY_PRIVATE_KEY-project credentials; without both the integration stays silent
RAY_URLhttps://dockray.ioDockRay instance
RAY_ENVIRONMENTVERCEL_ENV, then NODE_ENVenvironment column in the panel
RAY_RELEASEVERCEL_GIT_COMMIT_SHAversion of the deployed application
RAY_SAMPLE_RATE1share of error events sent
RAY_TRACES_SAMPLE_RATE0share of transactions sent; 0 disables tracing
RAY_SEND_DEFAULT_PIIfalseattaches the visitor's IP address and user agent

Environments

Every environment should report under an unambiguous name - production, staging, preview. The name is a column in the panel and a filter on the error list, so without it a production outage looks exactly like an error someone triggered in a test. Leave your local environment without credentials: with no token and no key the integration loads and stays silent, so you do not need a separate switch to turn it off.

Transaction names and tags

Every report from onRequestError carries tags built from the context Next supplies: router (App or Pages), route - the route pattern, such as /orders/[id], rather than the concrete path - route_type and render_source. The route pattern is what keeps one route as one row in the panel no matter how many identifiers passed through it.

What gets stripped from a report

Before an event reaches DockRay, the integration removes Authorization, Cookie, Set-Cookie, X-Api-Key and the browser collector's own token from the headers. The visitor's IP address and user agent are attached only with RAY_SEND_DEFAULT_PII=true - without it a report carries no user field at all.

JavaScript errors from the browser

Off by default. Turning it on needs two pieces.

The route that receives them - app/api/ray/browser/route.ts:

js
import { createBrowserErrorRoute } from '@dockcodes/dock-ray-next';

export const POST = createBrowserErrorRoute();
export const runtime = 'nodejs';

The collector, mounted once in the root layout:

js
import { RayBrowserReporting } from '@dockcodes/dock-ray-next/client';

export default function RootLayout({ children }) {
    return (
        <html>
            <body>
                <RayBrowserReporting />
                {children}
            </body>
        </html>
    );
}

NEXT_PUBLIC_RAY_JS_ERRORS=true turns the collector on - the prefix is intentional here, because the field only carries a flag, not a secret.

The browser reports to your route, never directly to the panel: authenticating needs the project's private key, and a key inside the client bundle is a published key. Your server forwards every report with its own key and fills in the envelope - id, timestamp, environment, release - so the browser never chooses which environment its errors land in.

The route answers 202 to everything - a valid report, a malformed one, one rejected by the rate limit - so a caller learns nothing about the guards. It drops bodies over 16 KB and allows twenty reports per address per minute. The browser-side collector caps itself too: one report per distinct error per page view, ten per page view by default, with ResizeObserver loop and cross-origin Script error. filtered out.

Reporting by hand from the browser

js
'use client';
import { captureBrowserException } from '@dockcodes/dock-ray-next/client';

export default function GlobalError({ error }) {
    captureBrowserException(error);

    return <html><body><h1>Something went wrong</h1></body></html>;
}

Vercel

When RAY_ENVIRONMENT and RAY_RELEASE are not set, the integration takes VERCEL_ENV as the environment and VERCEL_GIT_COMMIT_SHA as the release, so a preview deployment does not report as production.

Protecting the private key

The private key is a project secret, not an identifier. Keep it in environment variables, in a secrets manager or in the server configuration - never in the repository, in logs, in a screenshot or in code sent to the browser. One project can hold many keys, so production and staging should each get their own: either can be revoked on its own without interrupting the others. A suspicion that a key leaked is reason enough to revoke it and generate a new one.

Next Verification and common problems - Next.js
Chat with us The chat is closed right now Available: Mo–Fr 08:00–18:00