94

I was curious if anyone knew a javascript based method for detecting whether the web experience was being run as a PWA (progressive web app) or it was simply being run as a standard mobile website (with full browser UI).

Is there any difference between a PWA that is "installed" versus one that isn't but still has the service worker and/or app cache registered?

PorcupineRending
  • 1,245
  • 1
  • 11
  • 16
  • That distinction is somewhat murky, since both are fundamentally built using the same technologies. What exactly do you want to detect? – deceze Jan 19 '17 at 13:15
  • 3
    @deceze basically, whether or not it's been installed via as a legit PWA or if it's just running like a standard site. I'm not all that familiar with service workers and caches but I'm guessing that you can register both without something legitimately being installed as a PWA (like on a phone). Maybe the best way to check is whether the browser UI is visible but I'm not sure if that's accessible via JS. – PorcupineRending Jan 19 '17 at 16:45
  • Similar to this but for android https://stackoverflow.com/questions/18653024/check-if-web-app-is-added-to-home-screen-on-android/ – ikibiki Apr 01 '19 at 01:51
  • Is there any way visually to differentiate between PWA vs Mobile Web ? – vikramvi Jun 30 '19 at 03:53
  • @vikramvi Depends on the PWA's app manifest. If it's set to run with `display-mode: browser`, then it is visually the same as your web browser. However many PWAs use `standalone`, `minimal-ui` or `fullscreen`, which are visually different. – Alex Walker Nov 04 '19 at 18:17

5 Answers5

120

If this is for analytical purposes you could set the start URL in the manifest file to include a query string parameter, ex:

"start_url": "./?mode=standalone"

Then in your JavaScript you are able to check for this query string parameter.


Update (2020-08-19)

Pete LePage wrote a blog on how to setup a custom dimension in Google Analytics using the code below which checks the display mode using window.matchMedia:

let displayMode = 'browser';
  const mqStandAlone = '(display-mode: standalone)';
  if (navigator.standalone || window.matchMedia(mqStandAlone).matches) {
    displayMode = 'standalone';
  }
ga('set', 'dimension1', displayMode);

Read more: https://petelepage.com/blog/2020/08/measure-understand-how-installed-pwa-users-differ-from-browser-tab-users/

Update (2017-01-20):

Alternatively you could check in JavaScript using:

if (window.matchMedia('(display-mode: standalone)').matches) {
  console.log("This is running as standalone.");
}
Kevin Farrugia
  • 6,431
  • 4
  • 38
  • 61
48

Edit 11 Oct 2019: Added an extra switch to check if the app is launched via TWA - document.referrer.includes('android-app://')

This works for all - TWA, Chrome & Safari:

const isInStandaloneMode = () =>
      (window.matchMedia('(display-mode: standalone)').matches) || (window.navigator.standalone) || document.referrer.includes('android-app://');

 if (isInStandaloneMode()) {
    console.log("webapp is installed")
}
Gary Vernon Grubb
  • 9,695
  • 1
  • 24
  • 27
  • since it it probably wont change, wouldn't it make sense to just make it a variable instead of a function – stackers Nov 24 '19 at 23:40
  • Yes, I agree. Do you know if that would give any minor performance benefits? – Gary Vernon Grubb Nov 26 '19 at 05:02
  • 2
    I'd suggest keeping it as is since it became pretty complex already. And, functions are the simplest way to encapsulate things. Saving one entry in a call stack during function call is negligible. – amankkg Dec 26 '19 at 12:10
  • 1
    This doesn't work for me if the PWA has been added and started by Firefox on Android – mediafreakch Nov 09 '20 at 07:22
  • 1
    There seems to be a bug in FF which prevents the matchMedia approach to work: https://bugzilla.mozilla.org/show_bug.cgi?id=1285858#c29 – mediafreakch Nov 09 '20 at 08:40
  • This doesn't always work. If your PWA is set to fullscreen, display-mode will be fullscreen instead of standalone, and testing for that wouldn't be correct since the browser might just be set to fullscreen by the user. – Glenn Maynard Nov 05 '22 at 19:52
23
if (window.matchMedia('(display-mode: standalone)').matches) {
  console.log("This is running as standalone.");
}

This answer is correct but it's worth to mention that PWA could run on plenty of display modes:

  • fullscreen
  • standalone
  • minimal-ui
  • browser

If you run your PWA in a 'fullscreen' mode it will return false so additional checks are necessary like:

function isPwa() {
    return ["fullscreen", "standalone", "minimal-ui"].some(
        (displayMode) => window.matchMedia('(display-mode: ' + displayMode + ')').matches
    );
}

Note that window.matchMedia check will return true for the 'browser' display mode even when it's not an installed PWA app.

StPaulis
  • 2,844
  • 1
  • 14
  • 24
Jacek Gałka
  • 331
  • 2
  • 6
  • Thank you, that really helped... I re-wrote it like this: `function isPwa() { var displayModes = ["fullscreen", "standalone", "minimal-ui"]; return displayModes.some((displayMode) => window.matchMedia('(display-mode: ' + displayMode + ')').matches); }` – StPaulis Apr 10 '20 at 09:11
  • Good answer, but it also passes the check of isPwa() when we make spa build instead of pwa and run it in full-screen mode. I wanna check if a user is using it in installed mode. Anyway to check that? – Hassan Saqib Mar 10 '21 at 07:52
1

Progressive enhancement is more a concept than an specific function or method that involves several technologies. Now progressive web apps are base on service workers which you can verify if the browser support it.

// Check for browser support of service worker
if ('serviceWorker' in navigator)

Project lighthouse can help you to detect whether an application is progressive enhanced by performing evaluations of several technologies. Take a look on it.

enter image description here

Hope this help, to clarify.

Hosar
  • 5,163
  • 3
  • 26
  • 39
  • I guess I should specify. This is for analytics purposes so I want to know if there is a way to tell with Javascript whether someone is currently viewing the PWA version of the site or the regular version. I was thinking maybe checking to see if the service worker is registered but couldn't it be registered even on mobile web if the site hasn't been "installed"? – PorcupineRending Jan 19 '17 at 16:35
-4

In my PWA, created with Microsoft Visual Studio 2017, following statement works:

var isPWA = navigator.userAgent.match(/MSAppHost/i);
Dharman
  • 30,962
  • 25
  • 85
  • 135
stefischer
  • 43
  • 3