Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Way to detect if a web app is installed #1092

Open
marcoscaceres opened this issue Jun 9, 2023 · 30 comments
Open

Way to detect if a web app is installed #1092

marcoscaceres opened this issue Jun 9, 2023 · 30 comments
Labels
Feature Request TPAC2024 Topic for discussion at TPAC 2024

Comments

@marcoscaceres
Copy link
Member

marcoscaceres commented Jun 9, 2023

The navigator.standalone attribute has been in iOS since forever and has the nice semantics in that, as a boolean value, it distinguishes between installed web applications and those running in the regular browser tab.

It's slightly unfortunate that "standalone" will mean "installed" (as per the spec's definition), and there is also "display-mode: standalone", but I think that's ok.

What do folks here think? @dmurph, @aarongustafson, would love to hear your thoughts!

See also this webkit bug.

@marcoscaceres marcoscaceres changed the title should we standardize navigator.standalone should we standardize navigator.standalone ? Jun 9, 2023
@karlcow
Copy link
Member

karlcow commented Jun 9, 2023

Previously #273

@mgiuca
Copy link
Collaborator

mgiuca commented Jun 9, 2023

This is the first I'm hearing of navigator.standalone.

Q: Is there a difference between navigator.standalone and matchMedia('(display-mode: standalone)').matches? Does navigator.standalone return true for other non-browser display modes like minimal-ui, fullscreen, and future ones like window-controls-overlay?

I would prefer to have some way to express that as a CSS MQ. I seem to be able to express it using matchMedia('not (display-mode: browser)').matches, which is a bit of a mouthful, but makes sense using existing APIs. It was difficult to come up with that, but we can document it on MDN and elsewhere.

It's slightly unfortunate that "standalone" will mean "installed" (as per the spec's definition)

I don't follow this (also, which spec?). If you use navigator.standalone on a browser tab inside an app scope, while that app is installed, it will still be false, right? So it doesn't mean "installed". Do you mean that it's unfortunate that it means "running in a separate window outside the browser" as opposed to "having display-mode standalone"? If so, yes, that's why I think it's OK to tell developers to use matchMedia('not (display-mode: browser)').matches to say exactly what they mean.

@mgiuca
Copy link
Collaborator

mgiuca commented Jun 9, 2023

Note from chatting with Marcos: Yes it basically is matchMedia('not (display-mode: browser)').matches but a small exception for fullscreen (because display-mode: fullscreen is weird).

dm: fullscreen is true when you're in the browser but fullscreen mode. But navigator.standalone is false in that case.

Further discussion:
It sounds like there is a good reason to have a definitive Boolean "yes or no: is this in an installed context?" (Which we currently almost-but-don't-quite have with the MQ).

Ideally such a thing would be itself a new MQ, not a JavaScript Boolean with somewhat the wrong name. So we can design a new MQ for it. But that aside, should we just standardize navigator.standalone because it's been around for so long, and have other browsers implement it, to avoid compat issues.

Matt will ask around internally to see if we have seen compat issues due to a lack of navigator.standalone.

@marcoscaceres
Copy link
Member Author

Having a corresponding media feature/query would be great, particularly given the use case is generally to control the web page's UI (generally to take away install buttons and instructions). It could be as simple as (standalone: yes)... which would be clear when used with @media (standalone: yes and display-mode: fullscreen) {...}. If we go forward with a CSS media feature, we should probably ping some of our CSS WG friends.

@tomayac
Copy link
Contributor

tomayac commented Jun 9, 2023

FWIW, it's been something iOS-focused web developers have depended upon and expected to be in Chrome DevTools' iOS device simulation mode, so I filed crbug/1197498 some time ago. I'm not opposed to standardizing it as a legacy feature.

The future is definitely non-ambiguous media queries where you can exactly express what you want to test for, which is why I created the WebKit bug.

If WebKit decides to report it, there should probably a differentiation between navigation controls on (corresponds to minimal-ui) and navigation controls off (corresponds to standalone).

@karlcow
Copy link
Member

karlcow commented Jul 2, 2023

Update here. Standardizing navigator.standalone creates a potential webcompat issue for people who want to detect iPad (or being iPad) and send links to the appropriate download/banner.

See mozilla/bedrock#13328

What happened?

Mozilla to detect the iPad Pro was using (pf.indexOf('MacIntel') !== -1 && 'standalone' in navigator)

So Safari 17 Desktop with navigator.standalone was identified as an iPad and instead to have a download link to a DMG file it was redirecting to the iOS Appstore.

Mozilla fixed it.
but a quick search online shows potential for more breakages.

So this is to keep in mind in the solutions that needs to be evaluated.

@dmurph
Copy link
Collaborator

dmurph commented Jul 6, 2023

One potential difference here, if you want an "is this installed" bit, is that display mode css media query is spec'd to be the current display mode, which includes 'fullscreen'. So if you have an installed app that you go fullscreen, then it'll be "standalone" -> "fullscreen" -> "standalone" (when you exit fullscreen).

This seems to really confuse developers, so I propose we have a signal that is something like "is this URL within scope of an installed app" signal (this allows it to work with Safari & Chrome's different implementations of isolation).

@marcoscaceres
Copy link
Member Author

@dmurph, that's an interesting re-interpretation and might work.

However, when you say "This seems to really confuse developers", what is "this" exactly? Can you clarify a bit?

@aarongustafson
Copy link
Collaborator

One potential difference here, if you want an "is this installed" bit, is that display mode css media query is spec'd to be the current display mode, which includes 'fullscreen'. So if you have an installed app that you go fullscreen, then it'll be "standalone" -> "fullscreen" -> "standalone" (when you exit fullscreen).

This seems to really confuse developers, so I propose we have a signal that is something like "is this URL within scope of an installed app" signal (this allows it to work with Safari & Chrome's different implementations of isolation).

Reminder: there's a lengthy discussion of an “installed” signal on the App Info spec: w3c/manifest-app-info#42

There is also the Client Hint for display modes proposal too (though that's more server side). Of course I'm also still super skeptical about the wisdom in relying on display modes as an indication of installation. I'd much prefer an explicit signal that you are, in fact, viewing the site in it's installed state (hence the discussion above).

I'm not entirely sure what's to be gained from having this. I'm not deadset against it, I guess I'm just not convinced of the value yet.

@marcoscaceres
Copy link
Member Author

Discussing with @dmurph, as an alternative:

@media (installed: yes and display-mode: fullscreen) {...}

And we keep the legacy:

navigator.standalone; 

As WebKit/Safari Web Apps are fully isolated (they are an entirely different user agent), there is no way of sharing "is this web app installed". For a site in a browser to know if a web app is (or was) installed would break the privacy model of Safari.

@aarongustafson
Copy link
Collaborator

For a site in a browser to know if a web app is (or was) installed would break the privacy model of Safari.

I can understand how, when compared to the web overall, this would be an issue, but this is not something shared by apps developed in Swift, even those that make use of the web view, right?

I'm also curious to know what Apple's specific privacy concerns are, especially if the check only applied specifically within the context of the installed app and not in a casual browsing (e.g., browser tab) scenario.

@marcoscaceres
Copy link
Member Author

marcoscaceres commented Sep 12, 2023

Action here is to float this with the CSS Working Group.

You say "installed" in cases where you wouldn't want to show an install button... has the user "installed" this web application.

Only applies to top-level navigable. This can't apply cross origin. Cross-origin must return false (or "no").

@marcoscaceres marcoscaceres changed the title should we standardize navigator.standalone ? Way to detect if a web app is installed Apr 10, 2024
@dmurph
Copy link
Collaborator

dmurph commented Apr 10, 2024

Feedback here: https://issues.chromium.org/issues/331692948#comment15

For us, with the PWA, we offer more UI options primarily to match the PC native app and provide additional control options, such as a refresh button, because we know users don't have access to browser tools.

As a small example, we always hide the website's navbar when a user is logged in on the PWA. This provides more screen real estate for the app since we understand that's the main focus. We prefer users not to see the logout and settings options, which are rarely used; instead, they have to click to show the side menu.

This is supportive evidence for an 'installed' attribute that can be media-queried.

@dmurph
Copy link
Collaborator

dmurph commented May 16, 2024

Also interested in thoughts from folks on this doc: https://bit.ly/pwa-detecting-install

@marcoscaceres marcoscaceres added TPAC2024 Topic for discussion at TPAC 2024 and removed TPAC2023 labels Sep 5, 2024
@helo-sky
Copy link

helo-sky commented Nov 5, 2024

It's impossible to know if our app is running as a PWA when using Chrome Enterprise Kiosk & Signage, which is really impactful because Chrome Enterprise Kiosk doesn't allow users to open external links at all. We need to handle this, but there's no way to detect if our app is running as a PWA in Chrome Enterprise Kiosk.
Could you please add support for this?

@marcoscaceres
Copy link
Member Author

marcoscaceres commented Nov 7, 2024

Hey @tomayac or @reillyeon, can you please see #1092 (comment) ... it's a bit out of scope for this repo, but maybe a quick response to the above?

@tomayac
Copy link
Contributor

tomayac commented Nov 7, 2024

It's impossible to know if our app is running as a PWA when using Chrome Enterprise Kiosk & Signage, which is really impactful because Chrome Enterprise Kiosk doesn't allow users to open external links at all. We need to handle this, but there's no way to detect if our app is running as a PWA in Chrome Enterprise Kiosk. Could you please add support for this?

This looks more like a Chrome feature request than something we'd want to discuss in the manifest spec repository. Could you open a new Chrome bug for this, please?

@helo-sky
Copy link

@tomayac Chrome team sent us here
Check out the ticket https://issues.chromium.org/issues/331692948

@tomayac
Copy link
Contributor

tomayac commented Nov 10, 2024

@tomayac Chrome team sent us here Check out the ticket https://issues.chromium.org/issues/331692948

I'm not sure what Chrome Enterprise does exactly in kiosk mode. The usual flow would be to chck matchMedia('not (display-mode: browser)').matches. Maybe the Chrome Enterprise support knows more.

@helo-sky
Copy link

helo-sky commented Nov 10, 2024

@tomayac Chrome Enterprise behaves exactly like regular Chrome, except Chrome Enterprise cannot open external links in kiosk mode. In both cases, it is impossible to determine if an app is running as a PWA when fullscreen is enabled (which is always the case "fullscreen" in Chrome Enterprise Kiosk).

When Chrome Enterprise Kiosk runs a PWA, a regular browser page in fullscreen mode, or a PWA on Chrome, all return display mode: fullscreen if fullscreen is enabled.

check this comment: https://issues.chromium.org/issues/331692948#comment4

@dmurph
Copy link
Collaborator

dmurph commented Nov 20, 2024

I believe, from TPAC, we are in agreement on:
@media (installed: yes) {...}
and
navigator.standalone

where installed: yes will be true in installed contexts even if display-mode is fullscreen

(although, to bikeshed, should we do standalone: yes? I don't like how it overloads the 'standalone' term.... which already is a display mode. @marcoscaceres

@marcoscaceres
Copy link
Member Author

Discussed with @dmurph, let's stick to "installed".

@marcoscaceres
Copy link
Member Author

marcoscaceres commented Nov 21, 2024

AI Generated based on what we discussed:

Explainer: Standardizing and Implementing Web Application Context Detection

Overview

This feature standardizes the terminology and mechanism to detect whether a web application is operating in an "installed-like" context (e.g., launched as a standalone app, added to a home screen). The goal is to replace the ambiguous term "installed" with a clear and developer-friendly alternative while aligning browser implementations and specifications.

Problem Statement

Web applications often operate in different contexts, such as:

  • As standalone apps launched from the home screen or desktop.
  • In a browser tab as part of the general browsing experience.

Currently, developers rely on terms like "installed," which are inconsistently defined across platforms. This ambiguity leads to challenges in building cohesive user experiences.

Proposed Solution

Standardize the terminology and introduce clear mechanisms to detect and respond to a web app's context. The proposed term (e.g., "Standalone Mode", "PWA Mode") will be applied consistently in the Web App Manifest specification, browser implementations, and developer tools.


Feature Goals

  1. Clarity for Developers:

    • Provide an unambiguous, actionable term to describe app-like contexts.
    • Offer a simple way to detect the app's context using media queries or APIs.
  2. Cross-Browser Compatibility:

    • Ensure consistency across major browsers (WebKit, Chromium, Firefox).
  3. Backward Compatibility:

    • Avoid breaking existing functionality tied to the display-mode media query or APIs like navigator.standalone.

How It Works

Terminology

We propose replacing "installed" with:

  • "Standalone Mode": Indicates that the app is running independently, outside the browser's typical UI (e.g., no address bar, tabs).
  • Alternative options: "Home Screen App", "Launched as App", "PWA Mode".

Media Query Example

The display-mode media query will reflect the new terminology:

@media (display-mode: standalone) {
  body {
    background: #f0f0f0;
  }
}

API Example

A new property or method can provide a programmatic way to check the app's context:

if (navigator.standalone) {
  console.log('The app is running in Standalone Mode!');
}

User Experience

For end-users, this change is seamless. Developers gain better tools to optimize user experiences across contexts.


Implementation Phases

Phase 1: Specification Updates

  • Propose updates to the Web App Manifest spec via the W3C Web Apps Working Group.
  • Collaborate with browser vendors to standardize terminology and behavior.

Phase 2: Implementation in WebKit

  • Update the display-mode media query to reflect the new terminology.
  • Add APIs or enhance existing ones to provide context detection.
  • Conduct internal and interoperability testing.

Phase 3: Alignment with Chromium

  • Work with Dan Murphy (Chrome) and other browser vendors to ensure consistent implementation.

Phase 4: Developer Outreach

  • Publish updated documentation and examples.
  • Engage with the developer community through blogs, conferences, and forums.

Benefits

  1. Improved Developer Experience:

    • Clear, consistent terms reduce confusion.
    • Tools like media queries and APIs empower developers to create better app-like experiences.
  2. Better Cross-Browser Consistency:

    • Unified terminology ensures developers can rely on predictable behavior across browsers.
  3. Enhanced User Experience:

    • Developers can optimize design and functionality based on the app's context, leading to smoother interactions.

Next Steps

  • Gain consensus on the terminology in the W3C Web Apps Working Group.
  • Finalize the spec changes and align with browser vendors.
  • Implement the changes in WebKit and Chromium simultaneously, ensuring cross-browser interoperability.

By standardizing this terminology and implementation, we can make the web platform more robust, predictable, and developer-friendly.

@dmurph
Copy link
Collaborator

dmurph commented Nov 21, 2024

another version from AI that likely has weird problems:

Detecting Installed Web Apps: A New CSS Media Query and Property

Developers have long requested a reliable way to detect if a web app is installed on a user's device. This is important for tailoring the user experience, such as hiding install prompts or providing app-specific features. A new CSS media query and JavaScript property are being introduced to address this need and overcome limitations with existing methods.

The New Features:

  • installed: yes media query: This CSS media query will allow developers to apply styles specifically when a web app is installed. This helps customize the interface for installed apps.

    @media (installed: yes) {
      .install-button { 
        display: none; 
      }
      .app-specific-feature { 
        display: block; 
      }
    }
  • navigator.standalone property: This JavaScript property will provide a boolean value indicating whether the web app is running in a standalone context (i.e., installed). This allows for dynamic adjustments to the app's behavior.

    if (navigator.standalone) {
      // Enable app-specific features
    } else {
      // Show install prompt
    }

Use Cases:

This feature addresses several crucial use cases:

  • Detecting if a web app is installed: This is the primary use case, enabling developers to adjust the user interface and app behavior accordingly.
  • Controlling the web page's UI: Developers can use the media query to hide or show elements based on the installation status, such as removing install buttons or displaying app-specific features.
  • Providing a signal for installed apps to enable UI features: Installed web apps might have different UI requirements compared to when accessed through a browser. This feature allows developers to cater to those needs.
  • Addressing challenges with existing methods: The current display-mode media query can be confusing when dealing with fullscreen mode or when a site is opened within another app's PWA context. The new features provide a more reliable and straightforward solution.
  • Analytics: Accurately identify PWA usage and revenue. This is particularly important for:
    • Differentiating between a site opened in its own PWA context versus another app's PWA.
    • Reliable tracking even when fullscreen mode is used.
    • Server-side detection of PWA usage for analytics and link generation. This could potentially be achieved through a new HTTP header.
  • Cookie Management: Potentially separating cookies between the installed PWA and the web version to prevent conflicts and ensure accurate tracking.

Benefits:

  • Improved developer experience: Clear signals and dedicated features make it easier to build and optimize web apps.
  • Enhanced user experience: Tailored interfaces and app behavior create a more seamless and engaging experience for users.
  • Better cross-browser consistency: Standardization ensures consistent behavior across different browsers.
  • Accurate analytics: Gain insights into PWA usage and optimize accordingly.

Next Steps:

The proposal is currently being discussed within the W3C Web Apps Working Group and will be implemented in major browsers like WebKit and Chromium. This collaboration aims to create a consistent and reliable way for developers to detect and respond to the context of their web applications.

@benfrancis
Copy link
Member

benfrancis commented Dec 2, 2024

I just wanted to highlight that there are two orthogonal states of a web application which are being discussed here:

  1. Whether or not the web app has been installed
  2. The display mode of the current browsing context

Installed web apps can use any display mode, currently including:

  • fullscreen
  • standalone
  • minimal-ui
  • browser (default)

For the former I support the term "installed" being used because that is the term used by native applications on most operating systems and if the intention is for web apps to be treated as first class citizens then that should be reflected in the language used in CSS selectors and the DOM.

For the latter, the term used in the specification is "display mode", of which "standalone" is only one. Therefore I would suggest a key (whether a CSS selector or DOM property) of display-mode/displayMode with a string/enum value which can be set to any of the valid display modes listed above.

Note that because deep linking is not widely implemented, it's possible for a URL within the navigation scope of an installed web app with a standalone (or fullscreen or minimal-ui) display mode to be navigated to in an ordinary browsing context (i.e. a browser tab using the default browser display mode) without the manifest being applied. This could result in a situation where the app is "Installed" with a display mode of "standalone", but the current display mode is "browser". It should be made clear what to expect in that common edge case.


As an aside, may I politely suggest that the raw output of LLMs is not copy-pasted as a contribution in standards discussions? I wasted a lot of time reading the word spaghetti above in my email notifications before clicking through to the edited version on GitHub which discloses that it was generated by "AI" and not a human contributor.

@dmurph
Copy link
Collaborator

dmurph commented Dec 3, 2024

@benfrancis wrote:

Note that because deep linking is not widely implemented, it's possible for a URL within the navigation scope of an installed web app with a standalone (or fullscreen or minimal-ui) display mode to be navigated to in an ordinary browsing context (i.e. a browser tab using the default browser display mode) without the manifest being applied. This could result in a situation where the app is "Installed" with a display mode of "standalone", but the current display mode is "browser". It should be made clear what to expect in that common edge case.

Good to think about. We're planning on shipping something like this soon in Chrome (chrome://flags/#enable-user-navigation-capturing-pwa, reimpl option). However - the 'browser' installed mode doesn't have cross-engine consensus here. I think moving forward here with the current proposal, interpreted as 'this is displayed in an installed / standalone window' solves the immediate use-cases here around the display-mode + 'fullscreen' resolution problems. 'installed' might not be the best best name... 'standalone' seems more correct but it's already way too overloaded a term. So 'installed' seems good enough.

This doesn't block us from adding more media queries / values on the Chromium side to expose the 'installed but in the browser' mode in the future. If there is a request for that we can certainly look into it - but I don't think there is (at this point) cross-engine consensus on that yet.

So I'd like to move forward with the proposal of the css media query and the navigator.standalone property.

@benfrancis
Copy link
Member

benfrancis commented Dec 5, 2024

@dmurph wrote:

We're planning on shipping something like this soon in Chrome (chrome://flags/#enable-user-navigation-capturing-pwa, reimpl option)

Cool to know you're experimenting with this in Chrome! I'm interested to see how that works given your presentation on all the tricky edge cases.

I'd like to move forward with the proposal of the css media query and the navigator.standalone property.

To be clear, what exactly is the current proposal?

There were two proposals pasted above that were generated by large language models, but neither made sense to me.

What would the keys and possible values of a CSS media query and DOM property be and what do they mean?

E.g. If a web app is installed with a display mode of minimal-ui, would navigator.standalone be true or false?

Even if you ignore the browser display mode, "standalone" is currently the name of one of three "display modes", all of which could be used by an "installed" app.

@dmurph
Copy link
Collaborator

dmurph commented Dec 5, 2024

navigator.standalone is true if you're in an app window, no matter the display mode. So for 'minimal-ui', 'standalone', etc. Also, importantly, true if the app is fullscreen. It's not the best name, but it's already shipped in WebKit, so... not terrible. We could do navigator.installed instead, but I'm fine with not doing that.

The meaning is that the web contents is in an app window. @marcoscaceres we should clarify what frames can see this. I think navigator.standalone is only top level? I'm embarrassingly ignorant of the iframe terminology, but I think there is a concept of a more trusted iframe vs a less trusted one, and I would hope that these are populated for the trusted but not the untrusted.

@drubino-mozilla
Copy link

What do you have in mind as the definition of an "app window"? This could imply a number of things... like whether the app appears in the OS list of installed applications, whether it has its own icon on the taskbar/dock, whether it has an address bar visible, whether it's scoped to a particular domain, whether it's acting on a PWA manifest, and probably more. Each browser could offer one more configurations that might be described as an "app window" and the site developer won't know (or will assume and be wrong about) what it means. I think instead we should offer information on the mode a site is running in and the capabilities available to it on a feature-by-feature basis, at the level of granularity that is relevant to users and the site.

@benfrancis
Copy link
Member

benfrancis commented Dec 6, 2024

@drubino-mozilla wrote:

What do you have in mind as the definition of an "app window"?

@dmurph Would I be right to assume that "app window" is a less formal term for "application context", or at least a UI element which contains an application context?

"A top-level browsing context that has a manifest applied to it is referred to as an application context." (section 1.16.5 of the specification)

This is independent of any kind of UI design.

On Android and iOS I think it's fairly obvious because the application context is presented as a separate application window in the window switcher with its own icon, separate from the browser application. You're either in the browser app or you're in a separate app.

In the implementation I'm working on it's more fluid that that. Users can deep link in and out of different applications using the same browsing context. When they navigate to a URL inside the navigation scope of an installed app, the manifest is dynamically applied to the browsing context to create an application context. Then if they navigate outside the scope of the app the manifest is un-applied, or a different manifest is applied.

Things a developer might want to know are whether the app is installed (e.g. to stop suggesting the user install the app) and what the current display mode is (e.g. to subtly modify the UI design in fullscreen display mode), but I don't think these two things should be conflated (which is why "navigator.standalone" is a potentially confusing name).

BTW you also can't assume that the display mode defined in the manifest is the display mode used by the user agent when launching an app, because all display modes are optional for user agents to implement and they have a fallback chain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature Request TPAC2024 Topic for discussion at TPAC 2024
Projects
None yet
Development

No branches or pull requests

9 participants