There is no event for swiping an app away

We had a metric meaning "the app vanished during a video". It took three analyses to work out that it meant at least three different things.

· The Wordmere team · 5 min read

Of the rewarded videos our players started one week, well under half ended with the app still running. The rest were followed by a cold launch. We had an event for it, and the event was called rewarded_ad_lost.

The name was doing a lot of work it had not earned.

First reading: we are crashing

The obvious interpretation is that the app is dying under the ad. The timing supported it — most of the losses happened within thirty seconds of the video opening, with a median around ten. We had a plausible mechanism too: the game renders a 3-D scene behind the UI, and that scene kept rendering underneath every full-screen ad, because the hook that pauses it only reacted to a real background transition.

A memory-hungry renderer running under a video player on a phone is a good story. We wrote a fix, which pauses the scene whenever an ad goes up.

The fix was worth shipping. The story was wrong.

Second reading: people are leaving on purpose

Crashlytics had nothing. Not a reduced number of reports — nothing at all, for a failure supposedly affecting a large share of our ad views.

That is explicable: if the operating system kills your process for using too much memory, that is not a crash and no crash reporter will see it. But it meant the crash theory had no independent evidence, so we went back to the raw event stream and looked at what the sessions actually did.

Most of the lost videos were followed by a background transition and a relaunch within a minute. A large share of those had our own explicit backgrounding event attached. That is not a process being killed. That is a person leaving the app, waiting out the video they did not want to watch, and coming back.

So we rewrote the conclusion: around a third of full-screen ads were being escaped by players quitting out of them.

The correction

When this went to the founder, his reply was that he did not think all of these would be crashes. He was right, and more usefully he was right about a subset I had been confident about.

I had split the losses into "left on purpose" and "hard deaths", putting anything with no leave signal in the second bucket. More than a hundred interstitial losses had no leave signal at all, and I had called those real crashes.

They were not. On iOS, swiping an app away from the app switcher does not produce a background transition. The app goes to inactive and is then terminated. inactive is the state you also get for a phone call, a notification pulled down, or Control Centre — it is not a lifecycle event you would normally log, and we were not logging it.

So a deliberate force-quit and an out-of-memory kill look identical in our data. Both are: last event, then nothing, then a cold start.

Absence of a leave signal is not evidence of a crash. On iOS it is the expected shape of the most deliberate exit a player can make.

What settled it was looking at who those sessions belonged to. Almost all of the supposed hard deaths came from players who also quit ads in ways that did leave a signal. People who had never once quit an ad produced almost none of them. A behaviour that clusters in the players who demonstrably do that behaviour is that behaviour, not a crash that happens to prefer them.

Third reading, and the one that stuck

A later analysis moved it again, and this is the version we now believe.

On the newest iPhones the pattern is much tighter than "a person decides to skip". The app leaves the foreground a median of about three seconds after the video opens — too fast to be a decision about content nobody has seen yet — then cold-starts a few seconds later, and most of the time the player immediately taps the same video again. Those players come back the next day at a higher rate than average, which is not what people who are sick of your ads do.

That is not skipping. That is the player force-quitting an app that has gone unresponsive behind an ad that never appeared, and then trying again because they wanted the reward. The share doing it had been climbing with every build since the summer.

Three readings, three different mechanisms, one event name.

What we still cannot separate

We have not closed this. The data still cannot distinguish a force-quit from a memory kill, because iOS genuinely does not tell you, and we should be honest that the third reading rests on timing and on return behaviour rather than on a signal that says what happened.

Two things would fix it and we have shipped neither. Logging the inactive transition itself would at least mark the sessions where the app was alive at the moment it disappeared. MetricKit reports memory-limit terminations after the fact, which is the only first-party way to confirm the kills. Until one of those is in, "the app went away" remains a category rather than a cause.

The scene-pause fix stayed in, incidentally. It is a reasonable thing to do for battery and heat regardless of whether it fixes anything else, and we removed the stability claim from the release notes once we knew it was not one.

Two signals that will mislead you

If you are instrumenting this on iOS, two specific traps cost us time.

Firebase's user_engagement event looks like a session-boundary signal and is not. It fires on every screen change, so a session full of them tells you nothing about backgrounding.

And the generic uncaught-exception event that crash reporting SDKs expose effectively never appears for real devices in our data. If you are watching it as a safety net, you are watching a line that stays at zero through every category of failure described above.

Name the event for what you saw

The mistake was upstream of all the analysis, and it was the name.

rewarded_ad_lost encodes a conclusion. Everyone who read it, including me, started from "we lost the app" and went looking for the cause of a loss. Had it been called something flatter — we started a video and never observed it ending — the first question would have been what else could produce that, which is the question that actually took three attempts to ask.

Name events after the observation. Keep the interpretation in the analysis, where it can be wrong out loud and corrected, instead of baking it into a string that every future reader will inherit.