---
description: Convert your Lovable app into native iOS and Android mobile apps with Capacitor and Capawesome Cloud — build in the cloud (no Mac) and ship OTA updates.
title: Convert Your Lovable App to iOS & Android Apps - Capawesome
image: https://capawesome.io/docs/assets/images/social/blog/convert-lovable-app-to-mobile-app.png
---

<!doctype html> 

[Skip to content ](#convert-your-lovable-app-to-ios-android-apps) 

[🔐 Introducing the **Capacitor Vault** plugin — store secrets behind biometrics or a device passcode. ](/blog/announcing-the-capacitor-vault-plugin/) 

* [ SDKs ](/docs/sdks/)
* [ Formbricks ](/docs/sdks/capacitor/formbricks/)
* [ Geocoder ](/docs/sdks/capacitor/geocoder/)
* [ Google Sign-In ](/docs/sdks/capacitor/google-sign-in/)
* [ Grafana Faro ](/docs/sdks/capacitor/grafana-faro/)
* [ libSQL ](/docs/sdks/capacitor/libsql/)
* [ Live Update ](/docs/sdks/capacitor/live-update/)
* [ Managed Configurations ](/docs/sdks/capacitor/managed-configurations/)
* [ Media Session ](/docs/sdks/capacitor/media-session/)
* [ ML Kit ](/docs/sdks/capacitor/mlkit/)
* [ Navigation Bar ](/docs/sdks/capacitor/navigation-bar/)
* [ NFC ](/docs/sdks/capacitor/nfc/)
* [ OAuth ](/docs/sdks/capacitor/oauth/)
* [ Pedometer ](/docs/sdks/capacitor/pedometer/)
* [ Photo Editor ](/docs/sdks/capacitor/photo-editor/)
* [ PostHog ](/docs/sdks/capacitor/posthog/)
* [ Printer ](/docs/sdks/capacitor/printer/)
* [ Purchases ](/docs/sdks/capacitor/purchases/)
* [ RealtimeKit ](/docs/sdks/capacitor/realtimekit/)
* [ Screen Orientation ](/docs/sdks/capacitor/screen-orientation/)
* [ Screenshot ](/docs/sdks/capacitor/screenshot/)
* [ Secure Preferences ](/docs/sdks/capacitor/secure-preferences/)
* [ Speech Recognition ](/docs/sdks/capacitor/speech-recognition/)
* [ Speech Synthesis ](/docs/sdks/capacitor/speech-synthesis/)
* [ Share Target ](/docs/sdks/capacitor/share-target/)
* [ Square Mobile Payments ](/docs/sdks/capacitor/square-mobile-payments/)
* [ SQLite ](/docs/sdks/capacitor/sqlite/)
* [ Superwall ](/docs/sdks/capacitor/superwall/)
* [ Torch ](/docs/sdks/capacitor/torch/)
* [ Vault ](/docs/sdks/capacitor/vault/)
* [ Wifi ](/docs/sdks/capacitor/wifi/)
* [ Zip ](/docs/sdks/capacitor/zip/)
* [ Cordova ](/docs/sdks/cordova/)
* [ Cloud ](/docs/cloud/)
* [ Integrations ](/docs/cloud/live-updates/integrations/)
* Concepts
* Reference
* [ Troubleshooting ](/docs/cloud/live-updates/troubleshooting/)
* [ FAQ ](/docs/cloud/live-updates/faq/)
* [ Native Builds ](/docs/cloud/native-builds/)
* [ Set Up Environments ](/docs/cloud/native-builds/environments/)
* [ Overwrite Native Configurations ](/docs/cloud/native-builds/native-configurations/)
* [ Auto-Increment Build Numbers ](/docs/cloud/native-builds/auto-incrementing-build-numbers/)
* [ Configure the Web Build Script ](/docs/cloud/native-builds/web-build-script/)
* [ Build from a Monorepo ](/docs/cloud/native-builds/monorepo/)
* [ Use pnpm, Yarn, or bun ](/docs/cloud/native-builds/package-managers/)
* [ Install Private npm Packages ](/docs/cloud/native-builds/npm-private-registry/)
* [ Override the Java Version ](/docs/cloud/native-builds/override-java-version/)
* [ Custom iOS Provisioning Profiles ](/docs/cloud/native-builds/custom-ios-provisioning-profiles/)
* [ Build without Git ](/docs/cloud/native-builds/build-without-git/)
* [ Access Git Behind a Firewall ](/docs/cloud/native-builds/firewall-access/)
* [ Integrations ](/docs/cloud/native-builds/integrations/)
* Reference
* [ Troubleshooting ](/docs/cloud/native-builds/troubleshooting/)
* [ FAQ ](/docs/cloud/native-builds/faq/)
* [ App Store Publishing ](/docs/cloud/app-store-publishing/)
* [ Submit a Build ](/docs/cloud/app-store-publishing/submit-a-build/)
* [ Submit Automatically After a Build ](/docs/cloud/app-store-publishing/submit-automatically/)
* [ Troubleshooting ](/docs/cloud/app-store-publishing/troubleshooting/)
* [ FAQ ](/docs/cloud/app-store-publishing/faq/)
* [ Automations ](/docs/cloud/automations/)
* [ Reference ](/docs/cloud/automations/reference/)
* [ Troubleshooting ](/docs/cloud/automations/troubleshooting/)
* [ FAQ ](/docs/cloud/automations/faq/)
* [ Assist ](/docs/cloud/assist/)
* [ CLI ](/docs/cloud/cli/)
* APIs and SDKs
* [ Webhooks ](/docs/cloud/webhooks/)
* [ Integrations ](/docs/cloud/integrations/)
* Account
* [ Organization ](/docs/cloud/organizations/)
* [ Two-Factor Enforcement ](/docs/cloud/organizations/two-factor-authentication/)
* [ Audit Logs ](/docs/cloud/organizations/audit-logs/)
* [ Billing ](/docs/cloud/organizations/billing/)
* [ License Keys ](/docs/cloud/license-keys/)
* [ AI ](/docs/ai/)
* [ Insiders ](/docs/insiders/)
* [ Billing & Plans ](/docs/insiders/billing-and-plans/)
* [ FAQ ](/docs/insiders/faq/)
* [ License ](https://capawesome.io/legal/eula/)
* [ Support ](/docs/support/)
* [ Contributing ](/docs/contributing/)
* Contributing code
* [ Code of Conduct ](/docs/contributing/code-of-conduct/)
* [ Questions ](https://docs.github.com/en/discussions/collaborating-with-your-community-using-discussions/participating-in-a-discussion#creating-a-discussion)
* [ Blog ](/blog/)
* Categories

* [ Step 1 — Build Your App in Lovable ](#step-1-build-your-app-in-lovable)
* [ Step 2 — Export Your App to GitHub ](#step-2-export-your-app-to-github)
* [ Step 3 — Clone and Run Your App Locally ](#step-3-clone-and-run-your-app-locally)
* [ Step 4 — Add Capacitor and the Native Platforms ](#step-4-add-capacitor-and-the-native-platforms)
* [ Step 5 — Check Your .gitignore ](#step-5-check-your-gitignore)
* [ Step 6 — Commit and Push ](#step-6-commit-and-push)
* [ Step 7 — Create a Capawesome Cloud Account and Connect Your Repo ](#step-7-create-a-capawesome-cloud-account-and-connect-your-repo)
* [ Step 8 — Create Your Developer Accounts ](#step-8-create-your-developer-accounts)
* [ Step 9 — Generate Your Signing Certificates ](#step-9-generate-your-signing-certificates)
* [ Step 10 — Build Your Native App in the Cloud ](#step-10-build-your-native-app-in-the-cloud)
* [ Step 11 — Install the App on Your iPhone ](#step-11-install-the-app-on-your-iphone)
* [ Step 12 — Set Up Store Destinations and Deploy to Your Testers ](#step-12-set-up-store-destinations-and-deploy-to-your-testers)
* [ Step 13 — Add a Native Feature: The Camera ](#step-13-add-a-native-feature-the-camera)
* [ Step 14 — Add Live Updates (and Why They Matter) ](#step-14-add-live-updates-and-why-they-matter)
* [ Step 15 — Rebuild the Native App in the Cloud ](#step-15-rebuild-the-native-app-in-the-cloud)
* [ Step 16 — Fix the Status Bar Spacing with a Live Update (OTA) ](#step-16-fix-the-status-bar-spacing-with-a-live-update-ota)
* [ Step 17 — Prepare Your Store Listing (and What's Left to Submit) ](#step-17-prepare-your-store-listing-and-whats-left-to-submit)
* [ Common Errors (and How to Fix Them) ](#common-errors-and-how-to-fix-them)
* [ What's Next ](#whats-next)
* [ Final Thoughts ](#final-thoughts)

* Related links

# Convert Your Lovable App to iOS & Android Apps[¶](#convert-your-lovable-app-to-ios-android-apps "Permanent link")

You built an app with [Lovable](https://lovable.dev). You described what you wanted, watched it come to life in the browser, and now you have a real, working product. There's just one problem: it lives on the web, and you want it on the **App Store** and **Google Play**, sitting on people's home screens like every other app.

This is the gap nobody warns you about. Lovable is brilliant at building your web app, but it stops at the browser. Getting that same app onto a phone — as a real native app you can submit to the stores — feels like it requires a completely different skill set, a Mac, and hours of fighting with Xcode and Android Studio.

It doesn't. In this guide, we'll **convert your Lovable app into native iOS and Android mobile apps** using [Capacitor](https://capacitorjs.com/), then **build them in the cloud with [Capawesome Cloud](https://capawesome.io/cloud/)** — so you don't even need a Mac. We'll install it on a real iPhone, add a native camera feature, create the signing profiles and the Apple Developer and Google Play accounts, and walk through the entire real-world workflow to get a mobile app into the stores.

No prior mobile experience required. We'll explain every command and every tool as if you've never opened a terminal before.

[ ![Build and deploy your Capacitor app with Capawesome Cloud](https://capawesome.io/assets/banners/cloud-build-and-deploy-capacitor-apps.png?t=1) ](https://capawesome.io/) 

**Prefer to watch step by step?** This post has a companion video that walks through the entire process in real time — including the parts where things break and how to fix them:

## What You'll Build[¶](#what-youll-build "Permanent link")

To keep things concrete, we'll use a sample app called **Spendly** — a mobile-first expense tracker built with Lovable. It lets you add expenses, see a running total, and (once we add the camera) snap a photo of a receipt when logging a transaction.

Everything in this guide applies to _any_ Lovable app, not just Spendly. If you can open your app in a browser, you can follow along.

By the end, you'll have:

* A native **iOS and Android app** built entirely **in the cloud** — no Mac, no Xcode, no Android Studio required
* The iOS app **installed and running on a real iPhone device**
* The Android app **installed and running on a real Android device**
* iOS and Android developer accounts configured to submit your app for review in the App Store and Google Play Store
* A working **camera feature** that only a real native app can offer
* **Live Updates** set up, so you can ship changes without going through app review every time — including a real fix we'll push over the air

Let's go.

## A Quick Note on Lovable and Frameworks[¶](#a-quick-note-on-lovable-and-frameworks "Permanent link")

Before we touch any code, one important thing to know: **the kind of web app Lovable generates affects how it gets wrapped into a native app.**

For a long time, Lovable's default was a **React + Vite** single-page app. As of [May 13, 2026, that default changed](https://docs.lovable.dev/changelog#tanstack-start-is-now-the-default-for-new-apps): brand-new Lovable apps now use TanStack Start with server-side rendering (SSR)\*\* by default. SSR is great for the web — it gives you crawlable HTML and better SEO — but it introduces a wrinkle for mobile.

Here's why it matters. Capacitor wraps a **static web build** — a folder of HTML, CSS, and JavaScript with an `index.html` at its root — into the native app, and that bundle ships _inside_ the app on the device. An SSR app, by contrast, expects a server to render pages on each request. There's no server living inside a phone, so for Capacitor you want your app to produce **static, client-rendered output** instead.

**What we chose, and why:** for this guide, Spendly is a plain **client-rendered React + Vite single-page app (SPA)** that builds into a static `dist/` folder. We went this route because it's the simplest, most reliable fit for Capacitor — the entire app loads in the WebView with no server needed, which is exactly what a native shell expects. If you're starting a new app today, ask Lovable for a **single-page app** (or to skip SSR), so you get the same static `dist` output we use here. (Capacitor is framework-agnostic — for the full picture, see [Build Mobile Apps with Any Web Framework and Capacitor](/blog/build-mobile-apps-with-any-web-framework-and-capacitor/).)

Already have a TanStack Start (SSR) app?

You don't have to throw it away. TanStack Start can be configured to **pre-render / output a static SPA** instead of running SSR. The only hard requirement for Capacitor is the result: a static build folder containing an `index.html`. Whatever framework you use, point Capacitor's `webDir` at that folder. For a Vite SPA, that folder is `dist`.

If you remember nothing else from this section, remember this: Capacitor needs a **static build with an `index.html`**, and for our React + Vite SPA **that folder is `dist`.** Don't worry. We'll come back to it.

## The Big Idea: Build in the Cloud[¶](#the-big-idea-build-in-the-cloud "Permanent link")

The traditional way to build a mobile app requires a Mac with Xcode for iOS and a fully configured Android Studio for Android. That's a huge amount of setup — and if you're on Windows or Linux, iOS is simply off the table.

We're going to skip almost all of that. [Capawesome Cloud Native Builds](https://capawesome.io/cloud/native-builds/) compiles your iOS and Android apps on Apple Silicon hardware in the cloud, signs them, and hands you back an installable app — in a few minutes, from any operating system.

That changes the prerequisites dramatically:

* **You do _not_ need Xcode or Android Studio** to build and ship your app. The cloud does it.
* **You _only_ need them if you want to test in a local simulator/emulator** on your own machine. That's optional, and — fair warning — it's a lot more setup. We'll point out where it fits in, but the main path in this guide never touches them.

## Prerequisites[¶](#prerequisites "Permanent link")

Here's an honest look at what this takes before you start.

### Time[¶](#time "Permanent link")

Plan for about **1–2 hours** the first time, most of which is creating accounts and waiting on a cloud build or two. There are no giant local installs on the main path.

### What You Need[¶](#what-you-need "Permanent link")

| Requirement                                                           | Details                                                                                          |
| --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| **A computer**                                                        | Mac, Windows, or Linux — **any OS works**, because the build happens in the cloud.               |
| **A code editor**                                                     | [Visual Studio Code](https://code.visualstudio.com/) (free) is what we'll use. Any editor works. |
| [**Node.js**](https://nodejs.org/)                                    | Version 20 or newer (the **22 LTS** release is recommended) — runs the build tools.              |
| [**Git**](https://git-scm.com/)                                       | Downloads your code from GitHub.                                                                 |
| **A [Capawesome Cloud](https://console.cloud.capawesome.io) account** | Builds your apps in the cloud and pushes live updates. 14-day free trial.                        |

### Optional (only for local simulator/emulator testing)[¶](#optional-only-for-local-simulatoremulator-testing "Permanent link")

| Tool                                                                            | Why you might want it                         |
| ------------------------------------------------------------------------------- | --------------------------------------------- |
| [**Xcode**](https://apps.apple.com/app/xcode/id497799835) (macOS only, \~15 GB) | Run the app in the iOS Simulator on your Mac. |
| [**Android Studio**](https://developer.android.com/studio) (\~1 GB + SDKs)      | Run the app in an Android emulator.           |

You can skip both

The entire main path of this guide — building for iOS and Android and installing on a real iPhone — works **without** Xcode or Android Studio. Only install them if you specifically want a local simulator/emulator to play with, and know that it's a much heavier setup.

### Costs (only to publish to the public stores)[¶](#costs-only-to-publish-to-the-public-stores "Permanent link")

| Item                                                                    | Cost                                               |
| ----------------------------------------------------------------------- | -------------------------------------------------- |
| [Apple Developer Program](https://developer.apple.com/programs/enroll/) | **$99/year**                                       |
| [Google Play Console](https://play.google.com/console/signup)           | **$25 one-time**                                   |
| [Capawesome Cloud](https://capawesome.io/pricing/)                      | Starting at $19/month with a **14-day free trial** |

You need the Apple Developer account to install on a real iPhone and to publish. You can follow the whole build flow on the free trial.

### Install Node.js, Git, and VS Code[¶](#install-nodejs-git-and-vs-code "Permanent link")

These are quick. Download [VS Code](https://code.visualstudio.com/) and install it. Then:

macOSWindows

Install [Homebrew](https://brew.sh/), then Node.js:

`[](#%5F%5Fcodelineno-0-1)/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
[](#%5F%5Fcodelineno-0-2)brew install node
`

Git usually comes pre-installed (`git --version` to check).

Download the **LTS** installer from [nodejs.org](https://nodejs.org/) and the installer from [git-scm.com](https://git-scm.com/), and run both with the default options.

We'll use VS Code's **integrated terminal** for every command. Open it with **Terminal → New Terminal** (or `` Ctrl + ` ``).

Confirm Node is ready:

`[](#%5F%5Fcodelineno-1-1)node --version
[](#%5F%5Fcodelineno-1-2)npm --version
`

\\"command not found\\" after installing?

Close the terminal completely and open a new one. Freshly installed tools often aren't recognized until you restart the terminal.

✅ **Success:** `node --version` and `npm --version` both return a version number.

## Step 1 — Build Your App in Lovable[¶](#step-1-build-your-app-in-lovable "Permanent link")

If you already have a Lovable app, skip to Step 2\. If you're starting fresh, here's how Spendly was created.

[Lovable](https://lovable.dev) is an AI app builder. You describe the app you want in plain English, and it generates a working React app you can preview and refine in your browser — no coding required.

Here's the [exact prompt](/docs/assets/images/posts/convert-lovable-app-to-mobile-app/lovable-prompt/) we used to generate Spendly.

![The Spendly app generated and running inside the Lovable editor](/docs/assets/images/posts/convert-lovable-app-to-mobile-app/lovable-spendly-preview.png)

Keep it a simple single-page app

For the smoothest path to mobile, explicitly ask Lovable for a **single-page app (SPA)** — like the prompt above does. Since new Lovable apps now default to TanStack Start with **server-side rendering**, asking for an SPA keeps it client-rendered and producing the static `dist` folder Capacitor wraps into a native app.

✅ **Success:** Your app previews and works inside the Lovable editor.

## Step 2 — Export Your App to GitHub[¶](#step-2-export-your-app-to-github "Permanent link")

To work with your app on your own computer — and so Capawesome Cloud can build from it later — you first need the code in a **GitHub** repository. Lovable can push it there for you.

1. In the Lovable editor, click the **Upgrade** button in the top-right corner.
2. Click **Git** on the left menu and then the **Github** option.
3. Authorize Lovable (create a free GitHub account here if you don't have one).
4. Link your github account to this Lovable project.
5. Lovable will create a new repository and push your app into it automatically.

![The GitHub export button and Create Repository dialog in Lovable](/docs/assets/images/posts/convert-lovable-app-to-mobile-app/lovable-export-github.png)

After it finishes, you'll have a repo at an address like `github.com/YOUR-USERNAME/spendly`. 

If you got lost here, watch the video for the detailed step by step.

✅ **Success:** Visiting `github.com/YOUR-USERNAME/spendly` shows your app's code.

## Step 3 — Clone and Run Your App Locally[¶](#step-3-clone-and-run-your-app-locally "Permanent link")

Now download the code to your computer and make sure it runs. "Cloning" means copying the repo from GitHub onto your machine.

Open VS Code, start a terminal with **Terminal → New Terminal**, and run these one at a time (replace `YOUR-USERNAME`):

`[](#%5F%5Fcodelineno-2-1)git clone https://github.com/YOUR-USERNAME/spendly.git
[](#%5F%5Fcodelineno-2-2)cd spendly
[](#%5F%5Fcodelineno-2-3)npm install
[](#%5F%5Fcodelineno-2-4)npm run dev
`

* `git clone …` — downloads your code into a new `spendly` folder.
* `cd spendly` — moves into that folder.
* `npm install` — downloads all the libraries your app depends on.
* `npm run dev` — starts a local development server.

Then open the project in VS Code: **File → Open Folder**, select the `spendly` folder. Any new terminal you open is already inside it, so you can skip `cd spendly` from here on.

The terminal prints a local address — open it in your browser. Lovable apps typically run on **http://localhost:8080**, but use whatever address your terminal shows (it may differ).

![Spendly running in the browser at localhost](/docs/assets/images/posts/convert-lovable-app-to-mobile-app/spendly-localhost.png)

✅ **Success:** Spendly opens in your browser showing its UI.

Press `Ctrl + C` in the terminal to stop the dev server when you're ready to continue.

## Step 4 — Add Capacitor and the Native Platforms[¶](#step-4-add-capacitor-and-the-native-platforms "Permanent link")

**What is Capacitor?** It's the bridge that turns your web app into a real native mobile app — it wraps your existing code in an iOS and Android shell, no rewrite needed.

Install the core packages and initialize Capacitor:

`[](#%5F%5Fcodelineno-3-1)npm install @capacitor/core @capacitor/cli
[](#%5F%5Fcodelineno-3-2)npx cap init
`

`npx cap init` asks three questions. Answer them like this:

| Prompt                   | Answer          | What it means                                                                                                                                                                                            |
| ------------------------ | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **App name**             | Spendly         | The name shown under your app icon.                                                                                                                                                                      |
| **App Package ID**       | com.spendly.app | A unique ID in reverse-domain style. It can't be changed after you publish it to the stores. You should use a reverse domain name notation that combines your company website and your specific app name |
| **Web assets directory** | dist            | The folder your built app lands in. **For Lovable (Vite) apps this is dist.**                                                                                                                            |

This creates `capacitor.config.ts`:

capacitor.config.ts

`[](#%5F%5Fcodelineno-4-1)import type { CapacitorConfig } from '@capacitor/cli';
[](#%5F%5Fcodelineno-4-2)
[](#%5F%5Fcodelineno-4-3)const config: CapacitorConfig = {
[](#%5F%5Fcodelineno-4-4)  appId: 'com.spendly.app',
[](#%5F%5Fcodelineno-4-5)  appName: 'Spendly',
[](#%5F%5Fcodelineno-4-6)  webDir: 'dist',
[](#%5F%5Fcodelineno-4-7)};
[](#%5F%5Fcodelineno-4-8)
[](#%5F%5Fcodelineno-4-9)export default config;
`

Pick a Package ID you actually own

Your Package ID (also called the bundle ID / application ID) must be **globally unique** across the App Store and Google Play. In the companion video we picked one that was already taken and had to change it later — and changing it after creating the native projects means find-and-replacing it across `ios/` and `android/` and rebuilding. Save yourself the detour: use a reverse-domain ID based on a domain you control (e.g. `com.yourcompany.spendly`) from the start.

Now build your web app, add the native platforms, and sync:

`[](#%5F%5Fcodelineno-5-1)npm run build
[](#%5F%5Fcodelineno-5-2)npm install @capacitor/ios @capacitor/android
[](#%5F%5Fcodelineno-5-3)npx cap add ios
[](#%5F%5Fcodelineno-5-4)npx cap add android
[](#%5F%5Fcodelineno-5-5)npx cap sync
`

* `npm run build` produces the `dist/` folder (Capacitor needs it before adding platforms).
* `npx cap add ios` / `android` create the native `ios/` and `android/` projects.
* `npx cap sync` copies your built web app into both native projects.

Your project now looks roughly like this:

`[](#%5F%5Fcodelineno-6-1)spendly/
[](#%5F%5Fcodelineno-6-2)├── android/          ← native Android project
[](#%5F%5Fcodelineno-6-3)├── ios/              ← native iOS project
[](#%5F%5Fcodelineno-6-4)├── dist/             ← your built web app
[](#%5F%5Fcodelineno-6-5)├── src/              ← your Lovable app code
[](#%5F%5Fcodelineno-6-6)├── capacitor.config.ts
[](#%5F%5Fcodelineno-6-7)└── package.json
`

![Project structure after adding Capacitor and the iOS and Android platforms](/docs/assets/images/posts/convert-lovable-app-to-mobile-app/project-structure.png) 

No CocoaPods needed

If you've followed older Capacitor tutorials, you may have seen a step to install **CocoaPods** for iOS. You don't need it. **Capacitor 8 uses [Swift Package Manager](https://capawesome.io/blog/the-future-of-cocoapods-in-capacitor/)** for iOS dependencies, handled automatically.

✅ **Success:** `ios/` and `android/` folders appear, and the terminal shows `Sync finished`.

## Step 5 — Check Your `.gitignore`[¶](#step-5-check-your-gitignore "Permanent link")

This step is small but important, because Capawesome Cloud builds from your Git repository — which means **the `ios/` and `android/` folders must be committed to GitHub.** A common mistake is accidentally ignoring them.

Good news: `npx cap add` already added a `.gitignore` inside each platform folder that ignores only the _build artifacts_ (not the project itself), so you usually don't need to change anything. Just confirm:

* Your **root** `.gitignore` ignores `node_modules` and `dist` (the cloud rebuilds `dist` itself, so it shouldn't be in Git). Lovable's default already does this.
* The `ios/` and `android/` folders themselves are **not** ignored — they need to be in the repo.

✅ **Success:** Running `git status` shows the new `ios/` and `android/` folders ready to be committed (not ignored).

## Step 6 — Commit and Push[¶](#step-6-commit-and-push "Permanent link")

Save this milestone to GitHub so the cloud can build from it:

`[](#%5F%5Fcodelineno-7-1)git add .
[](#%5F%5Fcodelineno-7-2)git commit -m "Add Capacitor and native iOS/Android platforms"
[](#%5F%5Fcodelineno-7-3)git push
`

✅ **Success:** Your GitHub repo now shows the `ios/` and `android/` folders.

## Step 7 — Create a Capawesome Cloud Account and Connect Your Repo[¶](#step-7-create-a-capawesome-cloud-account-and-connect-your-repo "Permanent link")

This is where the magic of building without a Mac happens. **Everything in this section is done in the Capawesome Cloud Console — no terminal needed.**

1. **Sign up and create an organization.** Go to [console.cloud.capawesome.io](https://console.cloud.capawesome.io) and create an **organization** (your workspace). All plans include a **14-day free trial**.
2. **Create an app.** On the [Apps](https://console.cloud.capawesome.io/organizations/%5F/apps) page, select your organization, click **Create App**, give it a name (e.g. `Spendly`), and click **Create**. Open the app and **copy its app ID** — you'll paste it into your config when we set up Live Updates.
3. **Connect your GitHub repository.** Open the [Git](https://console.cloud.capawesome.io/apps/%5F/git) page for your app.
  * Under **Git Providers**, select **GitHub** and click **Connect** to authorize access.
  * Under **Git Repositories**, choose the repository owner, select your `spendly` repo, and click **Save**.

For the full connection flow and permissions, see the [GitHub integration docs](https://capawesome.io/docs/cloud/integrations/github/).

✅ **Success:** Your app in Capawesome Cloud shows your GitHub repo connected, and you have your app ID saved.

## Step 8 — Create Your Developer Accounts[¶](#step-8-create-your-developer-accounts "Permanent link")

To install on a real iPhone and to publish, you need developer accounts. This is a one-time setup with real timelines — **start it early.**

### Apple Developer Program — $99/year[¶](#apple-developer-program-99year "Permanent link")

Sign up at [developer.apple.com/programs/enroll](https://developer.apple.com/programs/enroll/). Apple takes up to 48 hours to approve new accounts. Registering as an organization additionally requires a D-U-N-S number (5–7 business days).

### Google Play Console — $25 one-time[¶](#google-play-console-25-one-time "Permanent link")

Sign up at [play.google.com/console/signup](https://play.google.com/console/signup). Paid once, never expires. Identity verification usually completes within a few hours.

Full walkthrough: [How to Create Your Apple Developer and Google Play Developer Accounts](/blog/how-to-create-apple-developer-and-google-play-accounts/).

✅ **Success:** Your Apple Developer account is active (and Google Play, if you're targeting Android).

## Step 9 — Generate Your Signing Certificates[¶](#step-9-generate-your-signing-certificates "Permanent link")

Every app submitted to the stores — and every iOS app installed on a real device — must be cryptographically signed. You need:

* **iOS:** a **development** certificate + provisioning profile (to install on your own device) and a **distribution** certificate + provisioning profile (for TestFlight and the App Store), each generated the same way.
* **Android:** a keystore file

This is where most first-timers get stuck, but you can generate everything **in your browser**, no Xcode or Android Studio required:

* **[iOS Certificate Generator](https://capawesome.io/tools/ios-certificate-generator/)** — generates your iOS certificate and CSR.
* **[Android Keystore Generator](https://capawesome.io/tools/android-keystore-generator/)** — creates a keystore file. Store it somewhere safe; you'll reuse it for every release.

Then upload them to Capawesome Cloud once, **in the Console**:

1. Open your app and go to the **Certificates** page.
2. Click **Create Certificate**, choose the platform, and upload the files:
  * **iOS:** your `.p12` certificate (with its password) and your `.mobileprovision` provisioning profile.
  * **Android:** your keystore file (with its keystore password, key alias, and key password).
3. Give it a recognizable name (e.g. `Production iOS Certificate`) and save.

Every future build picks the certificate up automatically — nothing to store on your machine.

Step-by-step guides:

* [iOS signing certificates](https://capawesome.io/docs/cloud/native-builds/certificates/ios/)
* [Android signing certificates](https://capawesome.io/docs/cloud/native-builds/certificates/android/)
* [iOS Certificates and Provisioning Profiles Explained](/blog/ios-certificates-and-provisioning-profiles-explained/).

**Remember that in the video this is shown step by step.**

To install on your own iPhone

Register your iPhone's UDID (use the free [iOS UDID Finder](https://capawesome.io/tools/ios-udid-finder/)) in your Apple Developer account and include it in a **development** provisioning profile. That lets you install a development build directly on your device. The easiest alternative is TestFlight — set up in Step 12.

✅ **Success:** Your certificates are uploaded to Capawesome Cloud.

## Step 10 — Build Your Native App in the Cloud[¶](#step-10-build-your-native-app-in-the-cloud "Permanent link")

Now the payoff. Trigger a cloud build straight from the connected repo — no Mac, no local toolchain, **all from the Console**:

1. Open your app and go to the **Builds** page.
2. Click **Build from Git**.
3. Select your **Git reference** (the `main` branch), the **Platform** (iOS or Android), and the **Build Type**:
  * **iOS → Development** (signed with your iOS _development_ certificate, with your iPhone included in the provisioning profile) — to install **directly on your own device**.
  * **iOS → App Store** (signed with your iOS _distribution_ certificate) — for **TestFlight and the App Store** (you can't install this one straight onto a device).
  * **Android → Release** (signed with your Android keystore) — for Google Play. For a quick test on any Android device, **Android → Debug** needs no certificate.
4. Pick the matching **certificate**, then click **Build**.

![Creating an iOS build in the Capawesome Cloud Console](/docs/assets/images/posts/convert-lovable-app-to-mobile-app/create-ios-build.png)

Builds run on Apple Silicon hardware and typically finish in **2–5 minutes**. When a build fails, the Console's [Ask AI](https://capawesome.io/docs/cloud/assist/) explains the cause and a fix in plain English.

Want a free, unsigned build to try first?

On the **Build Type** dropdown, choose **iOS Simulator** or **Android Debug** — neither needs a certificate. These can't be installed on a real iPhone, but they're great for a first end-to-end test. Full reference: [Getting Started with Native Builds](https://capawesome.io/docs/cloud/native-builds/setup/).

Watch the full Console walkthrough for each platform:

iOSAndroid

Simulator build and signed build:

Full workflow from Git to a downloadable AAB:

✅ **Success:** Your build completes in the Console with a downloadable artifact (IPA / APK / AAB).

## Step 11 — Install the App on Your iPhone[¶](#step-11-install-the-app-on-your-iphone "Permanent link")

Time to hold Spendly in your hand. The simplest paths, all without Xcode:

* **TestFlight (iOS):** push the build to TestFlight from Capawesome Cloud [App Store Publishing](https://capawesome.io/cloud/app-store-publishing/), then install it from the TestFlight app on your iPhone. Internal testers (up to 100) skip the review queue.
* **Direct install:** install a development build straight onto a registered device from the Capawesome Cloud Console.
* **Google Play Internal Testing (Android):** share a link and testers install from the Play Store immediately, no review.

![Install App dialog for iOS in Capawesome Cloud](/docs/assets/images/screenshots/cloud-install-app-ios.png) 

Full guide: [How to Distribute iOS and Android Apps to Testers](/blog/how-to-distribute-ios-and-android-apps-to-testers/). Console walkthrough:

Prefer a local simulator/emulator? (the heavier path)

If you'd rather test locally, you _can_ install [Xcode](https://apps.apple.com/app/xcode/id497799835) (Mac only) and/or [Android Studio](https://developer.android.com/studio), then run `npx cap open ios` / `npx cap open android` and press the Run button. Be warned: these are large downloads and a lot more configuration. The cloud + real-device path above is faster and works on any OS — that's why it's our main recommendation.

✅ **Success:** Spendly launches on your iPhone.

## Step 12 — Set Up Store Destinations and Deploy to Your Testers[¶](#step-12-set-up-store-destinations-and-deploy-to-your-testers "Permanent link")

Installing on your own phone is great, but to get the app to **other** testers you deploy it to a **store destination** — a target like **TestFlight** (iOS) or a **Google Play testing track** (Android) that you configure once in the Console and then deploy builds to.

This is walked through end-to-end in the companion video

Creating both destinations involves a fair amount of clicking through Apple and Google's consoles. The [companion video](https://youtu.be/%5F5l-wiVYkVY) demonstrates the whole flow in real time — including the credentials, a couple of errors, and the fixes. This section is the written map; the linked docs below have the click-by-click detail.

The two-step pattern is the same for both platforms:

1. **Create a store destination** (the target + its credentials).
2. **Create a deployment** of a signed build to that destination.

### TestFlight (iOS)[¶](#testflight-ios "Permanent link")

Create an **Apple App Store** destination on the **Destinations** page of your app. Using the `Apple ID + Password` method, you'll provide:

* **Team ID** — from your Apple Developer Membership details.
* **Apple App ID** — the _Apple ID_ property from the **App Information** section in App Store Connect (create the app there first, using your registered bundle ID).
* **Apple ID** \+ an **app-specific password** — generated on your [Apple ID account page](https://appleid.apple.com).

Then create an **iOS → App Store** build signed with your **distribution** certificate and deploy it to that destination — submissions are uploaded to TestFlight automatically. (You can also tick the deploy option on the build itself so a successful build ships to TestFlight in one go.)

Full detail: [Apple App Store & TestFlight Destination](https://capawesome.io/docs/cloud/app-store-publishing/destinations/apple-app-store/).

### Google Play Internal Testing (Android)[¶](#google-play-internal-testing-android "Permanent link")

Create a **Google Play Store** destination with:

* **Track** — `Internal` for internal testing.
* **Package Name** — your Android application ID (the same bundle ID).
* **Release Status** — `Draft` for the very first release (lets you finish setup in the console before it goes live).
* **JSON Key File** — a **service account** key from the Google Cloud Console, with the service account invited as a user in Google Play Console and granted release permissions.

Then create an **Android → Release** build (a **Debug**\-signed APK is rejected by Google Play) and deploy it to the destination. It appears under **Testing → Internal testing** in the Google Play Console, where you add tester emails.

Full detail: [Google Play Store Destination](https://capawesome.io/docs/cloud/app-store-publishing/destinations/google-play-store/).

For the bigger picture — automatic submissions after a build, all tracks, and Firebase App Distribution — see [Getting Started with App Store Publishing](https://capawesome.io/docs/cloud/app-store-publishing/setup/) and our [How to Distribute iOS and Android Apps to Testers](/blog/how-to-distribute-ios-and-android-apps-to-testers/) guide.

✅ **Success:** Your build is live on TestFlight and/or the Google Play Internal track, and your testers have been invited.

## Step 13 — Add a Native Feature: The Camera[¶](#step-13-add-a-native-feature-the-camera "Permanent link")

**What's a plugin?** A Capacitor plugin is a small bridge that lets your JavaScript call a real native device feature — camera, biometrics, geolocation, and [50+ more](https://capawesome.io/docs/sdks/capacitor/). This is what separates a real native app from a website in a wrapper.

We'll add the [Camera plugin](https://capacitorjs.com/docs/apis/camera) so users can photograph a receipt when adding an expense.

`[](#%5F%5Fcodelineno-8-1)npm install @capacitor/camera && npx cap sync
`

### Tell iOS and Android Why You Need the Camera[¶](#tell-ios-and-android-why-you-need-the-camera "Permanent link")

Both platforms require you to declare _why_ your app uses the camera, or it crashes when the camera opens. You only do this once.

**iOS** — open `ios/App/App/Info.plist` and add inside the top-level `<dict>`:

ios/App/App/Info.plist

`[](#%5F%5Fcodelineno-9-1)<key>NSCameraUsageDescription</key>
[](#%5F%5Fcodelineno-9-2)<string>Spendly uses the camera to let you photograph receipts.</string>
`

**Android** — open `android/app/src/main/AndroidManifest.xml` and add inside the `<manifest>` tag:

android/app/src/main/AndroidManifest.xml

`[](#%5F%5Fcodelineno-10-1)<uses-permission android:name="android.permission.CAMERA" />
`

### Use the Camera in Spendly[¶](#use-the-camera-in-spendly "Permanent link")

Open your "Add Transaction" form component under `src/`, import the plugin, and add a function plus a button:

`[](#%5F%5Fcodelineno-11-1)import { Camera, CameraResultType } from '@capacitor/camera';
[](#%5F%5Fcodelineno-11-2)
[](#%5F%5Fcodelineno-11-3)async function takePhoto() {
[](#%5F%5Fcodelineno-11-4)  const photo = await Camera.getPhoto({
[](#%5F%5Fcodelineno-11-5)    quality: 90,
[](#%5F%5Fcodelineno-11-6)    resultType: CameraResultType.Uri,
[](#%5F%5Fcodelineno-11-7)  });
[](#%5F%5Fcodelineno-11-8)  // photo.webPath is a URL you can show in an <img> tag
[](#%5F%5Fcodelineno-11-9)  return photo.webPath;
[](#%5F%5Fcodelineno-11-10)}
`

`[](#%5F%5Fcodelineno-12-1)<button type="button" onClick={takePhoto}>
[](#%5F%5Fcodelineno-12-2)  Add receipt photo
[](#%5F%5Fcodelineno-12-3)</button>
`

Capacitor handles the permission dialog

You don't write any code to ask for camera access. The first time a user taps the button, Capacitor shows the system "Allow camera access?" prompt — using the message you wrote in `Info.plist`.

✅ **Success:** Your code calls the Camera plugin and the project syncs without errors.

Hundreds more plugins — including Capawesome Insiders SDKs

The camera is just one example. Capawesome maintains a large library of [free, open-source Capacitor plugins](https://capawesome.io/docs/sdks/capacitor/), and for more advanced needs there's [**Capawesome Insiders**](https://capawesome.io/insiders/) — premium, production-ready SDKs built and maintained by official Ionic Developer Experts, with priority support. Insiders covers native features like [NFC](https://capawesome.io/docs/sdks/capacitor/nfc/), [Biometrics](https://capawesome.io/docs/sdks/capacitor/biometrics/), [Bluetooth Low Energy](https://capawesome.io/docs/sdks/capacitor/bluetooth-low-energy/), and [more](https://capawesome.io/docs/insiders/) — and most Capawesome Cloud plans already include a couple of Insider SDKs.

## Step 14 — Add Live Updates (and Why They Matter)[¶](#step-14-add-live-updates-and-why-they-matter "Permanent link")

Here's the feature that changes how you ship. Normally, **every** change to a native app — even a one-word typo fix — has to go through **app store review**, which can take days. [Capawesome Cloud Live Updates](https://capawesome.io/cloud/live-updates/) let you push changes to your app's **web layer** (HTML, CSS, JS, images) **over the air**, straight to users' devices in minutes — no review required.

Add the plugin in your first release

Adding a plugin requires a fresh native build and another store review. So install Live Updates **now**, before you have updates to ship — that way you're never stuck waiting on review when you need to push a fix. (We'll use exactly this capability in Step 16.)

Install and configure the plugin:

`[](#%5F%5Fcodelineno-13-1)npm install @capawesome/capacitor-live-update@latest
[](#%5F%5Fcodelineno-13-2)npx cap sync
`

Add the plugin config to `capacitor.config.ts`, pasting in the app ID from Step 7:

capacitor.config.ts

`[](#%5F%5Fcodelineno-14-1)import type { CapacitorConfig } from '@capacitor/cli';
[](#%5F%5Fcodelineno-14-2)
[](#%5F%5Fcodelineno-14-3)const config: CapacitorConfig = {
[](#%5F%5Fcodelineno-14-4)  appId: 'com.spendly.app',
[](#%5F%5Fcodelineno-14-5)  appName: 'Spendly',
[](#%5F%5Fcodelineno-14-6)  webDir: 'dist',
[](#%5F%5Fcodelineno-14-7)  plugins: {
[](#%5F%5Fcodelineno-14-8)    LiveUpdate: {
[](#%5F%5Fcodelineno-14-9)      appId: '00000000-0000-0000-0000-000000000000',
[](#%5F%5Fcodelineno-14-10)      autoUpdateStrategy: 'background',
[](#%5F%5Fcodelineno-14-11)      readyTimeout: 10000,
[](#%5F%5Fcodelineno-14-12)      autoBlockRolledBackBundles: true,
[](#%5F%5Fcodelineno-14-13)    },
[](#%5F%5Fcodelineno-14-14)  },
[](#%5F%5Fcodelineno-14-15)};
[](#%5F%5Fcodelineno-14-16)
[](#%5F%5Fcodelineno-14-17)export default config;
`

* `autoUpdateStrategy: 'background'` — checks for updates at launch, downloads silently, and applies them on the next open. No prompts, no extra code.
* `readyTimeout` \+ `autoBlockRolledBackBundles` — safety nets that [automatically roll back](https://capawesome.io/docs/cloud/live-updates/advanced/rollbacks/) a broken update so a bad release can't strand users.

A quick word on **channels**: a [channel](https://capawesome.io/docs/cloud/live-updates/channels/) is a named stream of live updates that a group of devices subscribes to. You use them to ship different bundles to different audiences — for example a `staging` channel for testers and a `production` channel for everyone else. Every device pulls from exactly one channel. We're not setting one here, so the SDK uses your app's built-in `default` channel — which is exactly where we'll deploy the update in Step 16\. Learn more in [Manage Channels](https://capawesome.io/docs/cloud/live-updates/channels/).

To make rollback work, call `ready()` as early as possible in your app. In a Lovable React app, open `src/main.tsx` and add near the top:

src/main.tsx

`[](#%5F%5Fcodelineno-15-1)import { LiveUpdate } from '@capawesome/capacitor-live-update';
[](#%5F%5Fcodelineno-15-2)
[](#%5F%5Fcodelineno-15-3)void LiveUpdate.ready();
`

Then sync:

`[](#%5F%5Fcodelineno-16-1)npx cap sync
`

✅ **Success:** The Live Update plugin is installed, configured with your app ID, and `ready()` is called on startup.

## Step 15 — Rebuild the Native App in the Cloud[¶](#step-15-rebuild-the-native-app-in-the-cloud "Permanent link")

We just added two plugins (Live Update and Camera) and a new permission. Those are **native** changes, so they need a fresh native build — a Live Update alone can't deliver them. First commit and push your changes:

`[](#%5F%5Fcodelineno-17-1)git add .
[](#%5F%5Fcodelineno-17-2)git commit -m "Add Live Updates and Camera plugin"
[](#%5F%5Fcodelineno-17-3)git push
`

Then trigger a new build exactly like in Step 10: in the Console, open the **Builds** page → **Build from Git** → select `main`, your platform, the signed build type, and your certificate → **Build**.

Install this new build on your iPhone (TestFlight or direct install, as in Step 11). Now your device is running a native shell that includes the camera and the Live Update SDK — which sets up the next step perfectly.

✅ **Success:** The updated build with the camera installs and runs on your iPhone.

## Step 16 — Fix the Status Bar Spacing with a Live Update (OTA)[¶](#step-16-fix-the-status-bar-spacing-with-a-live-update-ota "Permanent link")

Look closely at the app on your iPhone. There's a good chance the very top — your header or title — is tucked **underneath the status bar** (the clock and battery), or behind the notch. The bottom looks fine; the top is cut off.

![Spendly before the safe area fix, with the header hidden under the status bar](/docs/assets/images/posts/convert-lovable-app-to-mobile-app/spendly-safe-area-before.png) 

This isn't a bug — it's **edge-to-edge** mode. Modern Capacitor draws your web app across the _entire_ screen, including behind the system bars, so your app must keep important content out from under them using **safe area insets**: the CSS variables `env(safe-area-inset-top)`, `-bottom`, `-left`, `-right`.

Why the bottom often looks right but the top doesn't

Many Lovable apps wire bottom padding to `env(safe-area-inset-bottom)` already, so the bottom is handled. The top headers usually use a plain fixed padding (like `pt-6`) with no inset, so they slip under the status bar.

First, confirm `index.html`'s viewport tag includes `viewport-fit=cover` (Lovable apps usually already do — it's what enables the safe-area variables):

index.html

`[](#%5F%5Fcodelineno-18-1)<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
`

Then add the top inset to each page header. The trick is `max()`: keep the original padding on the web, and grow to the safe area on devices that need it:

`[](#%5F%5Fcodelineno-19-1)- <header className="... px-5 pt-6 pb-2">
[](#%5F%5Fcodelineno-19-2)+ <header className="... px-5 pt-[max(1.5rem,env(safe-area-inset-top))] pb-2">
`

Do this for each screen's top header. If a header has a colored or gradient background, this is exactly what you want: the background still fills the screen edge-to-edge, and only the _content_ shifts down below the status bar.

Let Lovable do the edit

You can ask Lovable: _"The app content runs under the status bar at the top on mobile. Add `env(safe-area-inset-top)` to the top padding of each page header using `max()`, keeping the existing padding as the minimum."_

### Now Ship It Over the Air — with a Web Build[¶](#now-ship-it-over-the-air-with-a-web-build "Permanent link")

Here's the moment that shows why Live Updates are special. This fix is **pure CSS** — no native code, no new plugin — so we can push it straight to the installed app **without** a new native build or a trip through app review.

A Live Update bundle is created with a **Web Build** — it works exactly like the iOS and Android builds you already did, except you pick **Web** as the platform. It's the same Builds page, fully in the Console, no terminal.

First, push your fix to GitHub so the cloud can build from it:

`[](#%5F%5Fcodelineno-20-1)git add .
[](#%5F%5Fcodelineno-20-2)git commit -m "Fix top safe area"
[](#%5F%5Fcodelineno-20-3)git push
`

Then, in the Console:

1. Open the **Builds** page and click **Build from Git**.
2. Select your `main` branch and choose **Web** as the **Platform**, then click **Build**. (Web builds run your `npm run build` in the cloud — a few seconds.)
3. When it finishes, **deploy** that build to your app's **`default` channel** — since we didn't configure a custom channel in the live update setup, that's the channel your installed app pulls from automatically.

You can watch it on the [Deployments](https://console.cloud.capawesome.io/apps/%5F/deployments) page, and roll back to a previous build from there anytime.

Channels are how the right update reaches the right app

A web build is deployed to a **channel**, and each device pulls updates from one channel. Every app comes with a `default` channel, which is what we use here. For real production apps, [versioned channels](https://capawesome.io/docs/cloud/live-updates/channels/#versioned-channels) keep each update [binary-compatible](https://capawesome.io/docs/cloud/live-updates/binary-compatible-changes/) with the native build it targets. (See also [Web Builds](/blog/announcing-capawesome-cloud-web-builds/) and [Channels](https://capawesome.io/docs/cloud/live-updates/channels/).)

Watch the full Live Updates Console walkthrough:

Full guides:

* [Getting Started with Live Updates](https://capawesome.io/docs/cloud/live-updates/setup/)
* [Capacitor Live Updates: The Complete Guide to OTA Updates](/blog/capacitor-live-updates-guide/)

Now **force-close** Spendly on your iPhone and reopen it.

Force-close to trigger the update during testing

With the background strategy, the app checks for updates on launch (and on resume if the last check was over 15 minutes ago). While testing, fully close and reopen the app, wait \~15–30 seconds, then open it once more to see the change applied.

✅ **Success:** The header now sits below the status bar — fixed on your device **without** rebuilding the native app or going through review. That's the whole point of Live Updates.

## Step 17 — Prepare Your Store Listing (and What's Left to Submit)[¶](#step-17-prepare-your-store-listing-and-whats-left-to-submit "Permanent link")

Your app is built, installable, and you can already push instant updates. The remaining work to go _live on the public stores_ is mostly paperwork. Apple and Google require a complete store listing before you can submit:

* **App icon** — 1024×1024px for iOS (no transparency), 512×512px for Google Play
* **Screenshots** — Apple requires iPhone 6.9" (1320×2868px) screenshots; mandatory
* **App name, subtitle, description, and keywords**
* **Privacy policy URL** — required by both, even for free apps
* **Age rating** — from a questionnaire in each console
* **Data collection disclosures** — Apple's Privacy Nutrition Labels and Google's Data Safety section

Full checklist: [How to Prepare Your App Store Listing](/blog/how-to-prepare-your-app-store-listing/).

### What still stands between you and "live"[¶](#what-still-stands-between-you-and-live "Permanent link")

This guide got you all the way to a signed, installable app with live updates wired in. To publish, you still need to:

1. **Complete Google Play's closed testing period** (personal accounts created after Nov 13, 2023): at least **12 testers** for **14 consecutive days** before you can request production access. iOS has no equivalent. [Details here](/blog/11-steps-to-get-your-web-app-on-the-app-store/#step-8-complete-google-plays-closed-testing-period).
2. **Submit for review.** In App Store Connect, assign your build and click Submit for Review (Apple review: \~3–5 days). For Google Play, apply for production access after closed testing (review: \~3–7 days). Capawesome Cloud [App Store Publishing](https://capawesome.io/cloud/app-store-publishing/) can automate both submissions with one click — or automatically on every successful build via [Automations](https://capawesome.io/docs/cloud/automations/setup/).

Our companion guide covers this end of the journey in full detail: [11 Steps to Get Your Web App on the App Store](/blog/11-steps-to-get-your-web-app-on-the-app-store/).

## Common Errors (and How to Fix Them)[¶](#common-errors-and-how-to-fix-them "Permanent link")

Setting this up for the first time almost always involves a little back-and-forth — several of these came up **live in the companion video**, which is a good thing, because you get to see exactly how to fix them. Here are the ones you're most likely to hit:

* **`Could not find the web assets directory: ./dist`** (when running `npx cap add` or `npx cap sync`). You ran the command before building. Run `npm run build` first so the `dist/` folder exists, then retry. Note that each framework compiles its assets to a **differently named folder** — Vite/React uses `dist`, Angular uses `www`, and others differ again — so make sure `webDir` in `capacitor.config.ts` matches your framework's output folder.
* **"This App ID … is not available" / bundle ID already taken** (registering the App ID in Apple). Bundle IDs are globally unique. Pick a reverse-domain ID based on a domain you control (e.g. `com.yourcompany.spendly`).
* **iOS build fails after changing the bundle ID.** If you change the bundle ID in Apple but not in your project (or vice versa), they no longer match and the build fails. The bundle ID in your native project must equal the App ID registered in Apple — find-and-replace it across `ios/` and `android/`, commit, and rebuild.
* **"Google Play Android Developer API has not been used in project … or it is disabled."** Open the link in the error to the Google Cloud Console, **enable** the API, wait a moment, and re-run the deployment.
* **"APK has been signed in debug mode."** Google Play won't accept a debug-signed build. Create an **Android → Release** build signed with your keystore, then deploy that.
* **Deployment rejected — version already exists.** Both stores reject a build whose version number is already uploaded. Bump your app's version / build number, create a **new** build, and deploy that one. To keep version bumping painless, see [Introducing CapVer](https://capawesome.io/blog/introducing-capver/), our approach to automatic, predictable versioning.

When a **build** fails, the Console keeps full logs, and [Ask AI](https://capawesome.io/docs/cloud/assist/) turns the error into a plain-English cause and fix. For deployment issues, see [App Store Publishing Troubleshooting](https://capawesome.io/docs/cloud/app-store-publishing/troubleshooting/) and [Live Updates Troubleshooting](https://capawesome.io/docs/cloud/live-updates/troubleshooting/).

## What's Next[¶](#whats-next "Permanent link")

You took a Lovable web app all the way to a native iOS and Android app — **built entirely in the cloud, no Mac required** — installed it on a real iPhone, added a camera feature, and pushed a real fix over the air with Live Updates. That's the hard part done.

From here:

* **Finish publishing.** Work through the store listing, Google's closed testing, and submission with the [11 Steps guide](/blog/11-steps-to-get-your-web-app-on-the-app-store/).
* **Automate the pipeline.** With [Automations](https://capawesome.io/docs/cloud/automations/setup/), a `git push` can trigger a native build, publish to TestFlight/Play, and deploy a live update — all on its own.
* **Add more native features.** Browse the [Capacitor plugin library](https://capawesome.io/docs/sdks/capacitor/) for biometrics, push notifications, geolocation, and more.

[Try Capawesome Cloud Free](https://capawesome.io)

## Final Thoughts[¶](#final-thoughts "Permanent link")

Lovable gets you from idea to working web app faster than ever — and with Capacitor and Capawesome Cloud, that web app doesn't have to stay stuck in the browser, and you don't need a Mac or a deep mobile toolchain to ship it. You can build it in the cloud, run it on real phones, add real native features, and push fixes to your users in minutes instead of waiting days for app store review.

Got stuck somewhere? The [Capawesome Discord server](https://discord.gg/VCXxSVjefW) is active and friendly — drop your question there. And subscribe to the [Capawesome newsletter](https://capawesome.io/newsletter) to stay up to date on new plugins, Cloud features, and guides like this one.

June 26, 2026 

Back to top