Skip to content
SEO & GROWTH

Magento SEO Checklist for 2.4.x: Severity, Admin Path and a Verify Step for Every Item

A Magento SEO checklist for 2.4.x stores: 50 items, each with a severity, the admin path or bin/magento command, and a way to verify it passes.

Shane Blandford
Shane Blandford · FOUNDERPUBLISHED · 29 MIN READ

This Magento SEO checklist is the audit sheet we run on a store before changing anything: 50 items for Magento Open Source and Adobe Commerce 2.4.7-2.4.9. Every item carries a severity, the admin path or bin/magento command that sets it, and a verify step with the result that counts as a pass, while the setup and the reasoning behind each setting live in the Magento SEO guide.

Disclosure: OCM Labs, which publishes this blog, builds SEO Suite, an SEO module for Magento. Items it covers carry an SEO Suite line. Every check here runs on a store without it.

How to run this audit

Work the areas in order, and inside each one clear Blockers and Highs before any Medium. A perfect title on a page Google cannot fetch is still invisible.

BLOCKERStops pages being crawled or indexed, or drops them from results
HIGHSplits or wastes ranking signals across duplicates, or hides key pages
MEDIUMWeakens how pages show or compete in results
LOWPolish; fix when the rest passes

You need:

  • Shell access for bin/magento config:show, which reads what is saved at each scope. If it prints nothing or an error at one scope, nothing is saved there: rerun it one level up and fall back to the module default before you call it a fail.
  • curl, for status codes, redirect hops and the raw HTML before JavaScript runs.
  • Search Console, the Rich Results Test, PageSpeed Insights and a site crawler.

An item is done when its verify line passes, whatever the admin form says. SEO Suite does not generate XML sitemaps, manage URL rewrites or redirects, monitor 404s, pull Search Console data or touch site speed, so those items read No. Its score is guidance, not a ranking prediction, and passing this list is not a ranking promise either.

Can Google crawl and index your Magento store?

When an item here fails, the robots.txt, meta robots and sitemap setup covers what to set.

2.1 robots.txt matches the admin field and blocks no product or category URL

  • Severity: Blocker
  • Where: Content > Design > Configuration > (website) > Search Engine Robots, the custom instructions field (design/search_engine_robots/custom_instructions); a physical robots.txt in the web root can shadow it
  • Verify: curl -s https://example.com/robots.txt prints the same rules as bin/magento config:show --scope=websites --scope-code=base design/search_engine_robots/custom_instructions (swap base for each website code you run), and no Disallow line matches a product or category URL. Search Console > Settings > robots.txt shows the file fetched without errors.

2.2 Default Robots is INDEX, FOLLOW on every production store view

  • Severity: Blocker
  • Where: Content > Design > Configuration > (website) > Search Engine Robots > Default Robots (design/search_engine_robots/default_robots)
  • Verify: bin/magento config:show --scope=websites --scope-code=base design/search_engine_robots/default_robots returns INDEX,FOLLOW for each website code, and curl -s https://example.com/ | grep -i 'name="robots"' shows the same value in the page head of every store view.
  • SEO Suite: Partly. It adds per-page and store-wide robots rules; native Default Robots stays the baseline.

2.3 Staging and development hosts cannot be indexed

  • Severity: Blocker
  • Where: HTTP authentication in the staging web server config, plus Default Robots set to NOINDEX,NOFOLLOW in the staging database
  • Verify: curl -sI https://staging.example.com/ returns 401. A Google search for site:staging.example.com returns nothing. Recheck production's Default Robots after every database copy.

2.4 Catalog search result pages stay out of the index

  • Severity: High
  • Where: Disallow: /catalogsearch/ in robots.txt if none were ever indexed; otherwise a noindex from the search results layout or an SEO module rule, with the Disallow added once they drop
  • Verify: If robots.txt already disallows /catalogsearch/ and Page indexing shows no search URLs indexed, URL Inspection on https://example.com/catalogsearch/result/?q=boots reports it as blocked by robots.txt and not indexed. Otherwise curl -s "https://example.com/catalogsearch/result/?q=boots" | grep -i 'name="robots"' shows a NOINDEX value, and the Disallow goes in only after Google drops these URLs.
  • SEO Suite: a store-wide robots rule for search result pages.

2.5 The XML sitemap is configured, generated by cron and submitted in Search Console

  • Severity: High
  • Where: Stores > Configuration > Catalog > XML Sitemap (sitemap/generate/enabled, sitemap/search_engines/submission_robots); Marketing > SEO & Search > Site Map
  • Verify: bin/magento config:show sitemap/generate/enabled returns 1. The Site Map grid shows a recent generation date that matches the frequency you set. curl -s https://example.com/robots.txt | grep -i sitemap prints the sitemap URL. Search Console > Indexing > Sitemaps shows the status as Success. No bin/magento command generates a sitemap, so if the date is stale, SELECT status, executed_at FROM cron_schedule WHERE job_code = 'sitemap_generate' ORDER BY scheduled_at DESC LIMIT 5; should show recent success rows.

2.6 The sitemap lists only canonical, indexable URLs that return 200

  • Severity: Medium
  • Where: Marketing > SEO & Search > Site Map; product, category and CMS page status and visibility
  • Verify: Load the sitemap URLs into a site crawler in list mode. Every URL returns 200, carries no noindex and declares itself as canonical.

2.7 The Page indexing report has been read, not glanced at

  • Severity: High
  • Where: Search Console > Indexing > Pages
  • Verify: Export the "Crawled - currently not indexed" and "Duplicate without user-selected canonical" lists. Sample 20 URLs from each and sort them by type (filter, sort parameter, simple child product, CMS page, real product). The mix matches what your layered navigation rule set in section 5 expects; ?product_list_order= URLs mean 4.4 failed, simple products mean 4.3 did. Record both counts with the date.

Do Magento URLs, rewrites and redirects resolve to one address?

URL settings are cheap to check and expensive to change; the URL suffix, category path and rewrite settings cover changing one safely.

3.1 Web server rewrites are on and no URL contains index.php

  • Severity: High
  • Where: Stores > Configuration > General > Web > Use Web Server Rewrites (web/seo/use_rewrites), plus the Apache .htaccess or nginx rewrite rules
  • Verify: bin/magento config:show web/seo/use_rewrites returns 1, and a full crawl finds no internal link containing /index.php/.

3.2 Product and category URL suffixes are set once and left alone

  • Severity: High
  • Where: Stores > Configuration > Catalog > Catalog > Search Engine Optimization (catalog/seo/product_url_suffix, catalog/seo/category_url_suffix)
  • Verify: bin/magento config:show catalog/seo/product_url_suffix and bin/magento config:show catalog/seo/category_url_suffix return the suffix your live product and category URLs end in, such as .html, at every scope where a value is saved.

3.3 Product URLs skip the category path, or canonicalize to one version

  • Severity: High
  • Where: the same group (catalog/seo/product_use_categories, catalog/seo/generate_category_product_rewrites); a store upgraded from an early 2.4 release keeps its old category/product rewrites
  • Verify: bin/magento config:show catalog/seo/product_use_categories returns 0, and bin/magento config:show catalog/seo/generate_category_product_rewrites shows whether rewrite generation is on. Then, whatever those return, curl -sI https://example.com/mens/boots/trail-runner.html returns 404, or curl -s on the same URL shows a rel="canonical" pointing at the short https://example.com/trail-runner.html. If generation returns 1, do not switch it off without a backup of url_rewrite and a log and backlink check for category-path URLs: Adobe warns that doing so permanently deletes the existing category/product rewrites.

3.4 Changing a URL key creates a permanent redirect

  • Severity: High
  • Where: the same group (catalog/seo/save_rewrites_history), which sets the default of the "Create Permanent Redirect for old URL" checkbox on product and category forms
  • Verify: bin/magento config:show catalog/seo/save_rewrites_history returns 1. On staging, change a test product's URL key, then curl -sI -u user:pass https://staging.example.com/old-key.html returns 301 with a Location header on the new key.

3.5 Redirects resolve in one hop, with no chains or loops

  • Severity: Medium
  • Where: Marketing > SEO & Search > URL Rewrites; Magento has no native command that regenerates them
  • Verify: curl -sIL https://example.com/old-key.html | grep -i -e '^HTTP' -e '^location' shows exactly one 301 followed by a 200. Your crawler's redirect chain report is empty.

3.6 One protocol and one host, with every variant 301ing to it in one hop

  • Severity: High
  • Where: Stores > Configuration > General > Web > Use Secure URLs on Storefront (web/secure/use_in_frontend); one host redirect rule at the web server or CDN
  • Verify: curl -sI http://example.com/, curl -sI http://www.example.com/ and curl -sI https://example.com/ each return a single 301 to https://www.example.com/, or whichever origin you chose. bin/magento config:show web/secure/use_in_frontend returns 1.

3.7 Out-of-stock and disabled products return the status code you intended

  • Severity: Medium
  • Where: Display Out of Stock Products (cataloginventory/options/show_out_of_stock); the Enable Product switch; URL Rewrites for replacement redirects
  • Verify: curl -sI one out-of-stock product URL and one disabled product URL. Write down what each returns and compare it with your written policy.

Are canonical tags folding Magento's duplicate URLs?

Sort orders, page sizes, child products and category paths all mint duplicate URLs; how Magento's canonical switches behave explains what each setting emits.

4.1 Canonical tags are on for products and categories

  • Severity: High
  • Where: both canonical settings in Stores > Configuration > Catalog > Catalog > Search Engine Optimization (catalog/seo/category_canonical_tag, catalog/seo/product_canonical_tag), at default and every store view scope
  • Verify: bin/magento config:show catalog/seo/category_canonical_tag and bin/magento config:show catalog/seo/product_canonical_tag both return 1. curl -s https://example.com/trail-runner.html | grep -i 'rel="canonical"' prints one tag with an absolute URL.
  • SEO Suite: one canonical on every product, category and CMS page, with a product mode and filtered and paginated category handling.
Setting a canonical URL on a Magento product, category or CMS page

4.2 Every page carries exactly one rel="canonical"

  • Severity: High
  • Where: theme templates, plus any module that writes to the page head (SEO, layered navigation, AMP)
  • Verify: curl -s https://example.com/trail-runner.html | grep -o -i 'rel="canonical"' | wc -l returns 1. Repeat on a category, a filtered category and a CMS page.
  • SEO Suite: Partly. It does not override a canonical hardcoded in a theme template; remove that one from the template.

4.3 Configurable product children are Not Visible Individually

  • Severity: High
  • Where: Catalog > Products > (simple child) > Visibility, or the grid's Update attributes action in bulk; fix the import template too
  • Verify: In Catalog > Products, filter Type to Simple Product and Visibility to Catalog, Search. Every row returned is a product you sell on its own, and none of the child URLs appear in the sitemap.

4.4 Sort, limit and view-mode parameters do not create indexable duplicates

  • Severity: High
  • Where: the category canonical (4.1), with no noindex on these URLs; robots.txt only as an optional crawl-budget step once Google has consolidated them, or from day one if they never were in the index
  • Verify: curl -s "https://example.com/mens/boots.html?product_list_order=price&product_list_limit=36&product_list_mode=list" | grep -i -e 'name="robots"' -e 'rel="canonical"' shows https://example.com/mens/boots.html as canonical and no noindex in the robots meta. In Page indexing, sort URLs collect under "Alternate page with proper canonical tag", not "Excluded by 'noindex' tag". If curl -s https://example.com/robots.txt carries the product_list_ Disallow lines, URL Inspection on a sort URL reports it as blocked by robots.txt and not indexed, and the lines went in only after Google had consolidated these URLs or on a store that never had them indexed.
  • SEO Suite: Yes. Its category canonical drops sort, limit and mode parameters, and it adds no robots value to those URLs, so they get the canonical alone.

4.5 Paginated category pages canonicalize to themselves

  • Severity: Medium
  • Where: category canonical output from your theme or SEO module
  • Verify: curl -s "https://example.com/mens/boots.html?p=2" | grep -i 'rel="canonical"' returns the ?p=2 URL itself, not page 1.
  • SEO Suite: a paginated category canonical mode.

Which layered navigation URLs are indexable, canonicalized or blocked?

Native filter URLs are query parameters such as ?color=49, and this is the rule set we audit them against. Filter, sort and price-range URLs get the canonical alone: a canonical to the unfiltered category and no noindex. A noindex paired with a canonical that points at another URL sends Google mixed signals. Leave these URLs crawlable so Google can read the canonical and consolidate them.

A robots.txt Disallow stays an optional crawl-budget step for parameter patterns that waste crawl: sort, limit, view mode and deep multi-filter combinations. Add it only after Google has consolidated those URLs, or from day one on a store that never had them indexed, because Google cannot read the canonical on a blocked URL. The layered navigation setup covers the reasoning.

INDEX?ROBOTS METACANONICALROBOTS.TXT
ONE FILTER VALUE PEOPLE SEARCH FOR (WATERPROOF BOOTS)Yes, as a real subcategoryindex, follow on the subcategoryThe subcategory's own URLAllow
ONE FILTER VALUE WITH NO SEARCH DEMANDNo, consolidated by the canonicalNo noindexThe unfiltered categoryAllow
TWO OR MORE FILTERS COMBINEDNo, consolidated by the canonicalNo noindexThe unfiltered categoryAllow; optional Disallow for deep combinations once Google has consolidated them, or from day one if never indexed
PRICE RANGESNo, consolidated by the canonicalNo noindexThe unfiltered categoryAllow; optional Disallow once Google has consolidated them, or from day one if never indexed
SORT, LIMIT AND VIEW MODENo, consolidated by the canonicalNo noindexThe unfiltered categoryAllow; optional Disallow once Google has consolidated them, or from day one if never indexed
PAGINATION, ?P=2 AND UPYesindex, followItselfAllow
CATALOG SEARCH RESULTSNonoindex, followItselfAllow until dropped, then Disallow; Disallow from day one if never indexed

These are the search and filter lines from the guide's starting robots.txt, line for line. Audit 2.1, 2.4 and 5.4 against your own version of them.

User-agent: *
# Internal search results
Disallow: /catalogsearch/
# Optional crawl-budget lines: add them only once Google has consolidated the matching URLs,
# or from day one on a store that never had them indexed
# Sort, direction, limit and view-mode parameters
Disallow: /*?*product_list_order=
Disallow: /*?*product_list_dir=
Disallow: /*?*product_list_limit=
Disallow: /*?*product_list_mode=
# Price ranges and store switching
Disallow: /*?*price=
Disallow: /*?*___store=

5.1 A written rule set says which filter URLs are indexable, canonicalized or blocked

  • Severity: High
  • Where: a shared document developers and merchandisers both read; it drives 5.2 to 5.4
  • Verify: For each attribute with Use in Layered Navigation set (Stores > Attributes > Product > (attribute) > Storefront Properties), the rule set names its class from the table above.

5.2 Single-filter URLs without search demand carry the category canonical and no noindex

  • Severity: High
  • Where: the category canonical (4.1) or your SEO module's filtered-category canonical; no robots rule that adds a noindex to these URLs
  • Verify: curl -s "https://example.com/mens/boots.html?color=49" | grep -i -e 'name="robots"' -e 'rel="canonical"' shows the unfiltered category as canonical and no noindex in the robots meta. In Page indexing, these URLs collect under "Alternate page with proper canonical tag", not "Excluded by 'noindex' tag".
  • SEO Suite: Yes. Its settings sit under Stores > Configuration > OCM Labs > SEO. Set Filtered Category Pages to "Use Default (inherit)", which leaves Magento's own robots value in place, and keep Filtered Category Canonical on the unfiltered category. Filtered Category Pages ships set to "noindex, follow", so change it before you rely on the canonical alone. A robots value set on an individual product, category or page still wins.

5.3 Multi-filter and price-range URLs carry the category canonical before any robots.txt block

  • Severity: High
  • Where: the same canonical as 5.2; an optional, later robots.txt line per the table above
  • Verify: curl -s "https://example.com/mens/boots.html?color=49&size=172" | grep -i -e 'name="robots"' -e 'rel="canonical"' shows the unfiltered category as canonical and no noindex in the robots meta, and the same command on ?price=50-100 shows the same. For any of these classes robots.txt already blocks, URL Inspection on a sample URL reports it as blocked by robots.txt and not indexed, and the block went in only after Google had consolidated that class or on a store that never had it indexed.
  • SEO Suite: Yes. The same two settings as 5.2 cover every filter combination, price included. The robots.txt step stays yours.

5.4 No URL class is blocked in robots.txt while it still relies on its canonical or noindex

  • Severity: High
  • Where: your rule set from 5.1, compared line by line with robots.txt
  • Verify: For each Disallow pattern, pick one URL it matches and confirm the rule set does not expect that URL's noindex or canonical to be read. The "Indexed, though blocked by robots.txt" count in Page indexing is zero or falling.

Does every page have its own title, description and copy?

Run these once sections 2 to 5 pass; the meta title and description guidance by page type covers what to write. A crawl finds the gaps, but checking content page by page while you fix it is slower, and how live content analysis works inside the Magento admin shows that check on the edit form itself.

6.1 Every product, category and CMS page has its own meta title and meta description

  • Severity: Medium
  • Where: the Search Engine Optimization section of each product, category and CMS page edit form
  • Verify: A crawl reports zero indexable pages with a missing title or description.
  • SEO Suite: the SEO Dashboard's Missing title and Missing description flags list the gaps; meta templates fill them at render time without writing to the product.

6.2 HTML Head suffix is set, and prefix and default description are left empty, for each store view

  • Severity: Medium
  • Where: Content > Design > Configuration > (store view) > HTML Head (design/head/default_title, design/head/title_prefix, design/head/title_suffix, design/head/default_description), plus catalog/seo/title_separator
  • Verify: bin/magento config:show --scope=stores --scope-code=default design/head/title_suffix returns the brand suffix you expect, and the same command for design/head/title_prefix and design/head/default_description returns an empty value. Repeat for every store code.
  • SEO Suite: Partly. Meta templates cover product, category and CMS pages; HTML Head defaults stay native.

6.3 Titles and descriptions are unique and sized to display

  • Severity: Medium
  • Where: product, category and CMS page edit forms
  • Verify: The crawler's duplicate title and duplicate description reports are empty for indexable URLs, and its title and description length reports show nothing past the display limits you work to.
  • SEO Suite: Partly. It scores title and description length; duplicates come from the crawler.

6.4 Product images carry descriptive alt text

  • Severity: Medium
  • Where: Catalog > Products > (product) > Images And Videos > (image) > Alt Text
  • Verify: A crawler with JavaScript rendering switched on reports zero product images missing alt text. Use rendering, because the product gallery is often built by JavaScript and a raw-HTML check undercounts it.
  • SEO Suite: Partly. Keyword-in-alt reads gallery labels, but the alt-text check covers description images only.

6.5 Each page template renders exactly one H1

  • Severity: Low
  • Where: theme templates and Page Builder content
  • Verify: curl -s https://example.com/mens/boots.html | grep -o -i '<h1' | wc -l returns 1 on a product, a category, a CMS page and the home page.
  • SEO Suite: Partly. Its subheading check reads your content, not the theme's H1.

6.6 No two products or categories target the same phrase

  • Severity: Medium
  • Where: a keyword map owned by whoever writes category copy
  • Verify: Search Console > Performance, filter to the target query, open the Pages tab. One URL takes the clicks. Two URLs trading places week to week is the fail.
  • SEO Suite: Partly. The Duplicate focus keyword flag catches a reused focus keyword; it is not duplicate-content detection.

6.7 Category pages carry indexable descriptive copy

  • Severity: Medium
  • Where: Catalog > Categories > (category) > Content > Description
  • Verify: curl -s https://example.com/mens/boots.html | grep -c "a sentence from your category copy" returns 1 or more, which proves the copy is in the HTML before JavaScript runs.
  • SEO Suite: Partly. It scores content length and internal links; the curl confirms the raw HTML.

Does your Magento product page emit valid structured data?

Audit what the page emits, not what the theme or module promises; the rich snippets walkthrough covers each schema type.

7.1 Product JSON-LD with an Offer validates on every product template

  • Severity: Medium
  • Where: theme or SEO module output; product attributes for brand, GTIN and MPN
  • Verify: The Rich Results Test on a simple product, a configurable product and an out-of-stock product detects Product snippets and Merchant listings with no errors, and price, priceCurrency and availability match what the page shows after catalog price rules. Minimum markup below; aggregateRating is left out (7.3).
  • SEO Suite: Partly. It emits Product JSON-LD with Offer, brand, GTIN and MPN; run the test on your templates.
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Trail Runner Waterproof Shoe",
  "sku": "TRW-10-BLK",
  "gtin13": "0123456789012",
  "image": "https://example.com/media/catalog/product/t/r/trail-runner-black.jpg",
  "brand": {
    "@type": "Brand",
    "name": "Example Outdoor"
  },
  "offers": {
    "@type": "Offer",
    "url": "https://example.com/trail-runner.html",
    "price": "129.00",
    "priceCurrency": "USD",
    "availability": "https://schema.org/InStock"
  }
}

7.2 Each product page describes the product once

  • Severity: Medium
  • Where: theme templates and any module that adds JSON-LD
  • Verify: The Rich Results Test lists one Product item, or two whose name, price and availability match exactly.
  • SEO Suite: Partly. It leaves the theme's Product microdata in place, so on Luma run this check after installing it.

7.3 aggregateRating appears only on products with reviews

  • Severity: Medium
  • Where: theme or module review markup
  • Verify: The Rich Results Test on a product with zero approved reviews shows no aggregateRating or review property. On a reviewed product, ratingValue and reviewCount match the visible review block.
  • SEO Suite: emits aggregateRating, and up to 5 reviews, only when the product has reviews.

7.4 BreadcrumbList is emitted once, and Organization and WebSite sit on the home page

  • Severity: Low
  • Where: theme templates and SEO module output
  • Verify: The Schema Markup Validator on a product URL lists one BreadcrumbList. On the home page it lists Organization and WebSite once each.
  • SEO Suite: Partly. It emits BreadcrumbList, and Organization and WebSite with a SearchAction on the home page; check the theme does not mark up breadcrumbs too.

7.5 Search Console's Merchant listings and Product snippets reports are clean

  • Severity: Medium
  • Where: Search Console > Shopping > Merchant listings, and Product snippets
  • Verify: Zero invalid items in both, and the valid item count is close to your count of indexable products. If it is far below, test a URL of the missing product type.

Do Magento store views keep their own canonical, hreflang and meta?

Skip this unless bin/magento store:list prints more than one store view; the hreflang and store view setup covers locale codes and x-default.

8.1 Store codes in URLs are on or off on purpose

  • Severity: Medium
  • Where: Stores > Configuration > General > Web > Url Options > Add Store Code to Urls (web/url/use_store)
  • Verify: bin/magento config:show web/url/use_store returns the value you chose, and the codes from bin/magento store:list match the path segments in your live URLs.

8.2 Each store view's pages canonicalize to their own URL

  • Severity: High
  • Where: base URLs at each store view scope (web/unsecure/base_url, web/secure/base_url); canonical output from 4.1
  • Verify: curl -s https://example.com/fr/bottes-randonnee.html | grep -i 'rel="canonical"' returns the /fr/ URL, not the default store view's URL.
  • SEO Suite: one canonical per page in each store view.

8.3 Same-language store views do not duplicate each other

  • Severity: High
  • Where: hreflang (8.4), plus copy that differs where markets do: spelling, currency, shipping and returns
  • Verify: URL Inspection on a product in your second English store view shows the Google-selected canonical equal to the user-declared one. Page indexing's "Duplicate, Google chose different canonical than user" lists no URLs from one store view pointing at the other.
  • SEO Suite: Partly. Its hreflang marks regional alternates; the copy differences are yours.

8.4 hreflang alternates are reciprocal, use valid codes and include x-default

  • Severity: High
  • Where: an SEO module, since Magento core emits no hreflang; the store locale (general/locale/code)
  • Verify: curl -s https://example.com/trail-runner.html | grep -i hreflang lists every store view plus x-default, and the same command on each alternate lists the original back. bin/magento config:show --scope=stores --scope-code=fr general/locale/code returns a value like fr_FR, and the matching tag reads fr-FR or fr (any letter case).
  • SEO Suite: hreflang across store views, with an x-default store and a locale override.

8.5 Meta fields are translated for each store view, not inherited from default

  • Severity: Medium
  • Where: product and category forms at store view scope with Use Default Value unticked; CMS pages, which have no scope switcher, as one page per store view
  • Verify: Crawl each store view and compare titles. No page on the French store view carries an English title or description.
  • SEO Suite: Partly. The Dashboard flags missing titles and descriptions; the translation is yours.

Does the store pass Core Web Vitals in field data?

Google's "good" thresholds at the 75th percentile are LCP 2.5 seconds or less, INP 200 milliseconds or less (INP replaced FID in March 2024) and CLS 0.1 or less. The Magento settings that move Core Web Vitals cover the fixes.

9.1 LCP, INP and CLS pass in field data

  • Severity: Medium
  • Where: theme, hosting, images and third-party scripts
  • Verify: Search Console > Core Web Vitals shows no Poor URL groups on mobile or desktop. PageSpeed Insights shows all three metrics passing in the field data section, not the lab score, for a product, a category and the home page.

9.2 The store runs in production mode

  • Severity: High
  • Where: your deployment pipeline
  • Verify: bin/magento deploy:mode:show prints Current application mode: production. Rerun it after any hand fix on the server.

9.3 Full page cache is on, and Varnish serves it in production

  • Severity: High
  • Where: Stores > Configuration > Advanced > System > Full Page Cache (system/full_page_cache/caching_application)
  • Verify: bin/magento cache:status shows full_page: 1. bin/magento config:show system/full_page_cache/caching_application returns 2, which is Varnish; 1 is the built-in cache. After any change, run bin/magento cache:clean full_page, then run curl -s -o /dev/null -w '%{time_starttransfer}\n' https://example.com/mens/boots.html twice and record both times; the second, served from the cache, is the lower one.

9.4 Category and product templates serve images sized for their slot

  • Severity: Medium
  • Where: theme image definitions in etc/view.xml, product image uploads, CDN resizing
  • Verify: PageSpeed Insights on a category and a product URL names the LCP element in its diagnostics, and that element is not a full-size upload scaled down by the browser.

9.5 Indexers run on schedule and report Ready

  • Severity: Medium
  • Where: System > Tools > Index Management, set to Update by Schedule; the server crontab
  • Verify: bin/magento indexer:status shows every indexer as Ready, with none at Reindex required. If one is, and it clears after a manual bin/magento cron:run, the server crontab is not running Magento's cron. If it does not, check cron_schedule for failed indexer jobs.

Can Google reach every product through internal links?

Magento already has the internal-linking mechanisms most stores need. The audit is whether they show up in the raw HTML.

10.1 Breadcrumbs render on product and category pages

  • Severity: Medium
  • Where: theme layout; the category path setting from 3.3 changes what a product page shows
  • Verify: curl -s https://example.com/mens/boots.html | grep -i breadcrumbs finds the breadcrumb block in the raw HTML. Run the same check on a product opened directly, since breadcrumbs are its only reliable links up the category tree.

10.2 Related products and up-sells are filled on your top products

  • Severity: Low
  • Where: Catalog > Products > (product) > Related Products and Up-Sells; Cross-Sells render in the cart, which Google does not crawl
  • Verify: curl -s https://example.com/trail-runner.html | grep -c 'product-item-link' (the Luma class; adjust for your theme) returns more than the page's own count, which shows related and up-sell links in the raw HTML.

10.3 Every visible product is reachable from a category

  • Severity: High
  • Where: the Categories field on the product edit form; Catalog > Categories > (category) > Products in Category
  • Verify: Compare the product URLs in your sitemap with the URLs a crawler finds starting from the home page. Any product in the sitemap but not in the crawl is an orphan, often from an import with an empty category column.

10.4 No internal link returns a 4xx or passes through a redirect

  • Severity: Medium
  • Where: CMS pages and blocks, menus, footer links and widgets; hardcoded links in CMS blocks are the usual source
  • Verify: The crawler's inlinks report shows zero internal links to 4xx URLs. Internal links to 3xx URLs are updated to the final URL.

10.5 CMS content links to the categories it mentions

  • Severity: Low
  • Where: Content > Pages and Content > Blocks; the Catalog Category Link widget, which follows the category if its URL key changes
  • Verify: curl -s https://example.com/trail-running-guide | grep -o 'href="[^"]*"' lists a link to each category the guide names.
  • SEO Suite: Partly. Its internal links check counts links on category and CMS pages; choosing the targets is up to you.

The Magento SEO checklist in one table

Copy this table into a sheet, add a Status column and a date, and you have the tracking file for the audit.

ITEMSEVERITYWHEREVERIFYSEO SUITE
2.1robots.txt matches admin, blocks no product or category URLBlockerdesign/search_engine_robots/custom_instructions (website)curl robots.txt matches config:show at website scopeNo
2.2Default Robots is INDEX, FOLLOW on productionBlockerdesign/search_engine_robots/default_robots (website)config:show and curl return INDEX,FOLLOWPartly
2.3Staging cannot be indexedBlockerWeb server auth; staging Default Robotscurl staging returns 401No
2.4Catalog search results kept out of the indexHighrobots.txt Disallow if never indexed; else layout or module noindexURL Inspection shows blocked and not indexed, or curl shows NOINDEXYes
2.5Sitemap configured, generated by cron, submittedHighsitemap/generate/enabled; Site Map gridconfig:show returns 1; Sitemaps report SuccessNo
2.6Sitemap holds only canonical, indexable 200 URLsMediumSite Map grid; product status and visibilityCrawler list mode: all 200, self-canonicalNo
2.7Page indexing report read and classifiedHighSearch Console > Indexing > PagesDuplicate buckets match the rule setNo
3.1Web server rewrites on, no index.phpHighweb/seo/use_rewritesconfig:show returns 1; crawl finds no index.phpNo
3.2URL suffixes set once, unchanged on a live storeHighcatalog/seo/product_url_suffix, catalog/seo/category_url_suffixconfig:show matches the suffix on live URLsNo
3.3No category path in product URLsHighcatalog/seo/product_use_categories; catalog/seo/generate_category_product_rewritesconfig:show returns 0 for the path and shows whether rewrite generation is on; category-path URL 404s or canonicalizes to the short URLNo
3.4URL key change creates a 301Highcatalog/seo/save_rewrites_historyconfig:show returns 1; old key returns 301No
3.5Redirects resolve in one hopMediumMarketing > SEO & Search > URL Rewritescurl -sIL shows one 301 then 200No
3.6One protocol, one host, one hopHighweb/secure/use_in_frontend; edge redirectsEach variant returns one 301No
3.7Out-of-stock and disabled products return intended codeMediumcataloginventory/options/show_out_of_stockcurl -sI matches your policyNo
4.1Canonical tags on for products and categoriesHighcatalog/seo/category_canonical_tag, catalog/seo/product_canonical_tagconfig:show returns 1 for bothYes
4.2Exactly one canonical per pageHighTheme and modules writing to headcurl count returns 1Partly; a canonical printed by the theme must be removed from the template
4.3Configurable children Not Visible IndividuallyHighProduct > VisibilityGrid filter shows no stray childrenNo
4.4Sort, limit and mode URLs carry the category canonical and no noindex; optional block once consolidatedHighCategory canonical; robots.txt optional, once consolidatedcurl shows the clean category canonical and no noindex; Page indexing lists them as Alternate page with proper canonical tagYes
4.5Paginated pages canonicalize to themselvesMediumTheme or module canonical outputcurl ?p=2 canonical is itselfYes
5.1Written filter URL rule set existsHighShared rule set documentEvery layered nav attribute has a classNo
5.2Single filters without demand carry the category canonical and no noindexHighCategory canonical or module filtered-category canonicalcurl shows the unfiltered canonical and no noindexYes
5.3Multi-filter and price URLs carry the category canonical before any blockHighCategory canonical or module filtered-category canonical; robots.txt optional, latercurl shows the unfiltered canonical and no noindex; blocked classes report not indexedYes
5.4No class blocked while it relies on its canonical or noindexHighRule set versus robots.txt"Indexed, though blocked" is zero or fallingNo
6.1Every page has its own meta title and descriptionMediumEntity edit > Search Engine OptimizationCrawl shows no blank titles or descriptionsYes
6.2HTML Head suffix set, prefix and default description empty, per store viewMediumdesign/head/title_suffix, design/head/title_prefix, design/head/default_descriptionconfig:show with store scope: suffix set, prefix and description emptyPartly
6.3Titles and descriptions unique and sizedMediumEntity edit formsCrawler duplicate and length reports emptyPartly
6.4Product images carry alt textMediumProduct > Images And Videos > Alt TextRendering crawl shows no missing altPartly
6.5One H1 per page templateLowTheme templates, Page Buildercurl H1 count returns 1Partly
6.6No two pages target the same phraseMediumKeyword mapOne URL takes clicks for the queryPartly
6.7Category pages carry indexable copyMediumCategory > Content > Descriptioncurl finds the copy in raw HTMLPartly
7.1Product JSON-LD with Offer validatesMediumTheme or module outputRich Results Test: no errorsPartly
7.2Product described onceMediumTheme microdata plus JSON-LDRich Results Test: one Product, or matching valuesPartly
7.3aggregateRating only with reviewsMediumReview markupNo rating on a zero-review productYes
7.4BreadcrumbList once; Organization and WebSite on homeLowTheme and module outputSchema Markup Validator countsPartly
7.5Merchant listings and Product snippets reports cleanMediumSearch Console > ShoppingZero invalid itemsNo
8.1Store codes in URLs set on purposeMediumweb/url/use_storeconfig:show matches store:list codesNo
8.2Each store view canonicalizes to itselfHighStore view base URLscurl canonical stays on the store viewYes
8.3Same-language store views do not duplicateHighhreflang plus copy differencesGoogle-selected canonical equals declaredPartly
8.4hreflang reciprocal, valid codes, x-defaultHighModule; general/locale/codecurl lists all alternates both waysYes
8.5Meta fields translated for each store viewMediumEdit forms at store view scopeNo English titles on other languagesPartly
9.1LCP, INP and CLS pass in field dataMediumTheme, hosting, images, scriptsCore Web Vitals report: no Poor groupsNo
9.2Production modeHighDeployment pipelinedeploy:mode:show prints productionNo
9.3Full page cache on, Varnish in productionHighsystem/full_page_cache/caching_applicationcache:status full_page 1; config returns 2No
9.4Images sized for their slotMediumetc/view.xml, CDNPageSpeed Insights LCP element not oversizedNo
9.5Indexers on schedule and ReadyMediumIndex Management; crontabindexer:status all ReadyNo
10.1Breadcrumbs render on product and category pagesMediumTheme layoutcurl finds breadcrumbs in raw HTMLNo
10.2Related products and up-sells filledLowProduct > Related Products, Up-Sellscurl finds product linksNo
10.3No orphan productsHighProduct > CategoriesSitemap URLs all found by crawlNo
10.4No broken or redirected internal linksMediumCMS blocks, menus, widgetsCrawler: zero links to 4xxNo
10.5CMS content links to categoriesLowContent > Pages, Blocks, Widgetscurl lists category linksPartly

If you worked items 6.1 to 6.7 by hand on twenty pages and have thousands left, SEO Suite scores every product, category and CMS page against 18 checks and lists the failures in one dashboard. It costs $250 for Magento Open Source and $500 for Adobe Commerce.

FAQ

How do I run a Magento SEO audit, and how long does it take?+
Run it in severity order, section by section as above. The config and crawl items usually fit in one working session per store view, because most are a config:show or a curl. The on-page items scale with the catalog, so on a large one work from a sorted list of failures.
Is Magento good for SEO out of the box?+
It has most of the pieces. Several need switching on, and a few are missing. Native Magento gives you URL rewrites, canonical settings, meta fields, a robots.txt editor and an XML sitemap generator. It emits no hreflang, Luma's product markup is microdata rather than JSON-LD, and layered navigation creates crawlable filter URLs with no indexing rules.
How do I stop layered navigation from creating duplicate pages?+
Filter, sort and price-range URLs get the canonical alone: a canonical to the unfiltered category and no noindex. A noindex paired with a canonical that points at another URL sends Google mixed signals. Leave these URLs crawlable so Google can read the canonical and consolidate them. A robots.txt block is an optional later step for patterns that waste crawl, once Google has consolidated them. Filter values people search for become real subcategories.
Should Magento product URLs include the category path?+
No, for almost every store. With Use Categories Path for Product URLs off, each product links to one short URL that survives recategorization. Old category-path URLs can still resolve, so run item 3.3, and keep the path on only if those URLs already carry backlinks.
Does Magento generate an XML sitemap automatically?+
Yes, once XML Sitemap generation is enabled, at least one sitemap exists in Marketing > SEO & Search > Site Map, and cron is running. There is no bin/magento command for it; item 2.5 checks the generation date and the sitemap_generate cron job.
How often should I re-run a Magento SEO audit?+
Re-run the Blocker items after every deploy, Magento upgrade, theme change or database copy between environments, since those flip robots settings and base URLs. Run the full list quarterly, and let the Page indexing and Core Web Vitals reports tell you which section to reopen in between.
Shane Blandford

Shane Blandford

FOUNDER

Founder of Orange Collar Media, a Denver ecommerce agency behind 800+ Magento and Shopify builds. In Magento since version 1.x - building, rescuing, and supporting revenue-critical stores since 2008.

All posts by Shane Blandford→

KEEP READING

Related from the Journal.

Your store can sell more. Let's find out how much.

Start a project