Skip to content
Codeskop

React

A thin React layer over the web SDK: a provider, an error boundary, and a hook. Works with React 18 and 19.

Install

Install the React adapter alongside the core package:

Terminal
npm install @codeskop/tracker @codeskop/tracker-react

react ^18.0.0 || ^19.0.0 is a peer dependency. The core package stays framework-free; only this adapter depends on React.

Set up the provider and boundary

Wrap your app once, at the root:

main.tsx
import { createRoot } from "react-dom/client";import { CodeskopProvider, CodeskopErrorBoundary } from "@codeskop/tracker-react"; createRoot(document.getElementById("root")!).render(  <CodeskopProvider config={{ apiKey: "cs_live_pk_YOUR_KEY", release: "1.4.0" }}>    <CodeskopErrorBoundary fallback={<p>Something went wrong.</p>}>      <App />    </CodeskopErrorBoundary>  </CodeskopProvider>,);
  • CodeskopProvider calls init(config) once, when it mounts.
  • CodeskopErrorBoundary catches errors thrown while rendering its children, reports them, and shows fallback instead of a blank screen.

Config is read once

The provider uses the config from its first render and ignores later changes, so an inline config={{ … }} object is safe and won't restart the SDK on every render. To change config at runtime, call init() from @codeskop/tracker directly.

Error boundary options

OptionTypeDescription
childrenReactNodeThe subtree to protect.
fallbackReactNode | (error, reset) => ReactNodeWhat to render after an error. Pass a function to get the error and a reset() that re-renders the children, which is handy for a "Try again" button. Renders nothing if omitted.
onError(error, errorInfo) => voidCalled alongside the report, for your own logging.
Dashboard.tsx
<CodeskopErrorBoundary  fallback={(error, reset) => (    <div role="alert">      <p>This section failed to load.</p>      <button onClick={reset}>Try again</button>    </div>  )}  onError={(error, info) => console.error(error, info.componentStack)}>  <Dashboard /></CodeskopErrorBoundary>

You can nest boundaries: wrap individual widgets so one failing panel doesn't take down the whole page.

The useCodeskop hook

useCodeskop() returns identify, reset, recordException, setEnabled and flush, the same functions the core package exports.

Profile.tsx
import { useEffect } from "react";import { useCodeskop } from "@codeskop/tracker-react"; function Profile({ user }: { user: User }) {  const { identify, recordException } = useCodeskop();   useEffect(() => {    identify(user.id);  }, [user.id, identify]);   async function save() {    try {      await saveProfile(user);    } catch (error) {      recordException(error); // event handlers aren't covered by error boundaries    }  }   return <button onClick={save}>Save</button>;}

The hook works anywhere, even outside a CodeskopProvider: every function is a safe no-op until the SDK is initialized.

The provider starts the SDK during its first render, before any child's effects run, so calling identify from a child's first useEffect works (from version 1.1).

What boundaries don't catch

This is a React limitation, not a Codeskop one: error boundaries only catch errors thrown during render. They don't see errors from:

  • event handlers such as onClick,
  • useEffect callbacks and other async code,
  • server-side rendering.

Uncaught errors from event handlers and promises are still captured by the SDK's global handlers. For errors you catch yourself, call recordException.

Next.js and other SSR frameworks

The provider is SSR-safe: it only starts the SDK in the browser, so nothing runs during server rendering and no typeof window checks are needed. The package ships a "use client" directive (from 1.1), so in the Next.js App Router you can use it straight from app/layout.tsx:

app/layout.tsx
// app/layout.tsx: works in a Server Component from 1.1import { CodeskopProvider, CodeskopErrorBoundary } from "@codeskop/tracker-react"; export default function RootLayout({ children }: { children: React.ReactNode }) {  return (    <html lang="en">      <body>        <CodeskopProvider config={{ apiKey: process.env.NEXT_PUBLIC_CODESKOP_KEY! }}>          <CodeskopErrorBoundary fallback={<p>Something went wrong.</p>}>{children}</CodeskopErrorBoundary>        </CodeskopProvider>      </body>    </html>  );}

Identifying signed-in users, reporting your app version from package.json, and fixes for common errors are in Web configuration.

Environment variables

Your bundler has to expose the key to browser code, for example NEXT_PUBLIC_ in Next.js or VITE_ in Vite. That's fine: public ingest keys are designed to be visible.

Next steps