ecommerce seo audit.
audit any store, on any platform, against the checks that decide whether products get crawled, indexed and understood
paste a store url. we read what googlebot reads on shopify, woocommerce, magento or a custom build, and hand back a ranked list of what to fix first.
- 83 checks
- 7 categories
- results in seconds
- no sign up
works on any platform. we fetch the store from our server and read exactly what a crawler reads on its first pass. nothing is stored against you, and there is no sign up.
> every check this runs
83 checks, grouped the way the report groups them. every check is weighted 1 to 5, and the 4s and 5s are marked below because they move the score most. the 15 shopify specific checks are not in this list.
auditing a shopify store? the shopify version runs all 98.
- technical 16
- meta and head 15
- content 11
- structured data 12
- ecommerce 13
- speed signals 10
- mobile 6
- https5weight 5 of 5
Reads the scheme of the URL finally served, after any redirect, and reports whether it is https.
- meta robots indexing5weight 5 of 5
Reads the meta robots and googlebot tags for noindex and nofollow directives.
- robots.txt site block5weight 5 of 5
Reads robots.txt for a Disallow rule that covers the whole site for every crawler.
- x-robots-tag header5weight 5 of 5
Reads the X-Robots-Tag response header, where indexing directives can sit without appearing in the HTML.
- http to https redirect4weight 4 of 5
Requests the http entry point and reports whether it redirects to https.
- robots.txt present4weight 4 of 5
Requests /robots.txt and reports the status code it returned.
- xml sitemap present4weight 4 of 5
Looks for an XML sitemap, both at the usual paths and on the Sitemap line in robots.txt.
- one hostname4weight 4 of 5
Requests the apex and www hostnames to see whether both answer with 200 instead of one redirecting to the other.
- 404 handling3weight 3 of 5
Requests a path that does not exist and reads the status code returned, rather than the page shown.
- noindex urls in sitemap3weight 3 of 5
Records which sitemaps answered, and states that their listed URLs are not fetched, so none of them are tested for noindex.
- redirect chain3weight 3 of 5
Counts the hops between the URL entered and the URL finally served.
- robots.txt sitemap line3weight 3 of 5
Looks for a Sitemap line in robots.txt and reads the URL it points at.
- sitemap contents3weight 3 of 5
Reads the retrieved sitemap to see whether it parses, whether it is an index or a urlset, and how many loc entries it holds.
- html compression2weight 2 of 5
Reads the Content-Encoding header on the HTML response to see which compression was applied.
- hreflang set2weight 2 of 5
Reads the hreflang annotations on the page and looks for a self referencing entry and an x-default.
- html cache-control1weight 1 of 5
Reads the Cache-Control header returned with the HTML document.
- title tag present5weight 5 of 5
Reports whether each sampled page carries a title tag with text in it.
- canonical tag present4weight 4 of 5
Reports whether the page declares a rel=canonical link in the head.
- canonical points to this page4weight 4 of 5
Compares the canonical URL against the page's own URL, with tracking parameters stripped from both.
- meta description present4weight 4 of 5
Reports whether the page carries a meta description with text in it.
- title length4weight 4 of 5
Counts the characters in the title tag and flags the point where Google truncates it.
- html lang attribute3weight 3 of 5
Reads the lang attribute on the html element and the language code it declares.
- meta description length3weight 3 of 5
Counts the characters in the meta description against the 70 to 160 character band.
- og:image3weight 3 of 5
Reports whether an og:image tag is present, which is the image a shared link carries.
- charset declared2weight 2 of 5
Reads the character encoding declared in the head.
- meta description repeats the title2weight 2 of 5
Compares the meta description against the title tag to see how much of it is repeated.
- og:description2weight 2 of 5
Reports whether an og:description tag is present, which is the summary a shared link carries.
- og:title2weight 2 of 5
Reports whether an og:title tag is present, which is the headline a shared link carries.
- title keyword position2weight 2 of 5
Detects the brand name from og:site_name, the title or the hostname, then reads whether the title opens with it.
- favicon link1weight 1 of 5
Looks for a link element with an icon rel in the head.
- twitter:card1weight 1 of 5
Reads the twitter:card tag and the card type it names.
- h1 present5weight 5 of 5
Reports whether each sampled page carries an h1 with text in it.
- exactly one h14weight 4 of 5
Counts the h1 elements in the document.
- image alt coverage4weight 4 of 5
Counts the img elements carrying an alt attribute against those with none.
- word count4weight 4 of 5
Counts the words in the visible text, with script, style and markup stripped out.
- duplicate titles across sampled pages3weight 3 of 5
Groups the titles of the sampled pages to see whether any two of them are the same.
- internal link count3weight 3 of 5
Counts the internal links in the server HTML of the home page.
- h1 length2weight 2 of 5
Counts the characters in the h1.
- h1 and title overlap2weight 2 of 5
Measures how many words the h1 and the title tag share.
- heading order2weight 2 of 5
Walks the heading levels in document order and reports where a level is skipped.
- outbound nofollow ratio1weight 1 of 5
Counts the external links on the home page and the share of them carrying rel=nofollow.
- text to html ratio1weight 1 of 5
Compares the bytes of visible text against the bytes of HTML delivered.
- product schema5weight 5 of 5
Looks for a Product node in the JSON-LD on the sampled product page.
- product schema fields5weight 5 of 5
Reads the Product node for name, image, description, brand, sku and gtin or mpn, plus the price, currency and availability inside offers.
- json-ld parses4weight 4 of 5
Parses every JSON-LD block on the sampled pages and counts the ones that fail.
- structured data present4weight 4 of 5
Counts the JSON-LD blocks and microdata itemtype values on the home page, and lists the types declared.
- breadcrumb schema3weight 3 of 5
Looks for a BreadcrumbList node in the JSON-LD on the sampled pages.
- faq schema visible3weight 3 of 5
Compares every Question name in FAQPage markup against the visible text of the page it is marked up on.
- organization schema3weight 3 of 5
Looks for an Organization, LocalBusiness, OnlineStore or Store node and reads its name and url.
- offer shape3weight 3 of 5
Reads each offers node for an Offer or AggregateOffer type and for an availability value written as a schema.org enum.
- aggregate rating2weight 2 of 5
Reads an AggregateRating node already on the page for a numeric rating value and a review or rating count, and reports nothing further when there is no such node.
- duplicate schema types2weight 2 of 5
Counts how many times each top-level schema type is declared on a page, so a type emitted twice is visible.
- website schema2weight 2 of 5
Looks for a WebSite node in the home page JSON-LD.
- microdata itemtypes1weight 1 of 5
Counts the microdata itemtype attributes across the sampled pages and lists the types they name.
- price in server html4weight 4 of 5
Looks for a currency-formatted price in the HTML your server returns, rather than one painted later by JavaScript.
- add to cart in server html3weight 3 of 5
Looks for an add to cart form or control in the server HTML of the sampled product page.
- faceted navigation3weight 3 of 5
Counts the filter and sort parameters linked from the sampled collection page, and reads what robots.txt and that page's own canonical say about them.
- search results disallowed3weight 3 of 5
Reads robots.txt for a Disallow rule covering an internal search path or query parameter.
- product page sampled3weight 3 of 5
Reports whether a product page was reached and fetched, since every product scoped check runs against it.
- availability signal2weight 2 of 5
Looks for stock wording such as in stock or sold out in the visible text of the sampled product page.
- visible breadcrumb2weight 2 of 5
Looks for a breadcrumb trail rendered in the markup, separately from any BreadcrumbList schema.
- cart and checkout disallowed2weight 2 of 5
Reads robots.txt for Disallow rules covering the cart and checkout paths.
- collection page sampled2weight 2 of 5
Reports whether a collection or category page was reached and fetched, since every collection scoped check runs against it.
- pagination signals2weight 2 of 5
Counts the links on the sampled collection page that carry a page parameter or a /page/ segment.
- products linked on collection2weight 2 of 5
Counts the distinct product URLs linked from the sampled collection page.
- image host1weight 1 of 5
Ranks the hosts serving images across the sampled pages.
- open graph product tags1weight 1 of 5
Reads og:type and the product:price:amount and product:price:currency tags on the sampled product page.
- render blocking scripts4weight 4 of 5
Counts the scripts in the head that carry neither async nor defer.
- html weight3weight 3 of 5
Measures the bytes of the HTML document itself, before any image, script or stylesheet loads.
- image dimensions3weight 3 of 5
Counts the img elements that declare width and height against those that leave the size to CSS.
- render blocking css3weight 3 of 5
Counts the stylesheets loaded in the head without a media condition.
- third party scripts3weight 3 of 5
Counts the distinct external hosts serving scripts to the page.
- html response time3weight 3 of 5
Records the wall-clock time this audit waited for the HTML response, from one request, from one location.
- image count2weight 2 of 5
Counts the img elements in the document.
- image lazy loading2weight 2 of 5
Counts the img elements carrying loading=lazy.
- inline css weight1weight 1 of 5
Measures the total bytes of the inline style blocks in the document.
- preconnect hints1weight 1 of 5
Counts the preconnect and dns-prefetch link hints declared in the head.
- viewport meta tag5weight 5 of 5
Reports whether the page declares a viewport meta tag.
- viewport width4weight 4 of 5
Reads the viewport tag for width=device-width against a fixed pixel width.
- pinch zoom allowed3weight 3 of 5
Reads the viewport tag for user-scalable=no or a maximum-scale value that blocks pinch zoom.
- fixed width markup2weight 2 of 5
Counts the elements declaring a fixed width above 480px in a width attribute or an inline style.
- responsive images2weight 2 of 5
Counts the img elements that offer a srcset alongside the src.
- tap targets and font size1weight 1 of 5
Notes that tap target size and font legibility need a rendered mobile viewport, which this HTML-only audit does not produce.
> why run this at all
a store is not a blog, and the failure modes are different
General site auditors check titles, headings and links, which stores also need. They rarely check whether the price is in the HTML or only in JavaScript, whether faceted navigation is generating an unbounded set of crawlable URLs, whether internal search results are indexable, or whether the Product markup carries the fields Google actually requires. Those are the checks that decide whether a product page earns a rich result or a crawler gives up on the category.
structured data fails quietly
A JSON-LD block with a trailing comma does not render an error anywhere a merchant will see it. It simply does not parse, and the rich result never appears. This audit parses every block on the pages it fetches, reports the ones that failed and why, and lists which required Product fields are missing from the ones that parsed.
the platform tells you which mistakes to expect
The audit identifies the platform first, from asset hosts, script markers and robots.txt fingerprints, and reports its confidence rather than asserting a guess. Where it finds Shopify, the Shopify checks run too. Where it finds WooCommerce, Magento, BigCommerce, Wix, Squarespace, PrestaShop, Shopware or Salesforce Commerce, it names it and says what the signal was.
reports that do not say what they could not see are worth less
This one lists its limits in the report itself, in full and not behind a toggle: how many pages were fetched, whether robots.txt was readable, whether a sitemap was found, and which checks were skipped because the input was not there. A skipped check is never counted as a pass.
> worked example
A WooCommerce store scores 71, grade C, across 47 scored checks. Technical passes cleanly. The failures are two: no Product structured data on the sampled product page, and 22 third-party script hosts. The warnings include a 240-character meta description, 61% of images carrying alt text, and no canonical on the sampled collection page. Four checks are marked skipped, because no collection page was found to sample from the home page links or the sitemap, and the report says so under limitations rather than scoring them.
takeaway, Read the skipped rows and the limitations block before the score. They tell you which parts of the store this run did not look at.
> when operators reach for this
- Operators comparing two stores on different platforms and needing the same check set applied to both.
- Developers verifying a migration: the same audit run before and after tells you which markup did not survive the move.
- Agencies producing a written baseline in the first hour of an engagement, before the crawl and the link data arrive.
- Merchants who have added structured data through a plugin or a tag manager and want to confirm it parses and carries the required fields.
- Anyone who suspects their product pages are client-rendered and wants to see what a crawler receives on the first pass.
> the calculation
- score
sum(weight × status points) ÷ sum(weight) × 100 - status points
pass 1 · warning 0.5 · fail 0Info rows and skipped checks are never scored, in either direction. - weights
1 cosmetic → 5 blocks indexing - grade
A ≥ 90 · B ≥ 80 · C ≥ 70 · D ≥ 60 · F below 60 - categories
technical · platform · meta and head · content · structured data · ecommerce · speed signals · mobile - what is fetched
home page + robots.txt + sitemap + up to four sampled pagesAt most 10 requests per audit. Sampled pages are chosen by URL shape from your home page links, falling back to the sitemap.
Frequently asked questions
- Which ecommerce platforms does it work with?
- All of them, because every check reads the HTML your server returns rather than a platform API. It detects Shopify, WooCommerce, Magento, BigCommerce, Wix, Squarespace, PrestaShop, Shopware and Salesforce Commerce Cloud from asset hosts, script markers and robots.txt fingerprints, and reports the confidence of that detection alongside the signals that fired. A custom build is audited exactly the same way, it is simply reported as custom.
- What are the ecommerce-specific checks?
- Whether a currency-formatted price appears in the server-rendered HTML rather than only in JavaScript, whether an add to cart form or button is in the markup, whether stock wording is present, whether a visible breadcrumb exists alongside the BreadcrumbList markup, whether internal search results and cart, checkout and account paths are disallowed in robots.txt, whether faceted navigation parameters appear in collection links and how they are handled, what the pagination links on page one indicate, and which host serves the product images.
- Does it measure Core Web Vitals?
- No, and it does not pretend to. Core Web Vitals need a rendering browser, and field data needs real visitors. What this audit measures is one server response from one location: how long it took, how many bytes the HTML was, how many render-blocking scripts and stylesheets are in the head, how many distinct third-party script hosts load, how many images are missing width and height attributes. Those are useful signals and they are labelled as signals, not as a performance score.
- What happens if my product page is client-rendered?
- The report will say so. Checks such as price in HTML, add to cart, and Product structured data will come back absent, and the text-to-HTML ratio check will flag a page that is almost all markup and almost no text. That is the same view a crawler gets before it decides whether to spend rendering budget on you, which is why it is worth seeing.
- How is this different from the Shopify SEO audit?
- This one is platform-agnostic and runs the technical, meta, content, structured data, ecommerce, speed and mobile groups. The Shopify audit runs all of those and adds a platform group for the things only a Shopify store can get wrong: Liquid errors, robots.txt.liquid overrides, collection-scoped product URLs, ?variant= parameters, app script counts, the myshopify domain in canonicals and hreflang. If you are on Shopify, that one is the better read. If you are not, or you are auditing a mixed estate, use this.
- Is my URL stored?
- There are no accounts and no email step, so nothing is stored against you. Results are cached briefly at the edge so that repeat requests for the same URL do not re-fetch the site, which is a courtesy to the store being audited rather than a record of who asked.
- Why are some checks marked skipped?
- Because the input was not available. If no product page could be found from your home page links or your sitemap, every product-scoped check is skipped rather than guessed. If robots.txt did not respond, the robots rules are reported as unknown rather than as absent. Skipped checks are excluded from the score entirely, so they neither penalise nor flatter the result, and they are listed in the limitations block at the end.
- Can I export the results?
- Yes. Copy the whole report as text, or download a CSV with one row per check carrying the check id, category, label, status, weight, finding, fix and which page it ran against. The check ids are stable, so two runs of the same store can be diffed against each other.
> related calculators, seo & metadata
- slug generatorany text → clean url-safe slug, ecommerce-tuned
- meta description testerchar + pixel width check with ecommerce serp preview
- title tag tester60-char limit, pixel width, product serp preview
- og image testerpaste url → preview how the page renders on social
- robots.txt generatorshopify / woocommerce presets with sitemap + crawl-delay
- schema markup generatorproduct, breadcrumb, faq, onlinestore & website json-ld, combined into one @graph