Multi-origin architectures vs. the PWA model
Multi-origin site architectures were once a common way to organize web experiences. But for Progressive Web Apps, splitting your site across multiple origins creates real friction. The same-origin policy restricts how service workers, caches, permissions, and installation prompts can be shared, which makes it difficult to deliver a unified app experience.
Some multi-origin setups are justified. Others are simply legacy habits worth breaking. Understanding the difference, and knowing the workarounds when you're stuck with multiple origins, is key to building PWAs that behave coherently.
When multiple origins make sense
There are legitimate cases where separate origins serve a clear purpose:
- Localization and language: Country-code top-level domains like
https://www.google.com.ar, or subdomains targeting regions such ashttps://newyork.craigslist.orgor language-specific sites likehttps://en.wikipedia.org. - Independent web apps: When a subdomain hosts an experience that is intentionally separate from the main site. A news site serving its crosswords game from
https://crosswords.example.comis a good example, allowing that app to be installed and used as its own PWA without sharing resources with the main site.
Multi-origin patterns to avoid
Beyond those cases, splitting a unified site into different origins generally works against the PWA model. Common but problematic patterns include:
- Site sections on subdomains: For instance a news site with
https://www.example.comfor home,https://sports.example.comfor sports, andhttps://politics.example.comfor politics, or an e-commerce site splitting categories and product pages this way. - User flows on separate subdomains: Using
https://login.example.comorhttps://checkout.example.comfor parts of a continuous user journey cuts against the idea of one cohesive app.
If migrating to a single origin isn't immediately possible, the following workarounds can help mitigate the constraints of the same-origin policy.
Service workers are origin-bound
A service worker script must live on the same origin as the page calling register(). A page at https://www.example.com cannot register a service worker hosted at https://section.example.com. Furthermore, a service worker only controls pages within its own origin and scope path.
There is no cross-origin workaround here: you must run separate service workers for each origin.
Cache and storage are siloed per origin
The Cache API, IndexedDB, and localStorage are all confined to a single origin. Code on https://www.example.com cannot access caches belonging to https://section.example.com.
Two practices help manage this:
- Use standard browser caching: Traditional HTTP caching works across origins, which the service worker cache doesn't. Apply conventional caching best practices alongside your service worker strategy.
- Keep each service worker install lightweight: If you maintain multiple service workers, pre-cache only what's essential so that navigating to a new origin doesn't force a heavy installation cost on the user.
Permissions don't carry over
Permissions granted by a user are scoped to the origin. Granting location access to https://section.example.com does not grant it to https://www.example.com.
Since permissions can't be shared, you must request each permission separately on every subdomain where the feature is needed. For web push, you can track whether the user already accepted the permission on another subdomain (for example, with a cookie) and avoid prompting again.
Installation is per origin
Each origin needs its own manifest with a start_url that resolves relative to it. A user who triggers the install prompt on https://section.example.com cannot install an app whose start_url points to https://www.example.com. The install prompt offers only the subdomain's own scope.
Another consequence: if every subdomain meets the install criteria, users may see multiple install prompts while browsing the site. To avoid this, restrict the prompt to the main origin:
- Listen for the
beforeinstallpromptevent on all subdomains. - Call
event.preventDefault()everywhere except the main origin to suppress the prompt.
Standalone-mode navigation gaps
When the user navigates outside the PWA's scope in standalone mode, behavior is up to the browser. Recent versions of Chrome, for instance, open a Chrome Custom Tab. This works against a unified experience when part of the experience—like a login page—lives on another subdomain.
For such small, self-contained subdomain pieces, an iframe workaround is possible:
- Load the subdomain URL (for example,
https://login.example.com) inside a full-screen iframe on the main page. - When the task in the iframe completes, use
postMessage()to pass the result back to the parent page. - After the parent receives the message, unregister the message listeners and remove the iframe from the DOM.
Bottom line
The same-origin policy places serious constraints on any multi-origin site that aims to deliver a coherent PWA experience. The recommended path is simple: avoid dividing your site across origins. If you're already on a multi-origin setup, the workarounds above can help close the gaps, but each comes with tradeoffs. When planning a redesign or long-term strategy, consolidating to a single origin should be a serious consideration, unless there's a strong reason to keep the subdomains separate.



