# AEO Audit for Magento 2  -  module reference

> Install and run the free AEO Audit module for Magento 2: 20 AI-visibility signals, CLI flags for CI, admin history, cron, and how to add your own checks.

Source: https://angeo.dev/docs/modules/aeo-audit/
Updated: 2026-10-17

Module reference

# AEO Audit for Magento 2  -  module reference

Covers `angeo/module-aeo-audit` 4.2.4 - Checked 16 October 2026 - MIT licensed

**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.

Package`angeo/module-aeo-audit`Latest version4.2.4Magento2.4.xPHP8.1 - 8.5LicenseMIT, freeLinks[GitHub](https://github.com/angeo-dev/module-aeo-audit) - [Packagist](https://packagist.org/packages/angeo/module-aeo-audit) - [Changelog](https://github.com/angeo-dev/module-aeo-audit/blob/main/CHANGELOG.md) - [Module page](https://angeo.dev/modules/aeo-audit/)

**On this page**

1. What it checks
2. Requirements
3. Installation
4. Running the audit
5. Admin panel
6. Configuration reference
7. Cron and stored data
8. Adding your own check
9. FAQ
10. Related

## 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_audit` permission.

## 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](https://angeo.dev/docs/modules/robots-txt-aeo/)  -  manage AI crawler rules in robots.txt and verify real bots
- [llms.txt](https://angeo.dev/docs/modules/llms-txt/)  -  generate llms.txt, llms.jsonl, Markdown mirrors and agents.md
- [Rich Data](https://angeo.dev/docs/modules/rich-data/)  -  one linked JSON-LD graph per page, with offers and policies
- [AEO Brand Visibility](https://angeo.dev/docs/modules/aeo-brand-visibility/)  -  measure whether AI assistants name and recommend your store
- [AI Agent Activity](https://angeo.dev/docs/modules/agent-activity/)  -  report on AI agent calls, crawler visits, fake bots and agent-built orders
- [All module reference pages](https://angeo.dev/docs/modules/) - [Compatibility matrix](https://angeo.dev/docs/compatibility/)

This page was written from the `README.md`, `composer.json` and `etc/*.xml` files of [tag 4.2.4](https://github.com/angeo-dev/module-aeo-audit/tree/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.
