Choose how in-scope links open your PWA with Declarative Link Capturing

Published on Updated on

Caution

Declarative Link Capturing was part of the capabilities project. The engineering team has decided that Declarative Link Capturing will not launch with its current design. Instead, the feature has been redesigned as described in Control how your app is launched. If your app implements the Declarative Link Capturing API, you should transition to the replacement Launch Handler API.

What is Declarative Link Capturing?

Clicking links on the web can sometimes be a pleasant surprise. For example, clicking a web page link to YouTube on a mobile device opens the YouTube iOS or Android app, if it is installed. But when you install the YouTube PWA on a desktop computer and click a link, it opens in a browser tab.

But it gets more complex. What if the link appears not in a website, but in a chat message that you receive in one of Google's chat apps? On desktop operating systems, which have the notion of separate app windows, if the app is open already, should a new window or tab be created for each link click? When you think about it, there are many ways links and navigations can be captured, including, but not limited to, the following:

Declarative Link Capturing is a proposal for a web app manifest property called "capture_links" that lets developers determine declaratively what should happen when the browser is asked to navigate to a URL that is within the application's navigation scope, from a context outside of the navigation scope. This proposal does not apply if the user is already within the navigation scope (for instance, if the user has a browser tab open that is within scope, and clicks an internal link).

Key Term

The navigation scope of a web app manifest is the "scope" item of a processed manifest. The navigation scope restricts the set of URLs to which an application context can be navigated while the manifest is applied. If the "scope" member is not present in the manifest, it defaults to the parent path of the "start_url" member.

Some special conditions like middle-clicking a link (or right-clicking and then "open in new tab") would typically not trigger the link capturing behavior. Whether a link is target=_self or target=_blank does not matter, so that links clicked in a browser window (or window of a different PWA) would be opened in the PWA even if they would normally cause a navigation within the same tab.

Suggested use cases

Examples of sites that may use this API include:

  • PWAs that want to open a window, rather than a browser tab, when the user clicks on a link to them. In a desktop environment, it often makes sense to have multiple application windows open at a time.
  • Single-window PWAs where the developer prefers to only have a single instance of the app open at any time, with new navigations focusing the existing instance. Sub-use cases include:
    • Apps for which it make sense to have only one instance running (e.g., a music player, a game).
    • Apps that include multi-document management within a single instance (e.g., an HTML-implemented tab strip).

Enabling via about://flags

To experiment with Declarative Link Capturing locally, without an origin trial token, enable the #enable-desktop-pwas-link-capturing flag in about://flags.

How to use Declarative Link Capturing?

Developers can declaratively determine how links should be captured by leveraging the additional web app manifest field "capture_links". It takes a string or a an array of strings as its value. If an array of strings is given, the user agent chooses the first supported item in the list, defaulting to "none". The following values are supported:

  • "none" (the default): No link capturing; links clicked leading to this PWA scope navigate as normal without opening a PWA window.
  • "new-client": Each clicked link opens a new PWA window at that URL.
  • "existing-client-navigate": The clicked link opens in an existing PWA window, if one is available, or in a new window if it is not. If more than one PWA window exists, the browser may choose one arbitrarily. This behaves like "new-client" if no window is currently open. 🚨 Careful! This option potentially leads to data loss, as pages can be arbitrarily navigated away from. Sites should be aware that they are opting into such behavior by choosing this option. This option works best for "read-only" sites that do not hold user data in memory, such as music players. If the page being navigated away from has a beforeunload event, the user would see the prompt before the navigation completes.

There is discussion about adding options that do not open a window at all, but instead fire a launch event in a chosen foreground window or the service worker. See the launch event explainer for details, and, more specifically, the sections on existing-client-event and service-worker.

Demo

The demo for Declarative Link Capturing actually consists of two demos that interact together:

  1. https://continuous-harvest-tomato.glitch.me/
  2. https://hill-glitter-tree.glitch.me/

The screencast below shows how the two interact. They show two different behaviors, "new-client" and "existing-client-navigate". Be sure to test the apps in different states, running in a tab or as an installed PWA, to see the difference in behavior.

Security and permissions

The Chromium team designed and implemented Declarative Link Capturing using the core principles defined in Controlling Access to Powerful Web Platform Features, including user control, transparency, and ergonomics. This API allows sites new additional control options. First, being able to automatically open installed apps in a window. This uses existing UI but makes it possible for the site to automatically trigger it. Second, the capability to focus an existing window on its own domain and fire an event containing the clicked URL. This is intended to allow the site to navigate an existing window to a new page, overriding the default HTML navigation flow.

Migrate to Launch Handler API

The Declarative Link Capturing API origin trial expired on March 30, 2022 for Chromium 97 and below. It will be replaced by a set of new features and APIs in Chromium 98 and above, which includes user-enabled link capturing and Launch Handler API.

In Chromium 98, automatic link capturing is now a user opt-in behavior rather than granted at install time to a web app. To enable link capturing, a user needs to launch an installed app from the browser using Open with and choose Remember my choice.

Example of an installed app's 'Open with' setting with the 'Remember my choice' option enabled.

Alternatively, users can switch link capturing on or off for a specific web app in the app management settings page.

Example of an installed app's settings page.

Link capturing is a ChromeOS-only feature for now; support for Windows, macOS, and Linux is in progress.

Launch Handler API

The control of an incoming navigation is migrated to Launch Handler API, which allows web apps to decide how a web app launches in various situations such as link capturing, share target or file handling, etc. To migrate from the Declarative Link Capturing API to the Launch Handler API:

  1. Register your site for the Launch Handler origin trial and place the origin trial key into your web app.

  2. Add a "launch_handler" entry to your site's manifest.

    • To use "capture_links": "new-client", add:"launch_handler": { "route_to": "new-client" }.
    • To use "capture_links": "existing-client-navigate", add: "launch_handler": { "route_to": "existing-client-navigate" }.
    • To use "capture_links": "existing-client-event" (which was never implemented in the Declarative Link Capturing origin trial), add: "launch_handler": { "route_to": "existing-client-retain" }. With this option, pages in your app scope will no longer navigate automatically when a link navigation is captured. You must handle the LaunchParams in JavaScript by calling window.launchQueue.setConsumer() to enable navigation.

The capture_links field and Declarative Link Capturing origin trial registration are good until March 30, 2022. This will ensure users on Chromium 97 and below can still launch the web app at a captured link.

For more details, check out Control how your app is launched.

Feedback

The Chromium team wants to hear about your experiences with Declarative Link Capturing.

Tell us about the API design

Is there something about the API that does not work like you expected? Or are there missing methods or properties that you need to implement your idea? Have a question or comment on the security model? File a spec issue on the corresponding GitHub repo, or add your thoughts to an existing issue.

Report a problem with the implementation

Did you find a bug with Chromium's implementation? Or is the implementation different from the spec? File a bug at new.crbug.com. Be sure to include as much detail as you can, simple instructions for reproducing, and enter UI>Browser>WebAppInstalls in the Components box. Glitch works great for sharing quick and easy repros.

Show support for the API

Are you planning to use Declarative Link Capturing? Your public support helps the Chromium team prioritize features and shows other browser vendors how critical it is to support them.

Send a tweet to @ChromiumDev using the hashtag #DeclarativeLinkCapturing and let us know where and how you are using it.

Helpful links

Acknowledgements

Declarative Link Capturing was specified by Matt Giuca with input from Alan Cutter and Dominick Ng. The API was implemented by Alan Cutter. This article was reviewed by Joe Medley, Matt Giuca, Alan Cutter, and Shunya Shishido. Hero image by Zulmaury Saavedra on Unsplash.

Last updated: Improve article

We serve cookies on this site to analyze traffic, remember your preferences, and optimize your experience.