angeo / module-aeo-audit
angeo/module-aeo-audit
Magento 2 AEO (AI Engine Optimization) Audit. v3 covers 15 signals — robots.txt AI bots, llms.txt + llms.jsonl, Product / Organization / FAQ schema, merchant return + shipping policies, sitemap.xml, UCP profile, AI product feed, OG tags, canonical + hreflang, JSON-LD quality, well-known endpoint matrix, Core Web Vitals via CrUX. Score Trend dashboard, Admin UI, cron, dynamic fix commands, dependency-injected extension point for custom checkers.
Angeo AEO Audit — AI Engine Optimization for Magento 2
One CLI command that tells you exactly why ChatGPT, Gemini, Claude, and Perplexity aren't recommending your store — and how to fix it.
- 🏠 Project home: angeo.dev
- 📦 Source: github.com/angeo-dev/module-aeo-audit
- 🐛 Issues: github.com/angeo-dev/module-aeo-audit/issues
- 📖 Full guide: Magento 2 AEO Guide 2026
Compatibility
| Component | Version |
|---|---|
| Magento Open Source | 2.4.6, 2.4.7, 2.4.8 |
| Adobe Commerce | 2.4.6, 2.4.7, 2.4.8 |
| Adobe Commerce Cloud | All current versions |
| PHP | 8.2, 8.3, 8.4 |
| Themes | Luma, Hyvä |
Tested with: Magento Open Source 2.4.7-p3 + PHP 8.3 + Hyvä 1.3.
What's new in v3.0.0
Major release — see CHANGELOG.md for the breaking-change
migration guide if you have custom checkers.
15 signals (up from 9), reflecting the actual AEO landscape of 2026: AI
shopping integrations, merchant policies, agentic commerce, and structured-data
quality.
6 new checkers:
merchant_policies—MerchantReturnPolicy+OfferShippingDetails—
required by Google AI Mode and ChatGPT Shopping since Jan 2026organization_schema— brand entity in AI knowledge graphsucp_profile— Universal Commerce Protocol (/.well-known/ucp), with
built-in security check that detects leaked JWK private keysjsonld_quality— three-page schema breadth audit (homepage / category /
product),WebSite+SearchAction,BreadcrumbList,ItemListwell_known— discovery matrix for/.well-known/{ucp,ai-plugin.json,security.txt,mcp}core_web_vitals— LCP / INP / CLS via Google CrUX API (free, opt-in
with API key)
Refactored architecture (this is the BC-break):
- Shared
Service\HttpCache— eliminates duplicate fetches across checkers
(hundreds of redundant HTTP requests on multi-store audits before, dozens
now) Service\StoreUrlSampler— single source of truth for product / category /
CMS URL sampling- New
--categoryand--fail-on-severityCLI flags for CI workflows - Per-checker exception isolation — slow or failing checkers no longer halt
the audit run
Note on access-log monitoring: an
ai_bot_trafficchecker was
prototyped during v3 development and excluded from the release after
security review — it encouraged broad read access on/var/log/nginx/,
didn't work on Cloud/containerised hosting, and was dominated by false
positives behind edge caches. AI-bot traffic is better measured at the
edge (Fastly/Cloudflare Analytics) or via APM (New Relic, Datadog) than
inside a PHP module. See CHANGELOG.md "Considered and rejected" for the
full rationale. Thelive_signalcategory remains inCheckerInterface
for third-party modules with secure live-signal sources — notably
angeo/module-aeo-brand-visibility.
What it checks — 15 signals
| # | Signal | Code | Weight | Category | What it validates |
|---|---|---|---|---|---|
| 1 | robots.txt — AI bots | robots_txt |
1.0 | technical | 12 AI bots, syntax errors, versioned UAs, conflicting rules |
| 2 | llms.txt — content map | llms_txt |
1.0 | technical | Spec compliance + store-locale + currency match + cross-host links |
| 3 | llms.jsonl — catalog | llms_jsonl |
0.75 | technical | JSON Lines validity, required fields, eCommerce fields |
| 4 | sitemap.xml | sitemap |
0.8 | technical | XML, lastmod, .gz, catalog disproportion |
| 5 | Product schema | product_schema |
1.0 | technical | JSON-LD on real product, offers, Hyvä detection |
| 6 | Merchant policies ★ NEW | merchant_policies |
0.9 | technical | hasMerchantReturnPolicy, OfferShippingDetails, priceValidUntil, itemCondition |
| 7 | Organization schema ★ NEW | organization_schema |
0.8 | technical | Organization / OnlineStore on homepage, sameAs, logo |
| 8 | UCP profile ★ NEW | ucp_profile |
0.9 | technical | /.well-known/ucp, signing keys, leaked-private-key detection |
| 9 | AI product feed | ai_product_feed |
1.0 | feed | Feed file, /.well-known/ai-plugin.json, REST endpoint |
| 10 | JSON-LD quality ★ NEW | jsonld_quality |
0.7 | technical | Breadcrumb, ItemList, WebSite+SearchAction, duplicate schemas |
| 11 | Canonical + hreflang | canonical |
0.7 | technical | Canonical agrees with og:url + JSON-LD url; hreflang on multi-store |
| 12 | Open Graph | open_graph |
0.7 | technical | All 5 OG tags, description length |
| 13 | FAQ schema | faq_schema |
0.5 | technical | FAQPage JSON-LD on homepage or sampled CMS page |
| 14 | Well-known matrix ★ NEW | well_known |
0.5 | technical | ucp / ai-plugin.json / security.txt / mcp inventory |
| 15 | Core Web Vitals ★ NEW | core_web_vitals |
0.5 | external_api | LCP / INP / CLS via Google CrUX (API key required) |
★ NEW = added in v3.0.0.
Installation
composer require angeo/module-aeo-audit
bin/magento setup:upgrade
bin/magento cache:flush
For full coverage, install the companion modules:
composer require \
angeo/module-llms-txt \
angeo/module-rich-data \
angeo/module-openai-product-feed \
angeo/module-openai-product-feed-api \
angeo/module-ucp \
angeo/module-aeo-brand-visibility
CLI usage
# Audit all stores
bin/magento angeo:aeo:audit
# Specific store
bin/magento angeo:aeo:audit --store=en_us
# JSON output (for dashboards / CI)
bin/magento angeo:aeo:audit --format=json
# Markdown report to file
bin/magento angeo:aeo:audit --format=markdown --output=/var/www/html/aeo-report.md
# Fast technical-only checks (skip external APIs)
bin/magento angeo:aeo:audit --category=technical
# Run only external-API checks (Core Web Vitals + any third-party live signals)
bin/magento angeo:aeo:audit --category=external_api,live_signal
# Fail build if score below threshold
bin/magento angeo:aeo:audit --fail-on=80
# Fail build if any critical-severity check fails
bin/magento angeo:aeo:audit --fail-on-severity=critical
# Run without saving to DB (CI / read-only environments)
bin/magento angeo:aeo:audit --no-save
Sample output:
AEO Score: [████████████████░░░░] 81% — Good
✓ Pass: 12 ⚠ Warn: 3 ✗ Fail: 1
Critical fixes needed:
→ Install angeo/module-openai-product-feed and register at chatgpt.com/merchants
💡 Fix with angeo modules:
composer require angeo/module-openai-product-feed angeo/module-openai-product-feed-api
composer require angeo/module-ucp
Configuration
Some checkers need configuration. All are accessed via:
Stores → Configuration → Angeo AEO.
| Setting | Purpose |
|---|---|
| CrUX API Key | Required by core_web_vitals checker. Free key from console.cloud.google.com — enable the Chrome UX Report API. Stored encrypted. |
Admin UI
- Marketing → Angeo AEO → AEO Audit Results — full history grid
- Marketing → Angeo AEO → Score Trend — line chart of AEO score over time
- Marketing → Angeo AEO → Run Audit Now — trigger an on-demand audit
Score interpretation
| Score | Label | Typical situation |
|---|---|---|
| 0–25% | Critical | Default Magento install. AI crawlers blocked. No schema. |
| 26–50% | Needs Improvement | Some fixes applied. Feed or merchant policies missing. |
| 51–75% | Needs Improvement | Core signals in place. UCP, ai-plugin.json, or hreflang missing. |
| 76–90% | Good | Strong foundation. Minor gaps in well-known or CWV. |
| 91–100% | Excellent | Full 2026 AEO compliance. |
Cron
Weekly audit every Monday at 03:00 server time. Results saved to DB,
last 50 per store retained.
bin/magento cron:run --group=default
For fast daily checks (without external APIs or log scans), schedule an
additional cron job calling the audit with --category=technical.
Extending with custom checks
Implement Angeo\AeoAudit\Api\CheckerInterface (or extend
Angeo\AeoAudit\Model\Checker\AbstractChecker, which provides HTTP cache,
URL sampling and JSON-LD parsing), and register via 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>
v3 interface:
public function getName(): string; // "My Custom Check"
public function getCode(): string; // "my_check"
public function getWeight(): float; // 0.0–1.0
public function getCategory(): string; // CheckerInterface::CATEGORY_*
public function getSeverity(): string; // CheckerInterface::SEVERITY_*
public function getFixCommand(): string; // "composer require vendor/fix-module" or ""
public function check(\Magento\Store\Api\Data\StoreInterface $store): CheckResult;
Migrating from v2? See CHANGELOG.md for the migration guide.
Running tests
vendor/bin/phpunit -c app/code/Angeo/AeoAudit/phpunit.xml
v3 ships with unit tests covering all 15 checkers, both services
(HttpCache, StoreUrlSampler), the AuditRunner, and the report value
objects.
Code quality
# Magento Coding Standard
vendor/bin/phpcs --standard=Magento2 \
--extensions=php,phtml --severity=10 \
app/code/Angeo/AeoAudit/
# PHPStan static analysis
vendor/bin/phpstan analyse -l 5 app/code/Angeo/AeoAudit/
The Angeo AI Visibility Suite
| Module | Signal | Purpose |
|---|---|---|
angeo/module-aeo-audit |
— | This module — audit all 15 signals |
angeo/module-robots-txt-aeo |
#1 | Inject AI bot rules into robots.txt |
angeo/module-llms-txt |
#2, #3 | Generate llms.txt and llms.jsonl |
angeo/module-rich-data |
#5, #6, #7, #13 | Product, Organization, FAQ JSON-LD + merchant policies |
angeo/module-openai-product-feed |
#9 | ACP product feed for ChatGPT Shopping |
angeo/module-openai-product-feed-api |
#9 | REST API — 6 ACP endpoints |
angeo/module-openai-instant-checkout |
— | Agentic Commerce Protocol — instant checkout from ChatGPT |
angeo/module-ucp |
#8 | Universal Commerce Protocol — /.well-known/ucp |
angeo/module-aeo-brand-visibility |
(extends) | Live AI visibility across ChatGPT, Claude, Perplexity, Gemini, Groq |
Contributing
Issues and PRs welcome at github.com/angeo-dev/module-aeo-audit.
Before opening a PR:
- Run
vendor/bin/phpunit -c phpunit.xml— all tests must pass - Run
vendor/bin/phpcs --standard=Magento2— no MCS violations - Add tests for any new checker
License
MIT — see LICENSE
Made with care by Ievgenii Gryshkun — open-source
contributions to the Magento + AI commerce ecosystem.
Changelog
All notable changes to angeo/module-aeo-audit will be documented in this file.
The format is based on Keep a Changelog,
and this project adheres to Semantic Versioning.
[3.0.0] — 2026-05-22
Major release. Adds 6 new checkers, refactors the checker architecture, and
requires changes in third-party modules that implementCheckerInterface.
⚠️ Breaking changes
CheckerInterface::check()signature changed from
check(string $baseUrl): CheckResultto
check(\Magento\Store\Api\Data\StoreInterface $store): CheckResult.
Custom checkers must be updated. The base URL is available via
$store->getBaseUrl()orStoreUrlSampler::getBaseUrl($store).CheckerInterfaceadds two required methods:getCategory(): stringand
getSeverity(): string. SubclassingAbstractCheckerprovides sensible
defaults (technical / weight-derived severity). Custom checkers extending
the interface directly need to implement both.AbstractCheckerconstructor signature changed. Now requires
HttpCacheandStoreUrlSamplerinstead ofCurl. DI handles this
automatically for checkers that don't override the constructor.
Added — 6 new checkers (now 15 total signals)
MerchantPoliciesChecker— validateshasMerchantReturnPolicy+
OfferShippingDetails+priceValidUntil+itemConditionon a sampled
product. Required by Google AI Mode and ChatGPT Shopping since Jan 2026.
Weight 0.9.OrganizationSchemaChecker— validatesOrganization/OnlineStore
JSON-LD on the homepage. Establishes brand entity in AI knowledge graphs.
Weight 0.8.UcpProfileChecker— validates/.well-known/ucp(Universal Commerce
Protocol, integration withangeo/module-ucp). HTTPS-only, JWK validation
including leaked-private-key detection (CRITICAL security check).
Weight 0.9.JsonLdQualityChecker— three-page scan (home + product + category) with
@contextvalidation, duplicate-schema detection,BreadcrumbList/
ItemList/WebSite+SearchActionpresence. Weight 0.7.WellKnownAggregateChecker— inventory matrix for/.well-known/ucp,
ai-plugin.json,security.txt,mcp. Weight 0.5.CoreWebVitalsChecker— LCP / INP / CLS via Google CrUX API
(requires API key under Stores → Configuration → Angeo AEO).
Categoryexternal_api. Weight 0.5.
Added — architecture
Service\HttpCache— request-scoped HTTP cache. Eliminates duplicate
fetches across checkers (a singlerunAll()for 10 stores went from
hundreds of HTTP requests to a few dozen).Service\StoreUrlSampler— centralized product / category / CMS URL
sampling, memoized per store. Replaces ad-hoc sampling logic inside
individual checkers.--categoryCLI flag — filter checkers by category
(technical|live_signal|external_api|feed). Useful for fast cron checks.--fail-on-severityCLI flag — fail the build oncritical/important
/infoseverity. Complements--fail-on=<score>for CI.- Per-checker timeout logging — slow checkers (>30s) emit warning to log;
checker exceptions no longer halt the audit run. Test/Unit/Model/Checker/CheckerTestHelpertrait — shared test scaffolding
for checker unit tests.
Enhanced — existing checkers
RobotsTxtChecker: detects versioned UAs (GPTBot/1.0),Crawl-delay
on bots that ignore it, HTTP sitemap directives, conflictingAllow:/
Disallow:rules. AI bot list expanded to 12.SitemapXmlChecker: detectssitemap.xml.gz, compares URL count to
active catalog product count (warns on >30% delta).LlmsTxtChecker: validates store-locale + currency match metadata;
flags cross-host links on subdomain stores.CanonicalChecker: now cross-checks canonical againstog:urland
Product JSON-LDurl; verifies HTTPS; checks hreflang presence on
multi-store setups.
Considered and rejected — ai_bot_traffic checker
An access-log-based AI-bot traffic checker was prototyped during the v3
development cycle and excluded from the release after a security and
usefulness review. The summary, recorded so the trade-off is documented:
- Encouraged poor permissions hygiene. The natural way to make
/var/log/nginx/access.logreadable to PHP-FPM isusermod -aG adm www-dataorchmod 644, both of which expose unrelated sensitive logs
(auth.log, syslog) to any future LFI/RCE in the application. The
bundled ACL guidance helped, but a module whose presence creates the
incentive at all violates "secure by default". - Unusable on managed platforms. On Adobe Commerce Cloud, Magento
Cloud, and any containerised hosting, nginx logs go to stdout and
centralised collection (Fastly/New Relic/Splunk). PHP-FPM cannot read
them at all. The check returns WARN on these platforms 100% of the
time, contributing only noise. - Dominated by false positives. Even on self-hosted setups, sites
behind Cloudflare/Fastly with edge caching never see the AI bots reach
origin — the bots are served from edge. WARN again. - Better-served externally. Edge analytics (Fastly, Cloudflare
Analytics), APM platforms (New Relic, Datadog), and dedicated log
analyzers (GoAccess, Matomo) measure AI-bot traffic without coupling
it to PHP application permissions.
This means 15 built-in signals, not 16. The live_signal category
remains in CheckerInterface for third-party modules that have their own
secure live-signal source — notably angeo/module-aeo-brand-visibility,
which queries AI provider APIs rather than parsing host logs.
Configuration
- New encrypted config field:
angeo_aeo/crux/api_key
(Stores → Configuration → Angeo AEO → CrUX API Key).
Suggested
- New
suggestentry:angeo/module-ucp— companion module for UCP profile. - New
suggestentry:angeo/module-aeo-brand-visibility— live AI
visibility checker (adds abrand_visibilitysignal via DI injection).
Migration guide for v2 → v3
For most users (using only built-in checkers): composer update. No code
changes needed.
For custom checkers extending AbstractChecker: update the check() signature:
- public function check(string $baseUrl): CheckResult
+ public function check(\Magento\Store\Api\Data\StoreInterface $store): CheckResult
{
- [$status, $html] = $this->fetch($baseUrl . '/path');
+ $base = $this->urlSampler->getBaseUrl($store);
+ [$status, $html] = $this->fetch($base . '/path');
}
For custom checkers implementing CheckerInterface directly: also add
getCategory() and getSeverity(). Sensible defaults:
public function getCategory(): string { return CheckerInterface::CATEGORY_TECHNICAL; }
public function getSeverity(): string { return CheckerInterface::SEVERITY_IMPORTANT; }
[2.1.2] — 2026-05-01
Fixed
- Recursive
@graphparsing in JSON-LD extraction — handles nested@graphand top-level array roots correctly - Bug-report URL in fallback error path now points to the correct repository
- Composer constraint accuracy: explicit
^ranges for Magento dependencies instead of* Test/directory excluded from production classmap
Added
- Unit tests for
ProductSchemaChecker,FaqSchemaChecker,ProductFeedChecker,LlmsJsonlChecker(9 of 9 checkers now have tests) CHANGELOG.mdandCONTRIBUTING.md- GitHub Actions CI workflow (PHPUnit + PHPStan + MCS)
- Magento Coding Standard as a
require-devdependency
Changed
- README updated with explicit Magento version compatibility (2.4.6, 2.4.7, 2.4.8)
- README mentions tested PHP versions (8.2, 8.3, 8.4)
- Removed hardcoded
versionfield fromcomposer.json— Packagist resolves from git tags
[2.1.1] — 2026-04-24
Added
getFixCommand()method onCheckerInterfacefor dynamic CLI fix suggestionsLlmsJsonlCheckerfor/llms.jsonlvalidation- Score Trend dashboard in admin UI
[2.1.0] — 2026-04-15
Added
- Score Trend dashboard
- Dynamic fix commands in CLI output
- Deeper
llms.txtvalidation (12 checks)
[2.0.0] — 2026-03-20
Added
- Deep robots.txt parser with first-match semantics
- Product schema validation including
offers.availability - Hyvä theme detection
- Admin UI with results grid
- Cron scheduling (weekly Monday 03:00)
- Extensible architecture via
CheckerInterface+di.xml
Changed
- Weighted scoring: critical signals weight 1.0, informational lower
[1.0.0] — 2026-02-10
Added
- Initial release with 6 AEO signal checks
- CLI command
bin/magento angeo:aeo:audit - Table, JSON, and Markdown output formats
| Version | Stability | QA Status | Released |
|---|---|---|---|
| 3.0.0 | stable | Fail | 2026-05-28 18:54:28 |
| 2.1.2 | stable | Not tested | 2026-05-15 10:02:00 |
| 2.1.1 | stable | Not tested | 2026-04-24 20:27:14 |
| 2.1.0 | stable | Not tested | 2026-04-24 19:37:35 |
| 2.0.1 | stable | Not tested | 2026-04-19 18:21:18 |
| 2.0.0 | stable | Not tested | 2026-04-16 19:27:52 |
| 1.0.0 | stable | Not tested | 2026-04-02 18:37:34 |
Requires 8
| Package | Constraint |
|---|---|
| magento/framework | ^103.0 |
| magento/module-backend | ^102.0 |
| magento/module-catalog | ^104.0 |
| magento/module-cms | ^104.0 |
| magento/module-config | ^101.2 |
| magento/module-store | ^101.1 |
| magento/module-ui | ^101.2 |
| php | ~8.2.0||~8.3.0||~8.4.0 |
Requires-dev 3
| Package | Constraint |
|---|---|
| magento/magento-coding-standard | ^33.0 |
| phpstan/phpstan | ^1.10 |
| phpunit/phpunit | ^10.0 |
Suggests 7
| Package | Reason |
|---|---|
| angeo/module-aeo-brand-visibility | Live AI visibility check across ChatGPT, Claude, Perplexity, Gemini |
| angeo/module-llms-txt | Generate llms.txt and llms.jsonl |
| angeo/module-openai-product-feed | ACP product feed for ChatGPT Shopping |
| angeo/module-openai-product-feed-api | REST API endpoints for ACP feed |
| angeo/module-rich-data | Product, Organization, FAQ JSON-LD and merchant policies |
| angeo/module-robots-txt-aeo | Fix robots.txt AI bot access |
| angeo/module-ucp | Universal Commerce Protocol profile (/.well-known/ucp) for Google AI Mode / Gemini |
| Tool | Status | Findings | Summary |
|---|---|---|---|
| PHPCS | Fail | 2 | 2 errors (gating threshold: error-severity=10, ruleset: Magento2) |
| PHPStan | Pending | 0 | |
| Cpd | Pass | 0 | |
| Security | Pass | 0 |
Turn an existing module into recurring revenue.
If you already maintain a Magento 2 module on GitHub or GitLab, listing it on Packagento takes about five minutes. We mirror your tags, handle distribution signing, and route paid licenses through Stripe Connect, so you can keep shipping the way you already do.