Icemoon ← All posts

Technical

Typing like a person: rhythm, errors and corrections

August 1, 2026 · 7 min read

Swipes get scrutinised because they are visible. Typing gets a fixed delay between characters and no further thought — which is odd, because typing produces far more data points per action than any gesture does.

What constant-interval typing looks like

The default in most automation is to send characters at a fixed rate. Sixty milliseconds, sixty, sixty. A twenty-character string produces nineteen identical intervals.

Nothing about human typing works that way. Inter-keystroke intervals vary by an order of magnitude within a single word, and the variation is not random — it has structure that is well documented, because keystroke dynamics have been studied for decades as a biometric.

The structure worth knowing

Digraph timing

The gap between two keystrokes depends on which two keys. Letter pairs you type constantly — th, er, in — come out fast because they are motor patterns rather than individual decisions. Pairs that need the same finger to move twice, or an awkward stretch, take noticeably longer.

Reproducing full digraph tables is overkill for most purposes. The useful takeaway is simpler: intervals should vary per character pair, not be drawn independently from one distribution.

Word boundaries

People pause at the ends of words more than inside them, and pause longer before words they had to think about. A password typed from memory has a very different profile from a sentence being composed.

The long tail

Most intervals cluster in a narrow band. A few are enormous — someone looked away, checked a message, reconsidered a word. A distribution with a fat tail models this far better than uniform jitter around a mean.

This is the same shape that shows up in the gaps between actions, and for the same reason: attention is not uniform.

Cheapest meaningful change: stop drawing every interval from the same narrow range. A mixture — mostly short intervals, occasionally a much longer one — is closer to real than any amount of fine-tuning around a constant.

Errors, and why they are optional

Real typing contains mistakes and corrections. Backspaces, retyped characters, occasionally a word deleted and rewritten.

Simulating this is tempting and mostly not worth it. Two reasons.

First, errors interact badly with correctness. A flow that mistypes a login and corrects it has introduced a failure mode for a cosmetic gain. If the correction logic is wrong, or the field autocompletes mid-error, you have broken the flow to look more natural.

Second, plenty of real input has no errors in it. Short strings, autofilled values, anything typed carefully. Error-free typing is not itself suspicious.

If you do model errors, keep them to longer free-text entry, keep the rate low, and make the correction immediate — people notice a typo within a character or two, not five words later.

The iOS-specific part

Typing on a phone is not typing on a keyboard, and several things only exist on mobile.

The keyboard has to be up. Text goes in through the real iOS keyboard, which means it has to appear first — and it does not always appear when you expect. A flow that types into a field before the keyboard is ready loses characters.

Fields fight back. Phone numbers reformat as you type. Card fields insert spaces. Some fields switch layout mid-entry — a numeric pad appearing where a letter keyboard was. Automation that assumes the field will accept what it sends, unchanged, breaks on all of these.

Autocorrect and predictive text. iOS may substitute a word you did not type. For free text this is realistic and harmless. For a username or a password it is a silent corruption, and the flow proceeds happily with the wrong value.

Layout changes cost time. Switching from letters to numbers to symbols takes a person a visible moment. Sending those characters at the same rate as adjacent letters is one of the clearer tells in mobile typing.

What actually matters, ranked

PropertyNaiveBetterWorth it?
Interval distributionConstantLong-tailed mixtureYes — cheap, large effect
Keyboard readinessType immediatelyWait for the keyboardYes — correctness, not realism
Layout switch costSame rate throughoutExtra time at switchesYes — clear tell, easy fix
Verify what landedAssume it workedRead the field backYes — catches autocorrect
Word-boundary pausesUniformLonger at boundariesModerate
Digraph-specific timingOne distributionPer-pairDiminishing returns
Errors and correctionsNoneOccasional, immediateUsually not — risk exceeds gain

Notice that two of the highest-value items are about correctness rather than realism. Waiting for the keyboard and reading back what landed will save you more runs than any timing model — and a flow that silently typed the wrong thing is worse than one that obviously failed.

Smart typing

This is why Icemoon has a distinct smart typing action rather than a single "type text" primitive: the awkward cases — keyboard readiness, reformatting fields, numeric layouts, verifying what actually landed — are handled as part of the action instead of being your problem to discover one broken flow at a time.

The timing model underneath uses the same principle as the gesture layer: generate fresh from a distribution rather than replaying a constant.

Typing that goes through the real keyboard

Icemoon drives stock iPhones from your Mac — real touch events, the device's own keyboard, and gestures generated fresh every time. No jailbreak.

Start free trial
All posts Home Install guide MCP server