The SDK ships a React wrapper at `@checktiv/sdk-web/react`. It provides:

- `ChecktivProvider` - holds the `ChecktivClient` in React context. Wrap your app (or the subtree that needs verification) with this.
- `useChecktiv()` - returns the `ChecktivClient` from context. Throws a clear error if called outside a provider.
- `ChecktivIdv` - mounts the managed IDV module into a DOM node. Handles cleanup on unmount.

`ChecktivIdv` (and any direct `mount('idv')` call) renders the managed IDV module, which self-registers on import. Add a one-time side-effect import of `@checktiv/sdk-web/idv` in your app (for example next to `ChecktivProvider`) so the module is registered before the first mount. Without it the mount fails with `sdk_load_failed`.

## Install

```bash
npm install @checktiv/sdk-web react react-dom
```

`react` and `react-dom` are peer dependencies. The SDK does not bundle them.

## Basic usage

```tsx
import { ChecktivProvider, ChecktivIdv } from '@checktiv/sdk-web/react';
import '@checktiv/sdk-web/idv'; // registers the IDV module that ChecktivIdv mounts

export function App() {
  return (
    <ChecktivProvider
      publishableKey="ah_pk_us_test_..."
      getSessionToken={async (ctx) => {
        const res = await fetch('/api/checktiv/token', {
          method: 'POST',
          body: JSON.stringify({ reason: ctx.reason }),
          headers: { 'Content-Type': 'application/json' },
        });
        return (await res.json()).token;
      }}
      theme={{ primaryColor: '#0b5fff' }}
    >
      <VerificationPage />
    </ChecktivProvider>
  );
}

function VerificationPage() {
  function handleEvent(event) {
    if (event.type === 'checktiv.idv.submitted') {
      // Capture complete. Wait for the webhook before acting on the outcome.
      console.log('Verification submitted');
    }
    if (event.type === 'checktiv.idv.error') {
      console.error('IDV error:', event.error);
    }
  }

  return (
    <div>
      <h1>Verify your identity</h1>
      <ChecktivIdv onEvent={handleEvent} />
    </div>
  );
}
```

## Server-side rendering

`ChecktivProvider` is SSR-safe. On the server (Node.js / edge), `init()` detects the absence of `window` and returns `null`. The provider renders nothing server-side; the client is created and mounted only in the browser.

In Next.js, you do not need `"use client"` on `ChecktivProvider` itself - the wrapper handles the guard internally. You do need `"use client"` on any component that calls `useChecktiv()` directly or renders `<ChecktivIdv>` (because those depend on the browser DOM).

```tsx
// app/verify/page.tsx  (Server Component)
import { ChecktivProvider } from '@checktiv/sdk-web/react';
import { VerifyClient } from './VerifyClient';

export default function VerifyPage() {
  return (
    <ChecktivProvider publishableKey="ah_pk_us_test_..." getSessionToken={...}>
      <VerifyClient />
    </ChecktivProvider>
  );
}

// app/verify/VerifyClient.tsx
'use client';
import { ChecktivIdv } from '@checktiv/sdk-web/react';
import '@checktiv/sdk-web/idv'; // registers the IDV module that ChecktivIdv mounts

export function VerifyClient() {
  return <ChecktivIdv onEvent={(e) => console.log(e)} />;
}
```

## Cleanup

`ChecktivIdv` calls `handle.destroy()` automatically when the component unmounts. You do not need to clean up manually. Under React's `StrictMode` double-invoke, the component mounts, destroys, and remounts cleanly.

## Using `useChecktiv()` directly

If you need the client for custom mount logic, call `useChecktiv()`:

```tsx
'use client';
import { useChecktiv } from '@checktiv/sdk-web/react';
import '@checktiv/sdk-web/idv'; // registers the IDV module that mount('idv') resolves
import { useEffect, useRef } from 'react';

export function CustomIdvMount() {
  const client = useChecktiv();
  const containerRef = useRef(null);

  useEffect(() => {
    if (!containerRef.current) return;
    const handle = client.mount('idv', {
      target: containerRef.current,
      onEvent: (event) => console.log(event),
    });
    return () => handle.destroy();
  }, [client]);

  return <div ref={containerRef} />;
}
```

## Events

`onEvent` receives every `checktiv.idv.*` event:

| Event type               | Meaning                                                                                |
| ------------------------ | -------------------------------------------------------------------------------------- |
| `checktiv.idv.ready`     | The capture frame loaded and is ready for the applicant.                               |
| `checktiv.idv.submitted` | The applicant finished capture. Terminal for capture; the verdict arrives via webhook. |
| `checktiv.idv.error`     | An error occurred. Check `event.error.code` and `event.error.recovery`.                |

Do not exhaustively switch on `event.type`. New event types may be added without a major version bump. Handle known types and ignore unknown ones.

## Related pages

- [Quickstart](/developers/sdks/quickstart) - full end-to-end example
- [Error reference](/developers/sdks/error-reference) - every error code in `checktiv.idv.error`
- [Verdict and webhooks](/developers/sdks/verdict-and-webhooks) - what to do after `checktiv.idv.submitted`