Every Shopify Plus fix we catalog
SEOLZ catalogs 74 fixes for Shopify Plus across 5 areas — SEO, answer-engine readiness, accessibility, security and site-health. Each lists the exact steps for Shopify Plus, with a link to the official docs.
SEO · 20 fixes
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 Plus
- All standard Shopify steps above apply. Additionally, use Shopify Scripts or Launchpad to ensure promotional banners and flash-sale bars are pre-rendered in theme sections rather than injected via client-side JavaScript.
- For checkout extensions: in the Shopify Plus Checkout Editor, all blocks are rendered server-side with reserved space — avoid injecting custom checkout content via external scripts that fire after load.
- Use Shopify's CDN image transformations ({{ image | image_url: width: 800 }}) and always pair with width/height attributes in Liquid to prevent CLS on checkout and account pages.
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 Plus
- Follow all standard Shopify steps above — Shopify Plus uses the same Liquid/theme architecture.
- Additionally, use Shopify Plus's Script Editor (or Shopify Functions) to review checkout scripts — remove or defer any non-critical checkout JS that may be loaded site-wide via theme.liquid.
- Use the Shopify Plus Organization Admin to push the optimized theme across multiple stores simultaneously if the same hero template is used across storefronts.
- Engage Shopify Plus's Launch Engineer or a Shopify Expert for server-side rendering (Hydrogen/Oxygen) migration if LCP cannot be brought under 2.5s through theme-level changes alone.
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 Plus
- Same as Shopify above, but you also have access to Shopify Scripts and more advanced theme customization.
- In Online Store → Themes → Edit Code → `layout/theme.liquid`, confirm the canonical tag outputs `{{ collection.url | prepend: shop.url }}` (stripping query strings) for all collection/filter pages.
- For enterprise-level filter apps (e.g., Searchanise, Klevu), check their admin under SEO Settings to enforce canonical-to-base-collection behavior.
- Use Shopify Plus's Launchpad or custom metafields to designate specific filter combinations (e.g., brand pages) that SHOULD have their own canonical — and configure those as standalone pages or alternate collection handles instead.
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 Plus
- Same steps as Shopify (above) — all standard admin alt text fields are available.
- ADDITIONALLY: Use the Shopify Admin REST or GraphQL API (productImageUpdate mutation, field: altText) to bulk-update alt text programmatically across large catalogs, which is especially useful for Plus merchants with thousands of SKUs.
- Shopify Plus merchants can also use Shopify Flow to trigger alt-text audits or Launchpad for scheduled content deployments.
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 Plus
- All steps are identical to standard Shopify (see above).
- For large-scale updates across thousands of SKUs, use the Shopify Admin REST API (products endpoint, 'metafields' or direct 'body_html'/'seo_description') or a trusted app such as Yoast SEO for Shopify or SEO Manager to bulk-edit meta descriptions via CSV upload.
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 Plus
- Same paths as Shopify above; additionally, use the Shopify Plus 'Metafields' feature or the Storefront API to programmatically set meta descriptions across large catalogues.
- For automated, template-driven descriptions on thousands of SKUs, install an app such as 'Smart SEO' or 'SEO Manager' from the Shopify App Store and configure description templates per product type.
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 Plus
- Follow the same steps as standard Shopify above.
- For headless or custom storefronts built on the Storefront API, ensure your frontend framework outputs the og:image meta tag in the <head> for each page, pulling the image URL from the Storefront API's product/collection/article image fields.
- Use Shopify Scripts or theme customizations in the Shopify Plus admin to apply global og:image logic consistently across all templates.
Missing titleQuick win
Add a unique, descriptive title tag (30–60 characters) to every page that is missing one.
On Shopify Plus
- Same admin workflow as Shopify — go to the relevant section (Products, Collections, Pages, or Online Store → Preferences) → 'Search engine listing' → 'Edit' → fill in 'Page title'.
- For bulk updates across many products, use the Shopify Plus bulk editor: Products → select multiple products → Edit products → add the 'SEO Title' column.
- Alternatively, export your product CSV (Products → Export), fill in the 'SEO Title' column in a spreadsheet, and re-import.
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 Plus
- Same as Shopify: go to Online Store → Themes → Edit code.
- In addition, check any Shopify Scripts or custom storefront (Hydrogen/Headless) implementations — in Hydrogen (React), search your component files for '<h1' and ensure only the primary content component renders it.
- For Launchpad or custom scripts that inject content: review any injected HTML for accidental H1 tags.
- Use Shopify's Theme Inspector (browser extension) to trace which Liquid section/snippet renders each H1 on a given page.
- Fix in section/snippet files and save; verify on live storefront with DevTools.
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 Plus
- Follow the same steps as Shopify above — Shopify Plus gives you identical theme-file access plus the robots.txt.liquid file is always editable.
- If you manage multiple storefronts, apply the change to each theme individually.
- Use the Shopify Plus Script Editor or custom app if you need to programmatically suppress noindex on specific search contexts (e.g. staff previews).
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 Plus
- Follow identical steps to standard Shopify (Products → Collections → select collection → Description field).
- If you use a custom storefront (Hydrogen/Headless), ensure your frontend template renders the collection.description field from the Storefront API — a developer may need to add this to the component that displays the collection page.
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 Plus
- Same path as Shopify: Admin → Products → select product → Description editor.
- Shopify Plus merchants with custom storefronts (Hydrogen/Headless) must also ensure the description field is rendered in the page template and is present in the server-side HTML — verify with View Source that text appears outside any JS bundle.
- Use Shopify Flow or a bulk-edit app (e.g. Metafields Guru, Bulk Product Edit) to scale updates across large catalogs efficiently.
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 Plus
- Follow the same steps as Shopify above.
- For large catalogs, use the Shopify Admin REST API (PUT /admin/api/products/{id}/images/{image_id}.json) to programmatically update the 'alt' field via a custom script or a Shopify Plus automation workflow.
- Alternatively, use a bulk-edit app such as 'Bulk Image Edit – Image SEO' (Hextom) available in the Shopify App Store.
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 Plus
- Follow all standard Shopify steps above — the Barcode field and theme code access are identical.
- For bulk GTIN updates across a large catalog, use the Shopify bulk product import/export CSV (Products → Export → All products) to populate the 'Variant Barcode' column, then re-import.
- Enterprise stores can also push GTINs via the Shopify Admin API (products endpoint, 'barcode' field on each variant) as part of a PIM integration.
- Verify the schema output using Google's Rich Results Test after the bulk update.
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 Plus
- Follow all the same steps as Shopify above; Shopify Plus uses the same theme architecture.
- If you use a custom storefront (Hydrogen/Headless), update the Product component to include JSON-LD with dynamic availability from the Storefront API's `availableForSale` field.
- For scripts applied store-wide, use Shopify Plus Scripts or Theme App Extensions rather than editing checkout.liquid directly.
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 Plus
- Follow the same steps as Shopify above; Shopify Plus gives you access to the Shopify Admin API and Bulk Operations GraphQL API for programmatic metafield population across large catalogs.
- Use Shopify Flow to automate metafield creation from product data or third-party PIM imports.
- Consider a PIM integration (e.g., Akeneo, inRiver) to manage spec data centrally and sync to Shopify metafields via API.
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 Plus
- Same workflow as Shopify: Admin → Products → select the product → 'Media' section → 'Add media'.
- For bulk image updates across many products, use the Shopify Bulk Editor (Admin → Products → select multiple → 'Edit products') or a CSV import via Admin → Products → 'Import' with an updated media column.
- Enterprise stores can also use the Shopify Admin API (POST /products/{id}/images) to programmatically upload images at scale.
- Add alt text to each image via the media thumbnail edit panel and save.
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 Plus
- Follow the same steps as Shopify above.
- For store-wide or programmatic title changes, use the Shopify Admin API (products endpoint, 'metafields' or direct 'title' field) or a third-party SEO app such as Plug In SEO or Smart SEO to manage title templates at scale.
- In the theme's product.liquid (or product JSON template), you can also set a title template — e.g. {{ product.title }} - {{ product.type }} | {{ shop.name }} — using Liquid in Online Store → Themes → Edit code → Sections/templates/product.liquid.
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 Plus
- Follow the same steps as Shopify above — Shopify Plus uses identical theme architecture.
- If you use a custom storefront (Hydrogen/Remix), add the canonical <link> server-side in your product route's loader, outputting the base product URL (without searchParams) inside the <head> component for every variant route.
- For headless setups, ensure your meta component or document HEAD template outputs <link rel="canonical" href={productBaseUrl}> where productBaseUrl strips all query/variant parameters.
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 Plus
- All steps from Shopify apply. Additionally, use Shopify Scripts or custom theme templates in the Theme Code editor to inject dynamic content blocks (e.g. size guides, brand stories) into product or collection templates at scale.
- For large catalogs, consider a metafield strategy: Admin → Products → [product] → Metafields section (bottom of page) — create a 'Long description' metafield and surface it in the theme template via Liquid.
Answer Engine Optimization · 6 fixes
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 Plus
- Follow the same steps as Shopify above.
- For enterprise stores using a custom storefront (Hydrogen/Headless), locate the JSON-LD component in your React/Next.js codebase and apply the same ratingValue bounds fix there.
- If using a third-party review platform (Yotpo, Okendo, etc.) at scale, coordinate with the platform's enterprise support to ensure schema output is valid before re-deploying.
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 Plus
- Follow the same steps as standard Shopify (edit article.liquid or use a structured data app).
- Shopify Plus merchants with a custom storefront or Hydrogen (headless) build should add Article and BreadcrumbList JSON-LD in the React/Next.js component that renders article pages — inject via a <script type='application/ld+json'> tag inside the page's <Head> component, populating values from the Storefront API response (article.title, article.author.name, article.publishedAt).
- Use the Shopify Storefront API fields: articles query returns title, authorV2.name, publishedAt, updatedAt, image.url — map these directly to your JSON-LD template.
- Validate with Google's Rich Results Test after deployment.
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 Plus
- Same as Shopify — use Edit Code on the relevant theme. Shopify Plus merchants can additionally use Shopify Scripts or a Storefront API-powered headless layer to inject JSON-LD programmatically.
- For organisation-wide rollout, add the JSON-LD injection to the <head> section of theme.liquid inside a Liquid conditional targeting the page handle (e.g. {% if page.handle contains 'how-to' %}).
- Use a structured data management app from the Shopify App Store for a no-code approach.
- 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 Plus
- Same as Shopify: Online Store → Themes → Edit code → theme.liquid, paste before </head>.
- On Shopify Plus you can also deploy the script tag globally via the Shopify Scripts editor or a custom Storefront API integration if you manage headless storefronts.
- Enterprise teams often use the 'JSON-LD for SEO' app which supports multi-location and organisation schema with a GUI.
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 Plus
- From your Shopify Plus Admin, go to Online Store → Themes.
- Click 'Actions' → 'Edit code' on your live theme.
- Open 'theme.liquid' in the Layout folder.
- Paste your <script type='application/ld+json'>…</script> block just before the closing </head> tag.
- Click 'Save'. For storefronts using Hydrogen/Headless, add the JSON-LD script inside the root layout component's <head> section.
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 Plus
- Same code path as Shopify above: Online Store → Themes → Edit code → product template file.
- On Shopify Plus you can also use Checkout Extensibility or Scripts for checkout-side data, but Product schema belongs in the storefront theme template as above.
- If your store uses a headless/custom storefront, add the JSON-LD block inside the <head> of your product page component, populating values from the Storefront API response.
- Validate with Google's Rich Results Test after deploying.
Accessibility (WCAG) · 22 fixes
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 Plus
- Follow the same theme-code editing steps as Shopify above.
- For headless or custom storefronts built on Hydrogen/Remix: open your component files in your code editor, locate the JSX element with the invalid role prop, remove or correct it, then redeploy via your CI/CD pipeline.
- Verify the fix on your staging environment before pushing to production.
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 Plus
- Follow the same Liquid code-editing steps as Shopify above; Shopify Plus gives you the same theme code editor plus access to checkout.liquid.
- For unlabelled elements specifically inside the checkout (e.g. remove-item buttons), edit checkout.liquid (available only on Shopify Plus) and add the appropriate aria-label attributes.
- Use Shopify's Accessibility app or a third-party accessibility overlay audit to surface remaining issues after editing.
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 Plus
- Shopify Plus uses the same theme-editing flow as standard Shopify.
- Go to Online Store → Themes → Edit code, then locate your dialog/modal/cart-drawer Liquid snippets (e.g. snippets/cart-drawer.liquid, snippets/modal.liquid).
- If you use a custom storefront or headless build via Shopify Storefront API, edit the React/Vue/Svelte component that renders the modal and add aria-labelledby or aria-label to the outermost dialog element.
- For third-party apps that inject dialogs (e.g. upsell popups), contact the app developer or use a custom Script Tag / Theme App Extension to patch the ARIA attributes after the element is inserted into the DOM.
- Verify with axe DevTools or a screen reader after each change.
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 Plus
- Same as Shopify above; additionally check any custom scripts injected via Shopify Scripts or checkout extensibility (Checkout UI Extensions) — aria-hidden conflicts can appear in custom checkout components.
- Review checkout.liquid (if on legacy checkout) for `aria-hidden` on any wrapper that contains form fields.
- Use the axe DevTools extension on the checkout flow specifically, as Shopify Plus merchants often have custom checkout markup.
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 Plus
- Follow all standard Shopify steps above; Shopify Plus also allows editing checkout.liquid (under Online Store → Themes → Edit code → Layout/checkout.liquid) for checkout-specific input fields.
- For custom checkout fields in the Checkout editor (Shopify Plus only), go to Settings → Checkout → Customize and use the drag-and-drop UI — for custom code blocks, add aria-label attributes directly in the custom HTML/Liquid blocks.
- If using Hydrogen (headless), edit the React component responsible for the input field and add an aria-label prop or a <label> element in your component JSX.
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 Plus
- Follow the same steps as Shopify above. Shopify Plus merchants using custom storefronts (Hydrogen/Remix) should fix the issue in the React component file that renders the affected element.
- In Hydrogen, locate the component (e.g. Navigation.tsx, ProductGrid.tsx) and replace ARIA role combinations with semantic HTML or correctly paired role/child-role attributes.
- Deploy via your standard CI/CD pipeline and verify with axe DevTools.
Button nameModerate effort
Add a visible or programmatically accessible name to every button so screen readers can announce what it does.
On Shopify Plus
- Same as Shopify above; additionally check any custom checkout.liquid (available on Plus) for unnamed icon buttons in the checkout header or upsell sections.
- For headless / Hydrogen storefronts, locate the relevant .jsx/.tsx component (e.g. CartIcon.jsx) and add aria-label to the <button> element in JSX.
Document titleQuick win
Add a unique, descriptive <title> element to every page so browsers, screen readers, and search engines can identify it.
On Shopify Plus
- Follow all the same steps as Shopify above.
- For the checkout page (exclusive to Plus): Online Store → Themes → Actions → Edit code → 'layout/checkout.liquid' → ensure a <title> tag is present and uses a dynamic value such as {{ page_title }}.
- Use Shopify's Bulk Editor or a SEO app (e.g. Plug In SEO, SEO Manager) to audit and fill missing title fields across hundreds of products at once.
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 Plus
- Follow all standard Shopify steps above.
- For checkout customisation, go to Settings → Checkout → Customise and check heading blocks inside checkout sections for empty content.
- In Launchpad or custom scripts, search for dynamically injected heading tags that may render empty based on logic conditions — add a fallback text string or conditional rendering guard.
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 Plus
- Follow all standard Shopify steps above.
- If using a custom checkout or headless storefront (Hydrogen/Remix), open the relevant React component files and audit JSX heading tags (h1–h6) to ensure sequential order, then redeploy.
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 Plus
- Follow the same steps as Shopify above — edit `theme.liquid` under Online Store → Themes → Actions → Edit code.
- If you use Shopify Markets for multi-language storefronts, the Liquid variable `{{ request.locale.iso_code }}` automatically outputs the correct BCP 47 locale code per market, so use `<html lang="{{ request.locale.iso_code }}">` to cover all markets dynamically.
- Click Save and verify via View Source on each market's storefront URL.
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 Plus
- Follow the same steps as Shopify above — Shopify Plus themes use the same `theme.liquid` layout file.
- If you use a custom Hydrogen/headless storefront, open your root layout component (e.g. `app/root.jsx` or `app/root.tsx`) and ensure the `<html>` element has `lang={locale}` where `locale` is derived from the Shopify Storefront API locale.
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 Plus
- Shopify Plus stores use the same theme code structure. Access Online Store → Themes → Actions → Edit code.
- For checkout-specific fields (checkout.liquid is available on Plus only): go to Online Store → Themes → Actions → Edit code → `layout/checkout.liquid` and inspect any custom input fields for missing `<label>` elements.
- Apply the same label/aria-label fix described in the Shopify steps above, paying particular attention to custom checkout upsell or gift-message input fields added via scripts.
- Use Shopify's Theme Inspector or a browser accessibility tool (axe DevTools extension) to verify after saving.
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 Plus
- Follow the same steps as Shopify above — edit `layout/theme.liquid` via Online Store → Themes → Edit code.
- On Shopify Plus, if you use custom checkout pages, also check `layout/checkout.liquid` and apply the same structural fix if a footer/contentinfo landmark exists there.
- Use the Shopify Theme Inspector or axe DevTools browser extension to verify after saving.
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 Plus
- Follow the same steps as Shopify above. On Shopify Plus, also check any custom checkout.liquid (Checkout › Branding, or the legacy checkout.liquid file) for a duplicate '<main>' or 'role="main"'.
- If using Hydrogen (headless), locate the root layout component (typically 'app/root.tsx' or 'app/routes/_index.tsx') and ensure only one '<main>' is rendered in the component tree.
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 Plus
- Same as Shopify above; additionally audit any custom checkout scripts in Settings → Checkout → Additional scripts and any Launchpad or Script Editor customisations that inject links.
- For headless storefronts using the Storefront API, fix aria-label and alt attributes in your front-end component files (React/Vue/etc.) in your repository and redeploy.
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 Plus
- Same as Shopify: Online Store → Themes → Actions → Edit code → Layout/theme.liquid.
- If you use a custom checkout, also check `checkout.liquid` (Shopify Plus only) for a second viewport meta tag and apply the same fix.
- Save both files and test zoom on storefront and checkout pages.
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 Plus
- Same as Shopify: Admin → Online Store → Themes → Actions → Edit code → Layout/theme.liquid.
- If your store uses a custom storefront (Hydrogen/Headless), locate the root HTML shell component (e.g. root.tsx or _document.tsx) in your repo and apply the same edit there.
- Redeploy via your CI/CD pipeline or Shopify CLI after saving.
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 Plus
- Follow all standard Shopify steps above; Shopify Plus stores use the same Liquid theme architecture.
- For headless or custom storefronts built on the Storefront API, audit each React/Vue component that renders a page title and ensure the outermost title element is an `<h1>`.
- For checkout extensibility (checkout.liquid or checkout UI extensions), add an `<h1>` to any custom checkout page templates where one is missing.
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 Plus
- Follow identical steps to Shopify above. On Shopify Plus you can also edit checkout.liquid (available to Plus merchants): go to Online Store → Themes → Edit code → layout/checkout.liquid to label any custom checkout dropdowns.
- For headless/custom storefronts using the Storefront API, edit the React/Vue component that renders the <select> and add a <label htmlFor="..."> or aria-label prop.
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 Plus
- Follow the same steps as Shopify above — Shopify Plus uses the same theme architecture.
- If you use a custom Hydrogen/Oxygen storefront, edit the root Layout component (app/components/Layout.tsx or Layout.jsx): add `<a href='#main-content' className='skip-link'>Skip to main content</a>` as the first child of <body>, and add `id='main-content' tabindex={-1}` to the <main> element.
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 Plus
- Follow the same steps as Shopify above — `layout/theme.liquid` is the key file.
- For headless or custom storefronts using the Storefront API, ensure the HTML document root rendered by your front-end framework includes `<html lang="[valid-BCP47-code]">`, matching the locale returned by the API.
- If you use Shopify's Translate & Adapt app for multi-language stores, confirm each published locale has a valid ISO code in Settings → Languages.
Security (OWASP) · 17 fixes
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 Plus
- Shopify Plus storefronts served directly through Shopify's infrastructure inherit the same automatic HSTS settings as standard Shopify.
- For headless/custom-domain setups routed through Cloudflare or another CDN, configure HSTS in that CDN layer: Cloudflare → your domain → SSL/TLS → Edge Certificates → enable 'HTTP Strict Transport Security (HSTS)' and set max-age to 12 months with 'Include subdomains' ON.
- Verify the deployed header via browser DevTools (F12) → Network → click any page request → Response Headers → confirm Strict-Transport-Security is present with max-age ≥ 31536000.
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 Plus
- SSL certificate provisioning is identical to standard Shopify — fully automatic.
- Go to Admin → Online Store → Domains and confirm 'SSL certificate active' for every custom domain, including any expansion stores.
- Enable 'Redirect all traffic to this domain' on the primary domain to enforce HTTPS site-wide.
- For headless or custom storefronts using the Storefront API, ensure your CDN/edge layer (e.g. Cloudflare, Fastly) is configured with a valid certificate and HTTPS-only routing.
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 Plus
- Same as Shopify — the underlying server infrastructure is fully managed by Shopify and cannot be changed by merchants.
- For enterprise setups with a custom reverse proxy or WAF in front of your Shopify Plus storefront, configure that proxy layer to strip or overwrite the upstream `Server` header before it reaches end users.
- If using Cloudflare (common for Plus): Cloudflare dashboard → your domain → Rules → Transform Rules → Modify Response Header → add a Remove rule for the `Server` header.
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 Plus
- Same as Shopify above. Shopify Plus merchants with custom Hydrogen storefronts on Oxygen should remove the header in their server middleware as described.
- If using a custom external front-end (e.g., Next.js on Vercel), apply the fix at the Next.js/Vercel layer — add `{ key: 'X-Powered-By', value: '' }` removal in next.config.js headers config, or use Vercel's Headers settings in the project dashboard under Settings → Headers.
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 Plus
- Same as Shopify above, with the added option of a custom domain checkout.
- For Hydrogen/Oxygen headless storefronts, open `server.ts` in your project root, locate the `fetch` handler, and inject the header: `response.headers.set('Content-Security-Policy', "default-src 'self'; script-src 'self' cdn.shopify.com; object-src 'none'");`
- Deploy via Oxygen (Shopify's edge hosting) and verify headers using browser DevTools → Network tab → select any page response → Headers.
Missing dmarcQuick win
Add a DMARC DNS TXT record at _dmarc.yourdomain.com to protect your domain from email spoofing and phishing.
On Shopify Plus
- Same DNS process as Shopify above — DMARC is a DNS-level record independent of Shopify Plus features.
- Shopify Plus merchants often use custom transactional email platforms (Klaviyo, Bronto, etc.): before enforcing DMARC, check each sending platform's documentation to ensure SPF and DKIM are configured for your domain in that platform.
- If you use Shopify's built-in email (Shopify Email): authenticate your sender domain under Settings → Email Marketing → Sender Domain and follow the SPF/DKIM setup steps so Shopify Email passes DMARC alignment before you set p=reject.
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 Plus
- Shopify Plus merchants have access to Cloudflare as part of their infrastructure — use Cloudflare Transform Rules to add the Permissions-Policy header (see generic Cloudflare steps: Transform Rules → Modify Response Headers → Add header name 'Permissions-Policy' with your policy value).
- Alternatively, use a Shopify app from the App Store that manages security response headers.
- In the Admin: Online Store → Themes → Actions → Edit Code → layout/theme.liquid — add the meta http-equiv fallback in <head> as a supplementary measure.
- Verify with Chrome DevTools → Network → Response Headers.
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 Plus
- Use a Cloudflare (or similar CDN/WAF) HTTP Response Header Transform Rule to add `Referrer-Policy: strict-origin-when-cross-origin` to every response — this is the only way to set a true HTTP header on Shopify Plus storefronts.
- In Cloudflare: Rules → Transform Rules → Modify Response Header → Add Header → Name: `Referrer-Policy`, Value: `strict-origin-when-cross-origin`, apply to hostname matches your store domain.
- As a belt-and-suspenders measure, also add the `<meta>` tag to `layout/theme.liquid` as described for standard Shopify above.
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 Plus
- Follow the same steps as Shopify above — DNS management location and Shopify-managed vs. external DNS apply identically to Plus merchants.
- Shopify Plus merchants using custom transactional email routing (e.g. via SendGrid or Postmark configured in the Plus admin) must also add the include: directive for that provider.
- For enterprise setups with a dedicated IP, confirm the exact SPF include string with your email delivery provider and add it to the record.
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 Plus
- Same as Shopify above — HSTS is managed at the infrastructure level.
- For Plus stores using Shopify's custom checkout domain or headless storefronts behind a custom CDN/proxy, configure the HSTS header in your CDN or load balancer (e.g., Cloudflare, Fastly, AWS CloudFront) as a custom response header rule.
- In Cloudflare: Security → Settings → enable HSTS, or Rules → Transform Rules → Response Header Modification → add header `Strict-Transport-Security` with value `max-age=31536000; includeSubDomains`.
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 Plus
- Same as Shopify above — the platform injects this header by default on storefront responses.
- For custom checkout extensibility or a headless storefront, ensure your middleware/server code sets res.setHeader('X-Content-Type-Options', 'nosniff') on all responses.
- Use Shopify Plus's Launchpad or a custom app with a web-pixel to audit headers regularly.
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 Plus
- Same as Shopify — the platform sets this header by default.
- If your Shopify Plus store is routed through a custom reverse proxy or CDN (Cloudflare, Fastly, Akamai), confirm the header is not being stripped at that layer.
- In Cloudflare: Rules → Transform Rules → Response Header Modification → Add X-Frame-Options: SAMEORIGIN for all hostname matches.
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 Plus
- Identical to standard Shopify — SSL is automatically managed by the platform.
- Go to Shopify Admin → Settings → Domains and confirm each domain shows 'SSL certificate: Active'.
- For enterprise domains with custom DNS setups (e.g. Cloudflare proxying), ensure the Cloudflare SSL mode is set to 'Full (strict)' and DNS records point to Shopify's IPs to avoid certificate conflicts.
- Contact your Shopify Plus Merchant Success Manager if you need a dedicated/custom certificate.
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 Plus
- Same automatic provisioning as Shopify applies. Go to Admin → Settings → Domains and verify SSL status.
- Shopify Plus merchants using Shopify's CDN follow the same DNS + re-add-domain steps as standard Shopify.
- If you use a third-party CDN (e.g. Fastly or Cloudflare) in front of your Shopify Plus store, the certificate must be installed at the CDN layer. Log in to your CDN dashboard and upload or provision a certificate that covers your storefront domain, then ensure your CDN's origin is set to your myshopify.com address.
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 Plus
- The process is identical to standard Shopify — SSL is managed automatically by the platform.
- Go to: Shopify Admin → Settings → Domains and verify DNS records match Shopify's required values.
- For expansion stores or custom checkout domains, ensure each domain/subdomain is added individually under Settings → Domains and has correct DNS pointing to Shopify.
- Shopify Plus merchants with a dedicated Merchant Success Manager can escalate SSL provisioning issues directly to that contact.
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 Plus
- Same as Shopify above; Shopify Plus merchants also have access to a dedicated Merchant Success Manager who can escalate SSL/port issues to Shopify infrastructure teams faster.
- For headless/custom storefronts on your own servers, ensure your server's firewall opens port 443 and your web server is configured with a valid TLS certificate (see generic steps).
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 Plus
- Same as Shopify above. Shopify Plus merchants should additionally check any custom Cloudflare Enterprise rules or edge middleware configured by their agency.
- Shopify Admin → Apps — audit all installed apps for header-manipulation behaviour.
- Cloudflare Dashboard → Rules → Transform Rules → Modify Response Headers — ensure no duplicate rule exists for `X-Content-Type-Options`.
- Use a staging/development store to verify headers before pushing changes to production.
Site Lifecycle · 9 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 Plus
- Core platform updates are managed by Shopify automatically.
- In your Shopify Plus admin, go to Online Store → Themes and apply any available theme updates after duplicating as a backup.
- Review all installed apps and custom channel integrations for version currency — contact your Shopify Plus Partner or Solutions Engineer for custom storefront (Hydrogen/Oxygen) version reviews.
- Check your Shopify Scripts and Checkout UI extensions for compatibility with the latest Shopify Checkout version.
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 Plus
- Same as Shopify above. Shopify Plus merchants often own multiple domains — audit every domain under Settings → Domains and at each external registrar.
- Assign a team member responsibility for monitoring domain expiry dates across all brand domains and storefronts, and document the registrar login credentials in a secure password manager.
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 Plus
- Follow all standard Shopify steps above. On Shopify Plus, you additionally have access to the checkout.liquid file (Admin → Themes → Edit Code → checkout.liquid), which lets you add the GTM snippet and custom dataLayer pushes directly on the checkout pages for more accurate begin_checkout and purchase event tracking.
- Use 'Elevar' (purpose-built for Shopify Plus) for server-side GA4 tracking and full ecommerce dataLayer coverage including checkout steps.
- Ensure you do not duplicate purchase events between GTM/GA4 and any native Shopify Google channel integration — disable one.
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 Plus
- Follow the same steps as Shopify above — edit theme.liquid in the active theme's Layout folder via Online Store › Themes › Actions › Edit code.
- If you use a custom checkout (Shopify Plus checkout.liquid), open checkout.liquid from the same Layout folder and add the lang attribute there too.
- Save and verify via View Page Source on both a storefront page and the checkout page.
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 Plus
- Follow all steps for Shopify above — the theme code and app ecosystem are identical.
- Additionally, if you use a custom storefront (Hydrogen/Headless), ensure your storefront query fetches 'availableForSale' from the Storefront API and maps it to the correct schema.org availability URL in your JSON-LD component.
- In Shopify Plus, you can also manage schema at scale via Scripts or Metafields — use a product metafield to store an override availability value that the schema template reads, giving merchandisers control without code changes.
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 Plus
- Follow all standard Shopify steps above.
- Use Shopify Scripts or Theme Customizations via the GitHub-connected store theme to inject automated 'Related Products' or 'Recently Viewed' sections across templates at scale.
- In Shopify Plus, use Metafields (Settings → Custom data) to tag products as 'Featured' and build a dynamic collection that auto-links to them from your homepage or landing pages.
- Use the Shopify Plus Bulk Editor (Products → select multiple → Edit products) to batch-assign collections to many orphaned products at once.
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 Plus
- Same auto-generated sitemap as Shopify (yourdomain.com/sitemap.xml). For enterprise catalogs with many variants or custom storefronts (Hydrogen/Storefront API), verify the sitemap covers all published product handles.
- In the Shopify Admin, go to Online Store → Themes → Edit Code. The sitemap is rendered by Shopify's engine, not a theme file — you cannot directly edit it, but you can supplement it using a custom sitemap app.
- Use an app like Sitemap Pro or Yoast SEO for Shopify (available in the Shopify App Store) for full control over which products are included.
- Resubmit the sitemap in Google Search Console after any catalog changes.
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 Plus
- Same as Shopify: the core Shopify Plus infrastructure suppresses server version details centrally.
- If your Plus store uses a headless/custom front-end (e.g., Next.js on Vercel or a Node server), suppress the header in that layer: in Next.js, add a `headers()` config in next.config.js to remove the `X-Powered-By` header (Next.js already removes it by default via `poweredByHeader: false`). For the underlying host (Vercel, AWS, etc.), use platform-level header rules.
- Contact your Shopify Plus launch engineer if server headers appear on your custom checkout subdomain.
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 Plus
- SSL management is identical to standard Shopify — certificates are auto-provisioned and auto-renewed by Shopify for all custom domains.
- For expansion stores and the checkout subdomain, verify each domain in Admin → Settings → Domains shows 'SSL certificate — Active'.
- Contact your Shopify Plus Merchant Success Manager if any domain stubbornly shows SSL unavailable after DNS is correct.