Building Progressive Web Apps on multi-origin sites

Demian Renzulli
8 min readApr 8, 2018

--

Note: An up-to-date and reviewed version of this article has been published in Web.dev. It is recommended to read that version instead of this one.

TL;DR

  • Same-origin policy imposes restrictions on multi-subdomain PWAs, like not being able to share service worker logic and caches between origins, the need to have a start_url relative to each origin in manifest files, and also, some noticeable UI changes when a user navigates among subdomains in full screen mode.
  • Therefore, for developers building a PWA from scratch, there are few reasons to adopt the strategy of dividing the site into subdomains.
  • There might be different motivations, though: localization, language, providing an independent set of Web applications, etc., but if there’s no major justification to maintain a multi-subdomain strategy, it’s worth considering migration to a single domain, in order to achieve a unified PWA experience.
  • If using a single domain is not an option, the workarounds explored in this article could be considered, in order to achieve a consistent UX for multi-subdomain PWAs.

Examples of common multi-domain patterns on sites

Many websites are built on top of multiple subdomains. Reasons for adopting this strategy vary, depending on the vertical, and company, but here are some common examples:

Vertical specific needs:

  1. eCommerce: It’s not uncommon for large eCommerce sites (Retail, Travel, etc.), to organize different parts of the site into different subdomains. For example:
  • Site sections: Grouping different parts of the site on subdomains, such as www.site.com, for Home, listings.site.com for Listings or Categories, product.site.com for Product Pages, etc.
  • User Flow: Separating different parts of the purchase flow (checkouts, sign-in, etc) from the main domain. For example, using secure.site.com to separate the booking and user account management pages, from the rest of the site.

2. News: Another common pattern occurs in the news vertical, where subdomains are used to structure the information architecture of the site. Having, for example the main site at: www.site.com, the Sports section at sports.site.com, Politics at politics.site.com, and so forth.

Localization / Language: Some sites use subdomains to divide sites targeted to different locations (e.g. Craigslist NYC) or to offer content for a specific language (e.g. Wikipedia in English). There is, of course, the usage of a top-level domain (TLD), to separate sites to be served in different countries (e.g. google.com.ar and google.com.br).

Device/Platform: Another common technique is to use different subdomains to offer different versions of a website to different devices. Using an “m.dot” subdomain is a common way to separate mobile from desktop. For example: a site can maintain its desktop version at www.site.com and mobile version at m.site.com.

Challenges for PWAs across different origins

When building a website structured on multiple domains, providing a unified UX is challenging because of the Same-Origin Policy, which imposes the following constraints:

  • Service Workers and caches can’t be shared between subdomains: Therefore, users navigating across subdomains would have to incur the installation cost of a new service worker for each origin being visited, and, won’t be able to leverage the resources cached by the previously installed service worker(s).
  • SW must belong to the same origin as the requesting page: The Register algorithm will check that the origin of the SW script URL is the same as page calling register. This means that, if a website wants to retrieve a SW located on a different domain (i.e:: www.site.com wants to register a SW from app.site.com), registration will fail.
  • Manifest start_url has to be relative to origin: Because of this constraint, each subdomain must have its own manifest, with a start_url, relative to its origin. As a result, a user receiving the Add to Home screen prompt on a subdomain won’t be able to install a home screen icon with a start_url relative to the main domain, which is usually the entry point for a web application (i.e. the home page).
  • Users will perceive the domain change on the UI: The browser will show an indication when the user moves across domains inside a standalone PWA. The UI indication depends on the browser version and vendor. Latest Chrome versions show thin bar with the url of the new domain on top of the full PWA UX. Others might open a new tab, when the user moves away from a subdomain.
  • Browsers restrict cross-origin HTTP requests from within scripts: Again, due to same-origin-policy, requests for resources inside scripts are restricted. There are some ways to make this work:
  1. The most recommended one is using CORS, that lets you specify in a request that you want to retrieve a cross-origin resource (in fetch this is enabled by default). You can find more details of this technique here.
  2. Using no-cors mode to request opaque resources. Opaque responses can’t be accessed with JavaScript but the response can still be served or cached by a service worker. Note: if you need to cache resources, this approach has many limitations, so using CORS is the recommended one.
  • AMP to PWA: A problem occurs if a company is hosting AMP pages on a different domain than the PWA site, and wants to use the amp-install-serviceworker to pre-install the SW and warm the cache, before the user accesses the full site. For security reasons, it’s not possible to import a service worker from a different origin, and therefore the registration of the service worker will fail. Examples:
  1. Having both AMP and non-AMP on the same domain, will allow the usage of this functionality. This applies both to the case of having AMP and non-AMP on the main domain (like www.site.com), or having both on subdomains (m.site.com, for example).
  2. Having the AMP Pages at www.site.com/amp/article, and the PWA at pwa.site.com, won’t allow amp-install-serviceworker to be run from the AMP Page, and therefore, the pre-installation won’t have any effect.

Workarounds

Caching: Based on the fact that a service worker can belong to only a single domain, here are some recommendations to implement a good caching strategy on sites with this structure:

  • Keep service worker installation lightweight: If it’s likely that users will jump between subdomains, you should avoid making them pay a big installation cost at every step they make. In other words: only pre-cache resources that are absolutely necessary.
  • Leverage browser caching: Using traditional browser caching best practices is always recommended. In this scenario, it presents the added benefit of reusing cached resources across subdomains, which service workers can’t do.
  • Pre-install service workers: The idea is to install the service worker just before a user arrives at a new domain. As with any preloading strategy, this technique should be used with caution: for example, only when it’s likely that a user will navigate to the new subdomain. This can be implemented in a similar way as the amp-install-serviceworker component does: opening a hidden iframe and loading a page that contains the script to register the Service Worker.
  • Note: On Webkit-based browsers, like iOS Safari, this technique won’t work, since SW inside third-party <iframes>, are partitioned off and not be in effect when you visit the URL for the <iframe> directly. It will only be in effect when you go back to the original URL, and have an <iframe> on that page.

Add to Home screen: There are two techniques to explore for those interested in achieving a consistent UX across domains:

  • Show the prompt on a single domain: To avoid showing the prompt on each subdomain, the site can be configured to only show it on a certain part of the site (for example, the home page), by capturing the beforeinstallprompt event and cancelling it for other site sections (see the technique explained here).
  • Show the prompt across the whole site: It’s more often the case that developers want to show the Add to Home screen prompt across the whole site, but only once, and ensure that the user are served the home page when accessing the PWA via the home screen icon. In this case the following technique can be applied:
  • As a start_url use a URL that redirects to the home page . For example: /subdomain.site.com/pwa, with a redirect to site.com.
  • Capture the beforeinstallprompt event, as mentioned before, to check for the existence of a cookie, that will be sent the first time the Add to Home screen prompt is shown.

UX: Moving across different subdomains shows a thin bar at the top of the full PWA with the new domain being visited.

For companies that don’t like this UX there’s a workaround to consider, based on Shadow DOM:

  • First, develop the PWA following the App Shell Pattern, decoupling the ‘content shell’ from content.
  • Then, to show the content, retrieve the new page (might be on the main domain or a subdomain), remove the head, and insert it in the shell, by using Shadow DOM. This is similar to the AMP + PWA pattern.

Automatic Sign-In: As different origins are counted as entire different websites, you have to find a way to associate them, to allow for automatic cross-origin sign-in.

To achieve that, you have to put the domains into the same OAuth project for passwordless auth across the projects (see instructions on how to configure the Google APIs project), and then link the sites for shared passwords with a Digital Asset Links JSON file, using the delegate_permission/common.get_login_creds relation (as explained here).

Choosing a long term strategy

Sites considering splitting into multiple subdomains: Here are some examples where splitting into multiple subdomains, might make sense, in the context of Progressive Web Apps:

  • Localization: Sometimes companies want to provide different PWAs to users in different countries, due to big UX differences between them. Using geographic TLDs could produce independent PWAs without the need of sharing cache storage or service worker logic.
  • Separation by content: In the world of Native Applications, many brands decide to break down the main App into independent experiences. The same strategy can be applied to Progressive Web Apps: A news site, for example, might have audiences that are very engaged with sports, but not so much with politics, and therefore provide a standalone webapp for each section, only for sports fans.
  • Platforms: Some platforms let users create their own experiences, and give them separate domains or subdomains to publish their sites (i.e: eCommerce platforms letting individual companies create online stores, as different websites). In this case creating multiple native apps for each client would be impossible, but letting them have their own PWA can be relatively straightforward.

Sites already built on top of multiple subdomains: Unless there’s an important reason to maintain a multi-subdomain strategy, for sites that want to provide a unified experience it’s worth considering migration to a single domain. If that’s not an option, other workarounds mentioned before should be explored to achieve a consistent UX.

--

--

Demian Renzulli

Eng @ UTN • Mobile Solutions Engineer @ Google • Working on Mobile and the Web • My opinions are my own.