I'm building a browser-based AI photo editor with a no-signup editing flow.
One of the first design choices was deciding what should count as usage.
The tempting implementation is simple:
User clicks “Edit” -> decrement quota
But a click is only intent. It is not yet an accepted unit of work.
A request can fail validation, fail before the upload is usable, or be rejected by the service before a job exists. Counting any of those as AI usage turns product or reliability friction into a user penalty.
For anonymous capacity controls, I use a different unit:
One successfully accepted job consumes one unit of anonymous quota.
The server validates and authorizes the request, then creates the job and records the accepted attempt in the same transaction.
BEGIN
validate and authorize the request
create the job
record one accepted quota attempt
COMMIT
If that transaction does not commit, there is no job and nothing is counted.
This also makes the system easier to reason about. Admission accounting happens once, at a clear server-side boundary. Later lifecycle events are recorded separately:
Those are useful signals for reliability and product quality, but they should not be confused with a browser click.
The browser can still provide immediate feedback and discourage accidental repeat submissions. It is a UX layer, not the enforcement boundary. The service remains the source of truth for request admission and quota accounting.
There is an important distinction here: an anonymous capacity quota is not the same thing as a paid credit system. If a product later sells credits, failed-result reversal or refund behavior needs its own explicit settlement policy. Reusing an anti-abuse quota rule for billing would be a mistake.
I'm applying this pattern in Turner AI, a free AI photo editor - no signup, no watermark:https://turner.art
For anonymous capacity controls, would you count an accepted job, an inference start, or only a successful output?