All articles

Tutorial

How Web Push Notifications Work in TWA Android Apps

August 17, 2026 · 7 min read

The Architecture of Web Push in Packaged Android Apps

A primary objective for businesses converting a Progressive Web App (PWA) into an Android app is the ability to engage users through push notifications. Many developers assume that once they package their web application for the Google Play Store using a Trusted Web Activity (TWA), they must integrate complex native Android SDKs, such as native Firebase Cloud Messaging (FCM), and write native Java or Kotlin code. This is a common misconception.

Because a TWA runs on top of the system browser engine (typically Google Chrome), your packaged app has full access to the standard W3C Web Push API and the Service Worker API. When your app is running inside a TWA, it behaves identically to how it does in a standard mobile browser, but with the added benefits of a native-like container. This means you can use your existing web-based push notification system to deliver notifications directly to Android devices, without changing your core codebase.

How Web Push Functions on Android

To understand how this operates, we must examine the underlying mechanics. When your PWA requests permission to send notifications, the underlying browser engine processes this request. Once granted, your service worker registers a subscription with a push service (for Android and Chrome, this is Google Cloud Messaging/Firebase Cloud Messaging). The push service provides a unique endpoint URL for that specific device and browser instance.

When your backend server wants to send a notification, it packages the payload, signs it with your VAPID (Voluntary Application Server Identification) keys, and sends an HTTP POST request to that endpoint. The push service receives the request and transmits it to the Android device. The Android operating system wakes up the browser engine, which in turn wakes up your service worker to handle the push event, even if your app is not currently open on the user screen.

Web Push vs Native Push Notifications

While web push is highly effective, it behaves slightly differently from traditional native push notifications. Understanding these differences helps set expectations and ensures a smooth user experience.

FeatureTWA Web PushNative Android Push
Implementation LocationService Worker (JavaScript)Native Android SDK (Java/Kotlin)
Delivery MechanismWeb Push Protocol (VAPID)Direct Firebase SDK / APNs Integration
Background BehaviorHandled by System Browser EngineHandled directly by OS and App Process
Permission PromptsTriggered via standard Web APITriggered via native OS permission dialogues

As shown, TWA web push relies entirely on standard web technologies. This simplifies development because you do not have to maintain separate notification codebases for your website, your desktop app, and your Android application. A single implementation serves all platforms seamlessly.

Step-by-Step Web Push Implementation Flow

To successfully deliver push notifications within your Google Play PWA, you must implement the standard web push flow. Below are the key phases of this implementation.

1. Generating VAPID Keys

VAPID keys are a pair of public and private cryptographic keys that identify your application server to the push service. They prevent unauthorized servers from sending notifications to your users. You can generate VAPID keys using various libraries, such as the web-push package in Node.js:

npx web-push generate-vapid-keys

Keep your private key secure on your application backend. Secure your public key inside your frontend codebase, as it will be used when subscribing users to notifications.

2. Registering the Service Worker

Your service worker must be registered and active before you can request push subscriptions. This script runs in the background and is responsible for listening to push events from the push service. Register your service worker in your main JavaScript file:

if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/service-worker.js'); }

3. Requesting Permission and Subscribing

Before prompting users for notification permissions, ensure the timing is optimal. Do not trigger permission prompts immediately upon first load. Instead, wait for a user action, such as clicking a toggle button in an account settings panel or concluding a successful purchase transaction.

To request permission and obtain a push subscription, utilize the following JavaScript pattern:

async function subscribeUser() { const registration = await navigator.serviceWorker.ready; const subscription = await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: urlBase64ToUint8Array(VAPID_PUBLIC_KEY) }); await sendSubscriptionToServer(subscription); }

The subscription object returned by the browser contains an endpoint URL and cryptographic keys (p256dh and auth). You must send this object to your backend server and store it securely in your database, linked to the user account.

4. Handling the Push Event in the Service Worker

When your backend server sends a notification payload to the subscription endpoint, the push service routes it to the device. Your service worker receives this payload through a push event listener. Open your service-worker.js file and add the following implementation:

self.addEventListener('push', function(event) { if (!event.data) return; const data = event.data.json(); const options = { body: data.body, icon: '/images/icon-192x192.png', badge: '/images/badge-72x72.png', data: { url: data.url } }; event.waitUntil( self.registration.showNotification(data.title, options) ); });

The badge option is highly useful for Android apps. It specifies a monochrome, small icon that appears in the Android status bar when a notification is active, providing a highly integrated native feel.

5. Handling Notification Clicks

When a user taps your notification, you want them to be taken directly to the relevant view within your PWA. Add a notificationclick handler to your service worker to manage this transition:

self.addEventListener('notificationclick', function(event) { event.notification.close(); event.waitUntil( clients.openWindow(event.notification.data.url) ); });

This handler automatically closes the active notification UI and opens your application to the specific deep link or route path provided in your notification data payload.

Important Android Specifics and Troubleshooting

While the Web Push API behaves standardly inside a TWA, there are several Android platform specific details that developers must keep in mind to ensure reliability.

First, Android 13 introduced a requirement for explicit notification permissions at the operating system level. When your TWA application attempts to request push permissions via the standard web API, Android automatically displays a native OS system prompt asking the user to allow notifications. You do not need to write native code to trigger this OS dialog; the browser engine handles this bridge automatically.

Second, ensure that your Digital Asset Links are configured correctly and that your URL bar is hidden. If your TWA fails to hide the URL bar because of a misconfigured assetlinks.json file, your push notifications might be treated as coming from a generic browser tab rather than your specific application identity, which impacts user trust and branding.

Finally, respect battery optimization settings. Android actively manages background processes to save battery power. If a user does not open your application for a long period, the OS may place the application and its background service worker into a sleep state. Using standard web push protocols ensures that the system browser engine coordinates with Google Play Services to deliver notifications as efficiently as possible, minimizing delivery delays even under strict battery optimization rules.

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