> ## 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.

# FAQ

> Frequently asked questions about the GBGBridge Web SDK.

## General

<AccordionGroup>
  <Accordion title="What browsers does the Web SDK support?">
    Modern evergreen browsers — Chrome, Firefox, Safari, and Edge. The SDK uses ES2020 features and `crypto.randomUUID()` with a timestamp+random fallback for older environments.
  </Accordion>

  <Accordion title="Does the Web SDK have any runtime dependencies?">
    No. Both `@gbg/go-bridge-web` and `@gbg/go-bridge-web-react` have zero runtime dependencies. React is a `peerDependency` for the React package.
  </Accordion>

  <Accordion title="What's the difference between the two packages?">
    `@gbg/go-bridge-web` is the framework-agnostic core (the `BridgeHost` class, message types, responder, error types, capability constants). `@gbg/go-bridge-web-react` is a React 19 adapter — a `BridgeHostProvider` and four hooks — that depends on the core as a peer dependency.
  </Accordion>

  <Accordion title="How large is the SDK bundle?">
    The core package is tiny (single-digit KB after minification + gzip); the React adapter adds little on top. Both are ESM and tree-shakeable.
  </Accordion>
</AccordionGroup>

## Integration

<AccordionGroup>
  <Accordion title="What frameworks does the Web SDK support?">
    Anything that lets you mount an `<iframe>`. React 19 has first-party support via `@gbg/go-bridge-web-react`. Vanilla JS, Vue, Angular, Svelte, and older React versions work with the core `@gbg/go-bridge-web` package.
  </Accordion>

  <Accordion title="Can I run the SDK on the server (SSR)?">
    No — the SDK accesses `window` and the DOM. Mark the component as client-only via `"use client"` (Next.js App Router), `dynamic(..., { ssr: false })` (Pages Router), or your framework's equivalent gate. The token-exchange step does run on the server.
  </Accordion>

  <Accordion title="Can I use multiple BridgeHost instances on one page?">
    Yes. Each `BridgeHostProvider` (or `new BridgeHost(...)`) owns its own iframe, origin allowlist, capabilities, and handler registry.
  </Accordion>

  <Accordion title="Why do I have to track the iframe in `useState` instead of `useRef`?">
    `BridgeHostProvider` rebuilds the underlying `BridgeHost` when the `iframe` prop transitions from `null` to a real element. `useRef` doesn't trigger re-renders, so the provider's effect would never fire.
  </Accordion>

  <Accordion title="Can I change capabilities after mount?">
    Either remount the provider (`key`-based) or call `registerCustomCapability` — that one reads live on every query, no remount needed.
  </Accordion>

  <Accordion title="Do I need to handle `capability.query` myself?">
    No. `BridgeHost` automatically registers `CapabilityQueryHandler` for the `"capability.query"` action.
  </Accordion>

  <Accordion title="What's the difference between a capability ID and an action ID?">
    Capability ID (e.g. `camera.document`) is a feature negotiation key — appears in the `capabilities` map. Action ID (e.g. `camera.document.capture`) is the specific operation — appears in `useBridgeCapability(...)` and inbound `payload.action`. Declaring the capability does not implicitly register a handler for the action; both are required.
  </Accordion>
</AccordionGroup>

## Messaging

<AccordionGroup>
  <Accordion title="Are messages guaranteed to be delivered?">
    `postMessage` is reliable in-process delivery within the browser, as long as `iframe.contentWindow` is non-null, the listener is attached, and the envelope validates. There is no built-in retry or delivery confirmation.
  </Accordion>

  <Accordion title="What's the maximum message size?">
    No hard limit imposed by the SDK. Browsers vary in `postMessage` payload limits. For images, capture at moderate resolution and use JPEG at quality \~85. For multi-megabyte transfers, upload from host to your backend and pass a URL through the bridge.
  </Accordion>

  <Accordion title="Is message order preserved?">
    Yes. `postMessage` delivers in send order; `BridgeHost` processes in arrival order.
  </Accordion>

  <Accordion title="Can I send a message before the iframe loads?">
    No — outbound sends require `iframe.contentWindow` non-null and `iframe.src` set. Sends before either is ready drop with a `console.warn`. Wait for a `journey.started` event or your own readiness signal.
  </Accordion>

  <Accordion title="What happens to events — does anyone respond?">
    Events are fire-and-forget. No response expected. Either side may emit them; receivers subscribe via `useBridgeHostEvent` or the iframe-side SDK.
  </Accordion>
</AccordionGroup>

## Capabilities

<AccordionGroup>
  <Accordion title="How does the journey discover what the host supports?">
    The journey sends a `capability.query` request as it loads. The host's built-in handler responds with `{ environment: "web", hostVersion, capabilities }`, and the journey adapts its flow accordingly.
  </Accordion>

  <Accordion title="What capabilities does the Web SDK support natively?">
    The SDK is a routing layer — it doesn't implement capabilities itself. Standard IDs are exported in `CAPABILITY_IDS` (`camera.document`, `camera.selfie`, `nfc.read`, `biometric.auth`, etc.). Web hosts realistically support `camera.document`, `camera.selfie`, and `analytics.forward`.
  </Accordion>

  <Accordion title="How do I report camera permission state to the journey?">
    Query the browser and pass through `CapabilityInfo.permissionState`:

    ```typescript theme={null}
    const status = await navigator.permissions.query({ name: "camera" as PermissionName });
    const capabilities = {
      "camera.document": { supported: true, version: "1.0", permissionState: status.state },
    };
    ```
  </Accordion>

  <Accordion title="What if the host can't fulfil a capability the journey requests?">
    Respond with `responder.unsupported("reason")` or `responder.error({...})`. If a capability is never available on your host, declare it `supported: false` upfront.
  </Accordion>
</AccordionGroup>

## Security

<AccordionGroup>
  <Accordion title="Are bridge messages encrypted?">
    Messages travel over the browser's in-process `postMessage` channel — they never leave the device. TLS doesn't apply because there's no network hop.
  </Accordion>

  <Accordion title="Can a malicious script on the host page exploit the bridge?">
    The bridge enforces an `allowedOrigins` allowlist on both inbound and outbound traffic. A script that repoints `iframe.src` to a hostile origin can neither send to nor receive from the host — both checks fail.
  </Accordion>

  <Accordion title="Can the journey exfiltrate host state?">
    Only what the host explicitly sends via `sendEvent` or `respond`. Same-origin policy prevents the journey from reading the host's DOM, cookies, or storage.
  </Accordion>

  <Accordion title="Where does the journey URL come from? Can I hardcode it?">
    The journey URL is minted server-side by your backend using `@gbg/go-core`. Don't hardcode it, don't generate it in the browser, and don't ship `@gbg/go-core` in your client bundle — its OAuth flow uses a client secret.
  </Accordion>
</AccordionGroup>

## Debugging

<AccordionGroup>
  <Accordion title="How do I see what messages are being exchanged?">
    Set a delegate:

    ```typescript theme={null}
    host.delegate = {
      onMessage(_h, m) { console.log("[in ]", m); },
      onMessageSent(_h, m) { console.log("[out]", m); },
    };
    ```

    Or read `host.receivedMessages` directly (capped at 200).
  </Accordion>

  <Accordion title="Why are messages being silently dropped?">
    The transport drops on three checks: `event.source` mismatch, origin not in allowlist, or envelope validation failure. Common causes: trailing slashes in `allowedOrigins`, scheme/port mismatch, or malformed envelopes. See [Troubleshooting](/docs/go-v2/developer-integration/sdks/web/troubleshooting#inbound-messages-silently-dropped).
  </Accordion>

  <Accordion title="Can I debug from inside the iframe?">
    Yes. Open browser DevTools and switch the document context to the iframe (Chrome: dropdown at the top of Console; Firefox: Inspector toolbar).
  </Accordion>
</AccordionGroup>

## Next steps

* [Getting Started](/docs/go-v2/developer-integration/sdks/web/getting-started) — First integration walkthrough.
* [Troubleshooting](/docs/go-v2/developer-integration/sdks/web/troubleshooting) — Detailed issue resolution.
* [API Reference](/docs/go-v2/developer-integration/sdks/web/api-reference) — Complete type reference.
