A domain verification record is a token a service asks you to publish in DNS so it can confirm that you control the domain. Most vendors want the token to stay after verification, many put it at the zone apex, and over the years those tokens pile up next to your SPF policy. Add them where they do the least harm, and remove them only after checking that vendor’s rule.
Three places a verification record can live
Every DNS-based verification uses one of three shapes:
| Shape | Example | What a lookup of the apex returns |
|---|---|---|
| TXT at the apex | example.com. TXT "vendor-site-verification=..." |
The token, together with every other apex TXT record |
| TXT at a dedicated label | _github-pages-challenge-octo.example.com. TXT "..." |
Nothing extra; the token lives at its own name |
| CNAME at a vendor-chosen label | token123.example.com. CNAME token123.vendor.example. |
Nothing extra; the vendor checks that the alias exists |
The apex is the easiest instruction for a vendor to write (“add this TXT record to your domain”), but it is the worst place for the record. DNS returns a record set as a unit, so a query for the apex TXT records returns every token there, including ones for services you stopped using years ago. A dedicated label gives the token a name of its own. RFC 8552 describes this pattern of underscore-prefixed leaf names whose meaning is scoped to the label, the same pattern used by _dmarc and _acme-challenge. The IETF draft on domain verification techniques (version 13, June 2026, not yet an RFC) recommends exactly this for new services: a _<provider>-challenge label, clear instructions on how long the token is needed, and removal once it is not.
A CNAME method proves control differently: the vendor gives you a label and a target, and checks that the alias resolves. It keeps the apex clean, but the label can hold nothing else, and the alias points into the vendor’s namespace for as long as it exists.
What six vendors ask for today
We checked each vendor’s current documentation on 4 October 2026. The record name is relative to the domain being verified.
| Vendor | Record name | Type | Must it stay after verification? | Source |
|---|---|---|---|---|
| GitHub Pages | _github-pages-challenge-<USERNAME> or _github-pages-challenge-<ORGANIZATION> |
TXT | Yes. GitHub says to keep the TXT record for the domain to remain verified | GitHub Docs |
| Google Search Console | Apex (@ or blank), or a name/value pair Google provides |
TXT, or CNAME to a dv.googlehosted.com target |
Yes. Removing the record loses verification | Search Console Help |
| Azure App Service | asuid for the apex or a wildcard, asuid.<subdomain> for a subdomain |
TXT | Keep it. While it exists, no other Azure subscription can validate the name | Microsoft Learn |
| Atlassian | Apex (@ or blank) |
TXT | Yes. Atlassian checks periodically and emails you if the record is missing or wrong | Atlassian Support |
| Meta (Facebook) | Apex (@) |
TXT | Yes. Meta may check it periodically | Meta for Developers |
| Apple Business | The domain being verified; value starts with apple-domain-verification= |
TXT | Depends. Removable after organization verification or Domain Capture and federation; must stay for brand features such as Branded Mail and Verify with Wallet on the Web | Apple Business guide |
Some details matter more than the table can show:
- GitHub Pages places the token on a label that includes your account name, and verifying a domain also covers its immediate subdomains. The point of verification is to stop other GitHub users from publishing a Pages site on your domain, so deleting the record removes that protection.
- Google Search Console accepts DNS records only for Domain properties; URL-prefix properties have other methods. The CNAME option exists for domains where TXT doesn’t fit.
- Azure App Service describes the TXT record as not strictly required but highly recommended, specifically as a defense against subdomain takeover. Azure’s own takeover guidance adds that the record doesn’t stop someone from creating an app with the same default hostname, but without the ownership proof they cannot attach your domain to it.
- Apple Business gives you 14 days to finish verification before you have to start over.
Not every vendor answers the “can I delete it?” question. Microsoft 365’s current pages on adding a domain describe the TXT method (and an MX fallback) but, in the versions we read, don’t say whether the ownership record may be removed afterwards. When a vendor is silent, treat the record as required until its support team says otherwise.
What a crowded apex looks like
Large organizations verify their domain with many services, and the apex TXT set shows it.
Live capture, 4 October 2026 (17:54 UTC). Asking 1.1.1.1 for the apex TXT sets of four well-known domains, keeping only the header line, any truncation notice, and the response size:
$ for d in google.com github.com stripe.com microsoft.com; do echo "== $d"; dig +nocmd @1.1.1.1 "$d" TXT +noall +comments +stats | grep -E "Truncated|ANSWER:|MSG SIZE"; done
== google.com
;; flags: qr rd ra; QUERY: 1, ANSWER: 17, AUTHORITY: 0, ADDITIONAL: 1
;; MSG SIZE rcvd: 1187
== github.com
;; Truncated, retrying in TCP mode.
;; flags: qr rd ra; QUERY: 1, ANSWER: 24, AUTHORITY: 0, ADDITIONAL: 1
;; MSG SIZE rcvd: 1928
== stripe.com
;; Truncated, retrying in TCP mode.
;; flags: qr rd ra; QUERY: 1, ANSWER: 39, AUTHORITY: 0, ADDITIONAL: 1
;; MSG SIZE rcvd: 2971
== microsoft.com
;; Truncated, retrying in TCP mode.
;; flags: qr rd ra; QUERY: 1, ANSWER: 59, AUTHORITY: 0, ADDITIONAL: 1
;; MSG SIZE rcvd: 4644
ANSWER is the number of TXT records at each apex: 17, 24, 39, and 59. Three of the four answers were larger than 1.1.1.1 would send over UDP, so dig received a truncated reply and asked again over TCP. Nothing failed; DNS is designed to work this way.
Live capture, 4 October 2026 (17:54 UTC). The same microsoft.com query with +ignore, which tells dig not to retry over TCP, so the truncated UDP reply itself is visible:
$ dig +nocmd @1.1.1.1 microsoft.com TXT +ignore +noall +comments +stats | grep -E "flags:|udp:|MSG SIZE"
;; flags: qr tc rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
; EDNS: version: 0, flags:; udp: 1232
;; MSG SIZE rcvd: 42
The tc flag means truncated, and the reply carries no records at all: 42 bytes instead of 4,644. The EDNS line shows the resolver’s UDP limit of 1,232 bytes. RFC 9715 recommends keeping DNS over UDP at or below 1,400 bytes to avoid IP fragmentation, names 1,232 as an acceptable alternative, and tells clients to fall back to other transports when UDP answers don’t arrive. A client or network that cannot complete the TCP retry gets no answer for these names.
Our ISP’s default resolver showed a different behavior in the same session.
Live capture, 4 October 2026 (17:54 UTC). google.com’s TXT set through the default resolver, first over UDP and then over TCP:
$ dig +nocmd google.com TXT +time=5 +tries=1 +noall +comments +stats | grep -E "timed out|ANSWER:|MSG SIZE"
;; connection timed out; no servers could be reached
$ dig +nocmd google.com TXT +tcp +time=5 +tries=1 +noall +comments +stats | grep -E "timed out|ANSWER:|MSG SIZE"
;; flags: qr rd ra; QUERY: 1, ANSWER: 17, AUTHORITY: 0, ADDITIONAL: 1
;; MSG SIZE rcvd: 1187
The UDP query timed out, as did repeated UDP queries for microsoft.com and stripe.com earlier that hour, while TCP returned the full set. We can’t see inside that resolver and don’t know the cause. The practical lesson is narrower: a large TXT set depends on more of the path working than a small one does.
Live capture, 4 October 2026 (17:57 UTC). What the 24 records at github.com are. The filter keeps only the name before the first =, drops random six-character suffixes, and replaces anything that is not a vendor name, so no token or account identifier is reproduced:
$ dig +short @1.1.1.1 github.com TXT | awk -F= '{ name = $1; sub(/^"/, "", name); sub(/-[a-z0-9]{6}$/, "", name); if (NF < 2) name = substr(name, 1, 2) "..."; else if (name ~ /[0-9]/) name = "(no vendor name)"; print name }' | sort | uniq -c | sort -rn
3 MS
2 google-site-verification
1 v
1 stripe-verification
1 shopify-verification-code
1 serval-domain-verification
1 openai-domain-verification
1 miro-verification
1 loom-site-verification
1 krisp-domain-verification
1 jamf-site-verification
1 facebook-domain-verification
1 docusign
1 cursor-domain-verification
1 calendly-site-verification
1 atlassian-domain-verification
1 apple-domain-verification
1 anthropic-domain-verification
1 adobe-idp-site-verification
1 TA...
1 (no vendor name)
One record is the SPF policy (v=spf1). The other 23 look like verification or service tokens, from roughly 20 services judging by their prefixes, including three MS= records and two google-site-verification records. From outside, nobody can tell which are still needed; only the domain owner’s records and vendor consoles can. One value carries no vendor name at all, only an identifier, which is exactly the problem an audit has to solve.
For comparison, our own apex is small.
Live capture, 4 October 2026 (17:54 UTC). Counting and.guide’s apex TXT records through the default resolver; we don’t publish their contents:
$ dig +short and.guide TXT | wc -l
2
Long values: 255-octet strings
RFC 1035 defines TXT data as one or more character-strings, each a length octet followed by up to 255 octets. A longer value has to be published as several strings inside one record. RFC 7208 tells SPF readers to join the strings without adding spaces, and the IETF verification draft asks providers to do the same with tokens.
Live capture, 4 October 2026 (17:54 UTC). github.com’s SPF record, split into its character-strings and measured:
$ dig +short @1.1.1.1 github.com TXT | grep "^\"v=spf1" | sed 's/^"//; s/"$//' | awk -F'" "' '{for (i = 1; i <= NF; i++) print "string " i ": " length($i) " characters"}'
string 1: 255 characters
string 2: 65 characters
The first string is exactly at the limit and the second carries the remaining 65 characters. In zone-file syntax, the record looks like this:
example.com. 3600 IN TXT "first 255 characters..." "remaining characters"
Three practical consequences:
- Two strings in one record are not two records.
"abc" "def"is a single TXT record whose value isabcdef. Two separate TXT records withabcanddefare unrelated values. - Dashboards differ. Some DNS providers split a long value for you, and others reject it or expect you to add quotes. Check the published result with
digrather than trusting the form. - Most verification tokens are short and fit in one string; values over 255 characters are usually DKIM keys or policies.
Why a dedicated label is cleaner
When a vendor offers a choice, pick the dedicated label or the CNAME method:
- It stays out of the apex response. Mail servers looking up your SPF policy, and every other client asking for apex TXT records, don’t download the token.
- It has a self-describing name.
_github-pages-challenge-octo.example.comtells the next person who owns it. An anonymous string at the apex doesn’t. - It can be removed without touching anything else. Deleting a whole name is a smaller change than editing one member of a busy record set.
- It works on names that already hold a CNAME. A TXT record cannot share a name with a CNAME (the A record or CNAME guide explains why), so apex-style tokens at the verified name are impossible for a subdomain that is already an alias.
The CNAME method has its own trade-off: the alias keeps pointing at the vendor. If you leave the vendor and keep the CNAME, you have the same kind of loose end the dangling DNS guide describes, so retire verification CNAMEs together with the account.
Add a verification record safely
- Choose the method. Use a dedicated label or CNAME if the vendor offers one. Read whether the record must stay, and note the answer.
- Add a new record; don’t edit an existing one. Put the token in its own TXT record. Never paste it into your SPF record, and never create a second
v=spf1record. - Copy the value exactly. Leave out surrounding quotes unless your provider requires them, and watch for a trailing space or newline from the clipboard.
- Check the authoritative answer before clicking Verify. Ask one of your zone’s nameservers directly, for example
dig @ns1.example.net _vendor-challenge.example.com TXT +norec +short, then confirm through a public resolver. The DNS lookup tool shows Cloudflare’s and Google’s answers side by side. - Record it. Write down the name, the vendor, the account or tenant it belongs to, who requested it, the date, and whether it must stay. That note is what makes the audit below possible.
If you are moving DNS providers, copy verification records along with everything else. The nameserver migration guide explains why an onboarding scan misses them and how to compare old and new zones.
Audit and clean up TXT records
Treat verification tokens as part of the hostname inventory described in the subdomain inventory guide, with one difference: tokens at underscore labels cannot be found by guessing names, so start from the zone itself.
- Export every TXT record from your DNS provider’s export or API, including records at underscore labels. A
digof the apex only shows the apex. - Classify each record. Separate email and certificate records (SPF,
_dmarc, DKIM selectors,_acme-challenge) from verification tokens and from records you cannot identify. Only the last two groups are candidates for removal. - Map each token to a vendor and an account. The prefix usually names the vendor. Then find the account: the vendor’s admin console lists verified domains and usually shows the expected token, so you can match values exactly. Duplicates, such as two tokens from one vendor, often mean two accounts or a token from an earlier attempt.
- Check the vendor’s rule. Use the table above or the vendor’s current documentation. If the account is active and the vendor says to keep the record, keep it. If the account is gone, the record is a removal candidate.
- Pay special attention to records that block takeovers. Azure’s
asuidrecords and GitHub Pages challenges protect names from being claimed by other customers. Remove them only after the hostname itself is retired. - Remove one record at a time, with a rollback note. Before deleting, save the exact name, type, TTL, and every character-string. Then delete, confirm with
digagainst the authoritative nameserver, and watch the vendor’s console and your email for a “verification lost” notice. If one arrives, re-add the saved record, or the new token the vendor now shows, if it has issued one. - Re-run the count and keep the inventory row: owner, vendor, account, required or removable, and the date of the last review.
Keep one row per token:
| Field | Example entry |
|---|---|
| Name and type | example.com TXT |
| Value prefix | vendor-site-verification= |
| Vendor and account | The service and the account, tenant, or organization that issued the token |
| Owner | The person or team who can confirm the account is still in use |
| Must stay? | Yes, no, or unknown, with a link to the vendor’s documentation |
| Last reviewed | Date, plus the decision taken |
The goal is not a minimum count but an apex where every record has an owner.