Shipping & Infra4 min read

Half my installs left at the login screen, and the server already allowed anonymous reads

Of 468 devices that opened the app, only 164 started walking. The biggest drop was the auth gate, and cancel events were firing six times per install.

#reality-check#analytics#android#ios
Concept diagram: funnel from first_open 468 to walk_started 164 with the login gate between them
A diagram summarising the post.

I have an app where you claim territory by walking with GPS. It is the only app in my fleet with real retention: of a mature cohort of 65 people measured from their first walk, 10 (15.4%) were still walking a month later.

But too few people got that far. Here is the funnel, counted per install.

first_open            468
auth_shown            333    <- 135 lost
auth_method_tapped    297
auth_succeeded        193    <- 104 lost
walk_started          164
walk_ended            118
territory_claimed      83

What does your app demand before anyone experiences its value?

Six cancels per install

Breaking down auth_failed by reason:

  • cancelled — 360 events across 59 devices, an average of six per install
  • Apple AuthorizationError#1000 — 144 across 23 devices, same character
  • Google timeout 17 · gave_up_waiting 11 · abandoned_process 8 — these are genuine technical failures

Nobody hesitated once and moved on. They opened and dismissed the sheet six times, then left.

The whole platform gap lives in this stretch too.

Per install Android iOS
first_open 288 180
auth succeeded 112 (51%) 81 (71%)
walk_started 77 (27%) 87 (48%)

Android is half of iOS. The dominant sign-in method differs, and the timeout-family failures cluster there.

People who reached the walk were fine

72% of those who start a walk finish it. And as above, 15% are still walking a month later.

The product is not the problem. The doorway is.

Then the server surprised me

Deferring login requires drawing the map without an account. If that is not possible, this is a large project.

I queried the row-level security policies.

territories  SELECT  {anon, authenticated}
users        SELECT  {anon, authenticated}

Already open. The map query function allowed anonymous execution too. Calling it directly with the anonymous key returned polygons, names, colours and country codes with no session at all.

The server needed no changes. The gate existed in exactly one place: a branch in the client's root view.

A fork in the road

There are two ways to let people in without an account.

Anonymous sign-in is smooth, and you can promote it to a real account later.

Local storage handed over at sign-in time is more work.

Which would you take?

I took the second. The auth database here is shared across many apps, and the signup trigger fans a profile row out to every app's schema. Creating anonymous accounts would wreck per-app metrics that are already polluted by exactly that. I chose measurability over smoothness.

What changed

  • The root branch sends signed-out users to the map. I also removed the observer that bounced users back to login on sign-out — leaving it rebuilds the wall you just removed.
  • An in-progress walk is checkpointed to disk under a fixed sentinel owner.
  • Login is requested only at the moment you try to save territory. At that point the function returns without touching the phase, so calling it again after sign-in resumes the exact route already walked.
  • Once sign-in resolves, sentinel-owned records are handed to that account.

The order is inverted. You walk, you see the shape you drew, and then it asks who you are.

Self-check

  • How many gates does a new user pass before their first taste of value?
  • Have you counted drop-off at those gates per install — not per user?
  • Are you assuming removing a gate needs server work? Have you actually read the policies?

The honest part

I do not know if it works yet. It went to review today, and the verdict metric is the first_open → walk_started ratio. Baseline is 27% on Android and 48% on iOS; I re-measure in 28 days.

The Android timeout failures are also still there. Fewer people pass through that door now, so the blast radius shrinks — the bug does not.

Count attempts per install in your own auth failure events. Near 1 means people decided. Six means something is holding them.

Related