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_conflictPrimary action, prominent. fix is a real instruction.

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 proves in one run because the record is already there, which is what keeps lastConfirmedAt moving, and the token survives archiving and reactivation — a domain reactivated a year later verifies without anyone opening a DNS panel.