Silent Pushes Are Inflating Your DAU and Retention
Silent push notifications can wake your app and fire session events with no human present. How one app's retention stopped tying out to DAU, and the checks to run.

Silent push notifications can wake your app in the background and, if your instrumentation is keyed to app launch instead of the app coming to the foreground, fire session events with no human anywhere near the phone. Every analytics tool downstream then counts a user as active who never opened the app. We watched this break a consumer mobile app's entire analytics stack, in Amplitude and PostHog at the same time, and the first symptom was subtle: retention stopped tying out to DAU and MAU.
The short answer: the app was awake, the user was not
On iOS, a background push (content-available: 1, no alert, no sound, no badge) tells the system new data is available, and the system wakes or launches the app in the background to process it. That behavior is by design; Apple's background update documentation covers when and how the system delivers these wakes. The app runs real code during that window. If that code path, or the analytics SDK configuration around it, emits a session start or any tracked event, your analytics now contains activity from a device sitting in a pocket.
This app sent silent pushes as part of normal content delivery. Each delivery woke some fraction of the installed base, the instrumentation treated the wake as an app open, and a session-start event went out. No crash, no error, and nothing visibly wrong in any dashboard. The numbers just drifted away from reality, one push at a time.
How it was noticed: retention did not tie out
The tell was internal inconsistency. DAU and MAU said one thing about how often people came back; the retention curves said another. Those metrics are computed from the same underlying events, so when they disagree, something in the event stream is lying. That is the tie-out instinct in one sentence: metrics that share a source must reconcile, and when they refuse to, the source is contaminated.
This is worth pausing on, because "retention does not match DAU" is the kind of discrepancy teams learn to live with. It gets blamed on definitions, on timezone boundaries, on tool differences. Sometimes those explanations are even right. The only way to know is to trace individual users through the raw events, the same way we handled a subscription app whose trial events silently never reached its attribution platform. In both cases, the per-user trace turned a vague discrepancy into an exact mechanism in a day.
Why Amplitude and PostHog both got hit
Neither vendor did anything wrong, and that is the uncomfortable part. Analytics tools define activity by the events you send them. Amplitude's session tracking documentation describes mobile sessions as beginning when the app moves to the foreground, with events arriving within the timeout window extending the session; it derives Start Session and End Session from the event stream it receives. PostHog's session documentation starts a new session on any event after 30 minutes of inactivity. Feed either tool events from a background wake and it will dutifully build sessions around them.
So the bug lives in the seam: the app-side decision about when an event deserves to exist. Multiple tools agreeing with each other is not evidence the data is right. If they share a corrupted input, they will agree on the corruption.
How to check your app this week
- Log the application state (foreground, background, inactive) as a property on every tracked event for a few days, then count events by state. Background events that are not deliberately expected are your phantom activity.
- Pull sessions with exactly one event and no screen view. Human sessions almost always render something.
- Plot session starts by hour and overlay your push send schedule. Phantom sessions cluster around send times, including hours when your users are asleep.
- Compare session-start counts against foreground transitions or screen-view counts over the same window. The gap is your inflation.
- If retention, DAU, and MAU are computed in different tools, reconcile a single cohort across them by user ID. Disagreement locates the contamination.
The fix is a state check, not a rewrite
Key your session and activity instrumentation to foreground transitions, not to launch or wake. On iOS that means checking the application state before tracking in any code path a background wake can reach, and keeping analytics calls out of the silent-push handler entirely unless you deliberately want to measure deliveries (in which case, track them as a separate, clearly named event that your DAU definition excludes). Then annotate the fix date in every affected tool as a permanent series break: your historical DAU, sessions, and retention were inflated, and comparing across the break will read as a product regression that never happened.
If your metrics refuse to reconcile
Metrics that share a source and still disagree are the most reliable smoke signal in analytics. We run fixed-scope tie-out audits that trace individual users across your event chain, find the mechanism, and hand your engineers the specific fix. If your retention has never quite matched your DAU, that is usually not a definitions problem.
Related Resources

42% of Your Email Clicks Might Be Bots. Here's How to Tell
Security scanners click every link in your emails before humans do. How bot clicks inflate click rates, corrupt segments and A/B tests, and the filter that fixes it.

The Traffic Drop That Wasn't: GA4 Double-Counted Pageviews
A site relaunch appeared to cut pageviews in half. The real story was years of double-fired GA4 tags. How to spot duplicate tagging and read a before/after honestly.

Google Consent Mode v2: When Your Setup Quietly Deletes Data
Basic consent mode implementations discard declined visitors forever, and most properties never qualify for modeling. The thresholds, the traps, and the checks.