Every measurable finding from the May baseline re-run against the live origin, plus a full API-level teardown of both free checkers, a site-wide crawl, and a reconciliation against an independent agent-readiness scan taken the same day. Working document — evidence first, interpretation second.
Three measurement passes, all first-party observation of the public surface. No client access, no analytics, no Search Console.
/, /robots.txt, /toolkit/aeo-checker/, /toolkit/seo-checker/). Bing, MSN and Yandex results re-confirmed on a second pass with full response headers.Layer 7 exposure probing — guessed paths such as .env, .git/config, backup files, user enumeration — was not performed. No written authorisation exists for security testing against a domain we do not own. That layer is recorded as not-in-scope, never as passed. Everything measured here is either a response header on a page fetched anyway, a file whose purpose is to be fetched (robots.txt, sitemap.xml, llms.txt), an advertised product endpoint used as designed, or a single 404 probe to test error handling.
The user-agent matrix declares each bot honestly. No browser user agent was spoofed to defeat a control that had been deliberately applied — fetching as a declared bot to test whether it is admitted is the point of the exercise, and is the only identity manipulation used.
This workbook was re-examined against its own evidence and revised. The changes, so a reader can see what moved and why:
all_platforms reconciliation is solved — the 3,419 total is the seven listed surfaces (516) plus google_ai_overviews_keywords (2,903). Previously flagged as an unexplained mismatch.The findings that survived scrutiny unchanged — F-01, F-05, F-11, F-12, F-18, F-19 — are the load-bearing ones.
Finding by finding, on the convention established in the 28 May delta.
| Finding | v1 · May | v2 · 28 May | v3 · 1 Sep | Status |
|---|---|---|---|---|
| Bing/MSN/Yandex WAF 403 §04 | 403 incl. robots.txt | 403, unchanged | Bing + MSN family all 200. Yandex + Baidu still 403 | Closed |
| robots.txt redirect loop | Loops via Error405 | Fixed, 200, 0 redirects | Still 200, 0 redirects | Holds |
| Duplicate card label ×4 §06.c | Same label ×4 | Unchanged | Four distinct agent labels | Closed |
| AEO page title/H1 §06.e | Split | Fixed, matched | Still matched | Holds |
| Title/H1 other pages | All sampled split | Home, /platform/, /accessibility/ split | 458/865 aligned · 407 still split | Partial |
| Schema coverage §06.a | Home: Org+WebSite. AEO page: template only | Identical | /platform/ gained SoftwareApplication. AEO page still template only | Partial |
| llms.txt §06.b | Hard 404 | Soft 404 via Error404 | Soft 404, unchanged. Same for ai.txt, llms-full.txt | Open |
| Comparison hub §06.d | 7 pages, 3 competitors missing | Unchanged | Still 7. Deque, Conductor, TPGi still missing | Open |
| Pricing page | Absent | Absent | /pricing/ → 301 → homepage | Open |
| AI citation share Finding 02 | 4% own-domain, 5-engine sweep | Directional re-check, no change | Not reproducible — no Brand Radar entitlement | Unknown |
| Brand memory drift | 0/37 branches mention AEO | Unchanged | Not re-scanned this pass | Unknown |
Thirty declared user agents, four URLs each, 1 September 2026. The Bing family result is the material change since May and was confirmed on a second pass with full headers.
// crawler matrix — www.siteimprove.com, 1 Sep 2026 BOT / robots.txt aeo-checker seo-checker — search engines — Bingbot 200 200 200 200 ← was 403 in v1 + v2 Bingbot Mobile 200 200 200 200 BingPreview 200 200 200 200 MSNBot 200 200 200 200 ← was 403 MSNBot-Media 200 200 200 200 Googlebot 200 200 200 200 GoogleOther 200 200 200 200 DuckDuckBot 200 200 200 200 YandexBot 403 403 403 403 ← still blocked Baiduspider 403 403 403 403 ← still blocked — AI / answer engines (all open) — GPTBot · OAI-SearchBot · ChatGPT-User 200 across all four ClaudeBot · Claude-SearchBot · Claude-User 200 across all four PerplexityBot · Perplexity-User 200 across all four Google-Extended · Applebot · Applebot-Extended 200 across all four Amazonbot · Bytespider · meta-externalagent 200 across all four cohere-ai · MistralAI-User · Diffbot · Timpibot 200 across all four AhrefsBot · desktop browser 200 across all four // second-pass confirmation, full headers $ curl -I -A "…bingbot/2.0…" https://www.siteimprove.com/ HTTP/1.1 200 OK Server: cloudflare CF-RAY: a3406c96cfa52436-DUS $ curl -I -A "…YandexBot/3.0…" https://www.siteimprove.com/ HTTP/1.1 403 Forbidden Server: cloudflare CF-RAY: a3406c9c6916cdeb-DUS Cache-Control: private, no-store · Referrer-Policy: same-origin → Cloudflare-issued block page, not an origin response
Every Bing and MSN variant now returns 200 on both the homepage and /robots.txt. The RFC 9309 §2.3.1.3 consequence described in v1 — a 4xx on robots.txt read as "do not crawl" — no longer applies. ChatGPT and Copilot can reach the origin.
Yandex and Baidu remain blocked at the Cloudflare edge. The 403 carries Cloudflare's block-page signature rather than an origin response, so this is a WAF rule, not application logic. Commercially this is close to immaterial for a US/EU enterprise buyer, but it is worth knowing the rule is selective rather than removed wholesale — someone narrowed it rather than deleting it.
evidence/bot-matrix-2026-09-01.txtThe served file is ten lines: a sitemap declaration and nine Disallow rules, all of which target UTM, gclid and fbclid parameter strings under User-agent: *. There is no AI-crawler section at all.
User-agent: * Sitemap: https://www.siteimprove.com/sitemap.xml Disallow: /*?utm_campaign=*Image*Editing*Aviary* Disallow: /*?utm_source=*jobalert.ie* Disallow: /*?utm_adgroup=*Software*AG*Exact* Disallow: /*?utm_keyword=*pandadoc* Disallow: /*?utm_ · /*&utm_ · /*?gclid= · /*&gclid= · /*?fbclid=
Functionally this is permissive, which is the right outcome. But three of those rules are campaign-specific artefacts — an Aviary image-editing campaign, an Irish job-alert source, a PandaDoc keyword — that read as accumulated debris rather than policy. For a vendor whose own free tool parses customers' robots.txt for AI-crawler directives, publishing a file with no AI-crawler section and four stale campaign rules is a missed opportunity to model the practice.
evidence/robots.txt · 200 OK, 0 redirects, browser UA945 of the sitemap's 948 entries are on www.siteimprove.com. Of those, 758 were also reached by crawling links from the homepage. The remaining 187 exist in the sitemap but were not reached by following links from the homepage at default crawl settings.
Precision note (revised): the first draft called these "orphaned." That overstates what the crawl proves. "Not reached in a homepage-seeded crawl" is the exact claim — some of the 187 may be reachable through deep pagination the crawl did not exhaust (blog and press archives especially) rather than truly unlinked. Either way the practical consequence holds: they sit far from the homepage in the link graph and receive little internal authority. Confirming true orphans would need a log-file or full-pagination pass.
// sitemap ∩ crawl sitemap <loc> total 948 (3 entries point at jp.siteimprove.com — cross-host) in sitemap AND crawled 758 in sitemap, NOT crawled 187 ← no internal link path crawled, NOT in sitemap 177 // the 187, by section /blog 75 /hello 9 /press 61 /events 4 /de 30 /on-demand-webinars 2 /toolkit 2
Pages this far from the homepage receive little internal authority, rank weakly, and are correspondingly less likely to surface as citations. The 61 press releases in this set matter specifically for the entity-freshness argument in v1 §05 — the April launch coverage is exactly the material that should be re-anchoring the brand entity, and it is poorly linked from the site's core.
sitemap.xml · 1 Sep 2026The toolkit is the top-of-funnel lead engine and the AEO Checker is its flagship. The AEO Checker is correctly listed. Almost nothing else is.
// EN toolkit URLs missing from sitemap.xml /toolkit/ ← the hub itself /toolkit/seo-checker/ /toolkit/accessibility-checker/ /toolkit/color-contrast-checker/ /toolkit/ada-compliance-checker/ ← also meta robots: noindex /toolkit/accessibility-statement-generator/ /toolkit/aeo-checker/ ← present // meanwhile, German equivalents ARE listed /de/toolkit/ · /de/toolkit/accessibility-checker/ · /de/toolkit/seo-checker/ /de/toolkit/color-contrast-checker/ · /de/toolkit/accessibility-statement-generator/
/toolkit/ada-compliance-checker/ carries meta robots: noindex while a near-duplicate at /glossary/ada-compliance-checker/ is indexable and holds the stronger title ("Instant ADA Compliance Website Checker — Free WCAG 2.0 Test"). That may be deliberate consolidation onto the glossary URL. Combined with six sitemap omissions and the German pages being listed where the English are not, it reads more like drift than a decision — worth a five-minute confirmation with whoever owns the sitemap generator.
Indexability Status field per URL.txt path and the entire /.well-known/ namespace soft-404CriticalThis is the v2 llms.txt observation with its actual rule identified. My first pass called this "dotted filenames"; that was wrong, and a wider probe set gives the real boundary. Two specific shapes return 200 OK on a missing resource. Every other shape 404s correctly.
// error handling by URL shape — 15 probes, browser UA, redirects followed
first final bytes
/nonexistent-page-zzz/ 404 404 593,457 correct
/nonexistent-zzz.json 301 404 593,457 correct
/nonexistent-zzz.xml / .yaml / .md 301 404 593,457 correct
/openapi.json 301 404 593,457 correct
/llms.txt 301 200 795 soft 404
/ai.txt · /nonexistent-zzz.txt 301 200 795 soft 404
/.well-known/agent-skills/ 301 200 795 soft 404
/.well-known/mcp/manifest.json 301 200 795 soft 404
/.well-known/openid-configuration 301 200 795 soft 404
/.well-known/oauth-authorization-server 301 200 795 soft 404
/.well-known/security.txt 301 200 795 soft 404
/.well-known/zzz-does-not-exist 301 200 795 soft 404
// the 795-byte body served with 200 OK
<title>Resource Not Found</title>
<h1 class="fiendly-error-header">Resource Not Found</h1> [sic]
<link rel="stylesheet" href="/Util/styles/errorpage.css"> Optimizely/Episerver stub
So the rule is not "extensions". It is the .txt extension plus the whole /.well-known/ prefix — the two namespaces that exist specifically so machines can discover capabilities. .json, .xml, .yaml and .md all behave correctly, which is why this survived earlier passes.
The consequence is not theoretical, and F-18 documents it happening. Any agent or scanner probing /.well-known/ for OAuth metadata, an MCP manifest, agent skills or security.txt receives 200 OK and an HTML page — the signature of a capability that exists. A security researcher looking for a disclosure contact at /.well-known/security.txt gets the same false positive.
Three fixes, in order: make /Util/Errors/Error404/ return a real 404 status; stop rewriting .txt and /.well-known/ requests into it; then publish an actual llms.txt. On that last point — there is still no evidence major AI vendors read llms.txt, and the v1 argument for shipping it was brand credibility rather than algorithmic lift. That argument has strengthened: an AEO vendor serving a fake 200 across the entire agent-discovery namespace is a worse look than serving nothing.
Other indexability observations, lower severity: 1,748 of 7,191 crawled URLs (24.3%) are 3xx redirects; 90 internal HTML URLs are non-indexable (43 noindex, 37 canonicalised, 10 both), of which 11 are German platform pages; internal search results at /search/ are crawlable and produce 10 URLs sharing the title "Siteimprove content search results".
21 template representatives fetched directly and their JSON-LD parsed. Every page carries WebSite + SearchAction from the master template; the table shows what each adds on top.
| Template | Types beyond WebSite/SearchAction | Verdict |
|---|---|---|
| /platform/ | Organization, SoftwareApplication, WebPage, VideoObject, ImageObject | Good |
| /platform/seo/ | FAQPage, Question, Answer | Good |
| /toolkit/accessibility-checker/ | FAQPage, Question, Answer | Good |
| /toolkit/color-contrast-checker/ | FAQPage, Question, Answer | Good |
| blog post | BlogPosting, Person, Organization | Good |
| homepage | Organization | Thin |
| /de/ homepage | Organization | Thin |
| /platform/seo/aeo-visibility/ | — none — | None |
| /toolkit/aeo-checker/ | — none — | None |
| /toolkit/seo-checker/ | — none — | None |
| /toolkit/ (hub) | — none — | None |
| /platform/accessibility/ | — none — | None |
| comparison hub + all 7 vs pages | — none — | None |
| glossary hub · glossary term | — none — | None |
| blog hub · press hub · case studies · webinars | — none — | None |
Unchanged across all three audits. /platform/seo/aeo-visibility/ carries only the template's WebSite/SearchAction: no Organization, no SoftwareApplication, no Product, no FAQPage. It runs 525 words of body copy and five H2s, no H3s.
Ahrefs measures it at 2 organic keywords and roughly 71 estimated monthly visits, none in the top three positions — against 6,435 keywords and 167,169 visits site-wide. The page carrying the entire category argument accounts for about 0.04% of organic traffic.
The fix is unusually cheap because the patterns already exist in the codebase: SoftwareApplication ships on /platform/, and FAQPage ships on three sibling pages. Neither requires new engineering.
Severity note (revised): downgraded from critical to warning. The page indexes and is reachable — it is significantly hampered, not broken, which is what "warning" means under this audit's rubric. Its strategic importance is high; its indexability severity is not critical, and the first draft conflated the two.
/toolkit/aeo-checker/ and /toolkit/seo-checker/ carry no FAQPage markup — yet both pages already contain question-shaped H3s written as FAQ content:
// seo-checker H3s — already FAQ-shaped, unmarked "Why you should use an SEO Checker" "What exactly does the Siteimprove SEO Checker do?" "How to read your Siteimprove SEO Website Checker report" "What to optimize with your SEO site checker" "How to monitor SEO progress" // aeo-checker H3s "Do you have visibility into how AI engines perceive your brand?" "Your existing SEO tools aren't built for this."
The content is written. The markup pattern is deployed two directories away. This is a content-entry task measured in hours.
The homepage Organization block is the single most machine-readable statement of what this company is. It is what feeds Google's Knowledge Graph and what an agent parses first for entity resolution. Here it is in full:
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "Siteimprove",
"description": "Siteimprove's all-in-one platform amplifies digital marketing,
so you can maximize your reach and provide and an exceptional,
inclusive digital experience.", ← [sic]
"url": "https://www.siteimprove.com",
"sameAs": [ linkedin · wikipedia · facebook · twitter ]
}
no logo · no address · no contactPoint · no foundingDate · no SoftwareApplication link
Two problems, and the first is the more important one. The description is the old positioning. "All-in-one platform amplifies digital marketing" is not Agentic Content Intelligence, is not AEO, and is not the Siteimprove.ai unified platform. The v1 audit found the brand's stale identity anchored in model training data and correctly called that slow to shift. This is the same stale identity — but in a field they control, that they can change this afternoon, and that Google reads directly.
Second, the description contains a grammatical error — "provide and an exceptional" — shipped in structured data on the homepage of a content-quality vendor.
Rewriting this one string is the cheapest positioning fix available anywhere in this audit. Adding logo, address and contactPoint alongside it takes the same edit from a correction to a genuine entity upgrade.
evidence/page-home.html// 936 internal HTML URLs, all 200 OK title present, H1 present 865 title (brand suffix removed) == H1 458 (52.9%) title != H1 407 (47.1%) H1 missing 71 ← 45 of them are /blog/author/* — one template title missing 3 duplicate titles 66 URLs across 19 groups duplicate H1 90 URLs across 31 groups // the duplicates that matter 22× "Watch Siteimprove's on-demand webinars" webinar template 10× "Siteimprove content search results" internal search, crawlable 2× H1 "Where accessibility meets performance" / and /platform/ — two top-level pages // content and length word count median 1,144 mean 1,343 min 12 max 11,445 pages < 300 words 139 (14.9%) titles over 60 characters 284 (30.3%) H1 over 70 characters 154 (16.5%)
Two things follow. The title/H1 finding has genuinely improved and should be restated with the real number: this is a 47% problem, not the "every page" problem v1 described from a four-page sample. And 45 of the 71 missing H1s are a single author-archive template — one fix, not 45.
The duplicated H1 across / and /platform/ is worth separate attention. Two of the highest-authority pages on the domain assert the identical proposition, which splits rather than concentrates the retrieval signal for the platform query.
Search engines discard hreflang annotations that are not mutually confirmed. A third of annotated URLs fail that test.
// hreflang issues, Screaming Frog issue analysis Missing Return Links 346 URLs (36.97%) HIGH Missing X-Default 887 URLs (94.76%) Noindex Return Links 49 URLs (5.24%) HIGH Non-200 hreflang URLs 8 URLs (0.85%) HIGH // the asymmetry, confirmed by hand https://www.siteimprove.com/ hreflang: none declared canonical: self https://www.siteimprove.com/de/ hreflang: en, de canonical: absent
The German homepage points at the English one; the English one declares no alternates at all, so the pair never confirms. The German page additionally ships no canonical tag while its English counterpart does — two different template behaviours for the same page type.
This compounds with the sitemap findings: the sitemap lists German toolkit pages the English equivalents are missing from, and includes three jp.siteimprove.com URLs in a sitemap hosted on www. The international configuration looks like it has been edited by several hands without a single owner.
Severity note (revised): downgraded from critical to warning. Non-reciprocal hreflang is discarded by search engines, which fall back to normal per-URL ranking — pages still index and rank, they just lose the locale-targeting benefit. Under this audit's rubric that is "indexes but hampered," not "cannot index / indexed wrong." Real, worth fixing, not critical.
/ and /de/Server response is fast and compression is on; the problem is what is being compressed.
// page weight, 936 pages median HTML 613,123 B mean 608,265 B max 998,544 B pages over 500 KB 932 of 936 (99.6%) median bytes of HTML per word of content 525 // homepage composition (non-overlapping) served decompressed 753,760 B on the wire (gzip) 199,328 B inline <script> 356,750 B (47.3%) inline <style> 286,590 B (38.0%) across 11 separate blocks plain markup + text 108,638 B (14.4%) <link rel=stylesheet> 0 <script src> 0 // timing, 3 runs ttfb 0.33 / 0.37 / 0.37 s total 0.41 / 0.45 / 0.46 s
Every page ships its CSS and JS inline, so nothing is cached across navigations — a visitor moving through five pages downloads roughly 640 KB of identical CSS and JS five times. This is a transfer, caching and CWV problem (it compounds with the absent cache headers in F-10), and it is what the independent scan's "18% content ratio" flag is pointing at.
Scope note (revised): the first draft also framed this as an AI-retrieval problem. That is not well supported and has been dropped — the same independent scan found the homepage's extracted text fits an agent context budget at about 1K tokens, so a crawler recovers the content cleanly regardless of the raw byte weight. The weight hurts human page-load and caching, not machine reading.
Size (Bytes) across 936 URLs · byte-mask composition analysis of homepage// homepage response headers, browser UA Strict-Transport-Security: max-age=63072000; includeSubDomains X-Frame-Options: SAMEORIGIN X-Content-Type-Options: nosniff Content-Security-Policy: present (very long, see F-13) Content-Encoding: gzip Access-Control-Allow-Origin: * ← on an HTML document Request-Context: appId=cid-v1:76b77375-… ← Azure App Insights app id cf-cache-status: DYNAMIC Cache-Control: absent ETag: absent Last-Modified: absent Referrer-Policy: absent Permissions-Policy: absent Vary: absent // site-wide Missing Secure Referrer-Policy Header 3,280 URLs (89.9%) HTTP (non-HTTPS) URLs 1 Protocol-Relative Resource Links 77
No Cache-Control, ETag or Last-Modified on HTML means cf-cache-status: DYNAMIC on every request and no conditional revalidation — every fetch, including every crawler fetch, hits origin. Access-Control-Allow-Origin: * on HTML documents is unusual and worth a deliberate confirmation rather than an assumption.
Images. 2,337 internal images. 1,690 (72.3%) carry no width/height attributes, a direct CLS contributor; 424 (18.1%) exceed 100 KB. On alt text, the numbers need care: 7 images have no alt attribute at all — the genuine defect — while 1,518 have an alt attribute that is empty. Empty alt="" is the correct markup for decorative images and cannot be judged automatically. The honest reading is 7 confirmed failures and 1,518 requiring human review, not 1,518 failures.
The Critical tags on the two tool findings (F-11, F-12) are product-quality severity — a shipped tool returning a wrong answer — not the site-indexability severity used elsewhere in this workbook. The two scales are not directly comparable; a critical product bug is not the same class of thing as a critical crawlability defect. They are flagged critical because each produces a demonstrably false or outdated result to a user, which for a measurement vendor is the reputational core of the product.
The July teardown's core conclusion holds unchanged in September: the endpoint, the response shape and the marketing copy are all as they were. What follows adds a defect the July pass did not test for.
$ POST marketingservices.siteimprove.com/api/Aeo/CheckAiAccessibility
{"domain":"siteimprove.com"}
{"result":{
"domain":"siteimprove.com", "status":"accessible",
"http": { chatgpt·claude·perplexity·gemini·copilot·grok·deepseek·rufus
→ each {conversational:bool, training:bool} },
"robots": { same eight engines, same two flags },
"hasSitemap": true, "error": null },
"diagnostics":{ "userAgentChecks":{…16 fetches…}, "robotsCheck":{…} }}
Eight engines × two bot classes = sixteen live user-agent fetches, plus a robots.txt parse and a sitemap check. Roughly three seconds. There is no schema parsing, no FAQ or HowTo detection, no Speakable, no Person or Organization extraction, no H1 or meta analysis, no content-depth measure and no score of any kind.
| Dimension the page promises | Signals it names | Measured? |
|---|---|---|
| Answer readiness | FAQ sections, HowTo formats, conversational query match, content depth | None |
| Trust, Accuracy & Accountability | Author attribution, publication dates, Person schema, About page | None |
| Organization, Service & Topic Clarity | A single H1, Organization schema, meta description | None |
| Technical & Accessibility Readiness | Structured data, FAQPage and HowTo schema, Speakable, HTTPS, site speed, crawler access | 1 of 6 |
Of roughly fifteen named signals, the API measures one: crawler access. The page's own words are "See exactly how AI engines read and rank your content" and "Know what makes AI treat your site as a credible source." Neither is what runs.
This is the most serious defect found in either tool, and it is new to this pass.
$ POST …/api/Aeo/CheckAiAccessibility
{"domain":"this-domain-does-not-exist-9f3k2.com"}
result.status "blocked" ← identical verdict to a real WAF block
result.hasSitemap true ← for a domain with no DNS record
result.robots all engines allowed ← robots.txt "permits" ChatGPT
result.error null
diagnostics.userAgentChecks[*]
status null
errorCode "ENOTFOUND"
errorMessage "fetch failed" ← the truth is captured, then discarded
The service knows the lookup failed and records it in diagnostics. The user-facing result throws that away and renders three false statements: that the site blocks AI crawlers, that it publishes a sitemap, and that its robots.txt admits every engine. A failed fetch is being treated as a negative result rather than as an absent result.
The failure mode matters commercially. A prospect who mistypes their domain — the single most common input error a free tool receives — is shown an alarming "blocked" verdict on a vendor's own instrument. That is a false positive generated by the tool of a company selling measurement trustworthiness in AI search.
Fix shape: propagate ENOTFOUND into result.error, introduce a fourth status (unreachable) distinct from blocked, and suppress the robots and hasSitemap assertions whenever the underlying fetch did not succeed.
evidence/aeo-*.jsonTwo things, and they should be said plainly because they push against the headline.
www.siteimprove.com/toolkit/aeo-checker/ produces sixteen fetches whose finalUrl is that exact page, not the root. I expected truncation and was wrong.nytimes.com partial with ChatGPT, Claude, Perplexity and Rufus blocked; levelaccess.com partial with Claude and Rufus blocked at the HTTP layer but not in robots; silktide.com accessible but blocking Rufus in robots; Deque, Semrush and Siteimprove clean. The user-agent list is current and the two-layer split (live fetch versus robots directive) is the right model.The engineering is sound and checks the one precondition that must hold before citation is possible. The problem is entirely the label on the box.
Mirror test. Run against its owner, the tool returns status: accessible, no blocks on any engine, sitemap found. By its own instrument Siteimprove passes — which is precisely why the instrument is too narrow to answer the question its marketing poses.
Not covered by the July teardown. It is a substantially more serious tool than the AEO Checker and fails in the opposite direction — under-marketed capability running on an outdated measurement stack.
$ GET marketingservices.siteimprove.com/checker/GrabSeoNextgenResults/
?url=…&email=…&reffererurl=… [sic — "reffererurl"]
HTTP 200 · 38.6 s · 161,820 B
AuditResults 30 checks — Has301Redirects, HasRedirectChains, HasNoindex,
HasOpenGraphTags, HasStructuredDataMarkup, HasSsl, HasEmptyH1,
MissingH1Tag, HasMultipleH1tags, MetaDescription (length),
MetaTitle (length), HasUnsafeLinks, UrlLength, …
LhAudits a real Lighthouse run
screenshotUrl Azure blob storage
id per-check GUID
Thirty genuine on-page checks plus a live Lighthouse audit and a screenshot. Note HasStructuredDataMarkup: the SEO Checker detects structured data. The AEO Checker, whose copy promises structured-data analysis, does not. The capability exists one product over.
The page markets "Core Web Vitals" scoring. The runtime predates the current set.
// LhAudits payload, decoded lighthouseVersion 9.6.8 formFactor mobile emulated device Moto G4 ← 2016 handset; Lighthouse moved to Moto G Power categories performance · accessibility · best-practices · seo · pwa ↑ PWA category removed in Lighthouse 12 audits returned 18 // Core Web Vitals coverage largest-contentful-paint present cumulative-layout-shift present first-contentful-paint present total-blocking-time present interaction-to-next-paint ABSENT experimental-interaction-to-next-paint ABSENT max-potential-fid ABSENT
INP replaced FID as an official Core Web Vital in March 2024. This build emits no INP audit under either its stable or experimental key. A tool sold on SEO authority is therefore scoring "Core Web Vitals" while measuring a superseded set — and still reporting a PWA score Google has retired. Upgrading the Lighthouse runtime is the whole fix.
evidence/seo-api.jsonWithin the same page: "The Siteimprove SEO checker crawls your site at scale" and "Run a single-page audit" / "baseline a single page or a key template". The API confirms the latter — one requestedUrl, one result. It also promises an "Action list with suggested owners (SEO, Content, Engineering)", which no field in the response supports.
The at-scale language belongs to the paid platform. Carrying it on the free tool's page sets an expectation the free tool cannot meet, which is the same seam as the AEO Checker, just narrower.
// estimated monthly traffic, siteimprove.com + subdomains
organic paid
2026-01 124,562 10,710
2026-02 129,883 2,249
2026-03 137,043 1,290
2026-04 145,431 1,079
2026-05 162,578 7,640
2026-06 159,361 12,519
2026-07 153,496 3,160
2026-08 159,707 641
2026-09 166,828 159
Organic is up roughly 34% year to date with a soft patch across June and July, now recovered. Paid has been wound down to almost nothing since June — an eighty-fold reduction from the January level. Whatever drove that decision, it places more load on organic and AI visibility than at any point in the period.
Revised since the first version of this workbook. The first cut reported Siteimprove's per-engine counts alone and read the ChatGPT/Copilot numbers as underperformance. Pulling the same metric for competitors on the same day overturns that reading — the numbers only mean something next to a peer set.
| Domain | Total (all surfaces) | Pages | ChatGPT | Perplexity | Gemini | Copilot | AI Overviews | AI Mode |
|---|---|---|---|---|---|---|---|---|
| siteimprove.com | 3,419 | 325 | 32 | 150 | 75 | 2 | 100 | 157 |
| levelaccess.com (direct) | 722 | 134 | 4 | 35 | 6 | 4 | 12 | 16 |
| deque.com (direct) | 430 | 128 | 12 | 23 | 6 | 1 | 9 | 16 |
| semrush.com (adjacent) | 89,194 | 17,337 | 6,356 | 10,382 | 3,053 | 3,271 | 4,645 | 5,523 |
| ahrefs.com (adjacent) | 28,040 | 3,559 | 5,471 | 4,161 | 918 | 1,328 | 980 | 1,549 |
The reconciliation is now solved. "Total (all surfaces)" exceeds the sum of the columns shown because one column is omitted for width: google_ai_overviews_keywords. For Siteimprove that surface alone is 2,903 citations, and 516 (the seven shown) + 2,903 = 3,419 exactly. The first version flagged this as an unexplained mismatch; it is not a mismatch, it is a surface I had not selected.
Two facts the peer set makes unavoidable, both of which correct the first draft of this section:
The defensible reading: the Bing-fed engines are an open category race where content volume and authority win, and no accessibility vendor has yet accumulated either at SEO-publisher scale. That is an opportunity framed correctly — an authority gap against the category, not a lingering access defect specific to Siteimprove.
The 3,419 is heavily concentrated in one Google surface pulling one kind of content.
google_ai_overviews_keywords 2,903 85% Google AIO, keyword-expanded google_ai_mode 157 5% perplexity 150 4% google_ai_overviews (page) 100 3% gemini 75 2% chatgpt · copilot · grok 34 1% Bing-fed + Grok, combined ───── total 3,419
Roughly 90% of the footprint is Google AI surfaces citing Siteimprove's glossary and blog. That ties directly to F-14: the AI-citation presence is real and category-leading, but it is built on the generic SEO-education content most exposed to answer-without-a-click substitution, not on the platform or accessibility-governance pages. A 60-day re-measure of the ChatGPT and Copilot columns remains the clean test of whether the unblock moves the Bing-fed surfaces — but it is now a test of upside, not a diagnosis of failure.
| Section | Org. keywords | Est. monthly visits | Share of site traffic |
|---|---|---|---|
| Whole site | 6,435 | 167,169 | 100% |
| /toolkit/ (8 free tools) | 201 | 1,493 | 0.89% |
| /why-siteimprove/competitor-comparison/ (7 pages) | 14 | 271 | 0.16% |
| /platform/seo/aeo-visibility/ | 2 | 71 | 0.04% |
The top 25 pages by traffic are almost entirely /blog/seo-* and /glossary/*-seo articles. The highest single page is seo content strategies at ~11,082 visits; the homepage ranks tenth on its own site at 4,201. No platform page appears except /platform/seo/technical-seo-auditing-tools/ at position 13.
Ranked by shared keywords, the nearest organic competitors are SEO tooling and SEO publishing, not accessibility governance.
// organic competitors, US, ranked by keyword overlap
semrush.com 2,171 common kw 3,685,655 traffic DR 92
hubspot.com 980 1,910,471 DR 93
ahrefs.com 813 4,105,955 DR 91
moz.com 645 560,505 DR 91
mtu.edu 621 389,501 DR 81
aioseo.com 616 95,684 DR 83
neilpatel.com 608 346,882 DR 91
searchengineland.com 563 105,656 DR 91
digitalmarketinginstitute 520 153,293 DR 85
rankmath.com 430 77,554 DR 88
debugbear.com 336 50,591 DR 76
conductor.com 245 122,087 DR 84
ada.gov 213 187,096 DR 91
absent from the top 15: Level Access · Deque · AudioEye · accessiBe
UserWay · Silktide · Monsido/Acquia · TPGi
Caveat on the metric. Keyword-overlap competitors are, by construction, whoever ranks for similar terms — so a site whose traffic is SEO-education content will surface SEO publishers, and accessibility vendors (who publish little such content) would not appear regardless of how directly they compete commercially. So this table is not, by itself, evidence of a strategy error. It is evidence of where the traffic is, which is the load-bearing fact.
Three consequences follow from that fact. First, the content engine competes for these queries against firms with twenty to forty times its organic traffic. Second, generic SEO-education queries are the class most exposed to answer-engine substitution, so this traffic is the most cannibalisable on the site. Third — and now confirmed rather than inferred — F-20 shows ~85% of Siteimprove's AI citations come from Google AI Overviews pulling exactly this content. So the company's AI-citation lead over its accessibility peers rests on the pages least connected to what it sells and most likely to be answered without a click. The presence is real; its durability is the open question.
This is a positioning decision for the CMO, not an SEO task, and — because of the metric caveat above — it is the one finding in this workbook whose framing I would put to that conversation before acting on it.
Three separate measurement systems fail on the company's flagship lead-generation page, all with the same cause: hosts allow-listed in script-src but omitted from connect-src.
// console errors, /toolkit/aeo-checker/ BLOCKED stats.g.doubleclick.net/g/collect GA4 measurement BLOCKED bat.bing.net/actionp/0 Microsoft Ads / Bing UET BLOCKED j.clarity.ms/collect (×3) Microsoft Clarity // the mismatch script-src allows bat.bing.com · www.clarity.ms · scripts.clarity.ms connect-src allows googleads.g.doubleclick.net · region1.analytics.google.com connect-src omits bat.bing.net · j.clarity.ms · stats.g.doubleclick.net
The scripts load, then cannot transmit. Conversion and behaviour data for this page is therefore under-reported by an unknown margin — which means any decision made about the AEO Checker's performance is being made on incomplete data. Three hostnames added to connect-src resolves it.
Severity note (revised): downgraded from critical to warning. This is a measurement-data-loss bug with real business cost, but it does not affect indexability, retrieval, or user-facing correctness, so it does not meet this audit's critical bar. It is the highest-value warning in the hygiene section, and the "unknown margin" is a genuine limit — I can prove the requests are blocked, not how many conversions that hides.
// uncaught errors, /toolkit/aeo-checker/
TypeError: Cannot destructure property 'computePosition' of
'window.FloatingUIDOM' as it is undefined. at page:121
TypeError: Cannot set properties of null (setting 'id') at page:2353
// debug statements shipped to production
console.log("not handling click") homepage nav handler, with the comment
"testing to not offset menu while working on new nav"
console.log("seo checkId: " + n.id) checkerbundle.js — logs an internal GUID
console.log("Setscore Success:", n)
// other
HubSpot forms embed script included twice on the same page
Geologica-Bold.ttf preloaded but unused — uncompressed font format, wasted on LCP path
11 duplicate DOM ids on /toolkit/seo-checker/, including id="checker-form" ×2
The duplicate ids deserve a line of their own: the SEO Checker page renders its form twice, producing eleven repeated id values. Duplicate ids break label[for] and ARIA references. On an accessibility vendor's own site, that is the kind of finding their own product would raise.
evidence/checkerbundle.jsThe two checkers submit to different systems entirely.
// AEO Checker HubSpot embedded form, EU hublet, portal 146950224
// SEO Checker Pardot form handler hello.siteimprove.com/l/550552/2021-11-23/379tnmz
via marketingservices.siteimprove.com/Checker/SubmitForm/
Three issues follow from the legacy path in checker-form.js:
gmail.com and nineteen role prefixes (info, sales, support…) in JavaScript. The server-side validator disagrees: GET /api/utility/isMailValid/?email=info@… returns true. Anyone bypassing the page bypasses the gate.error: function (data) { // TODO } followed by the same redirect as the success path. If the Pardot submission fails, the user sees their result and the lead is lost with no signal to anyone./toolkit/seo-checker/result/?website=…&email=… and the result page then calls GrabSeoNextgenResults/?url=…&email=…. Email addresses in query strings land in browser history, CDN logs and server access logs. The result page is correctly noindex, so this is not an indexing exposure — but for a company selling digital governance in an EU-first posture it is a data-handling pattern worth moving to a POST body.Minor, but worth noting alongside: the public script carries a developer's name and email in its header comment, and the query parameter is misspelled reffererurl throughout.
evidence/checker-form.js (4,289 B, read in full) · live isMailValid callsAn "Is Agentic" agent-readiness scan of siteimprove.com (Ora API, snapshot 2026-09-01T02:21:40Z) ran roughly an hour after this audit's measurement window and scored the site 61/100 — "Important blockers remain." It is worth reconciling: it is an independent instrument, on different infrastructure, measuring a partly overlapping surface on the same day.
Useful, because it was produced by a different tool from a different network — which partially answers this audit's single-IP caveat.
| Is Agentic finding | This audit |
|---|---|
| Sitemap: 948 entries | 948 <loc> entries. Exact match. |
| Homepage: 1 H1 + 4 H2s + 4 H3s | Identical heading counts (§05). Exact match. |
| Reachable to ChatGPT-User, ClaudeBot, Google-Extended, DeepSeekBot, ora-agent | Consistent with the 30-agent matrix (§03), and from separate infrastructure. Note it does not test Bingbot, so it does not independently confirm the unblock. |
| 18.0% content ratio; "remove excessive non-content markup" | Same phenomenon as F-09: 14.4% of homepage bytes are markup and text, the rest inline CSS and JS. |
Organization schema missing contactPoint, address | Confirmed — see F-19. |
This is the business consequence of F-05, caught in the wild rather than argued in principle.
The scanner probed the /.well-known/ namespace, received 200 OK on every path, and recorded three capabilities as present. All three are the same 795-byte "Resource Not Found" stub.
// what the scan reported OAuth 2.0 support Passed "OpenID Connect discovery endpoint found at https://siteimprove.com" Agent instruction / when-to-use Partial (67%) "Agent instruction file at /.well-known/agent-skills/ but no explicit when-to-use guidance" MCP server / manifest Partial (33%) "MCP endpoint found at /.well-known/mcp/manifest.json but response is not valid JSON" // what is actually served at all three HTTP 200 OK · text/html · 795 bytes · <title>Resource Not Found</title> // control /.well-known/zzz-does-not-exist → 200 OK · 795 bytes identical response
Siteimprove publishes no OpenID Connect discovery document, no agent-skills file and no MCP manifest. The scanner's "response is not valid JSON" note is it half-detecting its own false positive: the response is not valid JSON because it is an HTML error page.
Two things follow. The 61/100 is inflated — remove the false credit and it drops. And more consequentially: this is now a demonstrated pattern of an automated evaluator forming a wrong model of Siteimprove's capabilities directly from a server misconfiguration. Every agent, scanner and buyer-side evaluation tool probing that namespace will reach the same wrong conclusions, in either direction. For a company selling AI-visibility measurement, being systematically mis-measured by its own infrastructure is the finding to lead the remediation with.
Recorded so the score is not over-read in either direction.
logo and no address (F-19), so the passing line is the inaccurate one./openapi.json returns a genuine 404.developer.siteimprove.com, a GraphQL endpoint at api.siteimprove.com/v2/graphql returning a correct 401) is real and reasonable.The score itself is not worth defending or attacking. What it is worth is the demonstration in F-18: an independent evaluator, running unattended, built a materially wrong picture of Siteimprove's agent capabilities — inflating some, missing others — because of one server rule. That is the argument for fixing F-05 first.
What ran, what did not, and why. A check that could not capture evidence is recorded as unknown, never as passed.
| Layer | Status | Note |
|---|---|---|
| Crawler access matrix | Ran | 30 agents × 4 URLs, two passes, full headers on the material cases |
| robots.txt / sitemap / error handling | Ran | Fetched and parsed; sitemap reconciled against the crawl |
| Indexability and canonicals | Ran | 936 internal HTML URLs |
| On-page: titles, headings, content | Ran | Site-wide from crawl export |
| Structured data | Partial | Storage was off in the crawl config. Measured independently on 21 template representatives by direct fetch — good template coverage, not a site-wide count |
| Hreflang | Partial | Counts from SF issue analysis; link storage was off, so the per-URL report could not be generated. Asymmetry confirmed by hand on / and /de/ |
| Headers, weight, delivery | Ran | Direct measurement plus site-wide crawl data |
| AEO Checker teardown | Ran | API exercised across 6 domains plus 3 edge cases; browser inspection |
| SEO Checker teardown | Ran | API exercised against a domain I control; Lighthouse payload decoded |
| Demand and rankings | Ran | Ahrefs — Tier 2 estimates, not measured traffic |
| AI citation counts vs competitors | Ran | Added in the critical-review pass. site-explorer-ai-responses-count for 5 domains, same day, same method — this is what supports the peer comparison in F-20. Modelled estimates, not a census |
| AI share of voice (SoV) | Unknown | Blocked. Brand Radar returned Missing addon: Brand Radar ["Chatgpt"], so the v1 "4% own-domain share" could not be reproduced on its original prompt-sweep basis. Citation counts (above) are a different, coarser metric; they do not reconstruct share-of-voice on a fixed prompt set |
| Brand memory / perception scan | Unknown | No token-level scan this pass. The v1 finding (0/37 branches mention AEO) is neither confirmed nor refuted |
| Five-engine prompt sweep | Unknown | Not run. Would require the v1 methodology repeated |
| Core Web Vitals (field data) | Unknown | No CrUX or RUM access. Lab timing only (TTFB, transfer) |
| Mail authentication (SPF/DMARC) | Unknown | Attempted; the resolver returned empty TXT values. MX confirmed as Microsoft 365, NS as AWS Route 53 |
| Layer 7 exposure probing | Not in scope | Deliberately not run. No written authorisation for security testing. Untested, not passed |
| Accessibility conformance | Not in scope | Only incidental observations (duplicate ids, alt attributes). No WCAG audit was performed |
| Agent / API readiness surface | Partial | Not an original scope item. Reached via the Is Agentic scan (§12) and verified independently at 15 paths. The /.well-known/ and .txt behaviour in F-05 and F-18 is confirmed first-hand; claims about the GraphQL API, developer portal and onboarding are third-party and were not re-tested beyond status codes |
all_platforms citation figure reconciles once google_ai_overviews_keywords (2,903) is added to the seven listed surfaces (516): 516 + 2,903 = 3,419. The earlier "does not reconcile" note was my omission of that column, not a data fault.