Custom Monitoring Provider

How to extend the repo's monitoring layer with your own provider.

Only Sentry is registered by default, but the monitoring layer is extensible. A complete provider must be registered in four places: the provider enum, the React provider component, the server service, and the instrumentation registries (client + server).

1. Add the Provider Name

Update the provider enum:

packages/monitoring/api/src/get-monitoring-provider.ts

const MONITORING_PROVIDERS = [
'sentry',
'my-provider',
'',
] as const;

2. Register the Client Provider Component

packages/monitoring/api/src/components/provider.tsx

monitoringProviderRegistry.register('my-provider', async () => {
const { MyProvider } = await import('@kit/my-monitoring/provider');
return {
default: function Wrapper({ children }: React.PropsWithChildren) {
return <MyProvider>{children}</MyProvider>;
},
};
});

3. Register the Server Service

packages/monitoring/api/src/services/get-server-monitoring-service.ts

serverMonitoringRegistry.register('my-provider', async () => {
const { MyMonitoringService } = await import('@kit/my-monitoring');
return new MyMonitoringService();
});

4. Register Server Instrumentation

The server registration must export onRequestError. The client error.tsx relies on error.digest being set for any server-originated error so it can skip re-capturing — that dedup only works if every provider records server errors here, with the proper Next.js context (route, method, headers).

packages/monitoring/api/src/instrumentation.ts

instrumentationRegistry.register('my-provider', async () => {
const { initMyProviderServer, captureMyProviderRequestError } =
await import('@kit/my-monitoring/server');
return {
register: () => {
initMyProviderServer({
environment: process.env.NEXT_PUBLIC_MY_PROVIDER_ENVIRONMENT,
});
},
onRequestError: captureMyProviderRequestError,
};
});

5. Register Client Instrumentation

The client instrumentation owns the global window.onerror and unhandledrejection handlers. The provider must supply init and captureException; the buffer-then-replay machinery is handled for you.

packages/monitoring/api/src/instrumentation-client.ts

clientInstrumentationRegistry.register('my-provider', async () => {
const { initMyProviderBrowser, captureMyProviderException } =
await import('@kit/my-monitoring/client');
return {
init: () => {
initMyProviderBrowser({
environment: process.env.NEXT_PUBLIC_MY_PROVIDER_ENVIRONMENT,
});
},
captureException: (error, mechanism) => {
captureMyProviderException(error, { handled: false, type: mechanism });
},
};
});

6. Configure the Environment

NEXT_PUBLIC_MONITORING_PROVIDER=my-provider

Notes

  • The repo is ESM. Use import, not require.
  • All five registrations are required. If any is missing, the client/server experience will diverge or errors will silently drop.
  • Leaving the env var empty keeps the console fallback.