Get started

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

Create the client

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.

Browser method options are typed — pass the option names each method documents, and your editor will catch mismatches.

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

Legacy dispatch commands resolve a NativeCommandResult — branch on !result.triggered. New-generation namespaced helpers resolve an Action-result envelope that always has ok — branch on !result.ok. See Handling results for the full patterns.

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 @bdk/native/browser (or the package root; CDN at dist/cdn/bdk-native.global.js) in your web app. Use @bdk/native/server or a focused /server/* entry on your backend — await returns the typed result.

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" });