Working offline

JavaScript not working in your APK? Ten fixes

It ran in Chrome. Inside the app it is blank, or the buttons do nothing, or the console says CORS. Every one of these has the same root cause — the page is now a local file — and a fix that takes minutes.

10 min read Updated September 2026

JavaScript stops working inside an APK for one underlying reason: the page is no longer served from an https:// origin but loaded from the app's local files, and browsers apply stricter rules to local files. Module scripts are refused, fetch() of a local file is refused, root-relative paths resolve to the wrong place, and anything loaded from a CDN needs a connection the phone may not have. Below are the ten causes that account for nearly every "works in Chrome, blank in the app" report, in the order to check them, each with a test and a fix.

First, the two-minute test. Double-click your index.html so Chrome opens it from disk (file:///…), open DevTools (F12) and look at the Console. Red errors here are the same errors the app hits. Reproduce, fix, reload — no rebuild needed until it is clean.

1. type="module" scripts

Symptom: blank page; console says Access to script … from origin 'null' has been blocked by CORS policy. Cause: module scripts are always fetched with CORS, and a local file has no origin to satisfy it. Fix: remove type="module", remove import/export statements, and load dependencies with ordinary <script> tags in order. If the code is a Vite or similar build, set the build target to produce a classic IIFE bundle (Vite: build.rollupOptions.output.format = 'iife', or use the legacy plugin).

Offline Readiness CheckerScan your HTML for the things that break once it is bundled inside an APK Open the tool

2. Libraries from a CDN

Symptom: works on Wi-Fi, breaks on the train; console says $ is not defined or Failed to load resource. Fix: download the library file into your folder and reference it with a relative path. Do the same for CSS frameworks and icon fonts.

3. Paths that start with /

Symptom: 404s for your own files; unstyled page; images missing. Cause: /js/app.js means the device root, not your folder. Fix: js/app.js. Check href, src, CSS url() and strings your JavaScript builds into URLs.

4. fetch() or XMLHttpRequest for a local file

Symptom: Failed to fetch or a CORS error when loading data.json, a template, or a text file that sits right next to the page. Cause: local-file requests from a local page are blocked. Fix: inline the data as a JavaScript object (const DATA = {…}) or in a <script type="application/json"> tag you parse with JSON.parse(el.textContent). Requests to a real https:// API still work when online.

5. Case-sensitive file names

Symptom: one image or script missing in the app, fine on your computer. Cause: Hero.JPG on disk, hero.jpg in the HTML — Windows and macOS forgive it, Android does not. Fix: lower-case everything.

6. Missing viewport tag

Symptom: the page works but is tiny, laid out for a desktop and shrunk. Fix: <meta name="viewport" content="width=device-width, initial-scale=1"> in the head.

7. Syntax too new for the phone's WebView

Symptom: works on your phone, blank on an older one; console says Unexpected token. Cause: the WebView updates through Google Play, but an old phone that has not updated may lack support for very recent syntax (the ?. operator arrived in 2020, top-level await and class fields later). Fix: avoid the newest syntax, or transpile with a target of a few years back. Android 7 and up covers the vast majority of active devices; test on the oldest one you care about.

8. A service worker registration that throws

Symptom: an uncaught error at startup that stops the rest of the script. Cause: navigator.serviceWorker.register() fails from a local page. Fix: wrap it — if ('serviceWorker' in navigator && location.protocol.startsWith('http')) { … } — or remove it; the bundle is already offline.

9. Popups and target="_blank"

Symptom: a link or window.open() does nothing. Cause: a WebView has one window; there is nowhere for a second to open. Fix: for external sites, a plain link — the builder opens other hosts in the phone's browser. For your own pages, navigate in the same window.

10. alert() during load, or a script before the elements exist

Symptom: Cannot read properties of null; buttons that do nothing. Cause: the script runs in the head before the body is parsed — the same bug as on the web, but easier to miss when there is no Network tab slowing things down. Fix: move the script to the end of the body, or wrap it in DOMContentLoaded. (alert() itself works, it just looks like a browser.)

Still blank?

  1. Confirm index.html is at the root of the ZIP, not inside a folder.
  2. Confirm the file is under the size limit for your tier (5 MB free, 18 MB Pro) — a rejected upload is not a blank app, but a truncated one can be.
  3. Connect the phone by USB, open chrome://inspect on your computer, and inspect the app's WebView directly. The console you see is the app's own. If the builder's debug option is on, this works on any build.

Questions people ask

Why does it work when I open the file in Chrome but not in the app?

Usually it does not work from file:// in Chrome either — people test from a local server (localhost) which has a real origin. Open the file directly from disk and the same errors appear.

Can I keep using ES modules somehow?

Not directly from the bundle. Build them into a single classic script with esbuild, Rollup or Vite (IIFE output) and include that file instead.

My fetch() to my own API works. Why does fetch() of a local JSON fail?

Network requests to https:// addresses are allowed; requests to local files from a local page are not. Inline the JSON in a script tag.

Does the builder have a debug mode?

Builds allow WebView inspection, so you can connect the phone by USB and open chrome://inspect to see the app's console directly.

Which Android versions does the app support?

Android 7.0 and later. On those, the WebView is updated through Play independently of the OS, so modern JavaScript is available on almost every device.

Read next

Your HTML, installed on a phone today

Upload the file or ZIP, pick a name and an icon, and download a signed Android APK in minutes. Free to start — no Android Studio, no code changes, no card.

Convert HTML to APK — free