Web fallback
Detect when your page isn't running inside the native app and fall back to a web experience.
Set up once, run anywhere
createBdkNative() returns a client that works inside the native app and in any plain browser. Outside the app, native commands resolve cleanly with triggered: false instead of throwing, so the same build is safe to load everywhere.
In a browser tab outside the app, commands resolve pending (reason: "waiting_for_agent"). With no window at all (SSR, Node, a Web Worker) they resolve skipped (reason: "not_native"). Either way triggered is false — branch on that.
Check if you're in the app
bdk.isNative() returns a boolean synchronously. Use it inline to gate any native-only feature and fall back to a web equivalent.
isNative() can read false for a moment at startup before device info arrives. If you need certainty on the first tick, await ready() (next section) instead.
Wait for the native handshake
bdk.ready(timeoutMs = 0) resolves to BdkDeviceInfo | null and never rejects. A null result means you're outside the native app, so use it to branch your UI.
ready()/ready(0)resolves immediately: the cachedBdkDeviceInfoif present, otherwisenull.ready(timeoutMs)waits up to that many milliseconds for the device to report in, then resolves tonullif it never does.
Check whether a command ran
Every native command resolves a NativeCommandResult — inspect it to know whether the app received the command. triggered === true means it ran; anything else means there's no native shell, so branch on !result.triggered for a web fallback.
See Objects for the full shape. Outside the app a command resolves with triggered: false: in a browser tab it's pending with reason: "waiting_for_agent"; with no window at all it's skipped with reason: "not_native". A rejected command instead throws a BdkError with a code like BDK_NATIVE_UNAVAILABLE, BDK_UNSUPPORTED_VERSION, or BDK_UNSUPPORTED_PLATFORM.
Commands that return data (photos, location, pickers, biometrics, IAP) deliver it on an event — capturePhoto emits photoCaptured, pickPhoto emits photoSelected. Those events never fire in the browser, so always give such calls a non-native path and never block your UI on an event that can't arrive.
Build a web fallback
Decide native vs. web once at startup with ready(), then route every native-only call through an isNative() guard with a browser equivalent behind it. Listeners are safe to attach everywhere — in the browser they simply stay dormant, and a listener that throws is surfaced as BDK_LISTENER_ERROR through onError rather than crashing the page.
Never import @bdk/native/server/* into a browser bundle — those modules are server-only. Use @bdk/native/browser (or @bdk/native) on the client.