Technical
Targeting Android TWA Users with CSS and JavaScript
September 22, 2026 · 6 min read
A progressive web app (PWA) must serve two distinct audiences: standard web visitors using a mobile or desktop browser, and mobile users who downloaded the app from the Google Play Store. While the core codebase remains identical, the user experience should adapt to these contexts. A user who installed your app from Google Play should not see banners urging them to install the app. Similarly, they may benefit from a more native interface that hides web-specific navigation headers, adjusts padding around the system navigation bar, and matches the native app aesthetic.
Why You Must Detect the TWA Context
Trusted Web Activity (TWA) is a lightweight technology that renders your PWA inside a full-screen, system-level browser container without any browser chrome, such as the URL bar or navigation buttons. Because the app feels entirely native, displaying elements like web headers, footers, or PWA installation prompts ruins the illusion. It can also confuse users who have already downloaded the application from Google Play. Adapting your interface ensures your product feels polished and explicitly built for the Android platform.
Key adjustments often include hiding desktop navigation bars, adjusting headers to prevent overlap with the status bar, hiding manual app installation promotions, and disabling pull-to-refresh if the native wrapper already manages complex gestures.
Method 1: Query Parameters and URL Search Options
The most reliable way to identify a TWA session is to append a unique query parameter to the launch URL configured in your Android app manifest. When the TWA opens, it loads the specified web page. By detecting this query parameter, your web server or frontend router can flag the user session as an app instance.
In your Android build configuration, typically configured during the compilation of the application packages, the launch URL can be defined with an identifier:
https://yourdomain.com/?utm_source=playstore
To parse this in JavaScript and set a persistent indicator, you can use the URLSearchParams API. It is recommended to store this status in sessionStorage or localStorage so that subsequent navigations during the session remain identified as TWA loads, even if the query parameter is stripped during internal route changes.
const queryParams = new URLSearchParams(window.location.search);
if (queryParams.get('utm_source') === 'playstore') {
localStorage.setItem('app_platform', 'android_twa');
}
By storing this value, your application can render custom interfaces dynamically across any view. The primary drawback to this approach is that if a user shares a link from within the TWA containing this query parameter, desktop users opening that link might be falsely identified as TWA users. To prevent this, ensure your sharing functionality strips tracking parameters before writing URLs to the clipboard.
Method 2: Leveraging Display Mode Media Queries
The Web App Manifest specification defines the display-mode field, which dictates how the web app is launched. Common values include browser, minimal-ui, standalone, and fullscreen. A TWA launched via Android always opens in the display mode declared in the manifest, typically standalone.
You can target standalone users directly in your CSS using media queries. This requires no JavaScript intervention and executes instantly during the initial layout render, preventing layout shifts:
@media (display-mode: standalone) {
.web-only-navigation {
display: none;
}
.native-app-header {
display: block;
}
}
However, display-mode: standalone applies to both TWAs installed via the Play Store and standard PWAs installed directly from the mobile browser. If you must differentiate between direct PWA installations and Play Store TWA installations, you should combine display-mode checks with the query parameter method described above.
Method 3: JavaScript User-Agent Detection
Historically, developers modified the User-Agent string to detect native wrappers. In a TWA context, you can append a custom identifier to the default browser User-Agent string inside the Android wrapper configuration. This allows your backend server to deliver targeted HTML and CSS directly, improving initial loading speeds.
If you have configured your TWA wrapper to append a suffix like AppWrapper, you can detect this string using a standard regular expression in JavaScript:
const isTwaApp = navigator.userAgent.includes('AppWrapper');
While powerful, User-Agent detection is increasingly discouraged due to browser privacy updates and the deprecation of traditional User-Agent parsing in favour of User-Agent Client Hints. Use this method as a supplementary detection layer rather than your primary mechanism.
Hiding PWA Installation Banners
One of the most common requirements is hiding custom install banners. When a standard browser user visits your PWA, the browser fires the beforeinstallprompt event. If you have built custom UI cards prompting the user to install your application, you must intercept and cancel this event when running inside a TWA, as the app is already installed via the Play Store.
let deferredPrompt;
window.addEventListener('beforeinstallprompt', (e) => {
if (localStorage.getItem('app_platform') === 'android_twa') {
e.preventDefault();
return false;
}
deferredPrompt = e;
showInstallButton();
});
Comparing Detection Mechanisms
Selecting the correct approach depends on your architectural needs. The following table highlights the pros and cons of each detection strategy:
| Method | Primary Advantage | Limitations | Recommended Use Case |
|---|---|---|---|
| Query Parameters | Extremely reliable and easy to set up on launch. | Can be lost during navigation or shared via URLs. | General identification and session state initialization. |
| CSS Display Mode | Instant rendering with no layout shifts or JS dependency. | Cannot distinguish between Play Store TWAs and direct browser PWAs. | Applying broad style changes for installed applications. |
| User-Agent Customisation | Enables server-side rendering detection. | Requires wrapper updates and risks future browser deprecation. | Server-side adjustments or third-party analytics routing. |
Structuring Layout Styles for Android Screen Safety
Android devices feature various aspect ratios, rounded corners, camera notches, and software-based navigation bars. To ensure your TWA looks integrated, you must configure safe areas. Modern mobile browsers support the env() function to account for display cutouts and navigation zones.
Ensure your HTML head includes the viewport metadata with viewport-fit=cover specified:
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
Once configured, use the safe-area CSS variables to add dynamic padding to your header and footer zones, ensuring content is never hidden behind status bars or physical hardware notches:
.app-header {
padding-top: calc(12px + env(safe-area-inset-top));
}
.app-navigation-bar {
padding-bottom: env(safe-area-inset-bottom);
}
By combining CSS safe-area variables with session-based query parameter flags, you can dynamically transform a generic web application into an immersive, native-looking Android app that meets the design quality standards expected by Play Store reviewers and users alike.
Ready to ship your Android app?
Paste your PWA URL, get a signed APK and a Google Play ready AAB in minutes.
Build my app