> ## Documentation Index
> Fetch the complete documentation index at: https://docs.go.gbgplc.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Next.js usage

> Use the TypeScript Bridge SDK with Next.js App Router and Pages Router

The GBG GO Native Bridge is a browser-only library. It requires `window` and browser APIs that are not available during server-side rendering (SSR).

<Warning>
  All bridge code must execute on the client. The bridge cannot run on the server.
</Warning>

## App Router (recommended)

In the App Router, components are server-rendered by default. Because the bridge needs `window`, you have to opt the relevant subtree into the client with `'use client'` — typically by wrapping `BridgeProvider` in a small client-only component.

### Mark bridge components as client-only

```tsx theme={null}
// app/layout.tsx
import { BridgeWrapper } from './bridge-wrapper';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <BridgeWrapper>{children}</BridgeWrapper>
      </body>
    </html>
  );
}
```

The wrapper itself is a client component that just renders `BridgeProvider`:

```tsx theme={null}
// app/bridge-wrapper.tsx
'use client';

import { BridgeProvider } from '@gbgplc-internal/ggo-native-bridge-react';

export function BridgeWrapper({ children }: { children: React.ReactNode }) {
  return <BridgeProvider>{children}</BridgeProvider>;
}
```

The `'use client'` directive ensures the `BridgeProvider` and all bridge-related code only runs in the browser.

### Using hooks in client components

Any component that calls a bridge hook also needs `'use client'`. From there, the hooks behave exactly as they do outside Next.js:

```tsx theme={null}
// components/document-capture.tsx
'use client';

import { useNativeCamera, useBridge } from '@gbgplc-internal/ggo-native-bridge-react';

export function DocumentCapture() {
  const { isEmbedded, capabilitiesReady } = useBridge();
  const { isNativeAvailable, requestCapture } = useNativeCamera('document');

  if (!capabilitiesReady) return <p>Loading...</p>;

  return (
    <button onClick={() => isNativeAvailable && requestCapture({ side: 'front' })}>
      Capture
    </button>
  );
}
```

### Dynamic import fallback

If you need to conditionally load bridge code:

```tsx theme={null}
// app/page.tsx
import dynamic from 'next/dynamic';

const DocumentCapture = dynamic(
  () => import('../components/document-capture').then(mod => mod.DocumentCapture),
  { ssr: false },
);

export default function Page() {
  return <DocumentCapture />;
}
```

## Pages Router

```tsx theme={null}
// pages/_app.tsx
import type { AppProps } from 'next/app';
import { BridgeProvider } from '@gbgplc-internal/ggo-native-bridge-react';

export default function App({ Component, pageProps }: AppProps) {
  return (
    <BridgeProvider>
      <Component {...pageProps} />
    </BridgeProvider>
  );
}
```

Since Pages Router components are client-rendered by default, the bridge works without additional configuration.

## Things to avoid

| Pattern                                           | Problem                              | Solution                             |
| ------------------------------------------------- | ------------------------------------ | ------------------------------------ |
| Import bridge in Server Components                | Crashes — no `window`                | Add `'use client'` directive         |
| Call `NativeBridge.getInstance()` at module scope | Runs during SSR build                | Call inside `useEffect` or `useMemo` |
| Use `detectEnvironment()` in `getServerSideProps` | Returns `'standalone'` (no `window`) | Only call on the client              |

## Environment detection during SSR

If you need to know the environment during SSR (e.g., for conditional rendering), pass it as a prop from the client:

```tsx theme={null}
'use client';

import { detectEnvironment } from '@gbgplc-internal/ggo-native-bridge';
import { useState, useEffect } from 'react';

function useEnvironment() {
  const [env, setEnv] = useState<string>('standalone');

  useEffect(() => {
    setEnv(detectEnvironment());
  }, []);

  return env;
}
```

This avoids hydration mismatches by starting with `'standalone'` and updating on the client.
