Skip to main content

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.

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).
All bridge code must execute on the client. The bridge cannot run on the server.
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

// 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:
// 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:
// 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:
// 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

// 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

PatternProblemSolution
Import bridge in Server ComponentsCrashes — no windowAdd 'use client' directive
Call NativeBridge.getInstance() at module scopeRuns during SSR buildCall inside useEffect or useMemo
Use detectEnvironment() in getServerSidePropsReturns '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:
'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.