Measura
All posts
3 min readsdk, engineering

Why the Measura SDK waits for Wi-Fi by default

Most analytics SDKs transmit the moment they have a connection. Ours does not, and the default surprises people. The reasoning is about what mobile data actually costs the people using your app.

Measura Engineering


wifiOnlyMode defaults to true in the Measura SDK on every platform. Until the device sees Wi-Fi, events accumulate locally instead of going out over the network.

This is the single most surprising default we ship, and the one most likely to be reported as a bug during integration. It is deliberate.

The reasoning

Analytics SDKs are mostly built by teams operating where mobile data is effectively free and effectively always available. Under those assumptions, transmitting immediately is obviously correct: the data costs nothing, the connection is reliable, and lower latency is strictly better.

Neither assumption holds across much of the market we build for. Prepaid data is bought in small bundles and rationed. A background process that quietly consumes it is not a minor inefficiency, it is a cost passed to the user, and users notice which apps drain their bundle.

Attribution data is also not latency sensitive in the way product analytics can be. An install event that arrives four hours late attributes exactly as correctly as one that arrives in four seconds, because matching runs against the click timestamp rather than the arrival time. We are spending a user's money to buy immediacy that the product does not need.

So the default is: hold events, transmit when the connection is free.

What happens while it waits

Waiting is only acceptable if nothing is lost, so the queueing path carries most of the engineering weight.

Events go to a persistent store on disk, not just memory. On Android that is SQLite, which survives process death and device restart.

The queue holds ten thousand events. Past that, the oldest are dropped rather than the newest, so a device that has been offline for a very long time keeps its most recent and most relevant activity.

Events are batched fifty at a time and gzipped before transmission, so when the send does happen, it is compact.

Three other gates defer transmission alongside the Wi-Fi check: no connectivity at all, an unresolved API key, and low battery. That last one holds transmission below fifteen percent battery by default, on the same reasoning as the data cost. A background upload is not worth someone's remaining battery.

In every one of those cases the event is persisted rather than dropped. Deferral and loss are different things, and the distinction is the whole design.

When it fails anyway

Networks fail mid transmission. The SDK retries up to five times with exponential backoff, starting at one second.

The backoff doubles without a ceiling. If you are debugging a device that has been offline a long time, that is why the gap between retry attempts grows so quickly.

When retries are exhausted, the batch goes back to the persistent store rather than being discarded, and it goes out on a later session.

Turning it off

If your app serves a market where mobile data is cheap, or you need events promptly for an operational reason, set wifiOnlyMode to false at initialisation. The setting is per app and takes effect immediately.

We are not claiming the default is right for everyone. We are claiming it is the right default, because the cost of getting it wrong is asymmetric. An app that transmits too eagerly costs its users money silently. An app that transmits too conservatively shows up as delayed data in a dashboard, which someone notices and fixes in one line.

Defaults should fail in the direction that is easy to detect and cheap to correct.

Questions about any of this?

We would rather have the argument than have you take our word for it.