Every Shopify fix we catalog
SEOLZ catalogs 167 fixes for Shopify across 6 areas — SEO, answer-engine readiness, accessibility, security and site-health. Each lists the exact steps for Shopify, with a link to the official docs.
SEO · 45 fixes
Catalog coverageModerate effort
Ensure every product and category page is crawlable and discoverable by submitting a complete XML sitemap, fixing internal links, and removing any crawl blocks so Google can index your full catalog.
On Shopify
- Sitemap: Shopify auto-generates /sitemap.xml including product and collection pages. Submit it in Google Search Console: Settings → Sitemaps → enter 'sitemap.xml'. If products are missing, ensure they are 'Active' (not draft) under Products.
- robots.txt: In Online Store → Themes → (your theme) → Edit code → 'robots.txt.liquid'. Check for any Disallow rules blocking /products/ or /collections/ and remove them.
- Noindex: In Online Store → Preferences, confirm 'Password protection' is off. For individual pages, third-party SEO apps (e.g. Yoast for Shopify, SEO Manager) can accidentally add noindex — audit via the app's settings.
- Internal linking: In Online Store → Navigation, ensure your main menu links to all top-level collections. Within collection pages, confirm products are actually assigned to collections (Products → Collections → [collection] → add products).
- JavaScript navigation: Shopify's default themes use standard <a href> links in menus — safe for crawlers. If you use a custom or third-party theme with JS-only dropdowns, edit theme.liquid or the navigation Liquid snippet to ensure real href attributes.
Cwv clsModerate effort
Eliminate unexpected layout shifts by reserving explicit space for every image, video, embed, ad, and late-loading widget before it loads, so nothing on your page jumps around as it renders.
On Shopify
- Images: In Online Store > Themes > Edit Code, open the Liquid template(s) for your sections (e.g. sections/image-banner.liquid, snippets/product-image.liquid). Find every <img> tag and ensure width='{{ image.width }}' height='{{ image.height }}' attributes are set. Dawn and other modern Shopify themes include these by default — verify yours does too.
- Responsive aspect ratio: In your theme's CSS file (assets/theme.css or base.css), add .media { aspect-ratio: var(--ratio-width) / var(--ratio-height); overflow: hidden; } and make sure image wrappers use this class.
- Announcement bar: In the Theme Customizer (Customize > Announcement Bar section), the bar is rendered server-side and reserves space by default in modern themes. If you added a third-party announcement bar via a Script Tag or app, replace it with a theme section so the height is pre-reserved.
- Fonts: In Online Store > Themes > Edit Code > assets/base.css (or theme.css), find @font-face rules and add font-display: swap;. If using Google Fonts loaded via a <link> tag, add &display=swap to the Google Fonts URL in theme.liquid.
- Third-party widgets and chat: Go to Online Store > Themes > Edit Code > layout/theme.liquid. Move any injected widget <script> tags to just before </body> so they load last and cannot shift above-the-fold content. Wrap each widget's mount point in a min-height container.
- Cookie/consent banners: If using a Shopify app for GDPR consent, check the app's settings for 'banner position' and set it to a bottom-fixed bar. Apps like Pandectes GDPR or Consentmo have this option in their app dashboard.
Cwv lcpModerate effort
Reduce Largest Contentful Paint (LCP) to under 2.5 seconds by serving your hero image in a modern format, preloading it, and eliminating render-blocking resources.
On Shopify
- Convert your hero image to WebP before uploading: go to Online Store → Themes → Customize → the section containing your hero banner (e.g., 'Image banner' or 'Slideshow') → click the image picker and upload a WebP version of the image.
- Shopify's CDN automatically serves images via its Imgix-powered CDN, but you must request WebP explicitly in Liquid. In your theme code (Online Store → Themes → Edit code), find the hero section's Liquid file (e.g., sections/image-banner.liquid) and change the image_url filter to include format: 'webp' — e.g., {{ section.settings.image | image_url: width: 1500, format: 'webp' | image_tag: loading: 'eager', fetchpriority: 'high' }}.
- Add a preload link: in layout/theme.liquid, inside the <head> tag, add: <link rel='preload' as='image' href='{{ section.settings.image | image_url: width: 1500, format: 'webp' }}' fetchpriority='high'>. For Dawn and similar themes, look for an existing hero preload block and update it.
- Ensure the hero <img> tag does NOT have loading='lazy'. In the same section Liquid file, confirm the image_tag call uses loading: 'eager' (or omits loading entirely).
- Defer non-critical JS: in layout/theme.liquid, add 'defer' to any non-essential <script> tags. Remove any unused apps via Online Store → Apps to reduce JS payload.
- Verify the fix: re-run PageSpeed Insights on your homepage and confirm LCP drops below 2.5s on mobile.
Duplicate meta descriptionModerate effort
Write a unique, page-specific meta description for every page on your store so Google can display a relevant snippet in search results.
On Shopify
- For individual product pages: Admin → Products → click the product → scroll to 'Search engine listing' at the bottom → click 'Edit' → fill in the 'Meta description' field (max 320 chars; aim for 150–160) → Save.
- For collection pages: Admin → Products → Collections → click the collection → scroll to 'Search engine listing' → Edit → fill in unique Meta description → Save.
- For blog posts: Admin → Content → Blog posts → click the post → 'Search engine listing' → Edit → fill in Meta description → Save.
- For the homepage: Admin → Online Store → Preferences → 'Homepage meta description' field → Save.
- For bulk updates across many products, use the Shopify bulk editor (Admin → Products → select all → Edit products) and add 'Meta description' as a column, or export/import via CSV (column: 'Metafields: global.description_tag').
- Theme-level fallback: if a description field is left blank the theme may output a template default. Open Online Store → Themes → Edit code → search your theme's `product.liquid` / `collection.liquid` for `meta name="description"` and ensure it references `{{ product.metafields.global.description_tag }}` rather than a hard-coded string.
Duplicate titleModerate effort
Write a unique, descriptive title tag for every page on your store so no two pages share the same title.
On Shopify
- For individual pages/products: Go to Online Store → Pages (or Products / Collections), open the item, scroll to the bottom 'Search engine listing' section, click 'Edit', and update the 'Page title' field.
- For the homepage: Online Store → Preferences → set the 'Homepage title' field.
- For bulk edits across many products: use the Shopify bulk editor (Products → select multiple → Edit products) or export a CSV (Products → Export), edit the 'Title' and 'SEO Title' columns in a spreadsheet, then re-import.
- To control titles via theme (for category/blog archive templates): Edit your theme code at Online Store → Themes → Edit code. Open the relevant layout/template file (e.g. layout/theme.liquid) and locate the <title> tag; add Liquid logic such as {{ page_title }} | {{ shop.name }} to generate unique titles automatically.
- Consider an SEO app (e.g. Plug In SEO, SEO Manager, or Yoast SEO for Shopify) for bulk template-level title management across thousands of pages.
Faceted url indexableModerate effort
Point every faceted/filter URL's canonical tag to the clean, unfiltered category URL (or add noindex) so Google treats filtered pages as one authoritative page instead of thousands of duplicates.
On Shopify
- Shopify automatically generates canonical tags in its theme, pointing collection pages to their base URL. The problem arises when third-party filter apps (e.g., Boost Commerce, Infinite Options, SearchPie) or custom code add filter parameters to URLs without updating the canonical.
- Go to Online Store → Themes → your active theme → Edit Code.
- Open `layout/theme.liquid`. Find the `<head>` section and look for `{{ canonical_url }}` — Shopify populates this automatically for collections and it usually points to the base collection URL, which is correct.
- If a filter app is appending parameters and overriding the canonical, check that app's settings panel for a 'SEO' or 'Canonical URL' option and set it to use the base collection URL.
- If you use a custom JS/AJAX filter that rewrites the URL with parameters, add logic in your theme's `<head>` to always output the base collection canonical: replace any dynamic canonical output with `<link rel='canonical' href='{{ collection.url | prepend: shop.url }}'>` for collection pages.
- For filter URLs you want to block entirely, use the filter app's 'noindex' setting, or add a Liquid conditional in `theme.liquid` to output `<meta name='robots' content='noindex, follow'>` when URL parameters are present.
Images missing altModerate effort
Add descriptive alt text to every image on your store so search engines can understand them and all shoppers can access your content.
On Shopify
- FOR PRODUCT IMAGES: Go to Products > All products, open a product, hover over an image thumbnail, click the '…' (three-dot) menu, and select 'Edit alt text'. Type your description and click 'Save alt text'.
- FOR COLLECTION IMAGES: Go to Products > Collections, open a collection, hover over the collection image, click the pencil/edit icon, and enter alt text in the 'Image alt text' field.
- FOR THEME / CONTENT IMAGES: In the theme editor (Online Store > Themes > Customize), click any image block to reveal its settings panel — most blocks include an 'Image alt text' field on the right side.
- FOR BLOG/PAGE IMAGES: In Online Store > Blog posts or Pages, open the post/page, click the image in the rich-text editor, and use the 'Edit image' (pencil) icon to add alt text.
- FOR BULK EDITS: Use the free 'SEO Image Optimizer' app or a CSV export/import via a third-party SEO app (e.g., Plug In SEO, TinyIMG) to update alt text across many products at once.
Low performance scoreLarger project
Improve your Lighthouse/PageSpeed performance score by reducing page weight, deferring JavaScript, optimizing images, and fixing Core Web Vitals metrics so your store loads fast on mobile and desktop.
On Shopify
- Theme bloat — Online Store → Themes → Customize: disable or remove unused sections, apps, and feature blocks. Each app you remove from the theme eliminates its JS/CSS payload.
- App scripts — Apps → (review each installed app) → uninstall any apps whose scripts load on every page but are not actively used; residual script tags from deleted apps must be removed manually in Online Store → Themes → Edit Code → theme.liquid (look for <script> tags referencing old apps).
- Image optimization — Shopify automatically serves WebP via its CDN when the browser supports it; ensure your theme uses the img_url filter with width parameter, e.g. {{ product.featured_image | img_url: '800x' }}, so Shopify resizes and CDN-delivers the correct size. Add explicit width and height attributes in the img tag.
- Lazy-loading — In Edit Code → snippets/product-image.liquid (or equivalent), add loading='lazy' to all below-the-fold images; the hero/above-fold image should have loading='eager' and fetchpriority='high'.
- Font optimization — In theme.liquid, replace Google Fonts <link> imports with a self-hosted subset or use font-display: swap in your CSS (Online Store → Themes → Edit Code → assets/theme.css).
- Use a performance-focused theme — Dawn (Shopify's free default) scores significantly higher than many third-party themes. Consider migrating if your current theme is the root cause.
- Apps to help — 'Crush.pics' or 'TinyIMG' for bulk image compression; 'Tapita' or 'Hyperspeed' for script deferral and CSS optimization specific to Shopify.
Meta description too longQuick win
Shorten your meta description to 150–160 characters so Google displays your full message in search results instead of cutting it off with "…".
On Shopify
- In your Shopify admin, go to the page you want to edit: Online Store → Pages (for content pages), Products → [product name] (for products), or Online Store → Navigation (for the homepage via Online Store → Preferences).
- For the Homepage: go to Online Store → Preferences, scroll to 'Homepage meta tags', and edit the 'Meta description' field directly. Keep it under 160 characters.
- For Products or Pages: scroll to the bottom of the edit screen and click 'Edit website SEO'. The 'Description' field there is the meta description. Edit and save.
- For Collections: go to Products → Collections → [collection name] → scroll to 'Edit website SEO' at the bottom.
- Use a character-counter browser extension or paste the text into a tool like Google's SERP Simulator to confirm length before saving.
- Click 'Save' on every page you edit.
Meta description too shortModerate effort
Expand every meta description to 120–160 characters so Google shows your custom summary in search results instead of auto-generating one.
On Shopify
- For a product: Admin → Products → select the product → scroll to 'Search engine listing' section at the bottom → click 'Edit' → paste your new description into the 'Meta description' field (character counter is shown) → Save.
- For a collection: Admin → Products → Collections → select the collection → scroll to 'Search engine listing' → Edit → update Meta description → Save.
- For a page (e.g. About, FAQ): Admin → Online Store → Pages → select the page → scroll to 'Search engine listing' → Edit → update Meta description → Save.
- For the homepage: Admin → Online Store → Preferences → find 'Homepage meta description' → update → Save.
- For bulk updates across many products, use the free Shopify 'Bulk edit' feature: Products → select multiple products → Edit products → add the 'SEO Description' column.
Missing canonicalModerate effort
Add a self-referencing canonical tag to every page so Google knows which URL is the "official" version of that content.
On Shopify
- Shopify automatically outputs a canonical tag for product, collection, blog, and article pages via the default theme — verify by viewing page source and searching for `rel="canonical"`.
- If your theme is missing it, go to Online Store → Themes → Actions → Edit Code → open `theme.liquid` (or the relevant layout file).
- Inside the `<head>` block, add: `<link rel="canonical" href="{{ canonical_url }}">` — Shopify's `canonical_url` Liquid variable outputs the correct preferred URL automatically.
- For custom landing pages built with page templates, add the same Liquid tag to those template files.
- Install a dedicated SEO app (e.g. 'SEO Manager' or 'Plug in SEO') if you want a UI-driven audit and bulk canonical management without editing code.
Missing h1Quick win
Add a single, descriptive H1 heading to every page that currently lacks one, so search engines and shoppers immediately understand what the page is about.
On Shopify
- **Product pages:** Go to Admin → Products → click the product → the 'Title' field automatically renders as the H1 in most themes. Confirm by previewing the page and inspecting the heading level. If your theme overrides this, go to Online Store → Themes → Edit code → open 'sections/product-template.liquid' (or 'main-product.liquid' in Dawn-based themes) and ensure the product title is wrapped in `<h1>` not `<h2>` or a `<div>`.
- **Collection pages:** Admin → Products → Collections → click the collection → the 'Title' field renders as the H1 in standard themes. Verify in the theme file 'sections/collection-template.liquid' or 'main-collection-product-grid.liquid'.
- **Homepage:** Admin → Online Store → Customize → select the Hero or Header section → add or edit a 'Heading' block. Confirm in theme code ('sections/index.liquid' or the hero section file) that the heading tag is `<h1>`, not `<h2>`.
- **Blog posts & pages:** Admin → Online Store → Blog Posts (or Pages) → the post/page Title field renders as the H1 in standard themes. If missing, check 'sections/article-template.liquid' or 'sections/page.liquid'.
- For any theme customisation, use Online Store → Themes → Edit code, find the relevant template file, locate the title output, and change the wrapping tag to `<h1 class="…">{{ product.title }}</h1>` (replace the variable as appropriate).
Missing meta descriptionQuick win
Write a unique meta description of 120–160 characters for every page so Google has compelling snippet text to show in search results.
On Shopify
- For a product: Admin → Products → click the product → scroll to the 'Search engine listing' section at the bottom → click 'Edit' → fill in the 'Meta description' field (160-char counter shown) → Save.
- For a collection: Admin → Products → Collections → click the collection → same 'Search engine listing' section → Edit → fill Meta description → Save.
- For a page (About, Contact, etc.): Admin → Online Store → Pages → click the page → scroll to 'Search engine listing' → Edit → fill Meta description → Save.
- For the homepage: Admin → Online Store → Preferences → fill in the 'Meta description' field under 'Homepage title and meta description' → Save.
- To bulk-edit product descriptions: use a CSV export (Admin → Products → Export), fill the 'Body HTML' or use a third-party app like 'Bulk SEO Editor' or 'Smart SEO' to manage meta descriptions at scale.
Missing og descriptionQuick win
Add an og:description meta tag to every page so social platforms display a compelling preview when your store's links are shared.
On Shopify
- Shopify automatically populates og:description from each page's 'Search engine listing preview' description field — fill that in first.
- In the Shopify admin go to Online Store → Themes → click 'Customize' on your active theme.
- For global control: go to Online Store → Themes → Actions → Edit Code, then open theme.liquid (or snippets/seo.liquid if your theme separates it) and locate or add: <meta property="og:description" content="{{ page_description | escape }}"> inside the <head> block.
- For a specific product: Products → select the product → scroll to 'Search engine listing preview' → click 'Edit website SEO' → fill in the Meta description field. Shopify maps this value to og:description automatically.
- For a specific page or blog post: Online Store → Pages (or Blog Posts) → select the item → 'Edit website SEO' → fill in Meta description.
- Validate with the Facebook Sharing Debugger after saving.
Missing og imageModerate effort
Add an og:image meta tag to every page so social media platforms and messaging apps display a rich preview image when someone shares your store's link.
On Shopify
- From your Shopify Admin, go to Online Store → Themes → click 'Customize' on your active theme.
- For the global default og:image (homepage and pages without a featured image): go to Online Store → Preferences → scroll to 'Social sharing image' → upload a 1200×630 px branded image. Shopify uses this as the fallback og:image site-wide.
- For product pages: Shopify automatically uses the product's first image as og:image. Ensure every product has a high-quality main image uploaded under Products → [Product] → Images.
- For collection pages: Shopify uses the collection image as og:image. Set it under Products → Collections → [Collection] → Collection image.
- For blog posts: Shopify uses the post's featured image. Set it in Online Store → Blog Posts → [Post] → 'Featured image'.
- To customize og:image logic in code, go to Online Store → Themes → Actions → Edit code → open 'theme.liquid' (or your header snippet) and locate or add the og:image meta tag in the <head> section, using Liquid variables such as {{ product.featured_image | img_url: 'master' }} for product pages.
Missing og titleQuick win
Add an og:title meta tag to every page so your store looks great when shared on Facebook, Pinterest, LinkedIn, and other social platforms.
On Shopify
- From your Shopify admin, go to Online Store → Themes → click the '...' (Actions) button next to your live theme → Edit code.
- Open the 'Layout' folder and click 'theme.liquid' (or your theme's main layout file).
- Locate the <head> section. Most modern Shopify themes already include an 'og-tags.liquid' snippet — look for {% render 'og-tags' %} or {% include 'og-tags' %}. If it exists, open that snippet file under Snippets.
- Inside the og-tags snippet (or directly in theme.liquid if no snippet exists), add or confirm this line exists: <meta property="og:title" content="{{ page_title | escape }}" />
- The variable {{ page_title }} automatically outputs the correct title for every page type (product, collection, page, blog post, homepage).
- Click Save, then use the Facebook Sharing Debugger to verify the tag appears correctly for a product URL.
Missing titleQuick win
Add a unique, descriptive title tag (30–60 characters) to every page that is missing one.
On Shopify
- For a product: go to Products → select the product → scroll to the 'Search engine listing' section at the bottom → click 'Edit' → fill in the 'Page title' field.
- For a collection: go to Products → Collections → select the collection → scroll to 'Search engine listing' → click 'Edit' → fill in 'Page title'.
- For the homepage or a regular page: go to Online Store → Pages (or Preferences for the homepage) → select the page → scroll to 'Search engine listing' → click 'Edit' → fill in 'Page title'.
- For the homepage specifically: go to Online Store → Preferences → fill in the 'Homepage title' field at the top.
- Keep the title 30–60 characters and click Save.
Multiple h1Moderate effort
Reduce every page to exactly one H1 tag that clearly describes the page's main topic, removing or converting all extra H1s to lower-level headings (H2, H3, etc.).
On Shopify
- Go to Online Store → Themes → click 'Customize' on your active theme.
- For product pages: navigate to a product page in the theme editor. The product title is rendered by a Liquid snippet — usually 'product-title' or 'product.title' wrapped in an <h1>. Confirm only this tag is H1.
- To edit the raw template, click the three-dot menu in the theme editor → 'Edit code'. Open the relevant template file (e.g., templates/product.liquid or sections/main-product.liquid) and search for '<h1'. Change any unwanted H1 tags to <h2> or the appropriate level.
- Also check sections/header.liquid and snippets/ files — navigation or logo taglines sometimes carry accidental H1 tags.
- For blog posts or pages: open templates/article.liquid and templates/page.liquid, find all <h1 occurrences, and keep only the one wrapping the article/page title ({{ article.title }} or {{ page.title }}).
- Save changes and preview the page, then use browser DevTools to confirm a single H1.
Noindex detectedQuick win
Remove or replace the `noindex` directive on any page you want Google to find and rank, then verify the change with Google Search Console.
On Shopify
- Shopify's default themes do NOT add noindex to standard pages. The most common sources are: (1) a third-party SEO app, (2) a Shopify theme file, or (3) the 'Password Protection' mode which noindexes the whole store.
- Check for a password page: Admin → Online Store → Preferences → scroll to 'Password protection' — ensure 'Restrict access to visitors with the password' is OFF for a live store.
- Check SEO apps: Admin → Apps → open any installed SEO app (e.g., Plug In SEO, SEO Manager, Smart SEO) → look for a 'Robots' or 'noindex' setting for the affected page type.
- Check theme files: Admin → Online Store → Themes → Actions → Edit code → open `theme.liquid` (or the relevant template such as `product.liquid`, `collection.liquid`, `page.liquid`) → search for `noindex` — remove or change any `<meta name="robots">` tag that contains it.
- To noindex only specific pages intentionally, use an SEO app rather than hard-coding the tag, so it stays manageable.
Non self canonicalModerate effort
Ensure every page's canonical tag points to that same page's own URL — fix any canonical that currently points to a different page unless the redirect is genuinely intentional.
On Shopify
- Shopify automatically outputs a self-referencing canonical tag for all standard pages — if you have a non-self canonical, a theme customization or app has overridden it.
- Go to Online Store → Themes → your active theme → Edit code.
- Open theme/layout/theme.liquid (or the equivalent base layout file).
- Search for 'canonical'. If a hard-coded <link rel="canonical"> tag or a Liquid snippet override exists, remove or correct it.
- If the issue is on product pages specifically, also check snippets/product-*.liquid and sections/ files for any canonical override.
- Check installed apps (Apps → your app list) — SEO apps such as 'SEO Manager', 'Smart SEO', or 'Plug In SEO' may control canonicals; open the app settings and verify canonical logic.
- Save and verify via View Source on the live page that the canonical href now matches the page URL.
Page speed warningModerate effort
Reduce your page load time to under 1.5 seconds by compressing images, eliminating render-blocking resources, and enabling caching so Google and shoppers experience a fast site.
On Shopify
- Images: In Admin → Content → Files (or within product/collection editors), upload images at the correct display dimensions and use Shopify's built-in automatic WebP conversion (enabled by default on all themes using the 'image_url' filter with 'format: "webp"' in Liquid).
- Theme code: In Online Store → Themes → your active theme → Edit code, open 'theme.liquid'. Ensure <script> tags for non-critical JS have 'defer' or 'async' attributes.
- Apps: In Admin → Apps, remove every app you are not actively using — each installed app can inject scripts that slow every page.
- Speed apps: Install a trusted performance app such as 'Hyperspeed', 'TinyIMG', or 'Booster: Page Speed Optimizer' from the Shopify App Store to automate script deferral, image compression, and lazy loading.
- CDN: Shopify's global CDN (Fastly) is enabled automatically for all stores — no action needed, but ensure you are using Shopify-hosted image URLs (not external hotlinks) to benefit from it.
- Verify: Re-run Google PageSpeed Insights on your storefront URL after each change to confirm improvement.
Search results indexableModerate effort
Add a noindex robots meta tag to all internal search results pages and block the search path in robots.txt to prevent thin, duplicate, near-infinite pages from polluting Google's index.
On Shopify
- In your Shopify admin go to Online Store → Themes → (your active theme) → Actions → Edit code.
- Open the template file responsible for search results: it is usually templates/search.liquid or, for JSON templates, sections/main-search.liquid.
- Inside that file (or in layout/theme.liquid conditionally), locate the opening <head> tag and add: {% if template == 'search' %}<meta name="robots" content="noindex,follow">{% endif %}
- For robots.txt: Shopify generates robots.txt automatically. Go to Online Store → Preferences → robots.txt — click 'Edit robots.txt' (Shopify 2.0 themes expose a robots.txt.liquid file in the Templates folder). Add: Disallow: /search and Disallow: /search/
- Save both files and verify by visiting /search?q=test on your live store and using View Source to confirm the meta tag appears in <head>.
Seo category description missingQuick win
Write a unique 100–200 word description for every product category page explaining what it contains and who it's for.
On Shopify
- In your Shopify admin, go to Products → Collections.
- Click the collection you want to update.
- In the 'Description' rich-text field (directly below the collection title), type or paste your 100–200 word description.
- Use the toolbar to add any basic formatting (bold, bullet points) if helpful.
- Scroll down to the 'Search engine listing preview' section to also craft a unique meta description (separate from the on-page copy).
- Click 'Save'. The description will appear on the collection page according to your theme's layout — most themes render it above or below the product grid.
Seo category description thinModerate effort
Expand your category page description to at least 150–300 words of genuinely useful, keyword-rich content that explains what shoppers will find in the category.
On Shopify
- Go to Admin → Products → Collections.
- Click the collection you want to update.
- In the 'Description' rich-text field (below the collection title), write or paste your expanded description.
- Use the formatting toolbar to add paragraph breaks or bullet points as needed.
- Click 'Save'. The description renders on the collection page automatically via your theme's 'collection.description' Liquid variable.
- If your theme hides the description, go to Online Store → Themes → Customize, navigate to the Collection page template, and ensure the 'Collection description' block/section is enabled and positioned (above or below the product grid).
Seo category emptyQuick win
Either populate the empty category with relevant products, or apply a noindex tag and remove it from navigation so Google does not waste crawl budget on a page with no content.
On Shopify
- To ADD products: Admin → Products → Collections → click the empty collection → scroll to 'Products' section → add products manually, or update the conditions for a smart collection.
- To NOINDEX: Admin → Online Store → Themes → Actions → Edit code → open 'templates/collection.liquid' (or 'sections/collection-template.liquid') → inside the <head> block (or via {% block head %}) add: <meta name="robots" content="noindex, follow"> wrapped in a Liquid condition checking if the collection is empty: {% if collection.products_count == 0 %} … {% endif %}.
- Alternatively, install a free SEO app such as 'SEO Manager' or 'Yoast SEO for Shopify' which provide a per-page noindex toggle without touching code.
- To HIDE from nav: Admin → Online Store → Navigation → click the menu containing the collection → delete or drag-and-drop to remove the menu item → Save.
- To DELETE and REDIRECT: Admin → Products → Collections → open the collection → Delete collection. Then go to Admin → Online Store → Navigation → URL Redirects → Add redirect: set the old /collections/slug to your chosen destination.
Seo category sparseModerate effort
Add more products to the category or consolidate it with a closely related one so Google sees a substantive, valuable page worth ranking.
On Shopify
- Go to Online Store → Navigation to confirm the sparse collection is linked; note the collection handle (e.g. /collections/summer-hats).
- To add products: go to Products → Collections, open the sparse collection, click 'Browse' or edit conditions (for smart collections) to include more products.
- To add a category description: on the collection edit page, write a description in the 'Description' rich-text field above the product grid.
- To merge/redirect: reassign all products to the target collection, then install a redirect app (e.g. Easy Redirects) or go to Online Store → Navigation → URL Redirects → Add URL redirect, entering the old /collections/[slug] → new /collections/[target-slug] as a 301.
- Delete the now-empty old collection after confirming the redirect is live.
- In Google Search Console, use URL Inspection on the old URL to verify it returns a 301, then request indexing on the new target collection URL.
Seo facet url not canonicalizedModerate effort
Add a canonical tag pointing filtered and sorted category URLs back to the clean (unfiltered) category page URL to prevent duplicate content and crawl waste.
On Shopify
- Shopify automatically adds a self-referencing canonical to collection pages, but filtered/sorted URLs generated by the Online Store's native filter & sort (using URL parameters like ?sort_by= or ?filter.p.m.*=) do NOT automatically get a canonical pointing to the clean collection URL.
- Open your theme code: Online Store → Themes → current theme → Edit code.
- Open the layout file `layout/theme.liquid`.
- Find the `<head>` section and locate any existing canonical logic (search for 'canonical').
- Replace or supplement it with logic that strips query parameters for collection pages: `{% if template contains 'collection' %}<link rel="canonical" href="{{ shop.url }}{{ collection.url }}">{% else %}<link rel="canonical" href="{{ page_url }}">{% endif %}` — `collection.url` returns the clean URL without filter/sort parameters.
- Save and verify by visiting a filtered collection URL, viewing page source, and confirming the canonical points to the unfiltered collection URL.
- Alternatively, install a Shopify SEO app (e.g., Yoast SEO for Shopify, SEOAnt, or Booster SEO) which can manage collection canonicals automatically without editing theme code.
Seo product description minimalModerate effort
Expand thin product descriptions to at least 300 words by adding specifications, use cases, and benefits so Google has enough content to rank and shoppers have enough information to buy.
On Shopify
- Go to Admin → Products → All products and click the product you want to edit.
- Scroll to the 'Description' rich-text editor (the large text box below the product title).
- Use the toolbar to add formatted paragraphs, bullet lists, and headings (H2/H3) to build out your expanded description.
- To add an FAQ or specs table, use the Insert table icon in the toolbar, or paste pre-formatted HTML by clicking the '<>' (source) icon.
- Click 'Save'. For bulk editing across many products, install a bulk-editor app such as 'Bulk Product Edit & CSV import' (available in the Shopify App Store) to update descriptions at scale.
- Optionally use a Shopify AI-assist app (e.g. 'Shopify Magic' built into the description editor) to generate a draft, then edit it for accuracy.
Seo product description missingModerate effort
Write and publish a 200–400 word product description covering what the product is, its key specs, who it's for, and how to use it.
On Shopify
- In your Shopify Admin, go to Products → All products and click the product that is missing a description.
- Locate the Description field (rich-text editor) directly below the product title.
- Type or paste your 200–400 word description. Use the toolbar to add bold text for key specs and bullet points for feature lists.
- Click Save. The description is now live and visible to both shoppers and Google's crawler.
- To also populate the schema.org 'description' field, install a structured-data app (e.g., 'JSON-LD for SEO' or 'Yoast SEO for Shopify') and map the product description field there.
Seo product description thinModerate effort
Expand thin product descriptions to at least 300 words of unique, keyword-rich content that answers real shopper questions and gives Google enough text to understand what you sell.
On Shopify
- Go to Admin → Products → click the product you want to update.
- Scroll to the 'Description' rich-text editor (the large text box below the product title).
- Type or paste your expanded description directly into this editor. Use the toolbar to add bold headings, bullet lists, and paragraph breaks.
- To add a 'Why we chose this' or structured section, switch to HTML view (click the '<>' icon) and insert formatted HTML if needed.
- Click 'Save'. The description is rendered as plain HTML — it is fully crawlable by Google with no extra steps.
- For bulk updates across many products, use the Shopify bulk editor (Products → select multiple → Edit products) or a CSV export/import via Admin → Products → Export / Import.
Seo product image alt filenameModerate effort
Replace filename-based alt text on product images with short, descriptive phrases that accurately describe each image's content.
On Shopify
- Go to Products → All products and open a product.
- In the Media section, hover over a product image and click the '…' (three-dot) menu that appears, then select 'Edit alt text'.
- Type your descriptive alt text in the field and click 'Save alt text'.
- Repeat for every image in the gallery, including variant images.
- For bulk updates across many products, use the free Shopify app 'Bulk Image Edit – Image SEO' (by Hextom) or export your product CSV, fill the 'Image Alt Text' column, and re-import via Products → Import.
Seo product missing brandQuick win
Add a `brand` property to your Product structured data (schema.org/Product) so search engines can match your listings to brand-specific queries.
On Shopify
- From your Shopify admin, go to Online Store → Themes → click 'Edit code' on your active theme.
- Open the file `snippets/product-json-ld.liquid` (or similar — some themes use `sections/product-template.liquid` or `templates/product.json`). If no JSON-LD snippet exists, create one in Snippets.
- Locate the `@type: 'Product'` JSON-LD block and add: `"brand": { "@type": "Brand", "name": {{ product.vendor | json }} }` — `product.vendor` is Shopify's native brand/vendor field.
- Ensure every product in your catalog has its Vendor field filled in: go to Products → click a product → scroll to 'Organization' → fill in the 'Vendor' field.
- Save the file and verify with Google's Rich Results Test (search.google.com/test/rich-results).
Seo product missing gtinModerate effort
Add a valid GTIN (and/or MPN) to your Product structured data so Google can match your listings to its product catalog and show them in Shopping results and AI-powered product features.
On Shopify
- In your Shopify admin, go to Products → select a product → scroll to the 'Shipping' section → find the 'Barcode (ISBN, UPC, GTIN, etc.)' field and enter the product's GTIN.
- Shopify's default product JSON-LD does NOT automatically inject the barcode into Product schema. To add it to structured data, go to Online Store → Themes → Actions → Edit Code.
- Open 'templates/product.json' (or 'sections/main-product.liquid' in Dawn-based themes) and locate the existing Product schema block (search for '"@type": "Product"').
- Add the GTIN line inside that block: '"gtin": "{{ product.variants.first.barcode | escape }}"' — this dynamically pulls the barcode value you entered in the product admin.
- Alternatively, install a structured data app (e.g. 'Schema Plus for SEO' or 'JSON-LD for SEO') that reads the Barcode field and injects a complete, GTIN-enriched Product schema automatically — no code editing needed.
- Save changes and verify using Google's Rich Results Test on the product URL.
Seo product missing stock statusModerate effort
Add visible stock availability text to each product page and set the correct `availability` property (InStock, OutOfStock, or PreOrder) in your Product structured data (JSON-LD schema).
On Shopify
- In your Shopify admin, go to Online Store → Themes → click 'Edit code' on your active theme.
- Open the file `sections/product-template.liquid` (or `templates/product.liquid` / `sections/main-product.liquid` depending on your theme).
- Search for `availability` or `schema.org` to find the existing JSON-LD block. If none exists, find the closing `</script>` tag of any Product schema block.
- Within the `offers` object, set the availability dynamically: `"availability": "https://schema.org/{% if product.available %}InStock{% else %}OutOfStock{% endif %}"`.
- For the visible label, locate the area near your Add-to-Cart button in the same template and add: `{% if product.available %}<p class='stock-status'>In Stock</p>{% else %}<p class='stock-status'>Out of Stock</p>{% endif %}`.
- Save changes, preview a product page, then test with Google's Rich Results Test.
Seo product no imagesModerate effort
Add at least one high-quality image to every product page so Google can index it and shoppers can see what they're buying.
On Shopify
- Go to Products → All products in your Shopify admin.
- Click the product that is missing images.
- In the 'Media' section at the top of the product page, click 'Add media' and upload your image files (JPG, PNG, or WebP).
- After uploading, click the image thumbnail, then click 'Edit alt text' to add a descriptive alt text for each image.
- Click 'Save'. Shopify automatically includes product images in your sitemap.xml and in Product schema markup.
- To bulk-audit missing images, use the Shopify admin bulk editor or a free app like 'Bulk Image Edit' from the Shopify App Store.
Seo product no spec tableModerate effort
Add a structured specifications table or list to every product page so search engines and AI tools can extract and surface factual product details, and shoppers can make faster buying decisions.
On Shopify
- Go to Online Store → Themes → your active theme → Edit code.
- Open sections/main-product.liquid (or product-template.liquid in older themes). Locate the area after the product description block.
- Add a Liquid block that outputs a spec table using product metafields — e.g., {{ product.metafields.specs.dimensions }}, {{ product.metafields.specs.weight }}, etc. Use a standard HTML <table> with <th> for attribute name and <td> for value.
- To populate the data, go to Products → select a product → scroll to Metafields at the bottom of the page. Add your spec metafields there (or use the 'Metafields' section under Settings → Custom data to define a 'specs' namespace with fields for each attribute).
- For bulk entry, use a metafield app such as Metafields Guru, Metafields2, or the Shopify Bulk Editor (Products → Export/Import supports metafields in CSV).
- Alternatively, install an app like Tabs & Specs by Tabs Studio or SC Product Options that provides a built-in spec table UI without code edits.
Seo product price not in htmlModerate effort
Render product prices in server-side HTML so search engines and rich-result parsers can read them without executing JavaScript.
On Shopify
- In your Shopify admin, go to Online Store → Themes → click Actions → Edit code.
- Open the product template file: templates/product.json (Dawn and newer themes) or templates/product.liquid (older themes). The actual price rendering lives in a section — look in sections/main-product.liquid or similar.
- Confirm the price is output using a Liquid tag such as {{ product.price | money }} or {{ product.selected_or_first_available_variant.price | money }}. These render server-side and will appear in the static HTML.
- If a third-party app is overriding the price display with JavaScript, disable or reconfigure that app so Shopify's native Liquid price tag is what appears in the HTML source.
- Shopify automatically injects Product JSON-LD on product pages in most themes; verify it includes 'offers.price' by using View Page Source and searching for 'schema.org'.
- Use Online Store → Themes → Preview, then View Page Source in your browser to confirm the price value is visible in raw HTML before publishing.
Seo product single imageModerate effort
Add at least 4 high-quality product images (multiple angles, detail shots, and lifestyle/in-use photos) to every product listing to increase click-through rates and conversions.
On Shopify
- Go to Admin → Products → click the product name.
- In the 'Media' section at the top of the product detail page, click 'Add media' or drag and drop image files directly into the media area.
- Upload multiple images; drag them into your preferred display order (the first image is the main/thumbnail image).
- Click each image thumbnail, then click 'Edit alt text' to add a descriptive alt text for each photo.
- Click 'Save' when done. Images appear immediately in the storefront gallery.
Seo product title genericQuick win
Rewrite generic product page titles to include the product name plus at least one differentiating attribute (material, colour, size, pack size, or brand) in a natural, keyword-rich format.
On Shopify
- Go to Admin → Products → [select your product].
- Scroll to the bottom of the product page to the 'Search engine listing' section and click 'Edit'.
- Update the 'Page title' field with your new optimised title (max ~60 characters).
- Click 'Save'. The <title> tag for that product URL is updated immediately.
- For bulk updates across many products, use the free 'Bulk Edit' feature: Products → All products → select products → Edit products, then add the 'SEO Title' column.
Seo variant urls in sitemapModerate effort
Remove product variant URLs (e.g. ?variant=, ?sku=) from your XML sitemap so only the canonical product page URL is submitted to Google.
On Shopify
- Shopify's default sitemap.xml is auto-generated and intentionally excludes variant query-parameter URLs — if variant URLs are appearing, a third-party sitemap app or custom theme code is the culprit.
- Go to Apps → find any sitemap or SEO app you have installed (e.g., Yoast SEO for Shopify, SEO Manager, Sitemap by Millum). Open its settings and look for a 'Product variants' or 'Exclude URL parameters' option and disable variant URL inclusion.
- If the issue is in theme code, go to Online Store → Themes → your active theme → Edit code → search for sitemap.xml.liquid or any Liquid file that lists URLs. Remove any loop that iterates over product.variants and appends ?variant= parameters to sitemap entries.
- Shopify already outputs a self-referencing canonical tag for the base product URL on all variant URLs by default via theme.liquid — confirm this is intact by viewing source on any ?variant= URL and checking for <link rel='canonical'>.
- Resubmit your sitemap in Google Search Console: Settings → Sitemaps → add yourstore.com/sitemap.xml.
Seo variant urls not canonicalizedModerate effort
Add a canonical tag to every product variant URL pointing back to the base product page, so Google consolidates ranking signals onto one authoritative URL instead of splitting them across hundreds of near-duplicate pages.
On Shopify
- Shopify automatically adds a self-referencing canonical to base product pages, but variant URLs (e.g. ?variant=12345) do NOT get a canonical pointing to the base by default in most themes.
- In your Shopify admin, go to Online Store → Themes → your active theme → ⋯ (Actions) → Edit code.
- Open theme/layout/theme.liquid (or the equivalent layout file).
- Locate the existing <link rel="canonical"> line. Shopify's default canonical uses {{ canonical_url }}, which resolves to the variant URL when a variant is selected.
- Replace or wrap that line so variant pages always point to the product's base URL. The safest Liquid snippet is: {% if template == 'product' %}<link rel="canonical" href="{{ shop.url }}{{ product.url }}">{% else %}<link rel="canonical" href="{{ canonical_url }}">{% endif %}
- product.url in Liquid always returns the root product URL without variant parameters, so this forces all variant pages to canonicalise back to the base product.
- Save the file, then use Google Search Console's URL Inspection tool on a ?variant= URL to confirm the canonical shows the clean product URL.
Slow pageLarger project
Reduce page load time to under 3 seconds by compressing images, minifying CSS/JS, enabling caching, and improving server response speed.
On Shopify
- Images: In Shopify Admin → Content → Files, re-upload images at the correct display size. Use Shopify's built-in image CDN (all theme images are auto-served via Shopify's CDN as WebP when the browser supports it). In your Liquid theme files (Online Store → Themes → Edit code), use the 'image_url' filter with 'width' parameter and add 'loading=lazy' to img tags.
- Apps/scripts: In Online Store → Themes → Edit code → theme.liquid, audit third-party <script> tags; add 'defer' or 'async' where appropriate. Remove unused apps via Settings → Apps — every installed app can inject scripts even if you don't use it.
- Minification: Shopify automatically minifies CSS and JS when you use the standard asset pipeline. For further control, install a performance app such as 'Crush.pics' (images) or 'Hyperspeed' / 'Plug in Speed' from the Shopify App Store.
- Caching & CDN: Shopify's CDN is built-in for all theme assets and product images — no extra configuration needed. Ensure your theme is not loading external fonts or scripts from slow third-party domains.
- Hosting: Shopify manages server infrastructure; if TTFB is high, focus on reducing liquid template complexity and the number of installed apps rather than hosting settings.
Thin contentModerate effort
Expand thin pages to at least 300 words of unique, helpful content that genuinely describes your products, category, or topic.
On Shopify
- Product pages: Admin → Products → [select product] → scroll to the 'Description' rich-text editor. Write or paste your expanded description there. Use headings (H2/H3) and bullet lists via the toolbar for readability.
- Collection pages: Admin → Products → Collections → [select collection] → edit the 'Description' field that appears above the product grid. Most themes render this text on the page; if yours does not, check your theme's collection template.
- If the description field is not visible on the storefront, go to Online Store → Themes → Customize → navigate to the Collection template and ensure the 'Collection description' section/block is enabled.
- For auto-generated tag pages (e.g. /collections/all/types/hats), apply a canonical tag back to the parent collection via your theme's collection.liquid (or collection.json) template, or use an SEO app such as SEO Manager or Plug In SEO to set canonicals and noindex rules in bulk.
Title too longQuick win
Shorten your page title tag to 60 characters or fewer so it displays in full — not truncated — in Google search results.
On Shopify
- For a product: go to Products → select the product → scroll to the 'Search engine listing' section at the bottom → click 'Edit' → update the 'Page title' field (character counter shown).
- For a collection: go to Products → Collections → select the collection → same 'Search engine listing' section.
- For a regular page (e.g. About, Contact): go to Online Store → Pages → select the page → 'Search engine listing' section.
- For the homepage: go to Online Store → Preferences → 'Homepage title' field at the top.
- To bulk-edit many products at once, use a Shopify CSV export (Products → Export) — edit the 'SEO Title' column in a spreadsheet, then re-import — or use an app such as Plug In SEO or TinyIMG SEO.
Title too shortQuick win
Expand your page title to between 50 and 60 characters so it displays fully in Google search results and gives shoppers a clear reason to click.
On Shopify
- In the Shopify admin, go to the page you want to edit: Online Store → Pages (for content pages), Products → All Products (for product pages), or Online Store → Navigation → Collections (for collection pages).
- Open the specific page, product, or collection.
- Scroll to the bottom of the edit screen to find the 'Search engine listing preview' section and click 'Edit website SEO'.
- Update the 'Page title' field with your new 50–60 character title.
- Click 'Save'. The change goes live immediately.
Answer Engine Optimization · 15 fixes
Article missing authorModerate effort
Add a structured-data author field (schema.org Person) to every article and blog post so AI engines and search crawlers can verify who wrote the content.
On Shopify
- Go to Online Store → Themes → click 'Edit code' on your active theme.
- Open the template file that renders blog posts — typically 'templates/article.liquid' or a section like 'sections/article-template.liquid'.
- Locate the existing JSON-LD <script> block (or add one just before </body>).
- Insert or update the 'author' property inside the Article/BlogPosting object, using Liquid variables: '"name": "{{ article.author }}"'.
- For a sameAs link, add a metafield to the Author (Staff Account) or use a blog article metafield — set it in Settings → Custom data → Articles, then reference it as '{{ article.metafields.custom.author_profile_url }}'.
- Save, then test the live article URL in Google's Rich Results Test.
Invalid rating valueModerate effort
Fix the AggregateRating.ratingValue in your structured data so it falls within the valid numeric range (1–5 by default, or within the declared bestRating/worstRating bounds).
On Shopify
- Go to Online Store > Themes > current theme > Actions > Edit code.
- Search for 'ratingValue' across theme files — commonly in product.liquid, product-template.liquid, or a snippets/structured-data.liquid (or similar) file.
- Locate the line outputting ratingValue. Ensure the value comes from a real average (e.g. {{ product.metafields.reviews.rating.value }}) and is ≥ 1 on a 1–5 scale.
- Add explicit bestRating and worstRating fields alongside ratingValue: e.g. "worstRating": "1", "bestRating": "5".
- If you use a review app (Judge.me, Okendo, Stamped, etc.), the schema may be injected by the app — check the app's settings panel for a 'structured data' or 'SEO' toggle rather than editing theme files directly.
- Save, then validate with the Rich Results Test (search.google.com/test/rich-results).
Low answer first scoreModerate effort
Restructure your page content to lead with a direct, concise answer and add FAQ schema so search engines and AI assistants can surface your content as a featured snippet or direct answer.
On Shopify
- For content edits: go to Online Store → Pages (for policy/FAQ pages) or Online Store → Themes → Customize → select a product or collection template to edit sections.
- Move your direct-answer summary paragraph to the first text block or section in the page editor.
- Rename section headings to question format directly in the rich text editor.
- For FAQ schema: install a free app such as 'JSON-LD for SEO' or 'Smart SEO' from the Shopify App Store, which provide a UI to add FAQPage structured data without coding.
- Alternatively, paste the FAQPage JSON-LD snippet into your theme's layout file: Online Store → Themes → Edit Code → layout/theme.liquid, placing the <script type='application/ld+json'> block just before </body> and scoping it to the correct page using an 'if' condition.
- Verify with Google's Rich Results Test (search 'Rich Results Test' in Google).
Low review countModerate effort
Collect at least 5 published reviews so Google can display star ratings in search results for your product pages.
On Shopify
- Install a review app such as 'Product Reviews' (Shopify's free app) or a third-party app (Judge.me, Okendo, Stamped) from the Shopify App Store.
- In Shopify Admin → Apps → [your review app], navigate to 'Review Requests' or 'Emails' and configure an automated post-purchase sequence targeting products with fewer than 5 reviews.
- Within the app's settings, confirm that it automatically outputs 'aggregateRating' schema (JSON-LD) on the product page — most major apps do this out of the box.
- Once 5 reviews are published, visit Online Store → Themes → Actions → Edit Code → Sections/product-template.liquid to confirm the schema block shows reviewCount ≥ 5 (or rely on the app to inject it).
- Paste the product URL into the Rich Results Test (search.google.com/test/rich-results) and verify the AggregateRating entity shows reviewCount ≥ 5.
Missing schema articleModerate effort
Add Article and BreadcrumbList JSON-LD structured data to every editorial/blog page so search engines and AI answer engines can correctly identify, understand, and feature your content.
On Shopify
- From your Shopify admin, go to Online Store › Themes › Actions › Edit code.
- Locate the article template file: templates/article.liquid (or sections/article-template.liquid in newer themes).
- Scroll to just before the closing </article> or </div> tag, and paste both JSON-LD <script> blocks (Article and BreadcrumbList) using Liquid variables: {{ article.title }}, {{ article.author }}, {{ article.published_at | date: '%Y-%m-%d' }}, {{ article.url }}, etc.
- For BreadcrumbList, use Liquid to output: Home (/) › Blog (/blogs/{{ blog.handle }}) › Article title ({{ article.url }}).
- Alternatively, install a structured data app such as 'JSON-LD for SEO' or 'Schema Plus for SEO' from the Shopify App Store — these auto-generate Article and Breadcrumb schema for all blog posts without manual coding.
- Validate with Google's Rich Results Test after saving.
Missing schema breadcrumblistModerate effort
Add BreadcrumbList structured data (JSON-LD) to every page so Google can display your site's navigation path directly in search results.
On Shopify
- From your Shopify Admin, go to Online Store → Themes → click the three-dot menu on your live theme → Edit code.
- Open the template files where you want breadcrumbs: typically 'templates/product.liquid', 'templates/collection.liquid', and 'templates/page.liquid'.
- Paste a <script type="application/ld+json"> block containing the BreadcrumbList JSON-LD just before the closing </head> tag or at the top of the template body section. Use Liquid variables ({{ product.title }}, {{ collection.title }}, {{ shop.url }}) to populate name and item fields dynamically.
- Alternatively, install a structured data app such as 'Schema Plus for SEO' or 'JSON-LD for SEO' from the Shopify App Store — these auto-generate BreadcrumbList (and other schema types) across all page types without manual coding.
- Validate by visiting a product or collection page, viewing page source, and searching for 'BreadcrumbList', then test the URL in Google's Rich Results Test.
Missing schema faqpageModerate effort
Add FAQPage (and BreadcrumbList) JSON-LD structured data to pages that contain FAQ content so Google can display rich results directly in search.
On Shopify
- Go to Online Store › Themes › your active theme › Actions › Edit code.
- For FAQPage schema on a dedicated FAQ page: open Templates › page.faq.liquid (create it if it doesn't exist by duplicating page.liquid).
- Scroll to the bottom of that template file and paste your <script type='application/ld+json'> FAQPage block just before {% endblock %} or </div>.
- For BreadcrumbList on product/collection pages: open Snippets › and create a new snippet called 'schema-breadcrumb.liquid'. Paste your BreadcrumbList JSON-LD there, using Liquid variables like {{ product.title }}, {{ collection.title }}, {{ shop.url }} to make it dynamic. Then {% render 'schema-breadcrumb' %} from within product.liquid or collection.liquid.
- Alternatively, install a free app such as 'JSON-LD for SEO' or 'Schema Plus for SEO' from the Shopify App Store — these auto-generate both FAQPage and BreadcrumbList schema across relevant page types with no code editing required.
- Validate with Google's Rich Results Test after saving.
Missing schema howtoModerate effort
Add HowTo and BreadcrumbList structured data (JSON-LD) to pages that contain step-by-step instructions so Google can display them as rich results and answer-engine snippets.
On Shopify
- Go to Online Store › Themes › Actions › Edit Code.
- For a page template: open Templates › page.howto.liquid (create a new template if needed via 'Add a new template').
- Paste your <script type='application/ld+json'> block containing the HowTo and BreadcrumbList JSON-LD just before the closing </article> or </div> tag, or add it to the theme.liquid <head> section using Liquid conditionals (e.g. {% if template == 'page.howto' %}).
- Alternatively, install a structured data app (e.g. 'JSON-LD for SEO' or 'Schema Plus') from the Shopify App Store to generate and manage schema without touching code.
- Assign the custom 'page.howto' template to each instructional page via Online Store › Pages › select page › Theme template dropdown.
- Validate with Google's Rich Results Test.
Missing schema localbusinessQuick win
Add a LocalBusiness JSON-LD schema block to your store so search engines and AI assistants can surface your business name, address, phone number, and hours in rich results and answer boxes.
On Shopify
- In your Shopify admin go to Online Store → Themes → click the '…' (Actions) menu next to your live theme → Edit code.
- In the Layout folder, open theme.liquid.
- Paste your JSON-LD <script type='application/ld+json'>…</script> block just before the closing </head> tag.
- Click Save, then test with Google's Rich Results Test.
- Alternatively, install a free structured-data app such as 'JSON-LD for SEO' or 'Schema Plus for SEO' from the Shopify App Store for a no-code UI.
Missing schema organizationQuick win
Add Organization schema markup to your store's homepage so search engines and AI systems can definitively identify your business, logo, and social profiles.
On Shopify
- From your Shopify Admin, go to Online Store → Themes.
- Click the '...' (Actions) button next to your live theme and select 'Edit code'.
- In the Layout folder, open 'theme.liquid'.
- Find the closing </head> tag and paste your <script type='application/ld+json'>…</script> block directly above it.
- Click 'Save'. Verify using Google's Rich Results Test on your homepage URL.
Missing schema productModerate effort
Add Product schema (JSON-LD structured data) to every product page so search engines can display rich results like price, availability, and ratings directly in search listings.
On Shopify
- Go to Online Store → Themes → click the '…' menu next to your live theme → Edit code.
- In the Sections or Templates folder, open 'product.liquid' (or 'main-product.liquid' in Dawn and other OS 2.0 themes).
- Scroll to the bottom (or search for an existing 'application/ld+json' script block).
- Paste a <script type='application/ld+json'> block containing the Product JSON-LD, using Liquid variables to populate dynamic values: {{ product.title }}, {{ product.selected_variant.price | money_without_currency }}, {% if product.available %}https://schema.org/InStock{% else %}https://schema.org/OutOfStock{% endif %}, etc.
- Click Save, then visit any product page, right-click → View Page Source, and confirm the JSON-LD block appears in the HTML.
- Run the page URL through Google's Rich Results Test to verify no errors.
Missing schema webpageModerate effort
Add WebPage (and Organization) JSON-LD schema markup to every page so search engines and AI answer engines can confidently understand and describe your site's content.
On Shopify
- Go to Online Store → Themes → click the (…) menu next to your live theme → Edit code.
- To add sitewide Organization schema: open 'layout/theme.liquid'. Find the closing </head> tag and paste your Organization JSON-LD <script> block immediately before it.
- To add WebPage schema to specific page templates: open the relevant template file (e.g. 'templates/page.liquid', 'templates/index.liquid') and paste a WebPage JSON-LD block that uses Liquid variables — e.g. "name": "{{ page_title }}" and "url": "{{ canonical_url }}" — so each page gets dynamic values automatically.
- Alternatively, install a structured data app such as 'JSON-LD for SEO' or 'Schema Plus for SEO' from the Shopify App Store, which auto-generates and injects WebPage and Organization schema across all pages without editing theme code.
- Save changes and validate a representative URL using Google's Rich Results Test.
Non iso dateModerate effort
Change all datePublished (and dateModified) values in your structured data from informal formats like "09/23/2019 00:00:00" to the ISO-8601 format "2019-09-23" so search engines can correctly read your content's publication date.
On Shopify
- In your Shopify admin, go to Online Store → Themes → click 'Edit code' on your active theme.
- Search for 'datePublished' or 'dateModified' across theme files using the search box — these are most commonly in 'article.liquid', 'product.liquid', 'page.liquid', or a dedicated 'structured-data.liquid' snippet.
- Find the Liquid output tag generating the date (e.g. {{ article.created_at }}) and wrap it in a date filter to enforce ISO-8601 format: {{ article.created_at | date: '%Y-%m-%dT%H:%M:%SZ' }}
- Repeat for dateModified using the updated_at object property: {{ article.updated_at | date: '%Y-%m-%dT%H:%M:%SZ' }}
- Save the file and verify using Google's Rich Results Test (search.google.com/test/rich-results) on a page that uses the template.
- If you use a third-party SEO app (e.g. Yoast for Shopify, JSON-LD for SEO, Smart SEO), check that app's structured data settings/output to ensure it is also generating ISO-formatted dates.
Org missing sameasQuick win
Add a `sameAs` array to your Organization structured data, linking to your official social profiles, Wikipedia page, LinkedIn, and other authoritative directories so search engines can confidently identify your brand as a distinct entity.
On Shopify
- In your Shopify admin, go to Online Store → Themes → click the '…' (Actions) menu next to your live theme → Edit code.
- Open the file `layout/theme.liquid` (or search for an existing JSON-LD `<script type='application/ld+json'>` block in that file).
- Paste (or update) the Organization JSON-LD snippet — including the `sameAs` array — just before the closing `</head>` tag.
- Save the file, then verify with Google's Rich Results Test using your live homepage URL.
Page unreachableModerate effort
Ensure every page that should appear in AI-powered answers and rich results is actually reachable by crawlers, then add structured data so search engines and AI systems can read and surface its content.
On Shopify
- Go to Online Store → Pages (or Products / Collections) and confirm the page exists and is set to 'Visible' (not password-protected or unpublished).
- If a page was deleted, recreate it or add a URL redirect: Online Store → Navigation → URL Redirects → Add redirect. Map the old broken URL to the correct live page.
- Check robots.txt: your Shopify robots.txt is auto-generated. If you need to allow a previously disallowed path, go to Online Store → Themes → Edit Code → config/robots.txt.liquid (if customized) and remove any Disallow rules blocking the page.
- To add Product structured data, install a schema app (e.g., 'JSON-LD for SEO' or 'Schema Plus for SEO') from the Shopify App Store, or edit your theme's product.liquid / product-template.liquid file to include a JSON-LD script block.
- For FAQPage schema on a blog post or page, edit the page template in Online Store → Themes → Edit Code and add a <script type='application/ld+json'> block with FAQPage markup.
- After fixing, submit the URL in Google Search Console (URL Inspection → Request Indexing) and test with the Rich Results Test.
Accessibility (WCAG) · 63 fixes
Aria allowed attrModerate effort
Remove or replace any ARIA attributes that are not permitted on an element's assigned role so that assistive technologies can correctly interpret the element.
On Shopify
- In your Shopify Admin go to Online Store → Themes → click the '…' menu next to your active theme → Edit code.
- Use the search box (top-left of the code editor) to search for the offending `aria-` attribute string (e.g. `aria-checked`) across all Liquid and snippet files.
- Open the relevant file (commonly a section file under Sections/, a snippet under Snippets/, or `theme.liquid` under Layout/).
- Locate the HTML element, inspect its `role` and all `aria-*` attributes, remove or replace the disallowed attribute as described in the generic steps, then save.
- If the ARIA mismatch originates inside a third-party app widget (e.g. a review carousel or product filter), contact the app developer — you cannot directly edit app-injected markup.
- Republish/preview the theme and re-test with axe DevTools or Lighthouse to confirm the error is gone.
Aria allowed roleModerate effort
Remove or replace the invalid `role="presentation"` (or other disallowed ARIA role) on HTML elements where that role is not permitted, so assistive technologies can correctly interpret your page.
On Shopify
- Go to Online Store → Themes → click the three-dot menu next to your active theme → Edit code.
- Use the search box (top of file list) to search all theme files for the offending attribute, e.g. search for `role="presentation"` or the specific role name flagged.
- Open the relevant Liquid/HTML file (common culprits: `theme.liquid`, `product-card.liquid`, `header.liquid`, section files under /sections, or snippet files under /snippets).
- Locate the exact element and either delete the `role` attribute entirely (for interactive elements like buttons and links) or replace it with a permitted role (for non-interactive wrappers).
- Click Save, then re-test with the axe DevTools browser extension on the live storefront.
Aria command nameModerate effort
Add a discernible, screen-reader-accessible name to every button, link, and menuitem that uses an ARIA command role so assistive technology can announce what it does.
On Shopify
- Go to Online Store → Themes → click the three-dot menu next to your active theme → Edit code.
- Open the relevant Liquid template or snippet (e.g., sections/header.liquid, snippets/cart-icon.liquid, or snippets/icon-*.liquid) where the unlabelled button or link lives.
- Locate the `<button>`, `<a>`, or element with a custom ARIA role and add `aria-label="Descriptive action"` as an HTML attribute, e.g. `<button aria-label="Open cart">`. If it contains an SVG, also add `aria-hidden="true"` to the SVG tag.
- For icon fonts (e.g. Font Awesome), wrap the icon in a `<span aria-hidden="true">` and add a `<span class="visually-hidden">Label text</span>` sibling (Shopify's Dawn theme already includes a `.visually-hidden` CSS class).
- Save the file, then preview the theme and re-run axe DevTools in your browser to verify the fix.
Aria dialog nameModerate effort
Add a descriptive accessible name to every dialog and alertdialog element using aria-label or aria-labelledby so screen-reader users know what the dialog is about.
On Shopify
- From your Shopify Admin, go to Online Store → Themes → click 'Customize' on your active theme.
- To edit the underlying HTML, go to Online Store → Themes → click the '…' menu → Edit code.
- Open the relevant Liquid snippet — common locations are snippets/cart-drawer.liquid, snippets/modal.liquid, sections/header.liquid, or a similar file depending on your theme (Dawn theme uses snippets/cart-drawer.liquid).
- Find the outermost element of the dialog (look for role="dialog", <dialog>, or a class like 'modal', 'cart-drawer', 'popup').
- If the dialog has a visible heading (e.g. <h2 class="cart-title">Your Cart</h2>), add an id to that heading (id="cart-dialog-title") and add aria-labelledby="cart-dialog-title" to the dialog element.
- If there is no visible heading, add aria-label="[purpose of the dialog]" directly to the dialog element (e.g. aria-label="Shopping cart").
- Save the file and preview the theme; use a screen reader or the axe DevTools browser extension to verify the dialog is now named.
Aria hidden focusModerate effort
Remove `aria-hidden="true"` from any element that contains focusable children (links, buttons, inputs), or remove the focusable elements from inside the hidden container.
On Shopify
- In the Shopify Admin, go to Online Store → Themes → click the three-dot menu next to your active theme → Edit code.
- Search for `aria-hidden` across your theme files using the search box (top-left of the code editor) — check Sections, Snippets, and Layout files (e.g. `theme.liquid`, `header.liquid`, `footer.liquid`, `product-form.liquid`).
- For each occurrence, inspect the surrounding markup: if any `<a>`, `<button>`, `<input>`, `<select>`, or `<textarea>` is a descendant of the `aria-hidden="true"` element, apply the appropriate fix (remove the attribute, move the control outside, or restrict `aria-hidden` to the decorative icon only).
- If the issue comes from a third-party app injecting the markup, contact the app developer or disable the app temporarily to confirm the source.
- Save the file and verify with the axe DevTools browser extension on your live storefront.
Aria input field nameModerate effort
Add a meaningful accessible name (label) to every ARIA input field so screen readers can identify and announce it to users.
On Shopify
- Go to Online Store → Themes → click the three-dot menu next to your active theme → Edit code.
- Search for the ARIA role causing the issue (e.g., role="textbox") using the search bar in the code editor across Sections, Snippets, and Layout files.
- Open the relevant file (e.g., sections/header.liquid for a search bar, sections/main-cart-footer.liquid for cart inputs) and add a <label> or aria-label to the affected element.
- For Shopify's built-in search input, locate the search form snippet (often snippets/predictive-search.liquid or the Dawn theme's search-modal.liquid) and ensure the <input> element has aria-label="Search" or a linked <label>.
- Save the file and use the Shopify theme preview plus a browser axe extension to confirm the fix.
- If you use a third-party theme or app that injects forms (e.g., reviews, currency selectors), contact the app developer or use the 'Edit code' approach to override their template snippets.
Aria meter nameModerate effort
Add a descriptive accessible name (via aria-label, aria-labelledby, or a visible <label>) to every element that uses role="meter" so screen readers can announce what the meter represents.
On Shopify
- In your Shopify Admin, go to Online Store → Themes → click 'Edit code' on your active theme.
- Search across your theme files (Liquid templates and Snippets) for `role="meter"`, `<meter`, or any star-rating / progress-bar snippet (common filenames: product-rating.liquid, star-rating.liquid, snippets/rating.liquid).
- Open the relevant file and add `aria-label="Average customer rating"` (or the appropriate label) directly to the meter element, or add a visible label element linked via `aria-labelledby`.
- If you use a review app (e.g. Judge.me, Stamped, Yotpo), check the app's display settings or contact support — many review apps have an accessibility settings section or customisable widget templates where you can inject aria attributes.
- Save, then use the axe DevTools browser extension on your live store to confirm the rule no longer fires.
Aria progressbar nameQuick win
Add a descriptive accessible name to every progress bar element so screen readers can announce what it represents.
On Shopify
- In your Shopify admin go to Online Store → Themes → your active theme → Edit code.
- Search across template files (Sections, Snippets, Layout) for `role="progressbar"`, `<progress`, or any progress/strength widget JavaScript file in Assets.
- Open the relevant `.liquid` file or `.js` asset. For a Liquid-rendered bar, add `aria-label="{{ label_variable }}"` or `aria-labelledby` directly to the element tag.
- For third-party app widgets (e.g., a password-strength meter from a login app), check the app's settings panel for an accessibility label option; if none, contact the app developer or inject the attribute via a small JavaScript snippet added to theme.liquid before `</body>`: `document.querySelectorAll('[role="progressbar"]:not([aria-label]):not([aria-labelledby])').forEach(el => el.setAttribute('aria-label', 'Progress'));` — then replace the generic string with a context-specific label per selector.
- Save and preview. Use Chrome DevTools → Accessibility panel to confirm the computed accessible name is populated.
Aria prohibited attrModerate effort
Remove or replace ARIA attributes that are explicitly prohibited on an element's assigned role, ensuring every ARIA attribute used is valid for its context.
On Shopify
- Go to Online Store → Themes → click the three-dot menu next to your active theme → Edit code.
- Use the search box (top of the file list) to search for the prohibited attribute name (e.g., `aria-label`, `aria-checked`) across all Liquid template files (.liquid).
- Open the offending file (common culprits: `sections/header.liquid`, `snippets/product-card.liquid`, `snippets/cart-drawer.liquid`, `layout/theme.liquid`).
- Locate the HTML element flagged by your scanner, then remove or replace the prohibited ARIA attribute following the generic steps above.
- If the attribute comes from a Shopify App (e.g., a reviews widget or chat bubble), contact the app developer or switch to an accessible alternative app.
- Click Save, then re-test with the axe DevTools browser extension on your live storefront.
Aria required attrModerate effort
Add the required `aria-level` attribute (and any other missing required ARIA attributes) to every element that uses an ARIA role which mandates them.
On Shopify
- In your Shopify Admin, go to Online Store → Themes → click the three-dot menu next to your active theme → Edit code.
- Use the search box (top of the file list) to search for 'role=' across all Liquid template files (.liquid) to find every element using an ARIA role.
- For each `role="heading"` without `aria-level`, add the attribute: `aria-level="2"` (or the appropriate level). If the element is already an `<h1>`–`<h6>` tag, remove the redundant `role` attribute instead.
- For third-party app sections (e.g., review widgets, sliders), contact the app developer or override the rendered HTML in the section's Liquid file if accessible.
- Save each file and preview the storefront; re-run axe DevTools in the browser to confirm the violation is resolved.
Aria required childrenModerate effort
Ensure every ARIA parent role contains only its required, permitted child roles — and remove focusable elements (e.g. tabindex on img or a) that are not allowed inside that ARIA context.
On Shopify
- From your Shopify Admin, go to Online Store → Themes → (your active theme) → Actions → Edit code.
- The most common sources of ARIA child violations are in Sections or Snippets. Search the file list for files likely to contain menus, product grids, or carousels (e.g. header.liquid, collection-list.liquid, featured-collection.liquid, slideshow.liquid).
- In the relevant .liquid file, search for role= attributes using Cmd/Ctrl+F. Check each parent role element and verify its children match the permitted child roles per the WAI-ARIA spec.
- To fix img[tabindex] or a[tabindex] inside a restricted parent: either remove the tabindex attribute from the child, add the correct child role (e.g. role="menuitem") to the <a> tag, or restructure to use semantic HTML (<ul>/<li>, <nav>, <button>).
- Save the file, then preview your store and re-run axe DevTools (browser extension) to confirm the violation is cleared.
- If the issue comes from a third-party app (e.g. a mega-menu or carousel app), contact the app developer — you cannot edit app-injected code directly from the theme editor.
Aria required parentModerate effort
Wrap every ARIA child role (such as `tab`, `option`, `listitem`, `row`, etc.) in the correct required ARIA parent container role (such as `tablist`, `listbox`, `list`, `rowgroup`, or `grid`) so assistive technologies can correctly interpret the widget's structure.
On Shopify
- In your Shopify admin, go to Online Store → Themes → click 'Customize' on the active theme, then use 'Edit code' (or go directly to Online Store → Themes → Actions → Edit code).
- Identify the template or section file that renders the flagged widget (e.g., 'sections/product-tabs.liquid', 'snippets/tabs.liquid', or a custom section).
- Open the file and locate the element with the child ARIA role (e.g., `role="tab"`). Add a wrapping `<div role="tablist">` around all sibling tab elements.
- If you are using a theme app extension or a third-party app (e.g., a product tab app), contact the app developer to request a fix, or override the app's block template in your theme.
- Save the file, preview your storefront, and verify using Chrome DevTools → Accessibility panel that the tablist/tab hierarchy is correct.
Aria rolesModerate effort
Audit every element that has a `role` attribute and replace any invalid, misspelled, or non-existent ARIA role value with a valid WAI-ARIA role from the official specification.
On Shopify
- In your Shopify Admin, go to Online Store → Themes → (your active theme) → Actions → Edit code.
- Search across all Liquid/HTML files using the search box (top-left of code editor) for `role=` to find every instance.
- Open the relevant template file (e.g., `sections/header.liquid`, `snippets/product-card.liquid`, `layout/theme.liquid`) and fix or remove invalid role values.
- If the issue is in an app-injected widget (e.g., a chat widget, popup, or review app), contact the app developer — you cannot edit third-party app HTML directly.
- If using a theme with a built-in accessibility settings panel (e.g., Dawn), check Online Store → Themes → Customize for any role-related options.
- Save changes and verify with axe DevTools browser extension.
Aria toggle field nameModerate effort
Give every toggle control (checkbox, switch, or ARIA toggle button) a descriptive accessible name so screen readers can announce what it does.
On Shopify
- In your Shopify admin, go to Online Store → Themes → click the three-dot menu next to your active theme → Edit code.
- Open the relevant template or section file where the toggle appears (e.g. sections/header.liquid, snippets/newsletter-popup.liquid, or templates/product.liquid for product option toggles).
- Locate the <input type='checkbox'> or custom toggle element. For a checkbox, ensure there is a <label for='...'> whose 'for' value exactly matches the input's 'id'. Add both attributes if missing.
- For a custom toggle <div> or <button>, add aria-label='Descriptive name here' directly on that element, or add aria-labelledby pointing to an existing visible text element's id.
- Save the file, preview the theme, and use Chrome DevTools Accessibility panel (Inspect → Accessibility tab) or an axe browser extension to confirm the accessible name appears.
Aria tooltip nameModerate effort
Add a visible, descriptive text label to every element that has role="tooltip" so screen readers can announce its purpose.
On Shopify
- In your Shopify Admin, go to Online Store → Themes → click the three-dot menu next to your active theme → Edit code.
- Use the search box (top of the file tree) to search for 'role="tooltip"' across all Liquid template and snippet files.
- Open each file where a tooltip is found (common locations: snippets/product-card.liquid, snippets/icon-wishlist.liquid, sections/header.liquid).
- Ensure the tooltip's HTML element contains descriptive plain text, OR add an aria-label attribute with a descriptive string, e.g.: <div role="tooltip" aria-label="Add to wishlist">Add to wishlist</div>.
- If tooltips are injected by a Shopify app (e.g., a wishlist or product review app), open the app's settings in Admin → Apps and look for a 'Label' or 'Tooltip text' field; if none exists, contact the app developer.
- Save changes and verify with a screen reader or the axe browser extension.
Aria valid attrModerate effort
Find every misspelled or non-existent ARIA attribute name in your HTML (e.g. `aria-labeledby` instead of `aria-labelledby`) and correct each one to a valid ARIA attribute name.
On Shopify
- Go to Online Store → Themes → (your active theme) → Actions → Edit code.
- Use the 'Search files' box (top of the file tree) to search for `aria-labeledby` (or whichever misspelled attribute was flagged). Shopify's code editor searches across all Liquid, CSS, and JS files in the theme.
- Open each file returned, locate the misspelled attribute, and correct it (e.g. change `aria-labeledby` to `aria-labelledby`).
- If the error is inside a Shopify app embed (e.g. a reviews widget or chat widget), open Apps → (the relevant app) and check for a settings update, or contact the app developer.
- Click Save on each file you edit, then preview the theme and re-run axe DevTools to confirm the fix.
Aria valid attr valueModerate effort
Audit every ARIA attribute on your pages and correct any that point to a non-existent element ID, use a disallowed value, or reference an empty/misspelled target so that assistive technologies can correctly interpret your page.
On Shopify
- Go to Online Store → Themes → click the three-dot menu next to your active theme → Edit code.
- Search across all Liquid files (use the search icon in the code editor) for 'aria-labelledby', 'aria-describedby', 'aria-controls', 'aria-live', and other ARIA attributes to locate where they are set.
- For each ARIA attribute that references an ID (e.g., aria-labelledby="product-title"), make sure the referenced id="product-title" element is rendered in the same page template and the ID string matches exactly — including case.
- For keyword ARIA attributes (aria-live, aria-haspopup, etc.), replace any non-standard values with the correct allowed keyword from the WAI-ARIA spec.
- If the issue is inside an app-injected widget (e.g., a reviews or chat app), contact the app developer — you cannot edit their iframe or injected code directly.
- Save changes, then preview the theme and rerun an axe or Lighthouse audit to verify no aria-valid-attr-value errors remain.
Autocomplete validModerate effort
Add a valid, correctly matched `autocomplete` attribute to every personal-data form field so browsers and assistive technologies can autofill them reliably.
On Shopify
- Shopify's hosted checkout fields are rendered by Shopify's own servers and already include correct autocomplete attributes — you cannot edit that HTML directly.
- For any custom forms you've added (contact, registration, account address), go to Online Store → Themes → your active theme → Edit code.
- Open the relevant Liquid template (e.g., templates/customers/register.liquid, sections/contact-form.liquid, or a custom snippet under snippets/).
- Find each <input> tag and add or correct the autocomplete attribute: e.g., <input type='text' name='customer[first_name]' autocomplete='given-name'>.
- Click Save, then verify with a browser's built-in autofill or the axe DevTools extension.
Avoid inline spacingModerate effort
Remove hard-coded text-spacing CSS properties from inline `style` attributes so users can override them with their own stylesheets.
On Shopify
- Go to Online Store → Themes → Actions → Edit Code.
- Search all `.liquid` template files and section files for `style=` attributes containing `line-height`, `letter-spacing`, `word-spacing`, or spacing-related `margin`/`padding` on text elements.
- Cut the offending property out of the inline `style` attribute and add a CSS class to that element instead (e.g. `class="product-body"`).
- Open `assets/base.css` (or your theme's main CSS file) and define the spacing rule there under that class name.
- If a section's inline style is generated dynamically by a section schema setting (e.g. a 'Text size' range input), edit the schema to remove that setting or render it as a CSS variable applied via a stylesheet rule rather than a raw inline style.
- For third-party apps injecting inline spacing, contact the app developer or use the Theme editor's Custom CSS box (Online Store → Themes → Customize → Theme Settings → Custom CSS) to add an overriding rule — though the real fix requires the app to stop emitting inline styles.
Button nameModerate effort
Add a visible or programmatically accessible name to every button so screen readers can announce what it does.
On Shopify
- From your Shopify Admin, go to Online Store → Themes → click the three-dot menu next to your active theme → Edit code.
- In the Layout / Sections / Snippets folders, open the file that contains the offending button (common culprits: header.liquid, cart-icon.liquid, product-form.liquid, icon-*.liquid snippets).
- Locate the <button> tag. If it only contains an icon, add aria-label="Descriptive name" directly on the opening tag, e.g. <button type="button" aria-label="Open cart">.
- If the button uses an inline SVG, add aria-hidden="true" focusable="false" to the <svg> tag so screen readers ignore the graphic and read the button's aria-label instead.
- Alternatively, add a visually-hidden <span class="visually-hidden">Open cart</span> inside the button — Shopify's default themes already ship a .visually-hidden CSS class you can reuse.
- Click Save, then preview in a browser and verify with the axe DevTools extension or Chrome's Accessibility panel.
Color contrastModerate effort
Increase the contrast ratio between your text color and its background color to at least 4.5:1 so all users — including those with low vision — can read your content.
On Shopify
- Go to Online Store → Themes → click Customize on your active theme.
- Open Theme settings (the paint-palette icon) → Colors. Most Shopify themes expose global color pickers here — adjust the relevant swatch (e.g. 'Body text', 'Link color', 'Accent') to a darker shade that passes 4.5:1.
- If the color isn't exposed as a theme setting, go to Online Store → Themes → ⋯ (Actions) → Edit code, open assets/base.css (or theme.css / application.css), find the CSS rule containing the failing hex value, and replace it with a passing shade.
- For themes that use CSS custom properties, search for the hex value in theme.css and update the --color-* variable so the change applies globally.
- Save and preview; run Lighthouse (Chrome DevTools → Lighthouse → Accessibility) to confirm the issue is resolved.
Definition listModerate effort
Fix all `<dl>` (definition list) elements so they contain only valid `<dt>` and `<dd>` child elements, in the correct order, with no stray tags or text directly inside the list wrapper.
On Shopify
- Go to Online Store → Themes → click the three-dot menu next to your active theme → Edit code.
- Use the search box (top of the file tree) to search for '<dl' across all template files (.liquid). Common locations: product description in 'sections/product-template.liquid' or 'snippets/product-specs.liquid', and FAQ sections.
- Open each file containing a `<dl>`, locate the malformed markup, and correct the child elements so only `<dt>`, `<dd>`, or wrapping `<div>`s appear directly inside `<dl>`.
- If the content is entered via the Rich Text Editor in the theme customizer (Customize → a content block), switch the block to HTML/Code view and fix the raw markup there.
- Save each file, then preview the page and rerun your accessibility scanner to verify the fix.
DlitemQuick win
Wrap every `<dt>` (term) and `<dd>` (description) element inside a parent `<dl>` element so screen readers can correctly announce the list structure.
On Shopify
- In your Shopify admin, go to Online Store → Themes → click the three-dot menu on your active theme → Edit code.
- Use the search box (top-left of the code editor) to search for `<dt` or `<dd` across all Liquid template files.
- The most common locations are `sections/product-template.liquid`, `snippets/product-meta.liquid`, or a custom `snippets/` file that renders specifications or metafields.
- When you find a `<dt>` or `<dd>` whose immediate parent is not `<dl>` (e.g., it is inside a `<div>` or `<ul>`), change the outer wrapper tag from `<div>` (or whatever it is) to `<dl>` — update both the opening and closing tags.
- Click Save, then preview the page and re-run axe DevTools to confirm the issue is resolved.
Document titleQuick win
Add a unique, descriptive <title> element to every page so browsers, screen readers, and search engines can identify it.
On Shopify
- For the homepage: Online Store → Preferences → 'Homepage title' field — fill in your title and save.
- For product pages: Products → [select product] → scroll to the 'Search engine listing' section at the bottom → click 'Edit website SEO' → fill in the 'Page title' field.
- For collection pages: Products → Collections → [select collection] → 'Search engine listing' → 'Page title'.
- For standard pages (About, Contact, etc.): Online Store → Pages → [select page] → 'Search engine listing' → 'Page title'.
- For blog posts: Online Store → Blog Posts → [select post] → 'Search engine listing' → 'Page title'.
- For theme-level title tag control (e.g. checkout or other templates): Online Store → Themes → Actions → Edit code → open 'layout/theme.liquid' and verify the <title> tag uses a dynamic variable like {{ page_title }} — do not hardcode a static value.
Empty headingModerate effort
Find every empty heading tag on your store and add meaningful, visible text to it — or remove the tag entirely if it serves no structural purpose.
On Shopify
- Go to Online Store → Themes → Customize to open the theme editor.
- Navigate to the page reported (e.g. homepage, collection, product). Look for any 'Heading' or 'Text' sections/blocks that appear empty — they will show as blank in the editor canvas.
- Click the empty heading block in the left-hand section list, type meaningful text into the 'Heading' field, then Save.
- For headings inside custom Liquid templates, go to Online Store → Themes → (...) Edit code, open the relevant template file (e.g. sections/featured-collection.liquid), search for `<h1>`, `<h2>`, `<h3>` tags that have no text node between them, and either add text content or replace the tag with a semantically appropriate element.
- If you use a page-builder app (Shogun, PageFly, GemPages), open the page in that app's editor, select the empty Heading element, add text or delete the block, then republish.
- Verify with the axe DevTools browser extension on your live storefront.
Empty table headerModerate effort
Add descriptive text to every table header cell (`<th>`) so that screen readers can announce what each column or row represents.
On Shopify
- In your Shopify admin, go to Online Store → Themes → click 'Customize' (or 'Edit code' for direct file access).
- Click 'Edit code' to open the theme code editor. Tables in product descriptions are usually in sections like `product-template.liquid`, `page.liquid`, or custom section files.
- Use the search (Ctrl+F / Cmd+F) in the code editor to find `<th` tags with no inner text.
- Add descriptive text or an `aria-label` attribute to each empty `<th>`, then save.
- For tables inside product descriptions or page content edited via the rich-text editor, go to the relevant Product or Page in the admin, switch the description editor to HTML view (the `<>` icon), and edit the `<th>` tags there.
- Install the 'Accessibility Checker' app (e.g., accessiBe or Equal Web) from the Shopify App Store to scan for remaining issues after your fix.
Frame titleQuick win
Add a descriptive `title` attribute to every `<iframe>` element on your store so screen readers can identify the frame's content.
On Shopify
- Go to Online Store → Themes → click 'Customize' on your active theme.
- For iframes inside theme sections or blocks (e.g. a video or map section): click 'Edit code' (Online Store → Themes → ⋯ → Edit code) and open the relevant Liquid template (e.g. sections/video.liquid, sections/map.liquid, or snippets/map.liquid).
- Locate the `<iframe>` tag and add a `title` attribute: `<iframe src="..." title="{{ section.settings.video_title | default: 'Embedded video' }}">`.
- For iframes injected by Shopify apps, go to Apps → the specific app → look for an Accessibility or Widget Settings option. If unavailable, add a JavaScript snippet via Online Store → Themes → Edit code → theme.liquid (just before `</body>`): `document.querySelectorAll('iframe:not([title])').forEach(function(f){ f.title = 'Embedded content'; });` — but replace the generic fallback with specific labels per frame where possible.
- Save and preview, then inspect the iframe in browser DevTools to confirm the title attribute is present.
Heading orderModerate effort
Fix heading tags so they follow a logical, sequential order (H1 → H2 → H3…) without skipping levels anywhere on the page.
On Shopify
- Go to Online Store → Themes → click Customize on your active theme.
- For content sections (e.g., Featured Collection, Rich Text, Custom HTML), click each section and inspect what heading level is output. Many Shopify sections expose a 'Heading size' or 'Heading tag' dropdown — set these to the correct sequential level.
- For deeper control, go to Online Store → Themes → Actions → Edit code. Open the relevant section Liquid file (e.g., sections/featured-collection.liquid) and change hardcoded <h3> or <h4> tags to the correct level.
- For blog posts and pages, edit the page content in the rich-text editor (Online Store → Pages or Blog Posts → select post) and use the paragraph/heading dropdown in the toolbar to assign correct heading levels.
- Install the free axe DevTools browser extension and run it on your storefront to verify no heading-order violations remain.
Html has langQuick win
Add a valid `lang` attribute to the `<html>` element so browsers and assistive technologies know what language your page is written in.
On Shopify
- In your Shopify admin, go to Online Store → Themes.
- Next to your active theme, click Actions → Edit code.
- In the left-hand file tree under 'Layout', click `theme.liquid` (this is your root template).
- Find the opening `<html` tag near the top of the file.
- Shopify themes typically already output `<html lang="{{ request.locale.iso_code }}">` using a Liquid variable — if this variable is present, the lang is already dynamic and correct. If the tag reads simply `<html>` or has a hard-coded lang value, replace it with `<html lang="{{ request.locale.iso_code }}">` to dynamically match the store's active language.
- Click Save. Verify by viewing source on any storefront page.
Html lang validQuick win
Set a valid BCP 47 language code on the `lang` attribute of your page's `<html>` element (e.g., `lang="en"`) so browsers, screen readers, and search engines correctly identify the page language.
On Shopify
- In your Shopify Admin, go to Online Store → Themes.
- Click the three-dot menu (⋯) next to your active theme and choose Edit code.
- In the Layout folder on the left, click `theme.liquid`.
- Find the opening `<html` tag near the top of the file (it may already include `lang="{{ shop.locale }}"`). If the `lang` attribute is missing or has a hard-coded invalid value, replace it so the tag reads: `<html lang="{{ shop.locale }}">` — this dynamically outputs the language your customer has selected.
- Click Save. Preview the storefront, view page source, and verify the rendered tag reads e.g. `<html lang="en">`.
Image altModerate effort
Add a descriptive `alt` attribute to every `<img>` element on your store so screen readers and search engines can understand what each image shows.
On Shopify
- **Product images:** Admin → Products → select a product → click any product image thumbnail → in the image dialog, fill in the 'Alt text' field → click 'Save'.
- **Collection images:** Admin → Products → Collections → select a collection → click the collection image → add alt text in the dialog.
- **Theme content images (banners, slideshows):** Admin → Online Store → Themes → Customize → select the section containing the image → look for the 'Image alt text' or 'Alt text' field in the sidebar.
- **Blog/article images:** Admin → Online Store → Blog Posts → edit a post → click the image in the editor → click 'Edit' (pencil icon) → enter alt text.
- **Bulk editing product image alt text:** Use the Shopify bulk editor or an app like 'Bulk Image Edit – Image SEO' (from the Shopify App Store) to update alt text across many products at once.
- **Theme files (hardcoded images):** Admin → Online Store → Themes → Edit code → locate the relevant `.liquid` file → find `<img` tags and add `alt="{{ descriptive_variable }}"` or a hardcoded string.
Image redundant altModerate effort
Remove or empty the alt attribute on images whose caption or surrounding text already describes them, so screen readers don't announce the same information twice.
On Shopify
- For product images: go to Admin → Products → select the product → click the image → in the 'Image alt text' field, clear the text and leave it blank (Shopify stores this as alt="" in the rendered HTML).
- For theme images in sections/blocks: go to Online Store → Themes → Customize → select the section containing the image → find the 'Image alt text' or 'Alt text' field in the sidebar and clear it if the surrounding text already describes it.
- For images added in the rich-text editor (pages, blog posts): click the image in the editor → choose 'Edit alt text' → clear the field and save.
- For images hard-coded in Liquid theme files: go to Online Store → Themes → Edit code → locate the relevant .liquid file → find the img tag and set alt="" or use {{ image.alt | escape }} only when a meaningful unique alt exists.
- To audit all product image alt texts in bulk, export products via Admin → Products → Export, edit the 'Image Alt Text' column in the CSV, then re-import.
Input button nameQuick win
Add a descriptive label to every input button so screen readers can announce what the button does.
On Shopify
- In your Shopify admin, go to Online Store → Themes → click the three-dot menu next to your active theme → Edit code.
- Use the search/filter box to find theme files that contain `<input type="submit"` or `<input type="button"` — common files include `sections/main-cart-footer.liquid`, `snippets/product-form.liquid`, and `templates/customers/login.liquid`.
- Locate any `<input>` button tag with `value=""` or no `value` attribute and add or update the `value` to a descriptive label (e.g., `value="{{ 'cart.general.checkout' | t }}"`). Use Shopify's translation keys where possible to support multiple languages.
- Click Save, then preview the theme and use a screen reader or browser accessibility inspector (Chrome DevTools → Accessibility panel) to verify the button name is now announced.
LabelModerate effort
Add a visible or programmatic label to every form input so assistive technologies can identify its purpose.
On Shopify
- Go to Online Store → Themes → click 'Customize' on your active theme.
- For theme template files (e.g., contact form, newsletter): click 'Edit code' (Online Store → Themes → ··· → Edit code).
- Locate the relevant Liquid template (e.g., sections/contact-form.liquid, sections/footer.liquid, templates/customers/login.liquid).
- Find any <input> or <textarea> missing a <label> and add a linked <label for="INPUT_ID"> element above it, ensuring the input has a matching id attribute.
- For third-party app forms (reviews, popups, etc.), check the app's own settings for a 'label' or 'field name' option, or contact the app developer.
- Save the file, then verify with the axe DevTools Chrome extension on your live storefront.
Label title onlyModerate effort
Add a visible, persistent label to every form field so it is never labeled only by a tooltip (title) or hidden description (aria-describedby).
On Shopify
- In your Shopify admin, go to Online Store → Themes → click 'Customize' on your active theme, then click 'Edit code' (Actions → Edit code).
- Locate the relevant template or section file — common files are `sections/header.liquid` (search bar), `templates/customers/login.liquid` (login form), `templates/cart.liquid` (quantity/coupon fields), and `sections/footer.liquid` (newsletter signup).
- Find the `<input>` element that has only a `title` attribute or is wrapped without a `<label>`. Add a paired `<label for="FIELD_ID">Visible Label Text</label>` before the input, and ensure the input has a matching `id="FIELD_ID"`. For search inputs, you can add `aria-label="Search"` directly on the `<input>` tag if a floating label is preferred.
- Save the file, preview on a test theme if possible, then publish. Re-run your accessibility scanner to verify.
Landmark banner is top levelModerate effort
Ensure your site's banner landmark (<header> or role="banner") sits at the top level of the page, not nested inside another landmark region.
On Shopify
- In your Shopify admin, go to Online Store → Themes → click the '...' (Actions) menu next to your active theme → Edit code.
- Open the file `layout/theme.liquid` — this is the master page wrapper that controls the HTML structure for every page.
- Search for your `<header>` tag (or any element with `role="banner"`). Confirm it appears as a direct child of `<body>`, not wrapped inside a `<main>`, `<section>`, `<div role="main">`, or similar landmark.
- If the `<header>` is inside a landmark wrapper, cut and paste it to be directly under the opening `<body>` tag, outside any landmark-carrying elements.
- Save the file, then preview the theme and re-run axe DevTools or WAVE on a live page to verify the banner is now top-level.
Landmark complementary is top levelModerate effort
Move any `<aside>` element (or element with `role="complementary"`) so it is a direct child of `<body>`, not nested inside another landmark region like `<main>`, `<header>`, `<footer>`, or `<nav>`.
On Shopify
- In your Shopify admin, go to Online Store → Themes → Actions → Edit code.
- Open the relevant layout or section file — typically `layout/theme.liquid` for global structure, or the specific section file (e.g. `sections/product-sidebar.liquid`) where the `<aside>` lives.
- Locate the `<aside>` or `role="complementary"` element. If it is inside a `<main>` or `{% section 'content' %}` block, cut it out and place it as a sibling of `<main>` directly inside the `<body>` wrapper in `theme.liquid`.
- Adjust your CSS (in `assets/base.css` or the relevant stylesheet) to maintain the visual layout — for example, use a CSS grid or flexbox on the `<body>` or outer wrapper `<div>` so the aside and main appear side-by-side.
- Save changes, preview the theme, and re-run an axe or Lighthouse accessibility audit to confirm the violation is resolved.
Landmark contentinfo is top levelModerate effort
Move your footer element (or any element with role="contentinfo") to the top level of the page so it is not nested inside another landmark region.
On Shopify
- In your Shopify admin, go to Online Store → Themes → click 'Edit code' on your active theme.
- Open the file `layout/theme.liquid` — this is the master page template that wraps all pages.
- Locate the `<footer>` tag (or any element with `role="contentinfo"`). Check what HTML elements wrap it. It should be a direct child of `<body>` (or at most inside a plain, role-free `<div>` wrapper).
- If the footer is inside a `<main>` tag or a `<div role="main">` or similar landmark, cut the entire footer block (from its opening tag to its closing tag) and paste it outside/after the closing tag of that landmark element.
- Click 'Save'. Preview your theme and run axe DevTools in your browser to verify the fix.
- If your footer is in a separate snippet (e.g., `snippets/footer.liquid`), the fix is the same — move where that snippet is *included* in `theme.liquid`, not the snippet file itself.
Landmark main is top levelModerate effort
Move the `<main>` element (or `role="main"`) so it is a direct child of `<body>` and not nested inside any other landmark element such as `<header>`, `<nav>`, `<aside>`, or `<footer>`.
On Shopify
- In your Shopify Admin, go to Online Store → Themes → your active theme → Actions → Edit code.
- Open the file `layout/theme.liquid` — this is the master page shell that wraps every page.
- Look for the `<main>` tag or an element like `<div role="main">`. Check whether it is nested inside a `<header>`, `<nav>`, or other landmark element.
- If so, cut the opening and closing `<main>` tags (and their `role` attribute if present) out of the wrapping landmark and paste them so `<main>` is a direct sibling of `<header>` and `<footer>`, all children of `<body>`.
- Save the file and preview the theme. Re-run axe DevTools or WAVE on your storefront to confirm the violation is gone.
Landmark no duplicate bannerModerate effort
Ensure your page has only one banner landmark (a single `<header>` element or `role="banner"`) so assistive technologies can navigate your site correctly.
On Shopify
- Go to Online Store → Themes → click 'Customize' on your active theme.
- To edit raw HTML: from the Themes list, click the '…' (Actions) menu → Edit code.
- Open 'layout/theme.liquid'. Search for every '<header' and 'role="banner"' tag.
- Ensure only ONE top-level <header> (or role="banner") exists outside any sectioning element. This is usually the main site header wrapping your logo and nav.
- Any secondary <header> tags used inside announcement bars, promotional sections, or app-injected blocks should be changed to <div> (and any role="banner" removed).
- If a third-party app (e.g. a sticky header or announcement bar app) is injecting an extra <header>, check the app's own settings for an option to change the element tag, or contact the app developer.
- Save changes, then verify with the axe DevTools browser extension.
Landmark no duplicate contentinfoModerate effort
Remove duplicate `<footer>` elements or `role="contentinfo"` landmarks so your page has exactly one, site-wide footer region.
On Shopify
- Go to Online Store → Themes → click 'Customize' on your active theme.
- To edit theme code directly: Online Store → Themes → Actions → Edit code.
- Open 'layout/theme.liquid' — this is your global page wrapper. Search for `<footer` and `role="contentinfo"`. You should see exactly one. If duplicates exist here, merge or remove the extra one.
- Also check 'sections/footer.liquid' (or similarly named footer section file). Ensure it contains only one `<footer>` tag and does not repeat one that already exists in theme.liquid.
- If you have installed apps that inject content (e.g. review widgets, chat widgets, cookie banners), check their output in your browser's DevTools (right-click → Inspect) to see if they render a `<footer>` element. Contact the app developer to have them use a `<div>` instead, or wrap the app embed in a `<div role="none">` override.
- Save changes, then re-audit with the axe browser extension to confirm one contentinfo landmark.
Landmark no duplicate mainModerate effort
Ensure each page contains exactly one `<main>` landmark element (or one element with `role="main"`) so screen-reader users can navigate directly to the page's primary content.
On Shopify
- Go to Online Store › Themes › (your active theme) › Actions › Edit code.
- Open 'layout/theme.liquid' — this is the master page wrapper. Search for '<main' and 'role="main"'. There should be exactly one instance.
- If a duplicate appears in a section file (e.g. 'sections/main-product.liquid', 'sections/main-collection.liquid'), open each suspect file and replace any extra '<main>' with '<section aria-label="…">' or '<div>'.
- If a third-party Shopify app is injecting an extra '<main>', check the App Embeds area (Online Store › Themes › Customize › App Embeds) or review the app's own settings for layout override options, and contact the app's support if needed.
- Save changes, then use the Shopify Theme Preview to verify the fix before publishing.
Landmark one mainQuick win
Add a single `<main>` landmark element (or `role="main"`) to every page so that screen-reader users and assistive technologies can skip directly to the primary content.
On Shopify
- Go to Online Store → Themes → Actions → Edit code.
- Open 'Layout' → `theme.liquid` (this is the master template wrapping every page).
- Locate the opening `<div>` (often `<div id="MainContent">` or similar) that wraps the `{{ content_for_layout }}` tag — this holds the unique page content.
- Change it to `<main id="main-content" role="main">` … `</main>`. If the `<div>` has important CSS classes, keep them: `<main id="main-content" role="main" class="your-existing-classes">`.
- Also add a skip link as the very first child of `<body>`: `<a class="skip-to-main visually-hidden" href="#main-content">Skip to main content</a>` and add CSS to make it visible on focus.
- Click Save, then test with the axe browser extension on any storefront page.
Landmark uniqueModerate effort
Add a unique aria-label (or aria-labelledby) to every repeated landmark role so assistive technologies can distinguish between them.
On Shopify
- In your Shopify admin, go to Online Store → Themes → click the '…' menu next to your active theme → Edit code.
- Open the layout file (layout/theme.liquid) to locate your <header>, <nav>, and <footer> landmark elements.
- Also check theme section files in the 'sections/' folder (e.g. sections/header.liquid, sections/footer.liquid, sections/breadcrumbs.liquid) where individual nav elements live.
- Add aria-label="Primary navigation" (or an appropriate unique label) to each <nav> or <aside> that appears more than once. Example: <nav aria-label="Footer navigation">.
- If your theme renders navigation via snippets, check the 'snippets/' folder for files like navigation.liquid.
- Save changes, preview the theme, and re-run your accessibility scanner to confirm the violation is resolved. Consider using a Shopify accessibility app (e.g. accessiBe or AudioEye) for ongoing monitoring.
Link in text blockModerate effort
Make inline links visually distinguishable from surrounding body text by ensuring at least 3:1 color contrast between the link color and the non-link text color, or by adding a non-color visual cue (such as underline) to every link.
On Shopify
- Go to Online Store → Themes → (your active theme) → Actions → Edit code.
- Open `assets/base.css` (or `assets/theme.css`, `assets/application.css` — the name varies by theme). Use the search box (Ctrl/Cmd+F) to find `a {` or `a:link`.
- To use approach A (color only): change the link color hex value to one that achieves ≥3:1 contrast against your body text. To use approach B (add underline): add or change `text-decoration: underline;` to the `a` selector.
- If your theme uses a visual editor with color pickers, go to Online Store → Themes → Customize → Theme settings → Typography or Colors and look for a 'Link color' option — update it there first, then verify in the CSS.
- Click Save and then preview your storefront, inspecting a product description or blog post to confirm the change is applied.
Link nameModerate effort
Add a descriptive, screen-reader-accessible label to every link on your store so assistive technologies can announce where each link leads.
On Shopify
- Go to Online Store → Themes → (your active theme) → Actions → Edit code.
- Search for the offending link in the relevant Liquid template (e.g. sections/header.liquid for nav/cart icons, snippets/icon-*.liquid for SVG icons, or sections/footer.liquid for social links).
- For icon-only links (e.g. cart, search, account), add aria-label to the <a> tag: <a href='/cart' aria-label='Shopping cart'>…</a>.
- For social icon links in the footer snippet, locate each <a> and add aria-label='Follow us on Instagram' (or the relevant network).
- For linked product images in theme sections, open the relevant section file and ensure every <img> inside an <a> has a descriptive alt attribute — Shopify's Dawn theme uses {{ product.featured_image | image_tag: alt: product.title }}, so check that alt values are not blank.
- Save changes and verify with the axe DevTools browser extension or Shopify's built-in Theme Inspector.
ListModerate effort
Fix all HTML list elements so that `<ul>` and `<ol>` contain only valid `<li>` children, and `<li>` elements appear only inside a proper list container, ensuring correct semantic list structure throughout your store.
On Shopify
- From your Shopify Admin, go to Online Store → Themes → your active theme → Actions → Edit code.
- Identify which template or section file contains the broken list. Navigation menus are typically in 'sections/header.liquid' or 'snippets/nav.liquid'; product feature lists may be in 'sections/product-template.liquid' or a similar file.
- Use the built-in code editor's search (Ctrl/Cmd+F) to search for '<ul', '<ol', or '<li' and inspect their immediate children.
- Wrap any non-<li> direct children of <ul>/<ol> inside <li> tags, or ensure every <li> is nested inside a <ul> or <ol>.
- Save the file, then preview your store and re-run axe DevTools or WAVE on the affected page to confirm the issue is resolved.
- If the broken list comes from a third-party app, contact the app developer — you cannot safely edit app-injected markup without risking update conflicts.
ListitemQuick win
Wrap every `<li>` element in a proper `<ul>` or `<ol>` parent so screen readers and browsers can correctly identify and announce list structure.
On Shopify
- Go to Online Store → Themes → click the '…' menu next to your active theme → Edit code.
- Use the search box (top-left of the code editor) to search for '<li' across all files to locate orphaned list items.
- The most common locations are: 'sections/' files (e.g. header.liquid, footer.liquid, announcement-bar.liquid), 'snippets/' files, and 'layout/theme.liquid'.
- In the offending file, find the bare `<li>` tag(s) and add a `<ul>` opening tag immediately before the first `<li>` and a `</ul>` closing tag after the last `</li>`.
- If you use a page builder app (e.g. PageFly, GemPages, Shogun), open that app, find the block containing the list, and switch to its HTML/code editor view to wrap the items.
- Click Save, then re-test with the axe browser extension.
Meta refreshQuick win
Remove or disable any `<meta http-equiv="refresh">` tag that automatically redirects or reloads the page in under 20 hours.
On Shopify
- In your Shopify Admin, go to Online Store → Themes → click the '…' (Actions) menu next to your active theme → Edit code.
- In the file browser, open 'Layout/theme.liquid' — this is the global template that wraps every page.
- Use Ctrl+F / Cmd+F to search for 'http-equiv' or 'refresh' to locate the tag.
- Delete the entire `<meta http-equiv="refresh" ...>` line.
- Check any other layout files (e.g. 'Layout/password.liquid') and section/snippet files for the same tag.
- If a third-party app injected the tag, go to Online Store → Themes → Edit code and look inside 'Snippets/' or 'Sections/' for app-generated files, or disable/uninstall the responsible app from Apps in the Admin.
- Save all changed files and preview your storefront to confirm no automatic reload occurs.
Meta viewportQuick win
Remove `user-scalable=no` (and any `maximum-scale` value below 5) from your site's `<meta name="viewport">` tag so visitors can pinch-to-zoom on mobile devices.
On Shopify
- In your Shopify admin, go to Online Store → Themes.
- Next to your active theme, click Actions → Edit code.
- In the Layout folder, open `theme.liquid`.
- Search (Ctrl/Cmd+F) for `meta name="viewport"`.
- Edit the content attribute to read exactly: `content="width=device-width, initial-scale=1"` — remove `user-scalable=no` and any `maximum-scale` below 5.
- Click Save. Verify by opening your storefront on a mobile device and pinching to zoom.
Meta viewport largeQuick win
Remove or raise the `maximum-scale` value in your site's `<meta name="viewport">` tag so mobile users can pinch-to-zoom freely.
On Shopify
- In your Shopify Admin, go to Online Store → Themes.
- Next to your active theme, click Actions → Edit code.
- In the left-hand file tree under 'Layout', click theme.liquid.
- Use Ctrl+F / Cmd+F to search for `<meta name="viewport"`.
- Edit the content attribute: remove `maximum-scale=1` (or any value below 5) and remove `user-scalable=no` if present. A safe final tag looks like: `<meta name="viewport" content="width=device-width, initial-scale=1.0">`.
- Click Save. Verify on a mobile device that pinch-to-zoom works.
Nested interactiveModerate effort
Remove or restructure focusable elements nested inside interactive controls so that no interactive element contains another focusable child.
On Shopify
- In your Shopify Admin go to Online Store → Themes → (your active theme) → Actions → Edit code.
- Open the file most likely to contain the offending component. Product cards are typically in snippets/product-card.liquid or snippets/card-product.liquid (Dawn theme). Navigation dropdowns are in snippets/header.liquid or sections/header.liquid.
- Search for the outer interactive wrapper (e.g. <a … class="card__inner"> or <button>) and look for any focusable child element nested inside it.
- Restructure the Liquid template following the 'sibling' pattern in the code example above: replace the wrapping <a> with a <div>, then add a dedicated <a> for the product title/image and keep the Add to Cart button as a sibling.
- Save the file, then preview the theme and tab through the product grid with a keyboard to confirm focus order is correct.
- If you use a page-builder app (like Shogun or PageFly), open the page in that app's editor, select the block, and edit its HTML/custom code section directly using the same pattern.
Object altQuick win
Add a descriptive text alternative to every `<object>` element so screen readers can convey its content to users who cannot see it.
On Shopify
- In your Shopify admin, go to Online Store → Themes → click 'Customize' on your active theme.
- To edit raw HTML: go to Online Store → Themes → Actions → Edit code.
- Locate the template file that contains the `<object>` element (e.g. `sections/rich-text.liquid`, `templates/product.liquid`, or a custom section).
- Find the `<object>` tag and add `aria-label="Descriptive text here"` to its opening tag, and/or add fallback anchor/text between the open and close tags.
- If the `<object>` is embedded via a page's HTML content block (rich text), go to the page/product editor, switch the content field to HTML view (the `<>` icon in the rich text toolbar), and edit the tag there.
- Save your changes and verify with the axe DevTools browser extension.
Page has heading oneModerate effort
Add a single, descriptive `<h1>` heading to every page so screen readers and search engines can identify the page's main topic.
On Shopify
- **Product pages:** Go to Online Store → Themes → Actions → Edit Code. Open `templates/product.liquid` (or `sections/product-template.liquid` / `sections/main-product.liquid` in Dawn and most modern themes). Find where the product title is rendered — it is usually `{{ product.title }}` — and confirm it is wrapped in `<h1>…</h1>`. If it uses `<h2>` or a `<div>`, change the tag to `<h1>`.
- **Collection pages:** Open `templates/collection.liquid` or `sections/main-collection-banner.liquid`. Locate `{{ collection.title }}` and ensure it is inside `<h1>…</h1>`.
- **Homepage:** Open `templates/index.json` (or `index.liquid`) and check each section file rendered there. The first prominent text block (hero banner, featured title) should use an `<h1>`. Edit the relevant section `.liquid` file accordingly.
- **Custom pages:** Go to Online Store → Pages → click the page → switch the content editor to HTML view (< > icon) → ensure the first main heading uses `<h1>…</h1>`.
- **No-code option:** In the theme customizer (Online Store → Customize), some sections expose a 'Heading tag' dropdown — set it to H1 for the primary banner or page-title section.
- Save and preview each template, then verify with browser DevTools or the axe browser extension.
Presentation role conflictModerate effort
Remove conflicting ARIA attributes and tabindex from elements that are marked as presentational (role="presentation" or role="none"), so screen readers consistently ignore them.
On Shopify
- In your Shopify admin, go to Online Store → Themes → click the three-dot menu next to your active theme → Edit code.
- Use the search box (top of the file tree) to search across all files for 'role="presentation"' and 'role="none"' to locate every instance.
- For each match, inspect the surrounding HTML in the code editor: look for any aria-* attribute or tabindex on the same element.
- Remove the conflicting attribute(s) following the decision logic in the generic steps above — either strip the ARIA/tabindex, or remove the presentational role.
- Save the file. Preview the theme and re-run an axe scan on the changed page to verify the conflict is gone.
- If the element is inside a third-party app section (e.g. a slider or carousel app), contact the app developer to report the conflict, as you cannot directly edit third-party app code.
RegionModerate effort
Wrap all visible page content inside HTML landmark elements (such as `<main>`, `<nav>`, `<header>`, `<footer>`, or ARIA `role` attributes) so screen-reader users can navigate your store efficiently.
On Shopify
- From your Shopify Admin, go to Online Store → Themes → click the three-dot menu on your active theme → Edit code.
- Open `layout/theme.liquid` — this is the master template that wraps every page. Locate the outermost `<div>` or `<body>` content structure.
- Ensure the site logo/header area is wrapped in `<header role="banner">`, the primary nav in `<nav aria-label="Main menu">`, and the page body in `<main id="MainContent" role="main">`. Most modern Shopify themes (Dawn, Sense, Craft) already use these tags — verify they are present and that no promotional sections (e.g. announcement bars) sit outside them.
- Open individual section files under `sections/` (e.g. `sections/announcement-bar.liquid`, `sections/header.liquid`) and confirm their output HTML is nested inside the correct landmark in `theme.liquid`.
- For any custom sections that render standalone `<div>` blocks outside landmarks, either move them inside `<main>` in `theme.liquid` or add `role="region"` and `aria-label="[Section purpose]"` to the outermost `<div>` of that section file.
- Save changes, then visit your storefront and run axe DevTools (free Chrome/Firefox extension) to verify no 'region' violations remain.
Role img altQuick win
Add an accessible text label (aria-label) to every element that has role="img" so screen readers can announce what the image conveys.
On Shopify
- Go to Online Store → Themes → click the three-dot menu next to your active theme → Edit code.
- In the Layout or Sections panel, open the template file where the flagged element lives (e.g., sections/product-template.liquid, snippets/icon-star.liquid, or snippets/icon.liquid for SVG icons).
- Locate the element with role="img" — often an SVG or a <span> wrapping an icon font.
- Add aria-label="[descriptive text]" directly to the opening tag, e.g., <svg role="img" aria-label="Free shipping badge" ...>. For icon snippets that are purely decorative, add aria-hidden="true" instead.
- For Shopify's built-in star-rating or review app snippets, search snippets/ for 'role="img"' and patch each occurrence.
- Save the file, then preview the live theme and verify with axe DevTools or a screen reader.
Scrollable region focusableQuick win
Make every scrollable region on your store reachable and operable by keyboard by adding tabindex="0" (or placing focusable content inside it) so users who cannot use a mouse can scroll it.
On Shopify
- In your Shopify Admin, go to Online Store → Themes → (your active theme) → Actions → Edit code.
- Identify the template or section file that renders the scrollable region — common files include sections/product-template.liquid, sections/main-product.liquid, or snippets/product-description.liquid.
- Find the container div or section that has a CSS class applying overflow: auto / overflow: scroll (check assets/theme.css or assets/base.css for the class definition).
- Add tabindex="0" and an aria-label to that opening tag, e.g.: <div class="product-description" tabindex="0" aria-label="Product description">
- In the CSS file, add a focus style: .product-description:focus { outline: 2px solid #005fcc; outline-offset: 2px; }
- Save both files, then preview the theme and press Tab to confirm the element is focusable.
Select nameModerate effort
Add a descriptive, programmatically associated label to every `<select>` dropdown element on the site so assistive technologies can announce its purpose to users.
On Shopify
- In your Shopify admin, go to Online Store → Themes → click the three-dot menu next to your active theme → Edit code.
- Locate the template or snippet that renders the offending dropdown. Common culprits: 'snippets/product-variant-picker.liquid' (variant/size selectors), 'sections/collection-template.liquid' or 'snippets/sort-by.liquid' (sort dropdowns), and 'snippets/country-selector.liquid' (currency/country pickers).
- Find the bare <select> tag and add a linked <label> immediately before it, e.g.: <label for="SortBy">Sort by</label> <select id="SortBy" name="sort_by">. Make sure the 'for' value matches the select's 'id' exactly.
- If the design has no room for a visible label (e.g. a compact header sort), add aria-label="Sort results by" directly on the <select> tag instead.
- Click Save, then preview the storefront and verify with the axe DevTools browser extension or VoiceOver/NVDA.
Skip linkQuick win
Add a valid, matching target ID to every skip-navigation link so keyboard and assistive-technology users can bypass repeated header content and jump directly to the main content area.
On Shopify
- In your Shopify Admin go to Online Store → Themes → your active theme → Actions → Edit code.
- Open Layout → theme.liquid (or the equivalent base layout file).
- Immediately after the opening <body> tag, confirm a skip link exists — it often reads `<a class="skip-to-content-link" href="#MainContent">{{ 'accessibility.skip_to_text' | t }}</a>` in Dawn and most modern themes.
- Search the file (Ctrl+F) for the `id` referenced in that href (e.g. `MainContent`). In Dawn, the `<main>` tag carries `id="MainContent"` — verify it is present and spelled identically (case-sensitive).
- If the id is missing, find the opening `<main>` tag in theme.liquid (or in sections/header.liquid / templates/) and add `id="MainContent" tabindex="-1"`.
- If your theme uses a different fragment (e.g. `#content`), make the skip link href and the target id match exactly, then Save.
Svg img altModerate effort
Add a meaningful text alternative to every SVG image so screen readers can describe it to visually impaired shoppers.
On Shopify
- Go to Online Store → Themes → (your active theme) → Actions → Edit code.
- Locate the template or snippet file that contains the SVG — common locations are `snippets/icon-*.liquid`, `sections/header.liquid`, or `layout/theme.liquid`.
- Find the `<svg>` tag and add `role='img'` and `aria-labelledby='UNIQUE-ID'` as attributes.
- Insert `<title id='UNIQUE-ID'>Your descriptive label here</title>` as the very first line inside the `<svg>` element.
- For decorative SVGs (e.g. arrow chevrons), add `aria-hidden='true'` and `focusable='false'` instead.
- Save the file and verify with Shopify's Theme Preview; test with a screen reader or the axe browser extension.
TabindexModerate effort
Remove all positive tabindex values (tabindex="1" or higher) from your store's HTML elements, replacing them with tabindex="0" or relying on natural document order to control keyboard focus.
On Shopify
- Go to Online Store → Themes → click 'Customize' on your active theme.
- For theme-level HTML/Liquid changes: from the theme editor click the three-dot menu → 'Edit code'. Search all .liquid files (use Ctrl+F in each file, or the built-in search) for 'tabindex' to locate every occurrence.
- In each file, remove positive tabindex attributes or change them to tabindex='0'. Save each file.
- If a third-party app (e.g. a popup, reviews widget, or page builder like Shogun/PageFly) is injecting elements with positive tabindex values, check that app's settings for custom HTML blocks and edit the markup there, or contact the app developer.
- Verify by previewing your theme and tabbing through the storefront in a browser without clicking the mouse.
Valid langModerate effort
Add a valid BCP 47 language code to every `lang` attribute on your pages so assistive technologies can read content in the correct language.
On Shopify
- In your Shopify admin, go to Online Store → Themes → click 'Customize' on your active theme.
- To edit the root `lang` attribute: from the theme editor click 'Edit code' (or go to Online Store → Themes → Actions → Edit code).
- Open `layout/theme.liquid`. Find the opening `<html` tag — it typically reads `<html class="..." lang="{{ request.locale.iso_code }}">`. Shopify injects the store locale automatically via `request.locale.iso_code`, so ensure the locale itself is correct.
- Verify/update the store locale: Settings → Languages. The 'Published' language's locale code is what Shopify inserts. If that code is wrong, correct it here or switch to a valid language.
- For third-party section snippets or app blocks that hard-code a `lang` attribute, open the relevant `.liquid` file in the code editor and update the value to a valid BCP 47 tag.
- Save changes and re-test with the axe browser extension on your live storefront.
Security (OWASP) · 23 fixes
Dmarc policy noneModerate effort
Strengthen your DMARC policy from p=none (monitor-only) to p=quarantine, then p=reject, to actively block email spoofing of your domain.
On Shopify
- Shopify does not manage DNS records — your domain's DNS is controlled at your domain registrar (e.g., GoDaddy, Namecheap, Cloudflare) or wherever you pointed your nameservers.
- Log in to your DNS provider's control panel and locate the DNS management / DNS Records section for your store's domain.
- Find the existing TXT record with the Name/Host _dmarc (i.e., _dmarc.yourdomain.com) and click Edit.
- Change p=none to p=quarantine in the record value, save, and wait 24–48 hours for propagation. Monitor reports.
- After confirming no legitimate mail fails, edit the record again and change p=quarantine to p=reject.
- If you use Shopify Email or a third-party ESP connected to Shopify (Klaviyo, Omnisend, etc.), verify that service is included in your SPF record and has DKIM configured before tightening DMARC.
Hsts disabledQuick win
Enable HTTP Strict-Transport-Security (HSTS) by setting a max-age of at least 31536000 seconds (one year) so browsers always use HTTPS when visiting your store.
On Shopify
- Shopify automatically enforces HTTPS and injects the HSTS header with `max-age=31536000; includeSubDomains; preload` for all storefronts on the shopify.com infrastructure — no manual configuration is needed.
- If you use a custom domain, go to Shopify Admin → Online Store → Domains, ensure your custom domain shows a green padlock, and toggle 'Redirect all traffic to this domain' ON — Shopify then manages HSTS for that domain.
- If you use Shopify Plus with a custom reverse proxy or edge configuration (e.g. Cloudflare), set the HSTS header in your CDN/proxy layer as described in the Cloudflare or proxy steps below.
Hsts max age too shortQuick win
Increase your HSTS max-age to at least 31536000 (one year) so browsers enforce HTTPS-only connections for a meaningful period.
On Shopify
- Shopify automatically sets HSTS on all storefronts (myshopify.com and custom domains) with a compliant max-age — you cannot and do not need to set this header manually in the Shopify admin.
- If you are using a custom domain, go to Admin → Settings → Domains and confirm your domain shows a green padlock / 'SSL Active' status. Shopify manages the header at the CDN layer.
- If a third-party proxy (e.g. Cloudflare) sits in front of your Shopify store and is overriding headers, configure HSTS there instead (see the CDN/proxy provider's dashboard under Security or SSL/TLS settings and set max-age to 31536000).
- Verify the live header value at securityheaders.com by entering your storefront URL.
Https not availableQuick win
Enable HTTPS by installing a valid SSL/TLS certificate and redirecting all HTTP traffic to the secure HTTPS version of your store.
On Shopify
- Shopify automatically provisions and renews a free SSL certificate for every store — no manual installation is required.
- In your Shopify Admin, go to Online Store → Domains.
- Find your custom domain and confirm the SSL certificate status shows 'SSL certificate active' (green checkmark). If it shows 'Unavailable', click the domain and follow the on-screen prompts; Shopify will attempt to re-provision the certificate.
- Scroll down on the same Domains page and enable the toggle 'Redirect all traffic to this domain' — this enforces HTTPS and the canonical domain simultaneously.
- HSTS is managed by Shopify's infrastructure; no additional action is needed.
Info disclosure serverQuick win
Remove or obscure the Server HTTP response header so your web server software name and version are no longer exposed to the public internet.
On Shopify
- Shopify's infrastructure automatically manages all HTTP response headers at its edge network — store owners cannot access the underlying web server config.
- The `Server` header emitted by Shopify's own CDN (e.g., `server: shopify`) does not expose exploitable version strings; this is handled by Shopify and is outside merchant control.
- If you are using a custom domain proxied through Cloudflare: log in to Cloudflare → select your domain → Rules → Transform Rules → Modify Response Header → Create a rule to REMOVE the `Server` header. Set 'When incoming requests match… all requests' and 'Then… Remove → Header name: server'. Save and deploy.
- Verify by opening DevTools → Network → reload any page → inspect response headers for the absence or sanitization of `Server`.
Info disclosure x powered byQuick win
Remove or mask the X-Powered-By HTTP response header to stop advertising your server technology stack to attackers.
On Shopify
- Shopify's infrastructure automatically manages all HTTP response headers — store owners cannot directly modify server-level headers like X-Powered-By from the Shopify admin.
- Shopify does not expose X-Powered-By with sensitive stack information on standard storefronts; if a scanner flags this, verify whether it is coming from a third-party app, a custom Hydrogen/Oxygen headless front-end, or a connected external service.
- For Hydrogen (headless) storefronts deployed on Oxygen: open your Hydrogen project, locate server middleware or the entry server file, and add a response-header removal step (e.g., `response.headers.delete('x-powered-by')`) before sending the response.
- For third-party apps injecting the header, contact the app developer or disable the app if it poses a risk.
Insecure cookieModerate effort
Set the HttpOnly, Secure, and SameSite=Strict flags on every session and CSRF cookie your store sets so they cannot be stolen by malicious scripts or sent over unencrypted connections.
On Shopify
- Shopify's own session and cart cookies (e.g., _session_id, _secure_session_id) are managed by Shopify's infrastructure and already carry Secure and HttpOnly on Plus plans and standard storefronts — verify in DevTools.
- For CSRF tokens in custom theme forms, Shopify injects them via `{{ form.errors }}` and Liquid — you do not set these manually; ensure your theme uses standard Shopify form tags rather than custom JavaScript-built forms.
- For cookies set by custom apps or scripts injected via theme.liquid or Script Tags: go to Online Store → Themes → Edit Code → theme.liquid and review any `document.cookie` assignments in custom JavaScript; add '; Secure; SameSite=Strict' to every assignment.
- For private/custom app backends (Node.js, Ruby, etc.) deployed on external servers that set cookies: update your server's session middleware (e.g., express-session `cookie: { httpOnly: true, secure: true, sameSite: 'strict' }`) and redeploy.
- Install a trusted security scanner app (e.g., Shopify Security Scan in the App Store) to continuously monitor cookie flags after each change.
Missing content security policyModerate effort
Add a Content-Security-Policy (CSP) response header to every page so browsers block unauthorized scripts, styles, and resources from loading.
On Shopify
- Shopify's core storefront does not allow arbitrary HTTP response headers via the admin UI — the platform controls its own server headers.
- For custom CSP additions on storefront pages, use a Shopify app such as 'CSP Header Manager' or 'Locksmith' that injects security headers via a Shopify script tag workaround, or handle it at the edge.
- The most reliable approach for Shopify is to place the store behind a CDN/proxy such as Cloudflare (free tier available): in Cloudflare dashboard → Security → WAF → Transform Rules → HTTP Response Header Modification, add a new rule to set the `Content-Security-Policy` header value for your storefront domain.
- For Shopify Plus merchants using a custom storefront (Hydrogen/Oxygen or headless), add the CSP header in your server middleware: in your Hydrogen app, open `server.ts` and add `res.headers.set('Content-Security-Policy', '...')` inside your request handler.
- Always test at checkout — Shopify's hosted checkout (checkout.shopify.com) is a separate domain and outside your CSP scope; focus your policy on your storefront domain.
Missing dmarcQuick win
Add a DMARC DNS TXT record at _dmarc.yourdomain.com to protect your domain from email spoofing and phishing.
On Shopify
- DMARC is a DNS record — it is NOT managed inside the Shopify admin itself. You manage it at whichever domain registrar or DNS host controls your domain (e.g. GoDaddy, Namecheap, Cloudflare, Google Domains).
- In your Shopify admin, go to Settings → Domains to see which domain you are using and confirm where it is managed (Shopify-managed vs. third-party).
- If Shopify manages your DNS: go to Settings → Domains → click your domain → click 'DNS Settings'. Scroll to the 'TXT Records' section and click 'Add record'. Set Host/Name to '_dmarc' and Value to your DMARC policy string (e.g. v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com).
- If DNS is managed externally (e.g. Cloudflare, GoDaddy): log into that provider's DNS dashboard, add a new TXT record, set the Name/Host to '_dmarc' (or '_dmarc.yourdomain.com' depending on the interface), and paste the DMARC value.
- Also ensure Shopify's outbound email is covered: in Settings → Notifications → Sender email, verify your sending domain and follow Shopify's guide to authenticate it with SPF and DKIM so those emails pass DMARC alignment.
Missing permissions policyQuick win
Add a Permissions-Policy HTTP response header to explicitly restrict which browser features (camera, microphone, geolocation, etc.) your store's pages are allowed to use.
On Shopify
- Shopify's shared infrastructure does not expose a web-server config file (no .htaccess or nginx.conf), so you cannot set arbitrary response headers directly.
- The best approach is to use a Shopify app that injects security headers: search the Shopify App Store for 'Security Headers' apps (e.g., 'EasyAuth Security Headers' or 'Locksmith' for edge-level header injection).
- Alternatively, if your store is behind Cloudflare, add the header there (see Cloudflare steps below) — this is the most reliable method for Shopify stores.
- For a theme-level partial workaround: in the Shopify Admin go to Online Store → Themes → Actions → Edit Code. Open layout/theme.liquid and add a <meta http-equiv='Permissions-Policy' content='camera=(), microphone=(), geolocation=()'> tag inside the <head> section. Note: meta http-equiv is NOT a true HTTP header and offers weaker protection, but it is the only native in-theme option available without server access.
- Verify by loading your storefront and checking Response Headers in browser DevTools Network tab.
Missing referrer policyQuick win
Add a `Referrer-Policy: strict-origin-when-cross-origin` HTTP response header to every page so browsers control what referrer information is sent with requests.
On Shopify
- Shopify's hosted infrastructure does not let you set arbitrary HTTP response headers via the admin UI directly.
- The most practical approach is to inject the `<meta>` tag fallback: go to Online Store → Themes → Actions → Edit Code.
- Open `layout/theme.liquid` and add `<meta name="referrer" content="strict-origin-when-cross-origin">` immediately after the opening `<head>` tag.
- Save the file. Verify using browser DevTools → Network → select document → Response Headers (note: the meta tag approach controls browser behaviour even though it won't show as an HTTP header in DevTools; for the true HTTP header you need a Shopify Plus account with a custom edge/CDN layer or a reverse proxy like Cloudflare — see the Cloudflare step below).
- Shopify Plus stores using Cloudflare (or another CDN/WAF): add a Transform Rule or HTTP Response Header Rule to inject `Referrer-Policy: strict-origin-when-cross-origin` on all responses.
Missing spfQuick win
Add a DNS TXT record containing a valid SPF policy to your domain so email servers can verify that messages sent from your domain are legitimate.
On Shopify
- Shopify does not manage your domain's DNS records directly — you must edit DNS at wherever your domain is registered or hosted (e.g. GoDaddy, Namecheap, Cloudflare).
- In your Shopify admin, go to Settings → Domains and note your custom domain and which nameservers it uses (Shopify-managed or external).
- If your domain uses Shopify-managed DNS: go to Settings → Domains → click your domain → 'DNS Settings' → click 'Add custom record' → choose TXT → Host: @ → Value: your SPF string (e.g. v=spf1 include:_spf.google.com include:shops.shopify.com ~all) → Save.
- If using external DNS (Cloudflare, GoDaddy, etc.), log in to that provider's DNS dashboard and add the TXT record at '@' with your SPF value there.
- Shopify's own transactional mail is sent through their infrastructure; if you use Shopify Email or rely on Shopify's default sending, add 'include:shops.shopify.com' to your SPF record.
- Verify propagation with an SPF checker tool.
Missing strict transport securityQuick win
Add an HTTP Strict-Transport-Security (HSTS) response header with at least `max-age=31536000; includeSubDomains` to every HTTPS response your store sends.
On Shopify
- Shopify's infrastructure automatically enforces HTTPS and sends the HSTS header for all stores on *.myshopify.com and custom domains connected through Shopify.
- In your Shopify Admin go to Online Store → Domains. Ensure your custom domain is connected and the SSL certificate status shows 'Connected' (green padlock icon).
- Once the domain is connected and SSL is active, Shopify will serve the HSTS header automatically — no code change is needed.
- If you use a custom reverse proxy or a third-party CDN (e.g., Cloudflare) in front of Shopify, configure HSTS in that layer instead (see Cloudflare steps below).
- Verify by opening DevTools → Network → reload your homepage → click the document request → check Response Headers for 'strict-transport-security'.
Missing x content type optionsQuick win
Add the `X-Content-Type-Options: nosniff` HTTP response header to every page of your store so browsers never guess at file types.
On Shopify
- Shopify's core storefront automatically sends X-Content-Type-Options: nosniff on all Shopify-hosted pages — verify this is the case for your specific theme by checking Response Headers in browser dev-tools.
- If you are using a custom Shopify app, a Shopify Functions middleware, or a headless/custom storefront (Hydrogen/Oxygen), open your server-side code and add the header in your response handler (e.g. in your Remix loader or Express middleware: res.setHeader('X-Content-Type-Options', 'nosniff')).
- For a Hydrogen storefront on Oxygen: in your server.ts (or entry.server.tsx), add the header to the Response object before returning it from your request handler.
- If you proxy Shopify through a CDN (Cloudflare, Fastly, etc.), add the header as a custom response rule at the CDN layer to ensure it is present on every response.
Missing x frame optionsQuick win
Add an X-Frame-Options HTTP response header set to DENY or SAMEORIGIN to prevent your store's pages from being embedded in iframes on other websites.
On Shopify
- Shopify's core platform automatically sets X-Frame-Options: DENY on all storefront pages — verify this is still true by checking Response Headers in browser DevTools.
- If you use a custom Shopify app or third-party proxy that strips headers, contact that app's support to ensure they pass through or re-add the header.
- For Shopify Plus merchants using a custom domain behind Cloudflare: in your Cloudflare dashboard go to Rules → Transform Rules → Response Header Modification → Create Rule → Add Header: X-Frame-Options = SAMEORIGIN, apply to all requests.
Passive scan onlyModerate effort
Complement passive security scans with active Dynamic Application Security Testing (DAST) against a staging copy of your store before each release.
On Shopify
- Shopify's production infrastructure is managed by Shopify — you cannot run DAST against Shopify's shared servers. Focus active testing on any custom apps, custom storefronts (Hydrogen/Storefront API), or third-party integrations you own.
- For custom Shopify apps or Hydrogen storefronts: deploy a staging version to a separate Shopify development store or a staging server (e.g. Vercel preview URL).
- Point OWASP ZAP (downloadable from zaproxy.org) at your development-store or staging URL. Enable 'Ajax Spider' for JavaScript-rendered pages common in Headless/Hydrogen setups.
- In ZAP, add an 'HTTP Session' with a logged-in test-customer cookie to scan authenticated checkout and account flows.
- Review ZAP's Alerts panel; remediate High/Medium findings in your custom app code before submitting to the Shopify App Store or pushing to production.
- For the hosted Shopify theme layer, rely on Shopify's own security programme and focus your DAST budget on custom code you control.
Ssl cert expiring soonQuick win
Renew your SSL/TLS certificate before it expires to keep your store secure, trusted, and visible in search results.
On Shopify
- Shopify provisions and auto-renews SSL certificates for all stores and custom domains at no extra charge — you do not manually renew them.
- To verify the certificate is active: go to Shopify Admin → Settings → Domains. Each domain shows a green padlock and 'SSL certificate: Active' when healthy.
- If the certificate shows 'Unavailable' or 'Pending', click on the domain and choose 'Verify connection'. The most common cause of failure is DNS not correctly pointed to Shopify's servers (check your A record and CNAME point to Shopify).
- If it remains stuck, contact Shopify Support from Admin → Help — they can force a re-provision.
Ssl cert invalidModerate effort
Install a valid SSL/TLS certificate that exactly matches your store's domain name, so browsers trust your site and customer data is encrypted in transit.
On Shopify
- Shopify provisions and manages SSL certificates automatically for all stores on the myshopify.com subdomain and for connected custom domains.
- Go to Admin → Settings → Domains. Verify your custom domain is listed and shows a green padlock / 'SSL available' status.
- If it shows 'SSL unavailable' or a pending state, remove the domain and re-add it: click the domain name → Remove domain, then re-add it using 'Connect existing domain'. Shopify will re-provision the certificate within minutes to hours.
- Ensure your domain's DNS A record points to Shopify's IP (23.227.38.65) and the CNAME for www points to shops.myshopify.com — a misconfigured DNS record is the most common cause of Shopify SSL failures.
- If the certificate is still not provisioning after 48 hours, contact Shopify Support. Shopify does not allow you to upload a custom certificate on standard plans.
Ssl errorModerate effort
Replace or reissue your SSL/TLS certificate so it is valid for the exact domain name your store uses, eliminating the hostname mismatch error.
On Shopify
- Shopify provisions and renews SSL certificates automatically for all stores on the myshopify.com subdomain and for custom domains added correctly through Shopify.
- Go to: Shopify Admin → Settings → Domains.
- If your custom domain shows a warning or 'SSL unavailable', click the domain name and then click 'Re-verify connection' or remove and re-add the domain.
- Ensure your DNS A record points to Shopify's IP (23.227.38.65) and your CNAME for www points to shops.myshopify.com — a misconfigured DNS record is the most common cause of certificate mismatch on Shopify.
- Allow up to 48 hours after correcting DNS for Shopify to automatically re-provision a valid certificate. If it persists beyond 48 hours, contact Shopify Support.
Ssl not accessibleModerate effort
Enable HTTPS on your store by opening port 443 and installing a valid SSL/TLS certificate so every page is served over a secure connection.
On Shopify
- Shopify manages SSL certificates and port 443 automatically for all stores on the shopify.com infrastructure — you do not control firewall rules directly.
- Go to Admin → Online Store → Domains.
- If you have a custom domain, ensure it is correctly pointed to Shopify's servers (CNAME to shops.myshopify.com or Shopify's IP). Shopify will auto-provision and renew a Let's Encrypt certificate within 48 hours of correct DNS propagation.
- Enable the 'Redirect all traffic to HTTPS' toggle found at Admin → Online Store → Domains (scroll to the SSL certificate section).
- If port 443 remains unreachable after DNS propagates, contact Shopify Support — the issue is on their infrastructure, not yours.
Weak spfQuick win
Add a hard-fail (-all) or soft-fail (~all) mechanism to your SPF DNS record so that mail servers are explicitly told to reject or flag email from senders not listed in your record.
On Shopify
- SPF is a DNS record — it is NOT set inside Shopify's admin. You must edit it at the DNS provider where your domain's nameservers are hosted.
- If you bought your domain through Shopify: go to Shopify Admin → Settings → Domains → click your domain → click 'Manage' → 'DNS Settings'. Find the TXT record starting with v=spf1 and edit it to end with -all or ~all.
- If your domain is hosted elsewhere (GoDaddy, Namecheap, Cloudflare, etc.): log in to that provider's DNS management panel, find the TXT record for @ (root domain) starting with v=spf1, and add -all or ~all at the end.
- Shopify's email sending (order confirmations, etc.) uses its own SPF infrastructure — confirm you have 'include:shops.shopify.com' or 'include:myshopify.com' in your record before closing with -all.
X content type options weakQuick win
Set the X-Content-Type-Options response header to exactly `nosniff` (once, not duplicated) on every page and asset your store serves.
On Shopify
- Shopify's core storefront automatically sends `X-Content-Type-Options: nosniff` — if your scanner shows a duplicate or malformed value, the extra copy is almost certainly coming from a third-party app or a Cloudflare/CDN layer you've added.
- Check installed apps: Shopify Admin → Apps — look for any 'security headers' or 'HTTP headers' app and review its settings. Disable or remove any app that is independently setting this header.
- If you use Cloudflare in front of Shopify: Cloudflare Dashboard → your domain → Rules → Transform Rules → Modify Response Headers — delete any rule that sets `X-Content-Type-Options`, since Shopify already handles it.
- Verify the fix: open Chrome DevTools on your storefront, go to Network → select any page request → Headers, and confirm `X-Content-Type-Options: nosniff` appears exactly once.
X frame options weakQuick win
Change the X-Frame-Options response header from its current weak or missing value to either DENY or SAMEORIGIN so your store cannot be embedded in a malicious iframe.
On Shopify
- Shopify's core storefront already sends X-Frame-Options: DENY on most pages and you cannot alter server-level headers directly.
- For any custom Hydrogen (headless) or Oxygen-deployed storefront: open your server entry file (e.g. server.ts), find where you create the response or use a middleware, and add: response.headers.set('X-Frame-Options', 'DENY');
- For theme-level customisation you cannot set HTTP headers — if a scanner flags your Shopify store, confirm the header is already present using DevTools or securityheaders.com; if it is missing only on a specific embedded app or custom domain, contact that app's developer.
- Shopify Plus merchants using a custom domain behind Cloudflare: add a Transform Rule in Cloudflare dashboard → Rules → Transform Rules → Modify Response Header → add X-Frame-Options = DENY.
Site Lifecycle · 12 fixes
Cms versionModerate effort
Identify your ecommerce platform and CMS version, then ensure it is always kept up to date to protect your store from security vulnerabilities and avoid loss of vendor support.
On Shopify
- Shopify's core platform is SaaS and updated automatically — you do not manage core versions.
- Go to Shopify Admin → Online Store → Themes: check if your active theme has an 'Update available' banner and click 'Update theme' (save a backup first via 'Duplicate').
- Go to Shopify Admin → Apps: review all installed apps and ensure each is from an active, maintained developer — remove any apps that are no longer supported.
- Go to Shopify Admin → Settings → Plan to confirm your store is on an active plan with continued platform support.
Domain expiryQuick win
Enable auto-renew on your domain registration and set calendar reminders well before expiry to prevent accidental loss of your store's address.
On Shopify
- If your domain was purchased through Shopify: Go to Admin → Settings → Domains. Click the domain name. Shopify auto-renews Shopify-managed domains automatically; confirm the billing card under Settings → Billing is valid.
- If your domain is registered at a third-party registrar and only connected to Shopify: Log in directly to that registrar's website (e.g. GoDaddy, Namecheap) and follow the registrar-specific steps to enable auto-renew and verify payment details.
- To see the expiry date of a Shopify-managed domain, go to Admin → Settings → Domains and click the domain — expiry and renewal info are shown there.
Gtm auditModerate effort
Install Google Tag Manager on your store and configure GA4 with ecommerce event tracking (view_item, add_to_cart, purchase) so you can measure what's driving revenue.
On Shopify
- Install GTM via a trusted app such as 'GTM Kit' (free, Shopify App Store) — it injects both GTM snippets and pushes a GA4-compatible ecommerce dataLayer automatically.
- Alternatively, paste the GTM <head> snippet into Online Store → Themes → Edit Code → theme.liquid inside the <head> tag, and the <body> snippet immediately after the opening <body> tag.
- For native GA4 ecommerce events (view_item, add_to_cart, purchase), use the GTM Kit app's built-in dataLayer or install 'Elevar' / 'Analyzify' for fully managed server-side & browser-side event tracking.
- In GA4, connect via GTM as described in the generic steps. Do NOT also enable the Shopify 'Google & YouTube' channel GA4 integration at the same time — it will cause duplicate purchase events.
- Verify in GTM Preview and GA4 DebugView, then publish.
Html langQuick win
Add a correct `lang` attribute to your site's `<html>` tag so browsers, search engines, and assistive technologies know what language your store is written in.
On Shopify
- In your Shopify admin, go to Online Store › Themes.
- Next to your active theme, click Actions › Edit code.
- In the left-hand file list, open the Layout folder and click theme.liquid (this is the master template that wraps every page).
- Find the opening <html tag near the top of the file. It may already have attributes like class or dir.
- Add lang="en" (or your correct BCP 47 tag) inside it, e.g.: <html lang="en" class="no-js">
- Click Save. View your storefront, right-click › View Page Source, and confirm the <html> tag now shows the lang attribute.
Lifecycle oos schema not updatedModerate effort
Update the `offers.availability` field in your Product schema to `OutOfStock` (or `PreOrder`/`Discontinued`) whenever a product sells out, so Google's data matches your real inventory.
On Shopify
- Shopify's default themes (Dawn and most modern themes) generate Product schema automatically from the theme's Liquid code — they read the product's inventory to set availability dynamically.
- To verify your theme does this correctly, go to Online Store > Themes > your active theme > Edit code, then open 'snippets/product-schema.liquid' or search within 'sections/main-product.liquid' or 'templates/product.json' for 'availability' or 'InStock'.
- Find the Liquid logic that outputs availability. It should check 'product.available' (Shopify's built-in boolean). Correct code looks like: '"availability": "{{ product.available | json }}" ? "https://schema.org/InStock" : "https://schema.org/OutOfStock"'.
- If your theme hard-codes 'InStock' instead of using 'product.available', replace that hard-coded string with the conditional Liquid expression above and save.
- For a no-code fix, install a schema app such as 'JSON-LD for SEO' or 'Schema Plus for SEO' from the Shopify App Store — these apps generate dynamic availability from live inventory and override the theme's schema.
- Validate the fix on a sold-out product URL using Google's Rich Results Test (search.google.com/test/rich-results).
Lifecycle orphaned productsModerate effort
Add internal links from category pages, navigation, and related-product sections to every product page so crawlers and shoppers can find them without relying solely on your sitemap.
On Shopify
- Go to Products → All products and filter by 'Not in any collection' (use the 'Collection' filter and select 'No collection'). These are your prime orphan candidates.
- For each orphaned product, click into it and scroll to the 'Collections' section in the right-hand sidebar — assign it to one or more relevant collections.
- To surface products in navigation: go to Online Store → Navigation, edit your main menu, and ensure all collections containing the orphaned products are linked.
- For 'Related products' or 'You may also like' links: in Online Store → Themes → Customize, check whether your theme has a 'Related products' section on the product template. Enable it and configure it to pull from the same collection.
- For manual cross-links from blog posts: go to Online Store → Blog posts, edit a relevant post, and use the link tool to insert a hyperlink to the product URL.
- Install a free app like 'Frequently Bought Together' or 'Also Bought' to automate related-product links across all product pages at scale.
Lifecycle products missing from sitemapModerate effort
Add every canonical product URL to your XML sitemap so search engines can discover and index your products faster.
On Shopify
- Shopify auto-generates a sitemap at yourdomain.com/sitemap.xml that includes all published products — no setup required.
- If products are missing, the most common cause is that they are set to 'Draft' or have a URL redirect in place. Go to Products → the affected product → confirm its status is 'Active'.
- To verify and force a refresh, use the Shopify Search & Discovery app (free, by Shopify) or a third-party SEO app such as Yoast SEO for Shopify or SEO Manager — these apps surface sitemap details and let you control inclusion.
- Submit or resubmit yourdomain.com/sitemap.xml in Google Search Console → Sitemaps.
Lifecycle products too deepModerate effort
Reduce the number of clicks required to reach every product page to 4 or fewer from the homepage by flattening your site structure or surfacing buried products on shallower category pages.
On Shopify
- Online Store → Navigation: review your main menu structure. Each nested menu level adds a click, so limit nesting to one level deep (Collections, not Collections → Sub-collections → Sub-sub-collections).
- To surface buried products, go to Online Store → Navigation → main-menu and add direct links to deep product pages or their immediate parent collection.
- In your theme editor (Online Store → Themes → Customize), add a 'Featured Collection' or 'Product list' section to the homepage and point it at the collection that contains buried products.
- Use automated collections (Products → Collections → Create collection → Conditions) combined with tags to pull buried products into a shallower collection that is linked from the main navigation.
- Install a breadcrumb or mega-menu app (e.g. Qikify Mega Menu, Buddha Mega Menu) if your theme doesn't support multi-column navigation that exposes deeper products in one click.
- Verify: re-run a crawl or use Screaming Frog pointed at your store domain and check the 'Crawl Depth' column — no product should show depth > 4.
Mixed contentModerate effort
Audit every page, asset, and third-party embed on your store to ensure no HTTP resources are loaded on HTTPS pages, and fix any mixed-content violations before they silently break security warnings or block content in visitors' browsers.
On Shopify
- Shopify enforces HTTPS on all storefronts automatically, so the most common source of mixed content is hardcoded HTTP URLs in theme files or content.
- Go to Online Store → Themes → your active theme → Actions → Edit Code.
- Use the built-in search (the magnifying glass icon in the code editor) to search for 'http://' across all Liquid, CSS, and JS files. Update any found instances to 'https://'.
- Also check Online Store → Pages, Blog Posts, and product/collection descriptions — open each rich-text editor and look for embedded images or media inserted with HTTP URLs; update them to HTTPS.
- For third-party scripts added via Online Store → Themes → Edit Code → theme.liquid or layout files, ensure each <script src='...'> and <link href='...'> uses https://.
- To add the CSP upgrade-insecure-requests meta tag as a safety net, add <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"> inside the <head> tag in your theme.liquid file.
- Save and preview your store; open browser DevTools (F12 → Console) to confirm no mixed-content warnings remain.
Mobile viewportQuick win
Confirm your store has a correct responsive viewport meta tag so it displays properly on phones and tablets.
On Shopify
- Go to Online Store → Themes in your Shopify Admin.
- Click the '...' (Actions) button next to your active theme and select 'Edit code'.
- In the Layout folder on the left, click 'theme.liquid'.
- Search (Ctrl+F / Cmd+F) for 'viewport'. Most Shopify themes already include the correct tag inside the <head> section.
- If missing, add <meta name="viewport" content="width=device-width, initial-scale=1"> on a new line directly after the opening <head> tag.
- If it exists but has 'user-scalable=no' or 'maximum-scale=1', remove those values so only 'width=device-width, initial-scale=1' remains.
- Click 'Save'. Preview on a mobile device or use Google's Mobile-Friendly Test to verify.
Server versionModerate effort
Remove or suppress the Server version header so your web server software and version number are no longer exposed in every HTTP response.
On Shopify
- Shopify is a fully hosted SaaS platform — you do not have access to the underlying web server configuration files.
- Shopify manages all server headers centrally. The `Server` header on Shopify storefronts is already genericised (it does not expose a version number); no action is needed or possible from the theme or admin.
- If a scanner flags a version header on a Shopify store, confirm the request is hitting your Shopify domain (*.myshopify.com or your custom domain pointed to Shopify) and not a third-party app proxy or custom server you separately manage.
- For any custom storefronts built with the Shopify Storefront API hosted on your own server, apply the server-level fix appropriate for that server (Nginx, Apache, etc.) as described in the generic steps above.
Ssl expiryQuick win
Monitor your SSL/TLS certificate expiry date and set up auto-renewal so your store never goes offline or shows a security warning to shoppers.
On Shopify
- Shopify automatically provisions and renews a free SSL certificate for every custom domain connected to your store — no manual action is required.
- To confirm it is active: Admin → Settings → Domains → click your primary domain → look for 'SSL certificate — Pending' or 'SSL certificate — Active'.
- If a domain shows 'SSL unavailable', remove the domain and re-add it (Admin → Settings → Domains → Remove, then Add existing domain) to trigger re-provisioning.
- Ensure your DNS records (the CNAME and A records) point correctly to Shopify servers, as misconfigured DNS is the most common cause of SSL provisioning failure.
Generative Engine Optimization · 9 fixes
Ai crawler blockedQuick win
Your robots.txt explicitly blocks one or more AI assistants from crawling your store, so those engines can't discover, index, or cite your products when shoppers ask for recommendations.
On Shopify
- From Shopify admin go to Online Store > Themes > (the three-dot menu on your live theme) > Edit code.
- Under the 'templates' folder click 'Add a new template' and choose 'robots.txt' (this creates robots.txt.liquid).
- Shopify's default template loops over rules; to allow an AI bot remove any block that adds 'Disallow: /' for it, or append an explicit allow group such as 'User-agent: GPTBot' then 'Allow: /'.
- Save. Visit https://yourstore.com/robots.txt and confirm the bot no longer has 'Disallow: /'.
Ai crawler not specifiedQuick win
Your robots.txt doesn't explicitly allow several AI crawlers. They aren't blocked, but a number of AI engines act on explicit permission, so naming them removes any ambiguity.
On Shopify
- From Shopify admin go to Online Store > Themes > (the three-dot menu on your live theme) > Edit code.
- Under the 'templates' folder click 'Add a new template' and choose 'robots.txt' (this creates robots.txt.liquid).
- Shopify's default template loops over rules; to allow an AI bot remove any block that adds 'Disallow: /' for it, or append an explicit allow group such as 'User-agent: GPTBot' then 'Allow: /'.
- Save. Visit https://yourstore.com/robots.txt and confirm the bot no longer has 'Disallow: /'.
Geo brand name inconsistentModerate effort
Your brand name appears in multiple different formats across your site (schema, og:site_name, footer, logo). AI engines may treat the variants as separate entities.
On Shopify
- Edit your theme (Online Store > Themes > Edit code). Product schema usually lives in 'sections/main-product.liquid' or a JSON-LD snippet; Organization schema in 'theme.liquid' / a global snippet.
- Add the missing properties using Liquid variables ({{ product.title }}, {{ product.price | money_without_currency }}, {{ product.featured_image | image_url }}, {{ shop.name }}).
- Or install a structured-data app (Schema Plus, JSON-LD for SEO) that fills required Product/Organization fields automatically.
- Validate the page in Google's Rich Results Test.
Geo eeat trust signals weakModerate effort
Your store is missing trust signals (E-E-A-T) that AI engines and shoppers look for before recommending a store: clear policies, real contact details, and a credible business identity.
On Shopify
- Edit your theme (Online Store > Themes > Edit code). Product schema usually lives in 'sections/main-product.liquid' or a JSON-LD snippet; Organization schema in 'theme.liquid' / a global snippet.
- Add the missing properties using Liquid variables ({{ product.title }}, {{ product.price | money_without_currency }}, {{ product.featured_image | image_url }}, {{ shop.name }}).
- Or install a structured-data app (Schema Plus, JSON-LD for SEO) that fills required Product/Organization fields automatically.
- Validate the page in Google's Rich Results Test.
Geo faqpage missing productsModerate effort
Your product pages don't use FAQPage schema, so AI assistants can't pull direct answers to common buyer questions (sizing, materials, shipping) about your products.
On Shopify
- Edit your theme (Online Store > Themes > Edit code). Product schema usually lives in 'sections/main-product.liquid' or a JSON-LD snippet; Organization schema in 'theme.liquid' / a global snippet.
- Add the missing properties using Liquid variables ({{ product.title }}, {{ product.price | money_without_currency }}, {{ product.featured_image | image_url }}, {{ shop.name }}).
- Or install a structured-data app (Schema Plus, JSON-LD for SEO) that fills required Product/Organization fields automatically.
- Validate the page in Google's Rich Results Test.
Geo price not crawlableModerate effort
Your product prices appear to be rendered by JavaScript and may not be present in the static HTML, so AI crawlers (which often don't run JS) can't read or cite them.
On Shopify
- Edit your theme (Online Store > Themes > Edit code). Product schema usually lives in 'sections/main-product.liquid' or a JSON-LD snippet; Organization schema in 'theme.liquid' / a global snippet.
- Add the missing properties using Liquid variables ({{ product.title }}, {{ product.price | money_without_currency }}, {{ product.featured_image | image_url }}, {{ shop.name }}).
- Or install a structured-data app (Schema Plus, JSON-LD for SEO) that fills required Product/Organization fields automatically.
- Validate the page in Google's Rich Results Test.
Geo schema org missing sameasModerate effort
Your Organization schema has no sameAs links to your social profiles, Wikipedia, or other authoritative sources - so AI engines can't confidently connect the dots about your brand.
On Shopify
- Edit your theme (Online Store > Themes > Edit code). Product schema usually lives in 'sections/main-product.liquid' or a JSON-LD snippet; Organization schema in 'theme.liquid' / a global snippet.
- Add the missing properties using Liquid variables ({{ product.title }}, {{ product.price | money_without_currency }}, {{ product.featured_image | image_url }}, {{ shop.name }}).
- Or install a structured-data app (Schema Plus, JSON-LD for SEO) that fills required Product/Organization fields automatically.
- Validate the page in Google's Rich Results Test.
Geo schema product incompleteModerate effort
Your Product structured data is missing fields AI engines rely on to cite your products accurately (price, availability, currency, brand, ratings).
On Shopify
- Edit your theme (Online Store > Themes > Edit code). Product schema usually lives in 'sections/main-product.liquid' or a JSON-LD snippet; Organization schema in 'theme.liquid' / a global snippet.
- Add the missing properties using Liquid variables ({{ product.title }}, {{ product.price | money_without_currency }}, {{ product.featured_image | image_url }}, {{ shop.name }}).
- Or install a structured-data app (Schema Plus, JSON-LD for SEO) that fills required Product/Organization fields automatically.
- Validate the page in Google's Rich Results Test.
Llms txt missingQuick win
Your store has no llms.txt - the emerging standard (like robots.txt, but for AI) that tells language models which content to read and cite. SEOLZ has generated a ready-to-upload file from your own pages.
On Shopify
- In Shopify a file at the domain root needs a small workaround: create the content in admin under Content > Files (upload a .txt), then add a redirect/route, OR use a theme app/proxy that serves /llms.txt.
- Simplest reliable route: use an app such as 'Easy Robots.txt' style file managers, or host llms.txt via a Shopify app proxy that maps /llms.txt to your generated content.
- Paste the generated llms.txt content (SEOLZ pre-filled it from your store).
- Verify at https://yourstore.com/llms.txt.