Every change, three times
× every change
Seventy-one of them, and 61 run on a real phone in the demo app.
Typed, documented, identical on iOS and Android. Call them from the JavaScript you already write.
In-app purchases
Sell digital goods on both stores. Verify receipts server-side.
Web, iOS, Android: everyone runs your latest deploy, even users who never update the app.
The old way: ship every change three times and wait for review. With BDK, deploy once.
× every change
A new icon or native feature still needs a store build.
How App Review sees thisPick the tool you build in. This is the whole integration: the reference it reads, the files it writes, the phone answering.
Send a server push that opens the linked post using env credentials
Send the deep link from the server with env credentials
Server-only push uses env credentials and opens Post 42.
1import { sendPushNotification } from "@thebdk/native/server/onesignal";2 3const result = await sendPushNotification({4 message: "New reply on your post",5 title: "Inbox",6 subtitle: "From @jess",7 imageUrl: "https://cdn.example.com/preview.png",8 onLoadUrl: "https://app.example.com/posts/42",9 urlParams: [{ key: "ref", value: "push" }],10 data: { postId: 42, kind: "reply" },11 subscriptionIds: ["a1b2c3d4-1111-2222-3333-444455556666"]12});Integrate @thebdk/native into this app so camera and Face ID work when the deployed site runs inside BDK's native shell, while the normal web app keeps working in a browser.
First read https://docs.thebdk.com/llms-full.txt and the page for each feature you add. Use only the helper names, event names, and option keys documented there — don't invent API.
Then:
1. Add the @thebdk/native package.
2. Create one shared client in src/lib/bdk.ts with a browser-safe import:
import { createBdkNative } from "@thebdk/native/browser";
export const bdk = createBdkNative();
3. Build the features with the typed namespaced helpers only: bdk.media.*, bdk.ui.*,
bdk.navigation.*, bdk.iap.*, bdk.auth.*, bdk.location.*, bdk.device.*, bdk.share.*,
bdk.permissions.*.
4. Subscribe with bdk.on(event, cb) BEFORE you call anything interactive — the result
arrives on the event, not on the returned promise.
5. In a browser the call doesn't run: it resolves with triggered: false. Branch on
!result.triggered and keep a real web fallback so the Lovable preview and the web
build both still work. Don't describe that case as skipped or not_native, and don't
wait for a native event in the web UI.
6. Anything from @thebdk/native/server/* is backend-only. Read credentials from environment
variables — never put keys or server imports in client code.
Don't claim you created iOS or Android apps, wrapped the site, signed builds, submitted to a store, or verified native behaviour in the preview.
Finish with the files you changed, the web fallback you added, and this hand-off: publish this app to its URL, connect that URL at thebdk.com so BDK packages and signs the iOS and Android builds, then test native features in the BDK-packaged app.Right where your customer expected to land.
Available nowRunning in the BDK-packaged app
Adds camera and Face ID. The web preview keeps working on the fallback path.
npm install @thebdk/native, one import, everything else untouched. bdk.on(…) before it calls. No codebase? There is nothing to install. Connect your app's URL in the dashboard and the builds come out the same.
Machine-readable reference: llms.txt — the file your agent fetches. How agents use it →
Install the SDK — or don't
Have a codebase? npm install @thebdk/native — one dependency, fully typed. No codebase? Nothing to install. Step 3 is the whole job.
Call native features where you want them
Camera, biometrics, purchases, push — from your existing JavaScript. One build: browser tab or App Store install, it just runs.
Connect your URL. Get store-ready builds.
Paste your URL in the dashboard. BDK builds and signs both apps. After that, every deploy updates every phone.
import { createBdkNative } from "@thebdk/native/browser";
const bdk = createBdkNative();
await bdk.ready();
// Results arrive on events — subscribe, then call.
bdk.on("photoCaptured", (photo) => upload(photo.fileUrl));
await bdk.media.capturePhoto();
// Native UI, one line.
await bdk.ui.showBanner({
title: "Saved",
description: "Photo uploaded."
});That's the whole integration model. Full reference in the docs, every feature runnable in the live demo.
Apple rejects apps that are just a website. Push, Face ID, purchases and sharing make yours an app. No one can promise approval. The live demo is a BDK-packaged app you can judge for yourself.
No. Your app renders your live site — deploying your website is how web-based apps are meant to work, not a code-injection trick. Store review applies when the native side changes (icon, entitlements, or a runtime upgrade); for those, BDK hands you a fresh signed build to submit.
A native runtime for iOS and Android that renders your live web app full-screen inside a real, store-distributed binary — plus a typed JavaScript SDK, @thebdk/native, that bridges your code to the device: camera, biometrics, purchases, push. BDK packages and signs the store-ready binary; you submit it from your own developer accounts, guided step by step. Your web app stays a standard web app, hosted by you.
No. It runs as-is. Add @thebdk/native only where you want native features; everything else is untouched, and the same build keeps serving your regular website.
A PWA can't sit in the App Store or sell through in-app purchase. Capacitor hands you native projects to own — building, signing, and rebuilding stay your job, forever. BDK's runtime is managed: packaging, signing, and platform churn are its problem, not yours.