Native App Development · 9 min read · Updated 15 August 2026
How to export an AI-built app as a native iOS and Android project with Capacitor
Open My Projects, press More on the project card and choose Download ZIP. You get a Capacitor project: capacitor.config.json, package.json and a www folder holding your app, a manifest and a service worker. Run npm install, add the iOS and Android platform packages, then npx cap add ios and npx cap open ios. The export requires a paid plan.
What the export actually is
Capacitor wraps a web app in a native shell. The shell is a real iOS or Android project that you open in Xcode or Android Studio, sign with your own developer account and submit to the stores; inside it, a WebView loads your HTML from the app bundle rather than from a server. It is not a translation to Swift or Kotlin, and nobody's export is. Understanding that one sentence prevents most of the disappointment around "native export" in AI app builders.
What NorthernGo gives you is the Capacitor project scaffolding with your app already in the right folder, plus one small but crucial injection that makes the app still work once it is running from a device instead of a domain.
Here is the whole archive:
capacitor.config.json
package.json
www/
index.html
manifest.json
sw.js
That is genuinely all of it. Five files, no build step, no bundler, no dependency tree of your own — because the app is a single monolithic HTML document with its JavaScript inline and Tailwind loaded from a CDN. That architecture is what makes the export this small, and it also causes one of the limitations further down.
Step 1: Download the archive
Open My Projects, press More on the project card and choose Download ZIP. The file arrives as your-project-name-native.zip.
Two notes on access. The menu labels the entry Premium+, and the Free plan opens the upgrade dialog. The export route on the server, however, checks for Pro and answers This feature requires the Pro plan otherwise — so if you are on Premium and the download fails with a generic "could not create the ZIP file" message, that is the reason. Pro is also the plan whose feature list promises a ZIP ready for the App Store and Google Play.
The export always uses the latest saved version of the project, not whatever is on screen in the workspace. Save before you download.
Step 2: Unpack and install
Unzip it, open a terminal in the folder that contains capacitor.config.json, and install:
npm install
That gives you @capacitor/core and @capacitor/cli, both pinned to version 5. The platform packages are not included, which is the first place people get stuck, because npx cap add ios will refuse to run without them. Install them explicitly, matching the pinned major version:
npm install @capacitor/ios@^5 @capacitor/android@^5
If you would rather be on Capacitor 6 or later, upgrade @capacitor/core, @capacitor/cli, @capacitor/ios and @capacitor/android together in the same step. Mixing majors produces build errors that look like Xcode problems and are not.
Step 3: Add the native platforms
npx cap add ios
npx cap add android
npx cap sync
cap add generates the ios/ and android/ project folders. cap sync copies www/ into both and installs native dependencies — on macOS it runs CocoaPods for you, so CocoaPods needs to be installed. The archive also defines an npm run cap:sync script that does the same thing, which is the command to remember: every time you change anything in www/, run it again, or the device keeps showing the previous build.
Then open the native tooling:
npx cap open ios # requires macOS with Xcode
npx cap open android # requires Android Studio
Press Run and the app launches in a simulator, an emulator or a connected device. There is no way around the platform requirements here: an iOS build needs a Mac, and store submission needs a paid Apple Developer account and a Google Play developer account.
Step 4: Change the application id before you submit
The generated config is deliberately generic:
{
"appId": "com.northerngo.app.exported",
"appName": "NorthernGoApp",
"webDir": "www",
"bundledWebRuntime": false
}
Every export from every account carries that same appId. It is a placeholder, not an identity. Change it to your own reverse-domain identifier — se.dittforetag.appnamn — and set appName to the name you want under the icon, before you run npx cap add. The platform folders are generated from these values, so editing them afterwards means also changing applicationId in android/app/build.gradle and PRODUCT_BUNDLE_IDENTIFIER in Xcode, and the package directories on Android will no longer match the id. Doing it in the right order takes ten seconds; doing it in the wrong order takes an afternoon.
The export also contains no native app icons or splash images. Capacitor generates placeholders, and you replace them in Xcode's asset catalogue and Android's resource folders, or generate the whole set from one square source image with Capacitor's own asset tool. The square icon you uploaded for the PWA is a good source file for this, but it is not carried into the archive.
Why there is a project id in the head
Open www/index.html and you will find this immediately after <head>:
<script>window.NG_PROJECT_ID = "abc123"; window.PRO_PROJECT_ID = "abc123";</script>
Do not remove it. The injected SDK resolves which project it belongs to in a fixed order: window.NG_PROJECT_ID first, then an ?app= parameter in the URL, then the first label of the hostname for apps published on a subdomain. In a Capacitor WebView none of the last two exist — the page is loaded from localhost with no query string — so without that global the SDK falls back to a placeholder id and every database, login and account deletion call points somewhere useless. That single line is the difference between a working native build and one where nothing saves.
window.NG_PROJECT_ID is the one the SDK reads today; window.PRO_PROJECT_ID is written next to it for compatibility with apps generated by earlier versions of the platform. Keep both. If you rebuild the app in the workspace and export again, a fresh pair is injected into the new archive.
What the export does not do
This is the section worth reading twice, because the phrase "export your source code" is doing a lot of work in this industry.
- It is not an independent backend. The exported app still talks to the NorthernGo backend for data, authentication and AI, identified by that project id. Your users' records stay in the platform's Supabase database. You own and can edit every line of the front end, which is real, but if the goal is genuine independence you have to repoint the storage calls yourself — the trade-offs are laid out in avoiding vendor lock-in and the shape of the API is in the database guide.
- It is not offline-capable. The
www/sw.jsin the archive is a stub: it activates immediately and passes every request through to the network, returning the textOfflinewhen that fails. It precaches nothing. The service worker that actually makes an app usable in airplane mode is served by the platform on hosted subdomains and is not part of the export. - Tailwind still comes from a CDN. The generated document loads
cdn.tailwindcss.comand compiles the styles in the browser at load time. A native app whose first launch happens without a connection will therefore render unstyled. If you are shipping to a store, self-hosting the CSS insidewww/is the single highest-value change you can make to the exported code. window.NorthernGoPaymentsis not defined. The payments object is added by the platform when it serves an app on its own subdomain, not by the app's inline SDK. In a Capacitor build, call the checkout endpoint withfetchinstead, as described in the Stripe guide.- No
<link rel="manifest">is added toindex.html. The archive containswww/manifest.json, but nothing references it, and its values are generic — the name is NorthernGo Exported App and the icon is a placeholder letter. That matters only if you deploywww/to a static host as a web app, in which case add the link and edit the file. - No README, no environment file, no tests.
Troubleshooting
"No code saved yet." The project has no saved version. Open it, let it finish generating, save, then export.
"Could not create the ZIP file." The server refused the request. The overwhelmingly most common cause is the plan check described in Step 1.
npx cap add ios says the platform is not installed. The platform packages are not in the archive's dependencies. Install @capacitor/ios and @capacitor/android first.
The simulator shows a white screen. Open the WebView console. Two usual causes: a JavaScript error in the app itself, or the Tailwind CDN being unreachable, which leaves an unstyled page that can look blank against a white background.
Nothing saves in the native app, but it works on the web. Check that the NG_PROJECT_ID script is still the first thing inside <head>. If it was deleted or moved below the app's own code, the SDK resolved a placeholder id.
Changes to www/index.html do not appear on the device. Run npm run cap:sync (or npx cap sync) and build again. The native project holds its own copy.
The store rejects the bundle identifier, or a second app overwrites the first on a test device. Both were built with the default com.northerngo.app.exported. Give each project its own appId and regenerate the platform folders.
Frequently asked questions
Can I publish an app built with AI on the App Store and Google Play?
Yes, by exporting the project as a Capacitor ZIP and building it locally. You add the iOS and Android platforms, open the project in Xcode or Android Studio, set your own application id, and submit with your own developer accounts. NorthernGo does not submit on your behalf, and an iOS build still requires a Mac.
Is the exported code really mine, or does it still depend on NorthernGo?
The front end is entirely yours: one HTML file with all the markup, styling and logic, which you can edit freely. The data layer is not. Database, login and AI calls still go to the NorthernGo backend using the project id injected into the page, so records stay in the platform database until you repoint those calls to a backend of your own.
Why does the exported app show a white screen in the simulator?
Usually one of two things. Either a JavaScript error stopped the app before it rendered, which the WebView console will show, or the Tailwind CDN could not be reached, which leaves the page completely unstyled and often looking blank. Self-hosting the CSS inside the www folder removes the second cause for good.
What does window.NG_PROJECT_ID in the exported HTML do?
It tells the injected SDK which project it belongs to. Normally the SDK reads that from the URL, either an ?app= parameter or the subdomain, but a Capacitor WebView loads the page from localhost with no query string. The export therefore writes the id into the head, and removing that line breaks every database and login call in the native build.
Which plan do I need to download the ZIP export?
A paid one. The Free plan opens the upgrade dialog instead of downloading. The menu marks the entry Premium+, but the export route on the server checks for Pro, which is also the plan that lists a ZIP ready for the App Store and Google Play — so if a download fails with a generic error on Premium, the plan check is why.
Build it yourself
NorthernGo turns a plain-text description into a working web app with a database, login and a live URL. Local AI generation runs on your own GPU, is unlimited, and is free on every plan.