LOVABLE · BOLT · BASE44 → NATIVE FEATURES

Native app features for Lovable, Bolt and Base44: prompts to paste

Your SaasToStore app runs your live website. Inside the app, your site can also open the phone's share sheet, make it vibrate, scan a QR code and set reminders, on Android and iOS. You don't write that code: copy one of the prompts below, paste it into the chat of Lovable, Bolt or Base44, and the AI adds the feature to your site. In a normal browser, your site keeps working as it does today.

Updated November 3, 2026

Before you paste a prompt

Each feature is a plugin of your SaasToStore project. The prompt changes your site; the plugin puts the feature in the app.

  • Add the plugin, then launch a new build

    Open the plugin library of your project, add the plugin, then launch a new build: an app built before you added it doesn't have the feature. Plugins work in the native Android builds (Android Build (Native), Android TV) and in iOS apps. They are not in the Android Build (Web) (TWA), nor in the free test build, which shows your website as an app, without plugins.

  • Test in the app, not in the editor preview

    The preview of Lovable, Bolt and Base44 shows your site in a frame of the editor, and the plugins run only in your app, never in a frame. So nothing happens there, and that's expected: the prompts keep your site working without them. Publish your site, then open your app on a phone.

  • Your site changes, the app follows

    The app loads your published site. Once the plugin is in the app, a change you publish in Lovable, Bolt or Base44 reaches the app without a new build.

Where to paste the prompt

Each prompt stands on its own: paste one at a time, check the result, then paste the next. The AI adapts the file names to your project.

  • Lovable

    Paste it into the chat of your project. When the change is done, click Publish: the app loads your published site, not the preview.

  • Bolt

    Paste it into the Bolt chat, then deploy again, with Bolt's deploy button or on your own host. The app loads the deployed address.

  • Base44

    Paste it into the AI chat of your app, then publish. The app loads your app's public address.

Native share

A Share button that opens the phone's share sheet: messages, e-mail, social apps. Text and links only, no files. No permission and no prompt for the person.

Prompt · native share

Add a native share button to my project, using the SaasToStore app bridge.

Context: my website also runs inside a native mobile app built with SaasToStore. Inside that app, the function `window.saastostore.share` opens the phone's share sheet. In a normal web browser, and in the editor preview, it does not exist, and the site must keep working exactly as it does today. Do not change anything else.

1. If my project has no `src/lib/saastostore.ts` yet, create it (`.js` if my project doesn't use TypeScript); if it exists, only add what is missing:
   - `isInApp()`: returns `typeof window !== "undefined" && navigator.userAgent.includes("SaasToStoreApp")`.
   - `bridge()`: returns `typeof window !== "undefined" ? window.saastostore : undefined`. Never read `window.saastostore` during server rendering.
   - the TypeScript type of `window.saastostore` (optional), with this optional member:
     `share?: (o?: { title?: string; text?: string; url?: string }) => Promise<{ shared: boolean; error?: string } | null>`

2. On [THE PAGE OR ITEM TO SHARE], add a "Share" button. When it is tapped:
   - if `bridge()?.share` exists, call `bridge().share({ title: [TITLE], text: [SHORT TEXT], url: [FULL LINK TO THE PAGE] })`. `share` is a function, not an object. `url` must start with `https://` or `http://`. Its promise never rejects: if the result has an `error`, show a short message.
   - otherwise, if `navigator.share` exists, call `navigator.share({ title, text, url })` and ignore the error thrown when the person closes the sheet.
   - otherwise, copy the link to the clipboard and show "Link copied".

3. `shared: true` only means the share sheet opened, not that something was sent: don't show a "Shared" confirmation.

Replace the values in [BRACKETS] before pasting. Add the plugin in your project, then launch a new build.

Haptic feedback

Short vibrations that confirm a tap, a success or an error. No permission prompt. What the person feels depends on their phone and its haptic setting; on Android, a device that can't vibrate (most tablets and TVs) plays nothing.

Prompt · haptic feedback

Add haptic feedback to my project, using the SaasToStore app bridge.

Context: my website also runs inside a native mobile app built with SaasToStore. Inside that app, `window.saastostore.haptics` makes the phone vibrate briefly. In a normal web browser, and in the editor preview, it does not exist, and the site must keep working exactly as it does today. Do not change anything else.

1. If my project has no `src/lib/saastostore.ts` yet, create it (`.js` if my project doesn't use TypeScript); if it exists, only add what is missing:
   - `isInApp()`: returns `typeof window !== "undefined" && navigator.userAgent.includes("SaasToStoreApp")`.
   - `bridge()`: returns `typeof window !== "undefined" ? window.saastostore : undefined`. Never read `window.saastostore` during server rendering.
   - the TypeScript type of `window.saastostore` (optional), with this optional member:
     `haptics?: { impact(o?: { style?: "light" | "medium" | "heavy" }): Promise<{ ok: boolean; error?: string } | null>; notification(o?: { type?: "success" | "warning" | "error" }): Promise<{ ok: boolean; error?: string } | null>; selection(): Promise<{ ok: boolean; error?: string } | null> }`

2. In the same file, add three functions that do nothing outside the app and never wait for the result:
   - `tapFeedback()`: calls `bridge()?.haptics?.impact({ style: "light" })`.
   - `successFeedback()`: calls `bridge()?.haptics?.notification({ type: "success" })`.
   - `errorFeedback()`: calls `bridge()?.haptics?.notification({ type: "error" })`.
   Their promises never reject. Ignore a result with `ok: false` (for example `not_available` on a phone that can't vibrate): never show it to the person.

3. Call `tapFeedback()` when [MY MAIN BUTTONS] are tapped, `successFeedback()` when [A FORM, FOR EXAMPLE THE CHECKOUT] succeeds and `errorFeedback()` when it fails.

4. Don't vibrate on scroll, on every key typed, or several times in a row.

Replace the values in [BRACKETS] before pasting. Add the plugin in your project, then launch a new build.

QR code scanner

A Scan button that reads a QR code or a barcode with the camera: a ticket, a product, a link. On Android, the reader is Google's (Google Play services), and your app asks for no camera permission; phones without Google Play services, such as Amazon Fire and Huawei, don't have it. On iOS, the app opens its own reader and asks for the camera the first time. Try it with a real code on a real phone before you publish.

Prompt · QR code scanner

Add a QR code scanner to my project, using the SaasToStore app bridge.

Context: my website also runs inside a native mobile app built with SaasToStore. Inside that app, `window.saastostore.barcode` opens the phone's code reader. In a normal web browser, and in the editor preview, it does not exist, and the site must keep working exactly as it does today. Do not change anything else.

1. If my project has no `src/lib/saastostore.ts` yet, create it (`.js` if my project doesn't use TypeScript); if it exists, only add what is missing:
   - `isInApp()`: returns `typeof window !== "undefined" && navigator.userAgent.includes("SaasToStoreApp")`.
   - `bridge()`: returns `typeof window !== "undefined" ? window.saastostore : undefined`. Never read `window.saastostore` during server rendering.
   - the TypeScript type of `window.saastostore` (optional), with this optional member:
     `barcode?: { isAvailable(): Promise<{ available: boolean; reason?: string } | null>; scan(o?: { formats?: string[]; prompt?: string }): Promise<{ scanned: true; value: string; format: string } | { scanned: false; error: string } | null> }`

2. On [THE PAGE WHERE PEOPLE SCAN], show a "Scan a code" button only when `isInApp()` is true and `bridge()?.barcode?.isAvailable()` answers `available: true`. Otherwise keep the page as it is today (for example a field to type the code).

3. When the button is tapped, call `bridge().barcode.scan({ formats: ["qr"], prompt: "[TEXT ABOVE THE VIEWFINDER, 200 CHARACTERS MAX]" })`. Its promise never rejects:
   - `scanned: true`: use `value` to [WHAT TO DO WITH THE CODE, FOR EXAMPLE OPEN THE TICKET].
   - `error: "cancelled"`: do nothing, the person closed the reader.
   - `error: "not_allowed"` (iOS, camera refused): explain that the camera can be allowed in the phone's settings.
   - any other error: show a short message.

4. `value` is text from an unknown source: check it before using it, never insert it into the page as HTML, and never open it as a link without checking that it points to [MY DOMAIN].

Replace the values in [BRACKETS] before pasting. Add the plugin in your project, then launch a new build.

Local notifications (reminders)

A Remind me button that schedules a notification on the phone, shown at the chosen time even when the app is closed: an appointment, a session that starts, a cart left behind. No server is involved: this is not push, and it can't reach all your users at once. Android shows the reminder within a few minutes of the time; iOS is on time. Reminders survive a restart of the phone. Limits: 64 pending reminders, up to 366 days ahead.

Prompt · local notifications

Add reminders (local notifications) to my project, using the SaasToStore app bridge.

Context: my website also runs inside a native mobile app built with SaasToStore. Inside that app, `window.saastostore.localNotifications` schedules notifications on the phone itself, with no server. In a normal web browser, and in the editor preview, it does not exist, and the site must keep working exactly as it does today. Do not change anything else.

1. If my project has no `src/lib/saastostore.ts` yet, create it (`.js` if my project doesn't use TypeScript); if it exists, only add what is missing:
   - `isInApp()`: returns `typeof window !== "undefined" && navigator.userAgent.includes("SaasToStoreApp")`.
   - `bridge()`: returns `typeof window !== "undefined" ? window.saastostore : undefined`. Never read `window.saastostore` during server rendering.
   - the TypeScript type of `window.saastostore` (optional), with this optional member:
     `localNotifications?: { requestPermission(): Promise<{ granted: boolean; status: "granted" | "denied" | "prompt"; error?: string } | null>; schedule(o: { id?: number; title: string; body?: string; at?: number | string; in?: number; data?: object }): Promise<{ scheduled: true; id: number; at: number } | { scheduled: false; error: string; status?: string } | null>; cancel(o: { id: number }): Promise<{ ok: boolean; error?: string } | null>; getLastOpened(): Promise<{ notification: { id: number; title: string; body: string; at: number; data: object } | null } | null> }`

2. On [THE ITEM THAT DESERVES A REMINDER, FOR EXAMPLE A BOOKING], show a "Remind me" button only when `isInApp()` is true and `bridge()?.localNotifications` exists.

3. When the button is tapped (never when the page loads):
   - first call `bridge().localNotifications.requestPermission()`. If `granted` is false, explain that notifications can be allowed in the phone's settings, and stop.
   - then call `bridge().localNotifications.schedule({ id: [A NUMBER UNIQUE TO THIS ITEM], title: [TITLE, 200 CHARACTERS MAX], body: [SHORT TEXT], at: [THE TIME, AS A TIMESTAMP IN MILLISECONDS OR date.toISOString()], data: { [THE ITEM ID] } })`. Show "Reminder set" when `scheduled` is true, and a short message otherwise.
   These promises never reject.

4. When the person taps the notification, open [THE PAGE OF THE ITEM] with the id found in `data`:
   - listen to `window.addEventListener("s2s:localNotifications", (e) => …)` and act when `e.detail.type === "tap"`, using `e.detail.data`;
   - also call `bridge()?.localNotifications?.getLastOpened()` once when the app starts: if the app was closed, the event fired before the page was listening. It returns `{ notification }` once, then `{ notification: null }`.

5. When the item is cancelled or the reminder is no longer useful, call `bridge()?.localNotifications?.cancel({ id })`.

Replace the values in [BRACKETS] before pasting. Add the plugin in your project, then launch a new build.

Check the result

  • In a normal browser: the page looks and works as before, with no button that does nothing.
  • In your app, built after you added the plugin: the button shows and does its job.
  • Close the share sheet or the scanner without choosing anything: no error message appears.
  • Refuse the permission once (notifications; the camera on iOS): the page says what to do instead of failing silently.

Frequently asked questions

Does the same prompt work in Lovable, Bolt and Base44?+

Yes. Each prompt describes the change, not a tool, so the same text works in the chat of Lovable, Bolt and Base44, and in other AI builders that edit your site's code. The AI picks the right file names for your project.

Why does nothing happen in the editor preview?+

The preview shows your site in a frame of the editor. The plugins run only in the main frame of your app, never in a frame or in a browser, so window.saastostore does not exist there. The prompts keep your site working without it. To try a feature, publish your site and open your app on a phone.

Do I need a new build after pasting a prompt?+

Only to add the plugin. Plugins are written into the app when it's built: add the plugin in your project's plugin library, then launch a new build. After that, a change you publish on your site reaches the app without a new build, because the app loads your published site.

Are these plugins included in my plan?+

Standard plugins are included in the paid plans, with no license per plugin: add as many as your app needs. The free test build (Android, with the SaasToStore logo) shows your website as an app, without plugins.

Will my app ask for new permissions?+

Native share and haptic feedback ask for nothing. The QR scanner asks for the camera on iOS, the first time it scans; on Android it uses Google's reader and asks for nothing. Local notifications ask for permission on Android 13 and later and on iOS, when your site calls requestPermission() from a button.

Can I send a notification to all my users?+

Not with these prompts. A local notification is scheduled by your page on one phone, with no server. A message sent from your server to your users is push, a different plugin.

Related guides

Add the feature to your app

Paste your site's URL, add the plugins in your project, then build. Your site keeps working in the browser.

Start my app