The first generation of Android app blockers was, in design terms, a single switch. You set a daily budget, the app cut off the launch when the budget ran out, and the user could, at any time, open the app and disable the block. Most users did exactly that, within a week. The block was a fence, the fence had a gate, and the gate was right there.
The second generation added a PIN. Set a 4-digit code, enter it to change the rules, and the workaround is now a memory test. Better, but the user still has the PIN, and a determined user can always recover it. PIN also does not help in the moment of opening, which is the moment the block is supposed to interrupt.
The third generation added cooldown. Set a 5-minute delay between disabling the block and the change taking effect. Better still, but a frustrated user will wait 5 minutes. The cost of the workaround is just latency, not effort.
The pattern we use — and the one we think eventually wins — is what we call Scroll Debt. The cost of the workaround is not a delay, not a memory test, and not a confirmation dialog. The cost of the workaround is more of the same behaviour the user is trying to stop.
What the pattern is
When a user disables a block, our app does not just turn the block off. It records the disable as a "debt" event, marked with the app the user was trying to open. To clear the debt, the user has to perform a real action — by default, walk a configurable step count. The walk does not happen inside our app, and there is no shortcut inside our app that grants the steps. The hardware step counter on the phone is the only source of truth.
The first time a user disables a block, the debt is one step-cost — say 1,000 steps, the same as the daily unlock budget. The second disable in a 24-hour period doubles the cost. The third doubles again. After four disables in a day, the cost is too high to clear, and the user has to wait until the daily reset.
This is the part that changes behaviour. The cost of the workaround is not a delay the user can wait out, not a PIN the user can recover, and not a switch the user can flip. The cost is a real, physical action that takes 15-30 minutes of walking, with a multiplier that punishes repeat attempts.
Why it works
Most screen-time interventions are about the first time the user opens the app. They work for users who are aware of the pattern and want to break it. They do nothing for users whose problem is impulse. Scroll Debt targets the next time the user tries to work around the block. That is the moment of maximum frustration, and the moment when the user is most likely to be honest with themselves about the cost of the behaviour.
It also works because the cost is a real action in the real world, not a number in the app. The user cannot shake the phone, cannot close the app and reopen it, cannot type a different PIN, cannot wait. The cost is walking, and walking takes time and effort.
The third reason it works is the multiplier. A first disable is forgivable — a 1,000-step cost is a 15-minute walk. A second disable in a day is expensive — 2,000 steps, 30 minutes. A third is forbidding. The pattern makes the user choose between two things: actually wanting to open the app, and the cost of admitting that they did. Most of the time, the second is larger.
Where the pattern is wrong
The pattern does not work for users who cannot walk. A person with a mobility impairment, a person at a desk for ten hours, a person who is sick — all of these users will rack up debt they cannot clear. The apps that ship Scroll Debt have an accessibility setting that disables the gate, and that is the right call, but it is also a single switch that turns the whole feature off.
The pattern does not work for parents trying to gate their kid's phone. The kid is exactly the kind of user who is going to try to game the step counter, by shaking the phone or by walking laps around the house. The pattern works because the cost is real effort, and the kid has less of a stake in their own focus than the adult does.
The pattern does not work for "I need to send a single text". A user with a debt they cannot clear, who needs to use a gated app for a single urgent action, has no graceful way out. The apps that ship Scroll Debt have a one-time emergency override, but again, that is a switch that turns the whole feature off.
The implementation, in 50 lines
The state we keep is, per gated app, a disable_count and a debt_steps. The disable count is reset at midnight. The debt steps are the cumulative cost of disables in the current day, plus the daily unlock budget. To clear the debt, the user has to walk debt_steps minus the steps already walked today, with the multiplier applied.
fun debtCost(disables: Int): Int {
val base = 1000
var cost = base
for (i in 0 until disables) cost *= 2
return cost
}
fun canOpen(app: String, stepsToday: Int, disableCount: Int): Boolean {
val owed = debtCost(disableCount)
return stepsToday >= owed
}
The read of the step counter is the same sensor call as the walk-to-unlock gate. The state is local to the device. There is no account, no cloud, no telemetry.
The full app is StepShield Pro on Google Play: https://play.google.com/store/apps/details?id=com.appblocker.screentime.pedometer.workout.fitness.coaching. The privacy page is at nexusdriftstudio-a11y.github.io/steplockprivacy.html.
Top comments (0)