Web push is what turns a PWA install into an audience. Once a user installs your app and grants notification permission, you can send a message that opens the app, which routes through your tracker to the offer again, with the original click, campaign and sub IDs still attached. Done well, push adds a second, third and tenth visit to a click you paid for once. Done badly, it gets your app uninstalled and your domain reported within a week.
This article explains how web push works inside an installed PWA, what Android and iOS allow, when and how to ask for permission, how subscribers are attributed to the click that created them, how to read subscription failures, and how to send pushes that earn.
Quick answer
- Mechanism: service worker plus a push subscription from the browser's push service. Your server sends to that subscription; the service worker shows the notification; a tap opens the app.
- Android: Chrome and Samsung Internet, permission from a tap, notifications under the app's name and icon with the sending domain in the header.
- iOS: 16.4 and later, only for home-screen web apps, permission from a tap inside the installed app.
- Ask: on the first launch of the installed app, never on the browser tab before install.
- Attribution: the subscription is sent to the tracker with the click ID, so subscribers belong to campaigns, sources and sub IDs.
- Cadence: at most one a day, localized, relevant to the app the user installed.
How web push works
Three parties are involved:
- The service worker your PWA registers. It runs in the background for your origin, even when no page is open, and it has a
pushevent handler that shows the notification and anotificationclickhandler that opens the app. - The browser's push service. On Android Chrome this is Firebase Cloud Messaging; Safari uses Apple's push service. When the user grants permission, the browser creates a subscription: an endpoint URL at the push service plus two keys that encrypt messages to this one device.
- Your server. It stores the subscription and, when you send, encrypts the payload and posts it to the endpoint, signed with your VAPID key pair so the push service knows the sender is legitimate.
The payload is small: title, body, icon, optional image, a click URL and a tag. The service worker shows it with the app's name and icon. When tapped, the app opens at the click URL.
Permission state has three values: default (not asked yet), granted and denied. A denied state is sticky until the user changes it in settings, which is why the moment and wording of the request matter so much.
Android
Chrome installs a PWA as a WebAPK, a real app entry in Android. The notification permission belongs to that app: Settings, Apps, your app's name, Notifications. Chrome's site permission for the domain mirrors it, so they are two views of one switch. On Android 13 and later the permission dialog is the OS dialog that names the app.
Notifications show the app's name and icon, and the header includes the sending domain. Chrome adds that line for every web push so the user can see which site is behind the message; no manifest setting, header or service worker option removes it. Choose the domain accordingly. A PWA on app.brandname.com reads as a brand; one on track7.someexample.net reads as tracking.
Samsung Internet behaves like Chrome for push. Firefox for Android supports web push but is a small share of affiliate traffic. In-app browsers inside Facebook, Instagram and TikTok cannot install or subscribe, so the PWA page needs to open itself in Chrome first.
iOS
Apple added web push for home-screen web apps in iOS 16.4. The rules:
- The app must be added to the home screen. A page in a Safari tab cannot subscribe.
- Permission must be requested from a user gesture inside the installed app.
- Notifications show the web app's name and icon, with no URL line.
- Each home-screen app has its own storage, so an app added twice is two separate installs with separate subscriptions.
Because iOS has no appinstalled event and no install prompt, the first standalone launch is both the install signal and the right moment to ask for permission. Expect lower opt-in than Android, mostly because fewer users complete the add-to-home-screen step in the first place.
When and how to ask
The permission prompt is the most expensive click in the funnel. Browsers only show it during a user gesture, and Chrome treats requests that fire on page load as abusive, showing a quiet indicator instead of the dialog. Asking in the browser tab before installation, which many older PWA scripts do, wastes the one chance you get and leaves the installed app without permission.
The pattern that works:
- Install first. Let the user install from your page without any permission dialogs.
- Gate the first launch. When the installed app opens for the first time, show a short screen in the app's own design: the app name, one line on what notifications they will receive, and a Continue button.
- Request on the tap. The Continue tap calls the permission request. The OS or browser dialog appears.
- Subscribe immediately. If granted, create the push subscription and send it to the tracker with the click ID, then continue to the offer. If dismissed, continue to the offer and ask again on a later launch, at most once more.
- Retry silently on every launch. If permission is granted but the subscription did not reach the server (slow network, push service hiccup), the next launch should re-send it. Without this, one failed request loses the subscriber for good.
BATracker's PWA engine implements exactly this sequence: the gate appears on the first launch of the installed app while permission is undecided, at most twice per install, the subscription is sent on the Continue tap, and every later launch re-sends it within a short time cap so the redirect to the offer is never delayed. The browser-tab request after install was removed because browsers ignore it.
Attribution
A push subscriber is worth more when you know which campaign bought them. The tracker baked a click ID into the app when the PWA page was served, so the installed app knows its click. When the app subscribes, it posts the subscription together with that click ID. The tracker then stores the subscriber with the click, its campaign, traffic source, language and user agent.
What that gives you:
- Cost per subscriber per campaign and per zone. Compare it to cost per install and cost per conversion.
- Targeting. Send a push to subscribers of one app, optionally filtered by language.
- Closed loop. The push's click URL opens the app with
launch=1. The app calls the tracker's launch endpoint with the click ID, which records the launch and redirects to the offer chosen for that click, tokens filled. A conversion that follows lands on the original campaign.
In BATracker the app's Push tab lists active subscribers by language, the pushes sent with sent and failed counts, and a "Missed subscriptions" card that explains why a user who installed did not become a subscriber.
Reading subscription failures
An install without a subscription has one of a few causes. Instrument them; guessing is expensive.
| Reason | What happened | What to do |
|---|---|---|
| Permission not granted | User dismissed or denied the dialog | Review the gate wording and timing; do not ask more than twice |
| Push service refused | Browser could not register with its push service, common on devices without Google services or on flaky networks | Retry on next launch; accept some loss on such devices |
| Service worker not ready | Subscription attempted before the worker was active | Engine should wait for the worker, then retry |
| Timed out | Push service did not answer within the cap | Retry on next launch |
| Unsupported | No push support in this browser context, for example an in-app browser | Open the page in Chrome or Safari first |
BATracker records these reasons per install and shows them in the Push tab, so a campaign with many "permission not granted" entries tells you to fix the gate, while many "push service refused" entries point at the device mix of that traffic source.
Sending pushes that earn
Content
A push has a title (keep it under 40 characters so it is not truncated), a body of one or two short lines, the app's icon, an optional large image on Android, and a click URL. The default click URL should launch the app so the tracker routes the user to the offer with attribution. A direct offer URL skips attribution and should be used only when you intend that.
Write about the app the user installed. A sports app sends match reminders and odds; a casino app sends bonus and tournament messages; a dating app sends activity prompts. Fake system alerts, "missed call" bait and messages pretending to be from the OS or a bank get apps uninstalled, violate ad network policies and, on Android 13 and later, lead users to block the app's notification channel entirely.
Timing and frequency
- Match the offer's rhythm: pre-match for betting, evenings for casino and dating, mornings for finance.
- Start at one push a day or less. Measure uninstalls and permission revocations after each send before increasing.
- Spread sends across the subscriber's local evening rather than one global timestamp when the audience spans time zones.
- Do not send to a subscriber who has not opened in weeks more than once a week; dormant subscribers are the most likely to revoke.
Segmentation
Segment by language at minimum. A German subscriber receiving English copy is a lost subscriber. BATracker stores the language per subscriber and lets a push target one or more languages; the template builder also supports localized app listings so the install page and the pushes match.
Segment by campaign where offers differ. Because subscribers carry their campaign, you can send offer-specific pushes to subscribers acquired for that offer rather than one blast to everyone.
Measuring
Track per push: sent, failed (expired subscriptions are removed automatically), launches within a few hours of the send, and conversions and revenue attributed to clicks that launched after the send. Compare revenue per push per thousand subscribers across copy variants. Watch subscriber count the day after each send; a drop larger than normal means the message cost you more than it earned.
Compliance
Web push requires consent by design: nothing is sent without the permission dialog. Keep that consent honest:
- The gate text should describe what you will send.
- Respect platform policies for the traffic sources you run; several ad networks have specific rules about push consent on landers they send traffic to.
- Keep sending domains and app names consistent with the offer and avoid impersonating brands you do not represent.
- Gambling and dating advertising rules by country apply to push content as they do to ads.
Setting it up in BATracker
- Create or open a PWA App, confirm it is active, and enable push on the Push tab. Push keys are generated per app.
- Set the first-launch gate text and the Continue label in the app's labels, per language if you run several.
- Install the app on an Android phone from a campaign link, open the icon, tap Continue, grant permission. Within a minute the Push tab should show one active subscriber attributed to your click and campaign.
- Compose a test push: title, body, optional image, click URL left at the default launch URL. Send it to yourself and confirm the notification opens the app and lands on the offer.
- Set your sending plan and review the Missed subscriptions card after the first day of traffic.
Domain choice matters for the Android header line, so read PWA domain rotation before you pick the domain you will install thousands of apps from. For the install funnel around push, start with the complete PWA guide, and for the metrics, how to track PWA installs and launches.
Bottom line
Push is the reason a PWA install is worth more than a click. The mechanics are simple: a service worker, a subscription, a message. The results depend on three decisions: ask for permission on the first launch from a real tap and never before; attribute every subscriber to the click that paid for them so you can buy more of the right traffic; and send messages that belong to the app the user chose to install, at a frequency the audience tolerates. Instrument failures and uninstalls, because they tell you faster than revenue does whether you are earning or burning.
