Technical
Managing Start URL Query Parameters and TWA Caching
September 20, 2026 · 7 min read
Tracking App Launches with Custom Query Parameters
When deploying a Progressive Web App to the Google Play Store using a Trusted Web Activity, businesses and developers often need to track users arriving specifically from the Android application. The most straightforward approach is adding a tracking parameter, such as utm_source=android-app, to the start URL configured in your Trusted Web Activity wrapper.
However, adding query strings to the entry point URL introduces critical service worker cache matching failures. If not handled correctly, this tracking parameter can prevent the offline functionality of your app, causing it to display the default browser offline screen when launched without an active internet connection. Developers must understand how to configure these parameters properly and adjust their service worker fetch listeners to preserve offline capabilities.
The Core Problem: Cache-Busting Query Strings
Service workers cache files by mapping a request URL to a cached response. By default, the Cache API uses strict string comparison for URLs. If your service worker caches the clean homepage, but the Trusted Web Activity launcher opens the homepage with a tracking query parameter appended, the service worker treats this as an entirely different asset.
Because the query string does not match any entry in the cache, the service worker bypasses the local cache and attempts to fetch the resource over the network. If the user device has no network connection, the network request fails. The user is then presented with a network error page, defeating the entire offline utility of the Progressive Web App. To avoid this, developers must ensure their service worker caching strategy accounts for query parameters dynamically.
Implementing ignoreSearch in Service Worker Fetch Handlers
To resolve the cache-busting behaviour of query parameters, you must modify your service worker fetch handler. The Cache Storage API supports an options object inside the match method. Setting this parameter instructs the browser to ignore the query string when looking up cached resources.
When the browser performs the lookup, it strips the search query parameters and matches the base URL path. This ensures that the launch URL successfully matches the cached asset, allowing the application to load offline instantly. Developers must apply this option to both the service worker activation step and the fetch handler to guarantee complete compatibility.
How to Write the Fetch Listener with Search Ignoring
To implement search ignoring, modify the match method inside your service worker. The fetch listener should inspect incoming requests and apply the search ignore configuration to prevent routing failures. This ensures that any incoming tracking parameter is bypassed during cache verification.
The following example illustrates how the fetch listener should look when processing incoming requests with query parameters:
self.addEventListener('fetch', function(event) { event.respondWith(caches.match(event.request, { ignoreSearch: true }).then(function(response) { return response || fetch(event.request); })); });
By adding this configuration, the service worker matches the incoming request to the clean cached file, while still allowing your external analytics tools to read the tracking parameter from the window location object on the client side.
Removing Tracking Parameters from the Browser Address Bar
While query parameters are highly effective for initial tracking, leaving them visible in the address bar is not ideal. It can clutter the user interface and cause issues if users copy and share the URL, which would mistakenly mark web-based visits as Android app traffic. To prevent this, you should process and remove the query parameter from the address bar immediately after the application loads.
Using the History API, you can rewrite the browser path without triggering a page reload. This operation preserves the analytics data but cleans up the URL for the user. It is best to execute this script as early as possible during the application boot cycle.
The following logic handles this cleanup process on page load:
if (window.location.search.includes('utm_source=android-app')) { const cleanUrl = window.location.pathname + window.location.hash; window.history.replaceState({}, document.title, cleanUrl); }
This script checks if the tracking parameter is present, extracts the base path and hash, and updates the address bar without affecting the active session or causing performance overhead.
Comparing Detection and Tracking Methods for Android TWAs
While query parameters are widely used, developers can also leverage alternative methods to detect when their application is running inside a Trusted Web Activity wrapper. The table below compares the most common tracking methods, detailing their implementation complexity and impact on caching.
| Method | Implementation Complexity | Service Worker Impact | Reliability |
|---|---|---|---|
| Query Parameters | Low. Simply append to launch URL. | High. Requires search parameter ignoring in cache. | Excellent. Works across all browser versions. |
| Custom User-Agent | Medium. Requires customising native launcher. | Low. No impact on cache URL keys. | Good. Useful for server-side routing. |
| Referrer Header | None. Automatically sent by Android. | Low. Standard HTTP header validation. | Variable. Can be stripped by strict configurations. |
Best Practices for Clean Analytics Integration
First, maintain separate configurations for your web manifest and your native Trusted Web Activity launcher. Your web-accessible manifest should keep a clean entry point without tracking parameters, ensuring that desktop and standard mobile browser installs do not pollute your native app data. Only append the tracking query parameters within the native Android build configuration.
Second, ensure that your analytics software is initialised before you clean up the URL with the History API. If you rewrite the path before your analytics script runs, the tracker will miss the entry parameter and classify the session as organic web traffic. Load your analytics packages early, trigger the pageview event, and only then execute the history replace state cleanup script to ensure perfect data accuracy.
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