AEO Audit for Magento 2 — module reference
AEO Audit checks how ready a Magento 2 store is for AI answer engines such as ChatGPT, Gemini, Claude and Perplexity. One command scores 20 signals per store view. For every failed signal it tells you what is wrong and how to fix it.
The module only reads. It does not change your store. You can run it on production, on staging, or in a CI pipeline.
What it checks
The audit has two layers. Configuration signals check that the store is set up for AI engines. Evidence signals (added in 4.0.0) check that AI crawlers can really reach the store.
| # | Signal | Code | Weight | What it checks |
|---|---|---|---|---|
| 1 | robots.txt — AI bots | robots_txt | 1.0 | 12 AI bots, syntax errors, conflicting rules |
| 2 | llms.txt | llms_txt | 1.0 | llms.txt v2 structure, locale and currency, links |
| 3 | llms.jsonl | llms_jsonl | 0.75 | Valid JSON Lines, required fields |
| 4 | sitemap.xml | sitemap | 0.8 | XML, lastmod, catalog size |
| 5 | Product schema | product_schema | 1.0 | JSON-LD on a real product page, offers |
| 6 | Merchant policies | merchant_policies | 0.9 | Return policy and shipping details in the offer |
| 7 | Organization schema | organization_schema | 0.8 | Organization on the homepage, logo, sameAs |
| 8 | UCP profile | ucp_profile | 0.9 | /.well-known/ucp, signing keys, leaked private keys |
| 9 | AI product feed | ai_product_feed | 1.0 | Feed file and REST endpoint |
| 10 | JSON-LD quality | jsonld_quality | 0.7 | Breadcrumbs, ItemList, duplicate schemas |
| 11 | Canonical and hreflang | canonical | 0.7 | Canonical agrees with og:url and JSON-LD |
| 12 | Open Graph | open_graph | 0.7 | All five OG tags |
| 13 | FAQ schema | faq_schema | 0.5 | FAQPage on the homepage or a CMS page |
| 14 | Well-known files | well_known | 0.5 | ucp, ai-plugin.json, security.txt, mcp |
| 15 | Core Web Vitals | core_web_vitals | 0.5 | LCP, INP, CLS from Google CrUX (needs an API key) |
| 16 | WAF reality check | waf_reality | 0.9 | Does your CDN or firewall block bots that robots.txt allows? |
| 17 | AI crawler activity | ai_crawler_activity | 0.5 | Which AI crawlers really visited |
| 18 | A2A Agent Card | agent_card | 0.6 | /.well-known/agent-card.json, only when UCP declares A2A |
| 19 | llms.txt link relations | link_relations | 0.7 | rel="alternate" and rel="describedby" links |
| 20 | agents.md | agents_md | 0.7 | Delivery, returns and privacy pages reachable |
You can switch each signal on or off in the configuration. A switched-off signal is not part of the score.
Bots are judged by purpose
The audit knows three kinds of AI bot:
- Search bots (OAI-SearchBot, PerplexityBot, Claude-SearchBot) index pages for AI answers. Blocking one is a fail, because the store drops out of AI answers.
- Training bots (GPTBot, ClaudeBot, CCBot) collect pages to train models. Blocking one is your licensing choice. It is reported, but it does not lower the score.
- Opt-out tokens (Google-Extended, Applebot-Extended) never crawl. They are shown as notices.
The evidence layer
waf_reality and ai_crawler_activity work together:
| WAF check | Crawler activity | What it means |
|---|---|---|
| Edge blocks the probe | No visits | A real block. Allow AI crawlers in your WAF or CDN. |
| Edge blocks the probe | Healthy visits | Your CDN blocks fake bots and lets real ones in. No action. |
| Consistent | No visits | The store is probably not discovered yet. |
| Consistent | Search visits | The store is fully visible to AI. |
Crawler activity comes from built-in counting at the PHP level (on by default). You can add your web server access log, or your own source through BotHitSourceInterface. Only daily totals per bot are stored. No IP addresses, URLs or user agents.
Pages served from full-page cache or a CDN never reach PHP, so the built-in counter under-counts. The report says so.
Requirements
| Magento | 2.4.x (Open Source, Mage-OS or Adobe Commerce) — magento/framework ^103.0 |
|---|---|
| PHP | 8.1 – 8.5 — ~8.1.0||~8.2.0||~8.3.0||~8.4.0||~8.5.0 |
The audit works best with the other angeo modules installed, because most fix hints point to one of them. It also works alone.
Installation
composer require angeo/module-aeo-audit
bin/magento module:enable Angeo_AeoAudit
bin/magento setup:upgrade
bin/magento setup:di:compile # production mode only
bin/magento setup:static-content:deploy # production mode only
bin/magento cache:flush
Running the audit
# All store views
bin/magento angeo:aeo:audit
# One store view
bin/magento angeo:aeo:audit --store=en_us
# JSON for dashboards, Markdown for reports
bin/magento angeo:aeo:audit --format=json
bin/magento angeo:aeo:audit --format=markdown --output=/var/www/html/aeo-report.md
# Only fast technical checks, no external APIs
bin/magento angeo:aeo:audit --category=technical
# Fail a CI build below a score, or on any critical failure
bin/magento angeo:aeo:audit --fail-on=80
bin/magento angeo:aeo:audit --fail-on-severity=critical
# Do not save the result to the database
bin/magento angeo:aeo:audit --no-save
| Option | Meaning |
|---|---|
--store | Store view code. Default: all store views. |
--format | table (default), json or markdown |
--output | Write the report to a file |
--category | Only run checks of these categories, comma separated: technical, feed, external_api, live_signal |
--fail-on | Exit code 1 when the score is below this number |
--fail-on-severity | Exit code 1 when a check of this severity fails, for example critical |
--no-save | Do not store the result |
The score reads like this:
| Score | Label | Typical store |
|---|---|---|
| 0–25 % | Critical | Default Magento. AI crawlers blocked, no schema. |
| 26–75 % | Needs improvement | Some fixes done. Feed, policies or UCP missing. |
| 76–90 % | Good | Strong base. Small gaps. |
| 91–100 % | Excellent | All signals in place. |
Admin panel
- Marketing → Angeo AEO → AEO Audit Results shows every past audit.
- Marketing → Angeo AEO → Score Trend shows the score over time.
- Run Audit Now starts an audit from the admin. It is a POST action with a form key, and it needs the
Angeo_AeoAudit::run_auditpermission.
Configuration reference
All settings are under Stores → Configuration → Angeo → AEO Audit. The table shows each field, its config path (for bin/magento config:set) and its default value.
Signals (Checks) (18)
| Setting | Config path | Default |
|---|---|---|
| robots.txt — AI bot access | angeo_aeo/signals/robots_txt | Yes |
| llms.txt | angeo_aeo/signals/llms_txt | Yes |
| llms.jsonl — machine-readable catalog | angeo_aeo/signals/llms_jsonl | Yes |
| sitemap.xml — AI crawler discovery | angeo_aeo/signals/sitemap | Yes |
| Product JSON-LD schema | angeo_aeo/signals/product_schema | Yes |
| Merchant return & shipping policies | angeo_aeo/signals/merchant_policies | Yes |
| Organization JSON-LD schema | angeo_aeo/signals/organization_schema | Yes |
| UCP profile (/.well-known/ucp) | angeo_aeo/signals/ucp_profile | Yes |
| AI product feed | angeo_aeo/signals/ai_product_feed | Yes |
| JSON-LD quality | angeo_aeo/signals/jsonld_quality | Yes |
| Canonical & hreflang | angeo_aeo/signals/canonical | Yes |
| Open Graph tags | angeo_aeo/signals/open_graph | Yes |
| FAQPage schema | angeo_aeo/signals/faq_schema | Yes |
| well-known endpoint matrix | angeo_aeo/signals/well_known | Yes |
| Core Web Vitals (CrUX) | angeo_aeo/signals/core_web_vitals | Yes |
| A2A Agent Card | angeo_aeo/signals/agent_card | Yes |
| Edge vs robots.txt consistency (WAF reality) | angeo_aeo/signals/waf_reality | Yes |
| AI crawler activity (observed) | angeo_aeo/signals/ai_crawler_activity | Yes |
General (1)
| Setting | Config path | Default |
|---|---|---|
| Show fix suggestions | angeo_aeo/general/show_fix_suggestions | Yes |
Live Signal (Observed Crawler Activity) (4)
| Setting | Config path | Default |
|---|---|---|
| Built-in instrumentation | angeo_aeo/live_signal/instrumentation_enabled | Yes |
| Webserver access log path (optional) | angeo_aeo/live_signal/access_log_path | — |
| Evidence window (days) | angeo_aeo/live_signal/window_days | 30 |
| Counter retention (days) | angeo_aeo/live_signal/retention_days | 90 |
Scheduled Audit (1)
| Setting | Config path | Default |
|---|---|---|
| Cron schedule | angeo_aeo/cron/schedule | 0 3 * * 1 |
Sitemap Checker (2)
| Setting | Config path | Default |
|---|---|---|
| Placeholder slug handling | angeo_aeo/sitemap/placeholder_slug_mode | score |
| Placeholder slug threshold | angeo_aeo/sitemap/placeholder_slug_threshold | 1 |
Core Web Vitals (CrUX API) (1)
| Setting | Config path | Default |
|---|---|---|
| CrUX API Key | angeo_aeo/crux/api_key | — (stored encrypted) |
The CrUX API key is free. Create it in the Google Cloud console and enable the Chrome UX Report API. Without a key, the Core Web Vitals check is skipped.
To read an access log, point the module at a file the PHP user can read. Do not chmod the live log. Give targeted access instead, for example setfacl -m u:www-data:r /var/log/nginx/access.log. Only the last 8 MB of the file is read.
Cron and stored data
The scheduled audit runs every Monday at 03:00 by default. It keeps the last 50 results per store. Old bot counters are removed after the retention period.
| Job | Cron group | Schedule |
|---|---|---|
angeo_aeo_audit | default | 0 3 * * 1 by default, set in angeo_aeo/cron/schedule |
| Table | What it holds | Columns |
|---|---|---|
angeo_aeo_audit_result | Angeo AEO Audit Results | id, store_code, store_url, score, score_label, pass_count, warn_count, fail_count, checks_json, triggered_by, created_at |
angeo_aeo_bot_hit | Angeo AEO Bot Hit Counters | id, bot_code, bot_class, store_id, hit_date, hits, last_seen |
Adding your own check
Implement Angeo\AeoAudit\Api\CheckerInterface, or extend Angeo\AeoAudit\Model\Checker\AbstractChecker (it gives you the HTTP cache, URL sampling and JSON-LD parsing). Then register it in di.xml:
<type name="Angeo\AeoAudit\Model\AuditRunner">
<arguments>
<argument name="checkers" xsi:type="array">
<item name="my_check" xsi:type="object">Vendor\Module\Model\Checker\MyChecker</item>
</argument>
</arguments>
</type>
A checker returns its name, code, weight (0–1), category, severity and a fix command, and runs check(StoreInterface $store). One failing checker does not stop the audit.
FAQ
Does the audit change anything on my store?
No. It only reads pages and configuration. It writes only its own result rows, and you can turn that off with --no-save.
Why does blocking GPTBot not lower my score?
GPTBot collects pages for model training. Blocking it is a licensing choice and does not remove you from AI search. Blocking a search bot such as OAI-SearchBot does, so that one fails the audit.
Can I use it in CI?
Yes. Use --format=json for machine-readable output and --fail-on or --fail-on-severity to fail the build. Add --category=technical for a fast run without external APIs.
Why is Core Web Vitals skipped?
The check needs a free Google CrUX API key. Add it under Core Web Vitals (CrUX API) in the configuration. Small stores may also have no CrUX data yet.
Does it work with Hyvä?
Yes. The product schema check detects Hyvä, and the module has no storefront code.
Related
- Robots.txt AEO — manage AI crawler rules in robots.txt and verify real bots
- llms.txt — generate llms.txt, llms.jsonl, Markdown mirrors and agents.md
- Rich Data — one linked JSON-LD graph per page, with offers and policies
- AEO Brand Visibility — measure whether AI assistants name and recommend your store
- AI Agent Activity — report on AI agent calls, crawler visits, fake bots and agent-built orders
- All module reference pages · Compatibility matrix
This page was written from the README.md, composer.json and etc/*.xml files of tag 4.2.4, read on 16 October 2026. Settings, commands and defaults come straight from that code. If a newer release is out, the README on GitHub wins.