tools / repair

CDN localizer

A page that pulls Bootstrap, jQuery or a Google Font from a CDN works in the app — until the phone is offline, when it loads unstyled or not at all. This downloads each of those files into your ZIP and points the page at the local copy.

Localize a ZIP (or a single HTML file)

Files are fetched by your browser straight from the CDN — this only works for hosts that allow cross-origin downloads, which the big public CDNs do. Anything that cannot be fetched is listed so you can add it by hand.

Drop a site ZIP or an .html file .zip or .html · CDN files are fetched, your files are not uploaded

The app works — until the phone goes offline

Your ZIP ships inside the APK, so your own files are always there. Files your pages load from other servers are not: the Bootstrap stylesheet from jsDelivr, jQuery from cdnjs, the Inter font from Google Fonts. On Wi-Fi nobody notices. On a train, in airplane mode or on a first launch with no signal, the page appears without its styling, the buttons do nothing because the script never arrived, and text falls back to the phone's default font.

The fix is to make those files part of the ZIP. That is tedious by hand — especially for Google Fonts, where the stylesheet you link to is generated per browser and itself points at a dozen font files on another host. This tool does the whole chain.

What it does

  1. Reads every HTML file and finds <script src="https://…"> and <link rel="stylesheet" href="https://…"> tags (protocol-relative //cdn… links too).
  2. Downloads each file into vendor/<host>/<path>, mirroring the CDN's structure.
  3. For stylesheets, also downloads everything they reference with url() — icon fonts, web fonts, background images — and follows @import. Google Fonts CSS is saved as vendor/fonts.googleapis.com/<family>.css with its WOFF2 files beside it.
  4. Rewrites each tag to a relative path, removes the integrity and crossorigin attributes (they describe the remote request and are meaningless for a local file), and drops now-useless preconnect hints to the font hosts.

What it cannot do automatically

  • Hosts that block cross-origin downloads. A browser page can only fetch a file from another site if that site allows it (CORS). cdnjs, jsDelivr, unpkg and Google Fonts all do; some self-hosted CDNs and older font services do not. Those are listed so you can download them manually.
  • ES modules from CDNs (<script type="module" src="https://esm.sh/…">). A module imports more modules by URL at runtime, so a single download is not the whole program. Install the package and let your bundler include it.
  • Scripts that load other scripts. Analytics tags, chat widgets and ad scripts fetch further code dynamically — and need a connection to be useful anyway. Leave them as they are.

Why not just leave CDN links in?

It is allowed: bundled apps can load https:// resources whenever the phone is online. But an app is judged by how it behaves at its worst moment, and "blank when offline" is the most common one-star review a converted website gets. Localizing costs a few hundred kilobytes; it buys an app that opens instantly, everywhere.

Frequently asked questions

Is it legal to copy CDN files into my app?

For open-source libraries and Google Fonts, yes — their licences (MIT, BSD, Apache, SIL Open Font Licence) allow redistribution, usually requiring the licence notice to be kept. Commercial fonts and paid scripts depend on their licence terms; check them.

Why were the integrity attributes removed?

Subresource integrity describes a file fetched from another origin. For a file inside your own app it adds nothing and, combined with crossorigin, can stop the file from loading. The downloaded bytes are exactly those the CDN served.

The Google Font looks slightly different after localizing — why?

Google serves a stylesheet tailored to the browser that asks. Your desktop browser received WOFF2 files split by character range, which is what the Android WebView would receive too. If a language's characters are missing, localize from a page that uses them, or download the full family from Google Fonts.

Does this work for a single HTML file?

Yes. Drop the .html file and you get back a ZIP containing it as index.html plus the vendor folder — ready to upload as a ZIP.

Read in the docs

Related tools

Unzip it on a phone today

Upload the ZIP, name the app, pick an icon — and download a signed APK a few minutes later. Free builds, no watermark, no Android Studio.

Convert a ZIP — free site.zip → app-release.apk