Ten signed AEO clients can sit untouched for weeks while an agency waits for ten developers. The first deliverable should not depend on a plugin, a theme edit, or somebody finding time in a sprint.
I used to tell clients the content would fix the visibility. I was wrong about the order. Before changing content, I want to know which AI crawlers fetch the site and which pages they reach. An edge proxy puts that measurement in front of the origin, without changing the site’s code.
By the end of this workflow, you will have a routed domain and a repeatable way to build a one-page baseline for each client. Do the hands-on setup for ten domains in an afternoon if access is ready; DNS changes and a useful seven-day report take longer. You need a named DNS owner, permission to change nameservers, and about 15 minutes of hands-on work per domain. You do not need CMS admin or a developer.
Before you start: get the DNS owner’s name
A signed agreement is not DNS access. Ask for everything below on day one, in one email, with a named owner per line:
Domain registrar login: where the domain was bought, and who controls it.DNS host login, if different: where its records live, and who controls them.Nameserver change approval: one person who can approve the change in under 24 hours.Site stays where it is: confirmation that this is edge routing, not a migration or redesign.
No CMS password. No plugin install. The point is to leave the origin alone. Waiting until launch week to ask for registrar access is how a short setup becomes a two-week search for the person who bought the domain. General onboarding can stall for weeks on access held outside the sale. Ask all ten clients now, not one at a time.
Do not schedule ten routings until ten humans can approve ten DNS changes. That is the actual prerequisite.
Step 1: Put all ten domains in one inventory
Open a sheet. Add one row per domain with these exact columns:
domain | registrar | dns_host | cms | dns_owner | proxy_status | verified_bot_7d
Fill the first five columns before changing anything. registrar is where the domain was bought; dns_host is where its records live. They may not be the same account. Set proxy_status to pending_dns, and leave verified_bot_7d blank until you have a seven-day window to count.
clientdomain.com | GoDaddy | Cloudflare | WordPress | Sarah (ops) | pending_dns | —
clientdomain.com | Namecheap | Route53 | Shopify | founder's IT contact | pending_dns | —
Expected result: ten rows, each with a named, responsive dns_owner. The common mistake is entering “IT” or “client” as the owner and discovering later that neither can approve a change. If a name is missing, chase it before moving that domain to Step 2. A spreadsheet cell cannot change nameservers.
Step 2: Route the first website through the edge
Add the domain to Cloudflare and check its imported DNS records before changing nameservers. At the registrar, replace the current nameservers with the two Cloudflare assigns. Set the website’s A and CNAME records to Proxied (the orange cloud), not DNS only. Proxy the website records, not every record in the zone.
Run these checks, substituting the client’s domain:
dig +short NS clientdomain.com
curl -sI https://clientdomain.com | head -5
Expected result: the nameserver lookup shows the assigned Cloudflare nameservers, the website responds, and the page still loads as it did before. Then confirm the website records show the orange cloud in the edge dashboard. The curl response checks that the site responds; it does not, by itself, prove that bot verification is working.
The easy mistake is adding the zone but leaving a website record on DNS only. The site still looks fine, which makes this mistake unusually good at hiding. Traffic to that record bypasses the proxy, so your edge measurement misses it. Update proxy_status to active only after the nameserver, site, and proxy checks pass.
If the website record’s cloud is gray, you have DNS hosting, not edge routing. Fix that before looking at a bot chart.
Step 3: Separate verified crawlers from names in user-agents
Turn on bot measurement at the edge and use its verified-bot signal in the logs you retain. If you pass that signal to the origin, Cloudflare’s Managed Transform reference describes the cf-verified-bot header. Do not infer verification from the curl output or from a user-agent string.
Treat a user-agent as a claim. Anyone can send User-Agent: GPTBot/1.4, and the origin sees the proxy’s IP rather than the crawler’s. That is why crawler verification belongs at the edge, not in an origin-log reverse-DNS check. In one two-week analysis, roughly 1 in 17–18 requests claiming to be AI crawlers was spoofed. groas edge logs found 76.5% of claimed AI bot hits failed verification. The proportions differ; the operational lesson does not.
Filter to verified requests first. Then split them by job. OpenAI identifies GPTBot for training, OAI-SearchBot for search, and ChatGPT-User for on-demand fetches. A published 23.5-hour log sample counted 1,178 training fetches, 541 search-index fetches, and 189 live-answer fetches. A combined “AI bot hits” total would conceal the smaller bucket an AEO client is likely to ask about first.
For the live-answer view, apply the equivalent of this filter to your edge logs:
verified:true AND ua:(ChatGPT-User Perplexity-User Claude-User)
AND status:<400 GROUP BY path ORDER BY liveAnswerHits DESC
Expected result: a per-page count of successful, verified live-answer fetches. It may be small or zero. Those fetches are a useful citation proxy, not proof that an answer cited the page or sent a visitor. A user-agent match alone is weaker still: in a one-day sample across 111 small sites, 1,022 requests claiming ChatGPT-User returned 404, and 69% matched exploit patterns. The mistake is reporting those claims and errors as audience interest.
If you maintain your own crawler verification lists, cache the published lists for about an hour rather than hard-coding IPs. Keep the category split in the report: training, search indexing, and live-answer are not interchangeable. Report verified live-answer fetches per page, not a pile of claimed AI hits.
Step 4: Check the files that tell crawlers where to go
Open https://clientdomain.com/robots.txt and https://clientdomain.com/sitemap.xml from outside the edge. Check the edge log for verified crawler fetches of each path. Look for three familiar surprises: Disallow: / left from staging, a crawler block nobody discussed with the client, or a missing sitemap line.
Do not silently remove a training-bot block the client wanted. For an agreed baseline that allows the listed bots, the file could read:

# robots.txt baseline for AEO measurement
User-agent: GPTBot
Allow: /
User-agent: OAI-SearchBot
Allow: /
User-agent: ChatGPT-User
Allow: /
Sitemap: https://clientdomain.com/sitemap.xml
Expected result: both file URLs return 200, their contents match the client’s crawler policy, and verified fetches appear in the log when those crawlers request them. Do not promise a fetch on your timetable. The mistake is reading a blocked or missing file as evidence that the content needs rewriting. If OAI-SearchBot fetches robots.txt but not the sitemap, check the sitemap URL and what the file allows before touching page copy.
Fix access and crawler instructions before writing AEO content. A blocked crawler can produce a zero baseline even when the page itself is perfectly good.
Step 5: Move domains 2–10 in waves
Do not finish the first domain’s week-one report before starting the second domain’s routing. Add the domains to the edge, request the approved nameserver changes together, and check each website’s records as its DNS change takes effect. While one client waits on a registrar, verify another site’s proxy status and bot measurement.
Use the same order on every row:
- Confirm
dns_ownerreplied and approved the change. - Add the domain and inspect its DNS records.
- Change nameservers, then set the website records to
Proxied. - Run the
digandcurlchecks from Step 2 and load the site. - Mark
proxy_statusasactiveonly when the checks pass.
At about 15 minutes of hands-on work per domain, ten setups amount to just over two hours of clicks, plus waiting. That is an afternoon of work, not a guarantee that ten independent DNS changes finish by closing time.
Expected result: active rows for domains whose changes have taken effect; pending_dns stays on any that have not. The mistake is calling the whole batch complete because the requests were sent. Your remaining job is mostly chasing the named humans, not configuring servers.
Step 6: Send each client a one-page baseline
Within seven days of routing, and before changing a page, send one page per domain. Agree on baseline numbers in writing before changing anything; otherwise, a later discussion about what moved starts with an argument about the starting line.
Use the same compact format each time:
Domain: clientdomain.com | Week: May 5–12
Verified live-answer hits: 11 (ChatGPT-User 7, Perplexity-User 4)
Top fetched pages: /pricing (5), /compare (3), /faq (2)
Robots/sitemap: 200 / 200 | Blocked: none
The top-page line shows the leading pages, not necessarily every hit. Include the window, the verification filter, and the status filter when you explain the counts. If live-answer is zero, write 0. Do not turn it into a visibility percentage, and do not imply that a verified fetch produced a citation.
Expected result: a client can see what was fetched, where, and over what period. The mistake is padding a sparse baseline with training traffic or prompt scores to make week one look busy. A clean zero gives you a starting point; a flattering mixed bucket does not.
Troubleshoot in this order, not by rewriting content
Three failures account for most stalled setups I see:
- No one can approve the DNS change. Call the named owner from Step 1. Have the client arrange delegated access or put the domain under a registrar they control. A screenshot of DNS records is not permission to change them.
- The website still bypasses the proxy. Recheck the nameservers and the orange cloud on its website records. A loading site is not proof that requests traverse the edge.
- Crawler instructions are stale or blocked. If the edge serves an old
robots.txtor sitemap, set a short edge TTL or bypass cache for/robots.txtand/sitemap.xml, purge those paths, and fetch them again. Ifrobots.txtsaysDisallow: /, resolve that with the client’s intended crawler policy.
Check DNS ownership first, proxy status second, and crawler instructions third. Then look at the verified log. Do not sell a content rewrite as the fix for a measurement gap.
Price the ongoing work per domain, not per prompt
Prompt caps make an AEO retainer awkward to explain: every additional query you want to track becomes another margin decision. I would price this work per domain and keep the verified-fetch baseline distinct from any prompt-tracking report. They measure different things.
For agencies, groas offers SEO and AI Search at a flat monthly fee per client domain, with content, technical fixes, citations, and weekly reporting under the agency’s brand. The ten-client retainer cost breakdown covers the wider pricing decision. Make the domain the unit of the retainer; use the baseline to decide which content work to propose next. Do not make a client buy a bigger prompt allowance just to understand whether a crawler reached /pricing.
Verify the setup, then make the first content change
Before declaring a domain ready, check three things: proxy_status is active and the site loads unchanged; edge logs distinguish verified crawlers from claimed ones; and /robots.txt and /sitemap.xml return 200 with the intended contents. After the reporting window, send the client the written per-page baseline. A zero live-answer count is acceptable. An unverified count presented as verified is not.
Then change one thing: add a quotable block with a specific number, price, or definition to a page with live-answer fetches, and watch its per-page count the following week. If there are no such pages yet, keep the zero in the report rather than inventing a winner.
The developer was not the first bottleneck. Access was. Get the DNS owner named on day one, route the site, and show the client what verified crawlers actually fetched before you ask anyone to write another page.

