Skip to main content
The screen between “I created the record” and “proved” is where most verification flows lose people. This guide builds one that says something true at every moment.

Claim, and show the record

The record on the claim is what to render — host, name, type and value. It is null once the claim has ended, because there is nothing left to write.
Copy host, not name. Almost every panel appends the zone to what you type, and a copy button that hands over the fully qualified name is how people end up with domain_appended. Offer name as a secondary “fully qualified” affordance for the panels that want it.

Poll the verification, not the claim

The claim only moves once, at the end. What changes while someone waits is the process behind it, and the claim knows which one that is.
hooks/useVerificationState.ts
Deriving the interval from waitEstimate.secondsRemaining means the client asks roughly when there is something new to hear, instead of every five seconds forever.
POST /api/verifications/:id/runs forces a run and is rate limited per verification. Wire it to a button the person presses, not to a timer. Nothing about asking more often makes DNS answer sooner, and the honest interval is already on the verification.

One message, from two fields

A verification that has not proved always carries exactly one of diagnosis or waitEstimate, and they mean opposite things.
Render cause and fix verbatim — they already name your domain, your token and your nameservers. Do not pattern-match on their text; they are product copy and change. Key anything behavioural off code.

Style the three groups differently

Not every diagnosis is your reader’s fault, and treating them alike is the mistake worth avoiding.

Fix it

domain_appended · record_at_apex · value_formatted · record_on_www · no_matching_record · record_absent · cname_conflict · expired_tokenPrimary action, prominent. fix is a real instruction. expired_token is the cheapest of them: the record is in the right place and only its value is stale.

Wait

negative_cache · not_publishedCalm, with the countdown. No action button — there is nothing to press.

Escalate

servfail · lame_delegation · foreign_tokenPoint at the provider or the other account. Not something retyping the record will fix.

Status drives the frame around it

propagating versus needs_attention is the split that earns the product its keep — both are “not verified”, but only one is your reader’s problem.

Do not tell people to delete the record

Leaving it in place is the supported state. A later claim on the same name issues a new token, so the record already in the zone comes back as expired_token rather than as nothing found: the person edits one value instead of working out where the record goes again. Telling them to delete it turns that one-line edit back into the whole task. Archiving does not retract a proof either — every proof keeps its date. It does take back the links published from it, which is the point of archiving rather than a side effect of it.