Get started

Drive native iOS and Android features from your web app with @bdk/native.

Create the client

@bdk/native lets your web app use native iOS and Android features — camera, location, in-app purchases, and more — when it runs inside the BDK Native shell. Create the client once with createBdkNative() and reuse it everywhere.

Always create the client with createBdkNative(), never new BdkNativeClient(). It's ready the moment it returns.

import { createBdkNative } from "@bdk/native/browser";

// One instance, shared across your app.
export const bdk = createBdkNative();

const info = await bdk.ready(3000);
console.log(info ? `Native: ${info.deviceOS}` : "Plain web page");

Detect the native app

Use bdk.ready(timeoutMs) to wait for device info and bdk.isNative() to branch your code. In a plain browser there's no app, so render a web-only fallback.

  • bdk.ready(0) (the default) resolves immediately — cached BdkDeviceInfo if it arrived, else null.
  • bdk.ready(3000) waits up to the timeout (ms) for the deviceInfo event.

Option keys you pass to browser methods are the native command contract — pass exactly the keys each native command expects.

const info = await bdk.ready(3000);

if (bdk.isNative()) {
  // Cached device info: playerId, pushToken, deviceOS, bdkRelease, ...
  console.log(bdk.getDeviceInfo()?.deviceOS);
} else {
  // No native shell — render web fallbacks.
}

Get a command's result

Sending a command and receiving its result are two steps. Every browser method returns a Promise<NativeCommandResult> (see Objects) that only confirms the command was dispatched. Device data arrives later on an event you subscribe to with bdk.on(event, listener), which returns an unsubscribe function. Subscribe before you dispatch.

There are three result shapes:

  1. Dispatch-and-forget — commands like navigation. await confirms dispatch; no follow-up event.
  2. Dispatch + event — anything that returns device data: media (photoSelected, photoCaptured, videoSelected, videoCaptured), location, pickers (datePicked, optionPicked), biometricResult, purchases (purchaseSuccess, purchaseFailed, receiptReceived, …). Read the payload from the matching event.
  3. Resolved value — the server SDK. await returns the real outcome (see below).

Match the event to the command: bdk.media.capturePhoto() emits photoCaptured, bdk.media.pickPhoto() emits photoSelected. Both deliver a MediaResult ({ fileUrl, dataUri, data, contentType }).

// 2) Dispatch a command, then receive its result via an event.
const off = bdk.on("photoCaptured", (result) => {
  console.log("Captured:", result.fileUrl, result.contentType);
  off(); // unsubscribe when you are done
});

const dispatch = await bdk.media.capturePhoto();
console.log(dispatch.triggered, dispatch.queued); // dispatch status, not the photo

Browser and server SDKs

Use the browser SDK in your web app and the server SDK on your backend. Awaiting a server call resolves to the real, typed result.

Browser SDK@bdk/native/browser (re-exported from @bdk/native). The client shown above. A CDN global build is at dist/cdn/bdk-native.global.js.

Server SDK@bdk/native/server, plus focused entry points @bdk/native/server/onesignal, /server/iap, /server/branch, /server/chottulink, and /server/firebase-dynamic-links. For example, sendPushNotification(input) returns a PushNotificationResult with notificationId, numberOfRecipients, and sentSuccessfully.

Never import @bdk/native/server/* into a browser bundle — those modules are server-only and may carry secrets. Only the root and /browser entry points are browser-safe.

// Server-only. Awaiting resolves to the real, typed outcome.
import { sendPushNotification } from "@bdk/native/server/onesignal";

const result = await sendPushNotification({
  title: "New message",
  message: "You have a new reply",
  playerIds: ["a-onesignal-player-id"]
});

console.log(result.sentSuccessfully, result.numberOfRecipients);

Start an in-app purchase

Dispatch a purchase with bdk.iap.purchaseIos(), identifying the product with { id, type } where type is "product" or "subscription". Read the outcome from the purchaseSuccess or purchaseFailed event.

bdk.on("purchaseSuccess", ({ platform, data }) => {
  console.log("Purchased on", platform, data);
});

// Native payload contract: { id, type: "product" | "subscription" }
await bdk.iap.purchaseIos({ id: "com.example.pro", type: "subscription" });