Back to list
October 12, 2026•6 min read

Angular + Capacitor: a blank WebView after sync is usually webDir

Blank or stale WebView after npx cap sync? Usually webDir: Angular's application builder writes to dist/project/browser, not www or bare dist/project. Build, sync, live-reload traps.

AngularTypeScriptFrontendWebdev

ng build, then npx cap sync, open the app on a phone or emulator, and you get a blank WebView. Or worse, last Tuesday's UI. Angular is innocent again. Capacitor copied whatever folder you pointed at with webDir, and that folder either has no index.html at the root or still holds yesterday's bundle.

Last week was the blank window after packaging Electron: dist/.../browser paths, base href, and the load protocol. This post is the mobile twin of that story. Same Angular app, different native shell: Ionic UI optional, Capacitor required as the runtime.

The problem: webDir must point at the folder that holds index.html

Capacitor does not build your frontend. It takes already-built assets from webDir and copies them into the Android/iOS projects during npx cap sync. The docs are blunt: webDir is the directory of compiled web assets, and it should contain the final index.html (Capacitor Configuration). The workflow is build web, sync, run (Development Workflow).

Enter Angular. The application builder (default since Angular 17) writes the bundle to dist/project-name/browser, not dist/project-name. Same Output location change I called out for Electron: Angular application build system.

Meanwhile npx cap init often suggests www (the Ionic starter convention) or another framework default. The official getting started guide even warns you: the CLI tries to detect the right folder, but you should still verify it on the first sync (Installing Capacitor). If sync cannot find the web assets directory, the docs say to fix webDir.

What that looks like in practice (example, not a production war story):


  • webDir: 'www' while ng build writes to dist/my-app/browser → sync has nothing useful to copy.

  • webDir: 'dist/my-app' (missing browser) → native gets a folder that contains a browser subfolder, the WebView looks for index.html at the root, blank screen.

  • webDir is correct, but you ran cap sync without a fresh ng build → the device shows stale UI.

  • Meat: set webDir, then keep build → sync order


For a plain ng new project on Angular 17+, a typical config looks like this:

// capacitor.config.ts
import type { CapacitorConfig } from "@capacitor/cli";

const config: CapacitorConfig = {
  appId: "com.example.myapp",
  appName: "My App",
  // my-app = project name in angular.json; match outputPath / what ng build actually writes
  webDir: "dist/my-app/browser",
};

export default config;

Or JSON if you are not using TypeScript for the config:

{
"appId": "com.example.myapp",
  "appName": "My App",
  "webDir": "dist/my-app/browser"
}

Then the order Capacitor expects:

# 1. fresh Angular bundle (index.html lands in dist/my-app/browser)
ng build --configuration production

# 2. copy webDir into android/ and ios/ + update native deps
npx cap sync

# 3. run on a device / emulator
npx cap run android
# or: npx cap run ios

If you start from the Ionic CLI, Capacitor is already in new projects (ionic start), and wrappers like ionic capacitor sync do the same work underneath (Using Capacitor with Ionic Framework). Ionic starters often set outputPath to www. Then webDir: 'www' is correct. The trap shows up when you take a plain Angular app that writes to dist/.../browser and keep an Ionic-shaped www in the config.

Capacitor itself does not require Ionic UI. It wraps any web bundle. Ionic gives you mobile components (ion-button, ion-tabs, gestures). If you add Ionic to Angular and use ion-router-outlet, bootstrapping usually registers IonicRouteStrategy as the RouteReuseStrategy (that is what the official scaffolds do, e.g. Your First Ionic App). That is a separate layer from webDir, but worth knowing: native shell and routing stack are two different concerns.

Quick smoke check after sync (example):

# after sync, confirm index.html actually landed in Android assets
ls android/app/src/main/assets/public/index.html

Missing file means bad webDir or no build before sync. File exists but the screen is blank: open remote WebView debugging and look for asset 404s (often a stale sync or wrong root).

Pitfalls: live-reload, www vs browser, stale sync

Live-reload left in the config. server.url can point at a dev server. The docs mark it for live-reload only, not production (Capacitor Configuration). Leave http://192.168.x.x:4200 in the config, ship a release sync, and the phone aims at a laptop that is not in the user's pocket. For a production sync, keep server.url off.

www is not universal. It is the convention many Ionic starters use. A plain Angular CLI app on the application builder writes into browser. Always align webDir with what ng build actually emits, not with muscle memory from an old tutorial.

Sync without a build. npx cap sync copies what is already on disk. It does not run ng build for you. Changed a component → build first, then sync (or cap copy if you only changed web assets).

The ng add @capacitor/angular path. The official Angular + Capacitor page shows ng add @capacitor/angular, then build and npx cap add (Angular & Capacitor). The schematic does not excuse you from checking webDir after the first build.

Ionic CLI wrappers. ionic capacitor sync is convenient, but it still needs a correct webDir and a fresh build. The wrapper will not fix a wrong path.

Verdict

A blank or stale WebView after the first cap sync is almost always webDir and the build → sync order, not "Angular hates mobile." Point webDir at the folder that actually contains index.html (for a modern Angular app, usually dist//browser), build before every production sync, and do not leave a live-reload server.url in a release config. Ionic UI and IonicRouteStrategy are the comfort layer. First make Capacitor serve the right bundle.

Desktop had path bugs after electron-forge make. Mobile has path bugs after cap sync. Same Angular, same class of mistake, different shell.