Skip to main content
The journey delegates capture to the host via the camera.document.capture or camera.selfie.capture actions. Your host page presents the capture UI, produces the image data, and returns it through the bridge response. The Web Bridge SDK does not ship a built-in capture component. Browsers vary too widely in camera-API surface for a single component to work everywhere. This page shows how to build a development-grade capture surface using the browser’s native APIs and how to wire it to the bridge.
Development and testing only. The patterns below produce a plain image — they do not perform document detection, auto-cropping, liveness checks, or biometric encryption. Placeholder images will not pass server-side verification. Swap for a production capture SDK before shipping.

When you need a capture surface

The journey requests host-side capture through the camera.document.capture and camera.selfie.capture actions. A development capture surface lets you:
  • Prove early integration — Verify the bridge protocol, capability negotiation, and round-trip data flow before plugging in a production capture SDK.
  • Develop without hardware — A file-input or placeholder fallback covers laptops without cameras, browsers in restricted contexts, and CI environments.
  • Prototype the host UX — Build the host shell with a working capture flow while you focus on routing, branding, and integration concerns.

Three rungs of capture affordance

A capture surface typically offers three fallback levels, in priority order:

Live capture with getUserMedia (rung 1)

A minimal React component that opens a live preview, lets the user snap a photo, and returns base64-encoded JPEG:
For document capture, use facingMode: "environment" (back camera on mobile). For selfies, use facingMode: "user" (front camera).

File picker fallback (rung 2)

When getUserMedia fails or isn’t available, fall back to a file input. On mobile browsers, the capture attribute hints that the camera should open directly; on desktop, the OS file chooser appears.
User backs out of the picker without choosing? event.target.files is empty — treat as “no selection yet” and leave the capture surface open. Don’t fire cancelled to the journey on a picker back-out, just on an explicit user “Cancel” tap on your surface.

Wiring it to the bridge

Pair the capture surface with a useBridgeCapability hook that tracks the active responder and toggles UI visibility.
The handler stores the responder, flips state to render the surface, and the surface invokes callbacks that respond to the journey. If the user navigates away with an active responder still held, fire cancelled in your cleanup to avoid leaving the journey waiting.

Cleanup on unmount

If the component unmounts mid-capture, cancel the active responder so the journey isn’t stuck:

Returning the captured image

However the image was produced — live capture, file picker, or placeholder — the bridge response shape is the same:
The journey-side SDK decodes this into a standard image representation. Keep image dimensions reasonable (typically 1280×720 or 1920×1080) — multi-megabyte base64 strings stress the bridge channel and the journey’s upload step.

Permissions

Browser camera permissions are gated by the page being in a secure context (HTTPS, or localhost) and the iframe’s allow="camera" attribute. The host page also needs permission for itself — if your capture surface lives on the host page (not in the iframe), the host origin needs camera access. Check and surface permission state up front via navigator.permissions.query({ name: "camera" }):
Surface the result via CapabilityInfo.permissionState in your capabilities map so the journey can prompt before triggering the capture. See Capability Handling → Permission state.

Swapping for a production capture SDK

The capture surface is deliberately swappable. The handler, the BridgeResponder contract, and the wire format all stay the same — only the UI that produces the image changes. When you adopt a production capture SDK (with document detection, auto-cropping, glare check, liveness, etc.), replace the <CaptureSurface /> component with the SDK’s component and produce the same response shape. The onCapture / onCancel seam shown above is the integration point. Production SDKs typically expose onResult and onError callbacks that map cleanly to responder.success(...) and responder.error(...).

Next steps