From 8d70760ef8254b50b5a36312d8759c8f38e8eb8c Mon Sep 17 00:00:00 2001 From: Maciej Pienczyn Date: Wed, 18 Mar 2026 10:05:08 +0100 Subject: [PATCH] debug(pwa): send display-mode detection cookie for diagnosis Frontend now sends pwa_display cookie with the actual detected mode (standalone/minimal-ui/fullscreen/browser/unknown/ios-standalone). Backend logs this to diagnose why WebAPK detection fails. Co-Authored-By: Claude Opus 4.6 (1M context) --- templates/base.html | 32 +++++++++++++++++--------------- utils/analytics.py | 5 +++-- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/templates/base.html b/templates/base.html index 4623716..cb08022 100755 --- a/templates/base.html +++ b/templates/base.html @@ -2371,22 +2371,24 @@ } } - // PWA detection — set cookie for backend analytics - // WebAPK on Android may not report standalone via matchMedia reliably - var _isPWA = window.matchMedia('(display-mode: standalone)').matches - || window.matchMedia('(display-mode: minimal-ui)').matches - || window.navigator.standalone === true - || document.referrer.startsWith('android-app://'); - // Fallback: if browser mode query is supported but does NOT match, we're in PWA - if (!_isPWA) { - var browserMode = window.matchMedia('(display-mode: browser)'); - if (browserMode.media !== 'not all' && !browserMode.matches) { - _isPWA = true; + // PWA detection — send display mode info to server via cookie + (function() { + var modes = ['standalone', 'minimal-ui', 'fullscreen', 'browser']; + var detected = 'unknown'; + for (var i = 0; i < modes.length; i++) { + if (window.matchMedia('(display-mode: ' + modes[i] + ')').matches) { + detected = modes[i]; + break; + } } - } - if (_isPWA) { - document.cookie = 'pwa_mode=1; path=/; max-age=86400; SameSite=Lax'; - } + if (window.navigator.standalone === true) detected = 'ios-standalone'; + // Set cookie with detected mode for debugging + document.cookie = 'pwa_display=' + detected + '; path=/; max-age=86400; SameSite=Lax'; + // PWA = anything that is NOT 'browser' and NOT 'unknown' + if (detected !== 'browser' && detected !== 'unknown') { + document.cookie = 'pwa_mode=1; path=/; max-age=86400; SameSite=Lax'; + } + })(); // PWA Smart Banner logic (function() { diff --git a/utils/analytics.py b/utils/analytics.py index 27e7de1..c948299 100644 --- a/utils/analytics.py +++ b/utils/analytics.py @@ -100,8 +100,9 @@ def get_or_create_analytics_session(): user_session.user_id = current_user.id # PWA cookie arrives on 2nd request (after JS sets it) pwa_cookie = request.cookies.get('pwa_mode') - if pwa_cookie: - logger.info(f"PWA cookie found: '{pwa_cookie}' for session {user_session.id}") + pwa_display = request.cookies.get('pwa_display') + if pwa_display: + logger.info(f"PWA display mode: '{pwa_display}' pwa_mode={pwa_cookie} session={user_session.id} browser={user_session.browser}") if not user_session.is_pwa and pwa_cookie == '1': user_session.is_pwa = True logger.info(f"Setting is_pwa=True for session {user_session.id}")