auditing

How to audit a site for AEO and GEO

The full AEO and GEO audit loop: access, extraction, answer-readiness, citability and entity, then measurement. By hand, at scale, and re-crawled to prove it.

An AEO and GEO audit answers five questions about every page that matters, in a fixed order: can the crawlers that feed answer engines reach it, does the response actually contain the content, is that content shaped so a passage can be lifted, does the page give a system a reason to trust and attribute it, and what can you honestly measure afterwards. Each layer gates the one after it. A perfect answer block on a page that a CDN rule blocks is a perfect answer block nobody fetched.

That ordering is what separates an audit from a checklist. A checklist treats fifty items as equal. An audit finds the first layer that fails, fixes that, and ends with a re-crawl that shows whether the fix landed.

This guide walks the loop end to end. Each layer has a by-hand check for one URL, an at-scale method that needs no terminal, and the failure it is looking for.

What does an AEO and GEO audit check?

An AEO and GEO audit checks five layers, and the first one that fails is the one to fix. The table is the map for the rest of this guide.

LayerQuestionTypical failureGates
1. AccessCan the crawler fetch the URL?Bot disallowed in robots.txt, blocked at the CDN, 4xx/5xx, noindex, nosnippetEverything
2. ExtractionDoes the response contain the content?Client-rendered body, content loaded on click, main text buried in templateLayers 3 and 4
3. Answer-readinessCan a passage be lifted cleanly?No direct answer under the heading, keyword headings, tables built from divsWhether the page has anything to quote
4. Citability and entityIs there a reason to trust and attribute it?No figures or sources, no byline, stale or fake dates, no Organization markupWhether a lifted passage carries attribution
5. MeasurementWhat changed, and how do you know?Blended metrics, single-run prompt checks, no baselineWhether you can defend the work

Layers 1 to 4 are deterministic: the same check on the same page gives the same answer. Layer 5 is where the probabilistic part lives, which is why it comes last and is reported separately.

Before you start: scope, policy, and a baseline

Three decisions come before the first check, and skipping any of them makes the findings hard to act on.

Scope by template, not by URL count. Most findings are template findings, so pick two or three representative URLs per template for the by-hand pass and let the crawl confirm which URLs share each fault. Pull the URL list from your XML sitemap and from the Pages table in Search Console’s Performance report, so important pages are in it by traffic as well as by structure.

Write down the crawler policy. Before you can call a blocked bot a finding, you need to know whether someone blocked it on purpose. Training crawlers and search crawlers are separate decisions at every major vendor, and blocking a training crawler can be a legitimate policy. Training vs. retrieval crawlers sets out the options; the audit’s job is to check that the site does what the policy says, not to choose the policy.

Take a baseline crawl. Crawl the in-scope sections before changing anything and keep the result. Every later claim that a fix worked depends on a before-and-after pair from the same crawler in the same mode.

Layer 1: Can the crawlers reach the page?

Access means the crawler that feeds an answer engine is allowed to request the URL, the request succeeds, and nothing in the response tells the engine not to use it. It can zero out every other finding on a page, so it is audited first.

The vendor documentation sets the requirements. Google states that to appear as a supporting link in AI Overviews or AI Mode, a page must be “indexed and eligible to be shown in Google Search with a snippet,” and that “there are no additional technical requirements” (Google Search Central, last updated 2025-12-10). The same page lists “ensuring that crawling is allowed in robots.txt, and by any CDN or hosting infrastructure” as a best practice. OpenAI documents OAI-SearchBot as the agent for ChatGPT’s search features and says it can take “~24 hours from a site’s robots.txt update” for its systems to adjust (OpenAI). Perplexity documents PerplexityBot for surfacing sites in its search results and says changes may take up to 24 hours to reflect (Perplexity). Anthropic documents Claude-SearchBot for search result quality and ClaudeBot for training (Anthropic).

By hand, on one URL. Five checks, in this order:

  1. Open /robots.txt on every host you own, including subdomains, and read the rules that apply to OAI-SearchBot, Claude-SearchBot, PerplexityBot, and Googlebot. A specific user-agent group replaces the * group for that bot; it does not add to it.
  2. Request the URL as one of those bots. In browser developer tools, set a custom user-agent in the network conditions panel and reload. Anything other than a 200 on the document request is a finding.
  3. Check the status chain. A 301 to a 302 to a 200 is three fetches and a canonical question; a soft 404 returns 200 with nothing on it.
  4. View source and search for noindex, nosnippet, and max-snippet. On Google’s surfaces these govern AI features directly.
  5. Confirm the canonical points at the URL you are auditing, or at the URL you intend.

How to check whether AI crawlers can actually reach you is the full step-by-step for these checks.

At scale, without a terminal. Run a crawler three times over the in-scope URL list: once with its default user-agent, once with a search-bot user-agent string, and once more with a second vendor’s string. Export each run to a spreadsheet and put the status-code columns side by side. A status that differs between runs means something in front of your origin treats bots differently. Add a custom-extraction rule for //meta[@name='robots']/@content to catch noindex and nosnippet per URL, and one for //link[@rel='canonical']/@href to catch canonicals that point elsewhere. In Search Console, the Pages report under Indexing lists URLs excluded by noindex and by robots.txt for Googlebot.

GEOBee reads each page’s robots.txt verdict for eleven AI crawlers and reports it in the AI Bots column, alongside Status and Index; its AI Bot Access tab reframes the whole crawl around that one question (the three lenses lists the agents). It does not test CDN behavior on its own: robots.txt is what it reads, and the user-agent comparison above is how you catch an edge rule.

What a pass looks like: every in-scope URL returns 200 to the search agents your policy allows, carries no unintended noindex or nosnippet, and canonicalizes to itself or to an intended target.

Layer 2: Does the response contain the content?

A 200 proves the fetch succeeded, not that the page arrived. Extraction is the step where the response is reduced to the text a system will actually work with, and two things routinely go wrong in it: the text was never in the response, or it was there and got mistaken for template.

Never in the response. Standalone AI crawlers are not documented to execute JavaScript, and independent measurement has found that they don’t; Google renders, as part of indexing. Text injected by a client-side framework, loaded when someone clicks a tab, or fetched as the reader scrolls is absent from the bytes a non-rendering crawler receives. What do AI crawlers extract from your page? has the element-by-element inventory and the sources.

Mistaken for template. Main-content extractors keep one block and drop the rest. A short page wrapped in a large navigation and footer gives the extractor little to choose from, and content that lives only in a sidebar is formatted as boilerplate. Boilerplate ratio is the measurement method.

By hand, on one URL. Open view-source: on the page and use find for a distinctive sentence from the body, the one you would most want quoted. If it is not there, a non-rendering crawler does not have it. Then open the page in a browser reader mode and check whether the block it keeps is the block you meant, including the first heading and the answer under it.

At scale, without a terminal. In a crawler with custom extraction, add two rules: the text length of your main-content wrapper (string-length(normalize-space(//main))) and of the whole body (string-length(normalize-space(//body))). Export, divide one by the other, and sort by template. Rows where the main-content column is empty have no <main> element. Rows with a near-zero body length on a page you know is long are client-rendered. If your crawler can render, crawl the same list with rendering on and off and compare word counts: any URL whose word count jumps with rendering depends on JavaScript for its content.

In GEOBee, a quick scan reads the raw HTML without rendering, which is the view a non-rendering crawler gets, and the Words column reports the word count of the main content, so a long page showing a handful of words stands out. A deep scan renders each page through Lighthouse and adds JavaScript-discovered links, which surfaces URLs a static crawl never finds (scan modes).

What a pass looks like: the sentence you most want quoted appears in view-source, and the main-content block holds the body copy rather than navigation.

Layer 3: Is the content answer-ready?

Answer-readiness is whether a section of the page can be lifted on its own and still answer the question its heading asks. This is the AEO layer, and it is mostly an editing job.

The checks map to the eight signals in Answer Engine Optimization: a page-level guide, which is the full treatment. The four that most often fail an audit:

CheckPassCommon failure
First sentence under each headingStates the answerRestates the heading or starts a story
HeadingsName the question or the specific subjectKeyword labels like “Overview” or “Features”
Section independenceNames its subject without relying on earlier sections”This,” “it,” and “the above” with no referent
Tables and listsReal <table>, <ol>, <ul> elementsGrids of divs, or a table rendered as an image

By hand, on one URL. Read only the first sentence under each H2. If you can tell what each section answers from those sentences alone, the page passes the main check. Five checks for a page that ranks but never gets cited turns this into a fifteen-minute procedure with a pass condition for each check.

At scale, without a terminal. Use custom extraction to pull the H2 text and the first paragraph after each one: //h2 for the headings and //h2/following-sibling::p[1] for the paragraphs. Export to a spreadsheet, put headings and first paragraphs in adjacent columns, and read down them by template. Add count(//table) and count(//div[contains(@class,'table')]) to find templates that draw tables without the element.

GEOBee’s AEO lens scores eight signals with published weights, the largest being the answer block at 20 of 100, and its Answer column reports each page as Yes, Partial, or No for answer-readiness (the three lenses).

What a pass looks like: every section’s first sentence answers its heading, and every comparison on the page is in a real table or list.

Layer 4: Is the page citable, and is the entity clear?

Citability and entity clarity are whether a passage, once lifted, carries something worth attributing and an unambiguous source to attribute it to. This is the GEO layer. It covers the sentences themselves (figures with scope, named sources, quotations), the authorship and date around them, and the organization behind the site.

The best public evidence for the sentence-level part is the GEO research paper, which reports that adding citations, quotations, and statistics to a source raised its visibility in generated answers “by up to 40%” inside the authors’ own test setup (Aggarwal et al., arXiv 2311.09735). That is a finding about liftable text in a research pipeline, not a citation rate for production assistants. What makes a page citable reads the paper closely and turns it into writing rules.

The page-level part is documented by Google. Its guidance on helpful content says “we strongly encourage adding accurate authorship information, such as bylines to content where readers might expect it” (Google Search Central, last updated 2026-10-05). Its publication-date guidance asks for a visible date and datePublished or dateModified in structured data (Google Search Central). Its Organization guidance says some properties “are used behind the scenes to disambiguate your organization from other organizations” (Google Search Central, last updated 2026-09-08).

By hand, on one URL. Check five things: is there at least one specific, sourced figure or quotation; is there a visible author with a link to a page about them; does the visible date match dateModified, and did the content actually change on that date; does the site’s home or about page carry Organization markup with sameAs links; and is there a visible way to make contact.

At scale, without a terminal. Custom extraction does most of this: count(//a[starts-with(@href,'http') and not(contains(@href,'yourdomain.com'))]) for outbound links in the body, //meta[@name='author']/@content or your byline selector for authorship, and the raw JSON-LD block so you can filter in the spreadsheet for "@type":"Person", datePublished, and dateModified. Sort articles by dateModified and look for clusters: hundreds of pages modified on the same day usually means a template touched the date, not an editor.

GEOBee’s GEO lens weights seven signals: Citability 25, Author/E-E-A-T 15, Freshness 15, Entity clarity 15, Trust 10, Depth 10, and AI bot access 10 (the three lenses). The Schema column shows each page’s detected JSON-LD type, or None, Invalid, or Partial when it is missing or incomplete.

What a pass looks like: each important page has a named author, an honest date, at least one sourced specific, and markup that agrees with what is visible.

Layer 5: What can you measure honestly?

Measurement is the layer where an audit either holds up in a meeting or doesn’t. The rule is to report readiness and outcomes separately and never blend them into one score.

Readiness is what layers 1 to 4 produce: per-URL pass or fail on access, extraction, structure, and attribution signals. It is deterministic and you can re-run it.

Outcomes come from three sources, none complete:

  • Search Console. Google states that traffic from AI features is included in the Performance report under the Web search type (Google Search Central). The generative AI performance report reports impressions only, for AI Overviews and AI Mode, and Google says it had rolled out to all websites worldwide as of 31 August 2026 (Search Console Help).
  • Analytics referrals. In your analytics tool, build a segment where the session source contains the assistants’ domains, such as chatgpt.com, perplexity.ai, claude.ai, and copilot.microsoft.com. It undercounts: answers that are read and not clicked leave no trace.
  • A manual citation log. A fixed list of questions your pages answer, run on each assistant you care about, monthly, with the date and a screenshot. Run each question more than once and record the range of results rather than one answer, because responses to the same prompt vary between runs.

None of these attributes an outcome to a specific fix. Report them as context next to the readiness numbers, not as the result of them.

Turning findings into a work order

An audit of a real site produces more findings than anyone can ship in a quarter, so the output of layers 1 to 4 is a ranked list, not a report. The order that holds up is severity times page value, divided by effort, with access failures treated as gates that outrank every other finding on the same page.

Prioritizing AEO fixes: severity × page value is the spreadsheet: what goes in each column, the formula, and a worked example. Two rules from it matter most here. Collapse findings that share a fix, because forty pages missing the same markup is one template change. And confirm a gate is not deliberate before ranking it, because a blocked training crawler may be policy.

GEOBee’s JSON export carries every finding per URL with its severity, module, category, and one-line recommended fix, which fills the first columns of that sheet (exporting data).

Re-crawl to prove the change

A finding is closed when a fresh crawl shows it gone, not when the ticket closes. Verify by hand the same way you found it, then re-crawl the affected sections with the same crawler, the same settings, and the same scan mode as the baseline.

Three rules keep the comparison honest:

  • Compare like with like. A rendered crawl against a non-rendered one, or a crawl of 200 pages against a crawl of 2,000, produces deltas that come from the method, not the fix.
  • Read regressions first. A template change that fixes one page type can break another that shares it. The regressions are where that shows up.
  • Expect proportional movement. A score moves by the weight of the signal you fixed. Lifting a robots.txt block restores one access signal; it does not repair the thin content on the same page.

In GEOBee, a project’s Re-crawl captures a fresh snapshot and Compare lines it up against a baseline, with summary deltas for AEO, GEO, SEO, Pages, and Critical, and a per-page diff marking each URL as Improved, Regressed, Unchanged, Added, or Removed. It warns when the two crawls are from different scan modes (projects and compare).

Then schedule the next audit. Pages change, templates change, and vendors rename crawlers; a re-run of layers 1 and 2 across the whole site each quarter catches most of it.

What an audit can’t tell you

An audit can’t tell you whether a page will be cited, how often, or for which questions. It can’t see an assistant’s retrieval index, the sources competing for an answer, or how an engine weighs them.

What an audit can tell you is narrower and more useful: which of your pages are fetchable, readable, liftable, and attributable, which are not, why, and whether the fix you shipped changed that. That is the part of AI search that responds to work, and it is the part you can put a date on.


To run layers 1 to 4 across every URL and diff the result after each fix, download GEOBee. The 7-day trial includes deep scans, compare, and the full export.

On this page