Make Every Action Safe to Repeat
Systems & Architecture · forms, errors, data integrity
Updated 2026-08-04
- Assume every submit will be sent twice. The connection flickers, the response is lost, the user taps again, and two identical requests are now in flight with no way for the server to tell them apart.
- Give each attempt a stable identifier, an idempotency key, generated before the first send rather than on each retry. The server then recognizes the repeat and returns the original result instead of performing the action again.
- Disable the control the moment it is pressed, and keep it disabled until the outcome is known. This stops the honest double tap, though it does nothing about a retried network request.
- Treat these as the actions that must never happen twice:
- Payments, refunds, and transfers.
- Sending a message, invite, or notification.
- Creating an order, ticket, or record.
- Any action that consumes a quota or a credit.
- Make the lost response case survivable. When a request times out, the interface does not know whether it succeeded, so offer Check status rather than a plain Try again that risks a second charge.
- Never generate the identifier from a timestamp alone. Two devices can produce the same one, and the two actions cancel each other in a way nobody will diagnose quickly.
- Show the result of the repeat as the original result. A user who submits twice should see one order and one confirmation, not an error explaining that they already did this.
- Extend the same protection to links and deep links. A confirmation URL that a mail client prefetches will be visited before the user ever clicks it.
An interface that is safe to press twice is the only kind that survives a real network.
Related guides