Hreflang validator
Crawls all stores' product / category / CMS catalogs (in-database — no HTTP requests) and reports hreflang health issues.
What it checks
| Code | Severity | What it detects |
|---|---|---|
missing_reciprocal | warning | Entity exists in stores A + B but not in C → hreflang chain incomplete |
no_pair_found | warning | Entity exists in only one store → no cross-store hreflang at all |
missing_x_default | warning | x-default enabled but no x-default store selected |
duplicate_hreflang | warning | Two stores produce the same hreflang locale → Google picks one arbitrarily |
invalid_locale | error | Store's locale config produces something Google can't parse |
CLI
bin/magento seosuite:hreflang:validate
Output:
+---------+--------------------+----------+-------+--------+----------------------------------------------------+
| Severity| Code | Entity | Store | Target | Message |
+---------+--------------------+----------+-------+--------+----------------------------------------------------+
| warning | missing_reciprocal | product | 1 | 1234 | Product "AWP-001" missing in store(s) 3 — chain… |
| warning | duplicate_hreflang | store | 2 | - | Stores 1 and 2 emit the same hreflang locale "en"… |
| error | invalid_locale | store | 4 | - | Store "fr_misconfigured" produces invalid locale " " |
+---------+--------------------+----------+-------+--------+----------------------------------------------------+
Total: 3 issue(s) — errors: 1, warnings: 2.
Options
bin/magento seosuite:hreflang:validate
[-l <limit>] # Inspect at most N entities per type per store
[-f <format>] # table (default) | json
JSON output for CI
bin/magento seosuite:hreflang:validate --format json
{
"errors": 1,
"warnings": 2,
"issues": [
{
"severity": "warning",
"code": "missing_reciprocal",
"entity_type": "product",
"store_id": 1,
"target_id": 1234,
"message": "Product \"AWP-001\" missing in store(s) 3 — hreflang chain is incomplete."
}
]
}
Exit code is 1 when any errors are detected, 0 otherwise — useful as a gate in deploy pipelines.
Admin grid
Same data, persisted: Marketing → SEO Suite → Hreflang Health.
Click Run Scan in the toolbar → results land in byte8_seosuite_hreflang_issue and the grid renders. Each scan replaces the previous, so the grid always reflects current state.
Filter by severity, code, entity type, or store. Per-row actions:
- Auto-Match (only on
missing_reciprocal/no_pair_foundfor product/category) — runs the auto-matcher and marks the row resolved - Mass-dismiss — bulk mark resolved without action (for known-acceptable warnings)
Nightly cron
Off by default. Enable in Stores → Configuration → SEO Suite → Admin Dashboard → Enable nightly Hreflang scan (cron).
The job byte8_seosuite_hreflang_scan runs at 30 2 * * * daily. If it finds errors AND notify_on_errors = Yes, an entry lands in the admin bell-icon inbox.
Limitations
- No HTTP crawling — the validator inspects database state, not actual rendered pages. If a third-party module overrides hreflang rendering, the validator won't catch the divergence.
- Doesn't check Magento's URL Rewrite table for product/category URL key changes that broke pre-existing hreflang chains. Use the Index Budget Audit for those.
Next
- Auto-matcher — discover and persist cross-store hreflang pairs