Every Squarespace fix we catalog

SEOLZ catalogs 182 fixes for Squarespace across 6 areas — SEO, answer-engine readiness, accessibility, security and site-health. Each lists the exact steps for Squarespace, with a link to the official docs.

SEO · 52 fixes

Catalog coverageModerate effort

Audit your XML sitemap and internal linking so that every product and category page is discoverable and crawlable by Google — not hidden behind JavaScript, pagination, or missing links.

On Squarespace

  1. Squarespace auto-generates a sitemap at yoursite.com/sitemap.xml and includes all published pages and products.
  2. Pages panel: ensure all product pages and category pages (Folder or Index pages used as categories) are set to 'Public' (not Password Protected or Disabled).
  3. Pages › Products page › Settings: confirm 'Enable' is checked and the page is not hidden from navigation.
  4. Marketing › SEO: check 'Hide Page from Search Engines' is unchecked at the site level. Then for individual pages, open Page Settings › SEO and confirm 'Hide page from search engines' is off.
  5. Connect Google Search Console via Marketing › Google Search Keywords or via the manual HTML verification in Settings › Advanced › Code Injection, then submit yoursite.com/sitemap.xml.
  6. Add internal links to product collections from your homepage or navigation so Google follows them, not just the sitemap.
Code · Generic HTML (html)
<!-- CORRECT: Standard crawlable link -->
<a href="/products/blue-running-shoes">Blue Running Shoes</a>

<!-- WRONG: JavaScript-only — Googlebot cannot follow this -->
<span onclick="navigate('/products/blue-running-shoes')">Blue Running Shoes</span>

Standard crawlable product link — use plain <a href> tags, never JavaScript-only click handlers, for navigation links that Google must follow.

Cwv clsModerate effort

Eliminate unexpected layout shifts by reserving space for every image, video, embed, and dynamically injected element so nothing jumps when the page loads.

On Squarespace

  1. Images: Squarespace's image blocks automatically generate width/height attributes in modern templates (7.1). If you are on a 7.0 template, migrate to a 7.1 template to get this benefit automatically.
  2. Banners / announcement bars: In Pages → Not Linked → promotional pop-ups, or in the Announcement Bar settings, set position to 'bottom' or use a modal overlay style to avoid pushing page content down.
  3. Custom code embeds: Go to any page → Edit → Add Block → Code, and wrap third-party scripts (reviews, chat, social) in a <div style='min-height:150px'> so space is reserved. Enter this in Settings → Advanced → Code Injection (site-wide).
  4. Fonts: In Design → Fonts, choose from Squarespace's curated list; these are loaded with optimised settings. For custom fonts added via Code Injection → CSS, add font-display: swap; inside your @font-face rule in Settings → Advanced → Code Injection → CSS.
  5. Header scripts: Any JavaScript injected via Settings → Advanced → Code Injection → Header that modifies layout should be deferred with defer or async attribute to prevent shifts during initial load.
  6. Verify: Run PageSpeed Insights on your Squarespace domain; CLS should be < 0.1.
Code · Generic HTML (html)
<!-- CORRECT: explicit width and height prevent layout shift -->
<img
  src="/images/product-red-sneaker.jpg"
  alt="Red canvas sneaker, side view"
  width="800"
  height="800"
  loading="lazy"
>

Always declare width and height on every img element. The browser uses these to reserve space before the image file downloads.

Cwv inpLarger project

Reduce Interaction to Next Paint (INP) to under 200 ms by breaking up long JavaScript tasks, deferring non-critical third-party scripts, and lightening event handlers so the page feels fast and responsive after every tap or click.

On Squarespace

  1. Go to Settings → Advanced → Code Injection. Review any third-party `<script>` tags in the Header or Footer injection areas. Move scripts from Header to Footer, and add `defer` or `async` to reduce main-thread blocking during load.
  2. Remove any unused third-party integrations (chat widgets, marketing tools) from Settings → Integrations or from Code Injection — these are common sources of long tasks.
  3. Squarespace does not offer deep JavaScript customisation, so the primary levers are: (1) reducing the number of third-party scripts, (2) switching to lighter Squarespace-native blocks instead of embedded widgets, and (3) ensuring custom JavaScript added via Code Blocks uses `defer`.
  4. Monitor INP via PageSpeed Insights and Google Search Console → Core Web Vitals. For significant INP problems, a migration to a more flexible platform (e.g., Shopify or a headless stack) may be required if Squarespace's first-party scripts are the bottleneck.
Cwv lcpModerate effort

Reduce Largest Contentful Paint (LCP) to under 2.5 seconds by serving the hero image in a next-gen format (WebP/AVIF), preloading it, and eliminating render-blocking resources.

On Squarespace

  1. IDENTIFY LCP IMAGE: Run PageSpeed Insights on your Squarespace URL. LCP is almost always the banner/header image on your homepage.
  2. WEBP: Squarespace automatically serves WebP to supporting browsers via its Imgix CDN — no manual conversion needed.
  3. OPTIMISE SOURCE: Upload hero images at 2500px wide maximum and use JPEG at 85% quality before uploading. Squarespace resizes and converts automatically, but a smaller source = faster processing and delivery.
  4. REDUCE BANNER SIZE: In Pages › your page › Banner › Edit, use a focal-point crop to reduce unnecessary image area. Shorter banners render faster.
  5. INJECT PRELOAD (7.1 + Code Injection): Go to Settings › Advanced › Code Injection › Header. Paste: <link rel='preload' as='image' href='YOUR_HERO_IMAGE_URL' fetchpriority='high'>. Find your hero image URL by right-clicking the live image and copying the src.
  6. DEFER JS: In Code Injection › Footer, move non-critical third-party scripts here. Add 'defer' attribute to any custom <script> tags you have injected.
  7. REMOVE UNUSED PLUGINS/BLOCKS: Delete any Squarespace blocks or extensions you are not using — each can add render-blocking weight.
  8. VERIFY: Re-run PageSpeed Insights after saving.
Code · Squarespace (html)
<!-- Squarespace: Code Injection › Header — preload LCP hero image -->
<link
  rel="preload"
  as="image"
  href="https://images.squarespace-cdn.com/content/YOUR_SITE_ID/YOUR_IMAGE_FILENAME.webp"
  fetchpriority="high"
>

Paste in Settings › Advanced › Code Injection › Header. Find your hero image URL by right-clicking the live image and selecting 'Copy image address'.

Duplicate meta descriptionModerate effort

Write a unique, page-specific meta description for every page on your store so Google can display a compelling, accurate snippet for each one in search results.

On Squarespace

  1. For a standard page: in the Pages panel, hover over the page and click the gear icon (Settings), select the 'SEO' tab, and type a unique description in the 'SEO Description' field.
  2. For a blog post: open the post editor, click the gear icon (Post Settings), go to the 'SEO' tab, and enter a unique meta description.
  3. For a product page (Squarespace Commerce): open the product in the Products panel, click the gear icon, select the 'SEO' tab, and fill in 'SEO Description'.
  4. For the site homepage: go to Pages → click the gear next to 'Not Linked' or your home page → SEO tab → update 'SEO Description'.
  5. Squarespace does not offer a built-in bulk meta-description editor; you must update each page individually via its Settings → SEO tab.
  6. After saving, use a browser extension (e.g. SEO Meta in 1 Click) to confirm the new description is live in the page source.
Code · Generic HTML (html)
<head>
  <meta charset="UTF-8">
  <meta name="description" content="Shop women's running shoes at Acme Store — lightweight, cushioned designs for road and trail. Free shipping on orders over $50.">
  <title>Women's Running Shoes | Acme Store</title>
</head>

Place inside the <head> element of every page. Replace the content value with a unique 120–160 character description for that specific page.

Duplicate titleModerate effort

Give every page a unique, descriptive title tag that accurately reflects that page's specific content.

On Squarespace

  1. For individual pages: Pages panel → hover the page → gear icon (Page Settings) → SEO tab → edit 'SEO Title'.
  2. For blog posts or portfolio items: open the item editor → top-right Settings cog → SEO → 'SEO Title'.
  3. For store products: Commerce → Products → edit product → Social tab or SEO section → 'SEO Title'.
  4. To set a global title format for all pages of a type (e.g. all blog posts), go to Design → Not directly available — Squarespace does not have a bulk SEO title template editor; each page/post title must be set individually or via the Squarespace API if you have developer access.
Code · Generic HTML (html)
<head>
  <title>Merino Wool Running Socks – Free UK Shipping | BrandName</title>
</head>

Place inside <head>. Make the title unique per page — include the specific item name and brand.

Faceted url indexableModerate effort

Point the rel=canonical on every faceted/filter URL to its clean parent category URL (or add noindex), so Google treats filtered pages as a single authoritative page instead of thousands of duplicates.

On Squarespace

  1. Squarespace's native shop pages and category pages do not heavily use faceted URLs — filtering is typically handled client-side without URL changes, so this issue is less common. However, some third-party filter integrations or URL parameters may still exist.
  2. To check: navigate to a filtered view of a shop page on your site and look at the URL bar. If query parameters appear (e.g., ?category=pants&color=navy), view page source and find the <link rel='canonical'> tag.
  3. Squarespace does not provide a native UI to override canonical tags page-by-page for dynamically filtered URLs. However, you can inject a canonical tag override via Settings → Advanced → Code Injection → Header. Add: <link rel='canonical' href='https://yoursite.com/shop'> — note this applies sitewide to every page so it's only appropriate if you want a single canonical for all shop variants.
  4. A more surgical approach: use a Code Block on individual pages (for static category pages) via Pages → [Page] → Edit → Add Block → Code, and inject the canonical override there.
  5. For most Squarespace stores, the best approach is to avoid enabling URL-generating filter plugins and rely on Squarespace's native client-side filtering, which does not change the URL and therefore does not create faceted URL indexing issues.
  6. Verify with Google Search Console URL Inspection after any changes.
Code · Generic HTML (html)
<head>
  <!-- Canonical points to the CLEAN category URL, not the filtered variant -->
  <link rel="canonical" href="https://www.example.com/womens-pants">
</head>

Place this in the <head> of every filtered/faceted page. The href must be the clean parent category URL — never the filtered URL itself.

Images missing altModerate effort

Add descriptive alt text to every product and content image so search engines and screen readers can understand what the image shows.

On Squarespace

  1. Page/block images: Open the page in the editor → hover over the image block → click the pencil (Edit) icon → select the 'Design' or 'Image' tab in the block settings → find the 'Alt Text' field → enter your description → Apply/Save.
  2. Product images: Commerce → [select product] → click the image thumbnail in the media area → in the image editor panel, find 'Alt Text' → enter description → Save.
  3. Gallery block images: Click the gallery block → Edit → click any individual image → fill in the Alt Text or Caption/Alt field → Save.
Code · Generic HTML (html)
<!-- BEFORE (missing alt — bad) -->
<img src="/images/red-leather-bag.jpg">

<!-- AFTER (descriptive alt — correct) -->
<img src="/images/red-leather-bag.jpg" alt="Red leather crossbody bag with gold buckle clasp">

<!-- Decorative image (intentionally empty alt — correct) -->
<img src="/images/divider-line.png" alt="">

Place this wherever an <img> tag appears in your HTML. Replace the placeholder text with your real description.

Images missing alt bulkModerate effort

Add descriptive alt text to every product and content image at the template level so search engines and screen readers can understand all images on the page.

On Squarespace

  1. In the Squarespace editor, click any image block → click the pencil/edit icon → go to the 'Design' or 'Image' tab → fill in the 'Alt Text' field.
  2. For Squarespace Commerce product images: go to Commerce → Products → edit a product → click each product image → fill in the 'Alt Text' field in the image panel.
  3. For Gallery Blocks or Gallery Sections, click the block → Edit → click each individual image → enter alt text.
  4. Squarespace does not provide direct template code access, so alt text must be entered image by image through these UI fields.
Code · Generic HTML (html)
<!-- Informative product image — describe what the image shows -->
<img src="/images/red-running-shoes-side-view.jpg"
     alt="Red canvas running shoes, side view, white rubber sole"
     width="800" height="800">

<!-- Decorative image — empty alt tells screen readers to skip it -->
<img src="/images/divider-wave.svg"
     alt=""
     role="presentation"
     width="1200" height="40">

Correct alt text pattern for informative images vs. decorative images.

Low performance scoreLarger project

Improve your Lighthouse/PageSpeed performance score by reducing page weight, eliminating render-blocking resources, optimising images, and addressing Core Web Vitals so Google ranks your store higher in search results.

On Squarespace

  1. Squarespace hosts all sites on its CDN with GZIP automatically — focus on what you control: content and third-party code.
  2. Optimise images before uploading: resize to the largest display size needed (max ~2000 px wide) and compress with Squoosh to WebP under 200 KB. Squarespace resizes on the fly but starts from your uploaded file.
  3. Avoid embedding heavy third-party iframes (YouTube embeds load a large JS bundle) — use a lite-embed approach: Pages → Edit → replace standard YouTube blocks with a linked thumbnail image.
  4. Remove unused Code Injection: Settings → Advanced → Code Injection — delete any old analytics, chat, or pixel scripts you no longer use.
  5. Minimise custom fonts: Design → Fonts — each additional font family adds an external HTTP request; limit to 2 families total.
  6. Disable or limit Squarespace Fluid Engine animations and parallax effects on product/category pages — these contribute to CLS and INP on mobile.
  7. Re-test with PageSpeed Insights; note that Squarespace's platform constraints mean scores above 70–80 mobile are hard to achieve without migrating to a more flexible platform.
Code · Generic HTML (html)
<!-- In <head>: preconnect to critical third-party origins to reduce connection latency -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

<!-- Preload your Largest Contentful Paint image (hero/banner) so it loads earlier -->
<link rel="preload" as="image" href="/images/hero.webp" fetchpriority="high">

<!-- Hero image: eager load, explicit dimensions to prevent CLS -->
<img
  src="/images/hero.webp"
  alt="Descriptive alt text for your hero image"
  width="1200"
  height="600"
  fetchpriority="high"
  decoding="async"
>

<!-- All other images: lazy load, explicit dimensions to prevent CLS -->
<img
  src="/images/product-shot.webp"
  alt="Descriptive product alt text"
  width="800"
  height="800"
  loading="lazy"
  decoding="async"
>

<!-- Defer non-critical third-party scripts (analytics, chat, pixels) -->
<script src="https://example-analytics.com/tracker.js" defer></script>

<!-- Load non-critical CSS asynchronously to unblock render -->
<link rel="preload" href="/css/non-critical.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/css/non-critical.css"></noscript>

Paste these patterns into your <head> and image markup to address the most common Lighthouse failures.

Meta description too longQuick win

Shorten your meta description to 150–160 characters so Google displays it in full instead of cutting it off with "…" in search results.

On Squarespace

  1. For regular pages: open the page in the Pages panel → click the gear icon (⚙) → select the 'SEO' tab → edit the 'SEO Description' field.
  2. For product pages (Squarespace Commerce): go to Commerce → Inventory → click the product → scroll to the 'SEO' section at the bottom → edit 'SEO Description'.
  3. For blog posts: open the post → click the gear icon → 'SEO' tab → 'SEO Description'.
  4. Keep text under 160 characters and save.
Code · Generic HTML (html)
<meta name="description" content="Award-winning Bang & Olufsen headphones, speakers and TVs. Visit our Malaysia showroom at The Gardens Mall, Level 2. Free shipping on orders over RM500.">

Place this inside the <head> element of every page. Replace the content value with your page-specific description (max 160 characters).

Meta description too shortModerate effort

Expand your meta description to 120–160 characters so Google displays a compelling, complete snippet in search results that drives more clicks to your store.

On Squarespace

  1. For regular pages: Pages panel → hover over the page → click the gear icon (⚙) → 'SEO' tab → update the 'SEO Description' field → Save.
  2. For product pages (Squarespace Commerce): Commerce → Inventory → select the product → 'SEO' tab → update the description → Save.
  3. For blog posts: Blog panel → select the post → click the gear icon → 'SEO' tab → update the description → Save.
  4. For the homepage: Pages → hover over 'Not Linked' or your home page → gear icon → SEO tab → update description.
Code · Generic HTML (html)
<meta name="description" content="Shop the official Nike national team jerseys — advanced Dri-FIT heat tech meets bold heritage design. Free shipping on orders over $75. Explore the full collection now.">

Place this inside the <head> element of your HTML page. Replace the content value with your 120–160 character description.

Missing canonicalModerate effort

Add a self-referencing canonical tag to every page so Google knows which URL is the definitive version of that content.

On Squarespace

  1. Squarespace automatically injects canonical tags on all standard pages, blog posts, and product pages — no manual setup required.
  2. To verify: visit any page on your store, right-click → View Page Source, and search for 'canonical'. You should see a `<link rel='canonical'>` tag pointing to the current page's clean URL.
  3. If you need to override a canonical (advanced use): Squarespace does not offer a native per-page canonical override field. You can inject a custom tag via Settings → Advanced → Code Injection → 'Header' field. However, be aware this injects on ALL pages — use conditional logic carefully or consider a third-party SEO app from the Squarespace Extensions marketplace.
  4. For Squarespace Commerce product pages, canonicals are handled automatically; focus on ensuring your domain is set to a single preferred version (www vs. non-www) under Settings → Domains.
Code · Generic HTML (html)
<link rel="canonical" href="https://www.yourstore.com/your-page/" />

Paste this inside the <head> element of every page. Replace the href value with the full, absolute preferred URL of that specific page.

Missing h1Quick win

Add a single, descriptive H1 tag to every page that currently lacks one, clearly stating the page's main topic.

On Squarespace

  1. Open the page in the Squarespace editor.
  2. Click the pencil/edit icon on the content block at the top of the page.
  3. In the text editor, type your main heading, select it, and from the text format toolbar choose 'Heading 1' (shown as H1 or a large 'H').
  4. For product pages: Squarespace Commerce automatically uses the product name as the page H1 — go to Commerce → Inventory → open the product → ensure the product Title is filled in.
  5. For blog posts: the Post Title field automatically becomes the H1.
  6. Save and publish, then verify with View Page Source (Ctrl/Cmd+U), searching for '<h1>'.
Code · Generic HTML (html)
<h1>Women's Running Shoes</h1>

Place exactly one of these per page, as the first heading in the main content area.

Missing meta descriptionModerate effort

Write and add a unique meta description (120–160 characters) to every page that is missing one, so Google can display an accurate, compelling snippet in search results.

On Squarespace

  1. For any regular page: Pages panel → hover over the page → click the gear icon → 'SEO' tab → fill in the 'SEO Description' field.
  2. For a product page: Commerce → Products → click the product → 'SEO' tab on the product editor → fill in 'SEO Description'.
  3. For a blog post: Pages → Blog → click the post → the post settings gear icon → 'SEO' tab → 'SEO Description'.
  4. For the homepage: Pages → hover over your homepage → gear icon → SEO tab → SEO Description.
  5. Note: Squarespace enforces a 400-character limit on this field; keep your description within 120–160 characters to avoid truncation in search results.
Code · Generic HTML (html)
<head>
  <meta charset="UTF-8">
  <meta name="description" content="Shop our full range of handmade leather wallets. Free shipping on orders over $50. Slim, durable & personalised — order yours today.">
  <title>Handmade Leather Wallets | YourStoreName</title>
</head>

Place this tag inside the <head> element of every HTML page. Keep the content between 120–160 characters.

Missing og descriptionModerate effort

Add an og:description meta tag to every page so that social media platforms display a compelling, accurate preview when your pages are shared.

On Squarespace

  1. For standard pages: go to Pages → hover the page → click the gear icon (Settings) → SEO tab → fill in 'SEO Description'. Squarespace uses this value as og:description.
  2. For product pages: open the product in the Commerce panel → click the gear icon → SEO → enter the SEO Description.
  3. For blog posts: open the post editor → click the gear icon → SEO → enter the SEO Description.
  4. If you need finer control, go to Settings → Advanced → Code Injection → Header and add the tag manually (note: this applies site-wide and cannot be page-specific from this location).
  5. Validate by sharing a page URL on Facebook or using the Sharing Debugger.
Code · Generic HTML (html)
<head>
  <!-- Open Graph / Social Sharing -->
  <meta property="og:type"        content="website" />
  <meta property="og:url"         content="https://www.example.com/page-url/" />
  <meta property="og:title"       content="Page Title – Brand Name" />
  <meta property="og:description" content="A concise, compelling summary of this page in 100–160 characters that encourages clicks." />
  <meta property="og:image"       content="https://www.example.com/images/social-preview.jpg" />
</head>

Place all Open Graph tags inside the <head> element of every page.

Missing og imageModerate effort

Add an og:image meta tag to every page so that social media platforms and messaging apps display a rich, branded image preview whenever someone shares your store's link.

On Squarespace

  1. In the Squarespace editor, go to Pages → click the settings gear (⚙) next to any page → open the 'Social Image' tab → upload a 1200×630 px image specific to that page.
  2. For a site-wide default og:image, go to Website → Website Tools → Social Sharing → Social Sharing Image → upload your brand image.
  3. For Squarespace Commerce product pages, open a product → scroll to 'SEO' or 'Social Image' within the product editor → upload the product-specific social image.
  4. For blog posts, open the post editor → click the settings gear → Social Image tab → upload the image.
  5. Note: Squarespace injects og:image tags automatically based on these settings — no code editing is required.
  6. Publish and validate using Facebook's Sharing Debugger.
Missing og titleQuick win

Add an og:title meta tag to every page so your store's title appears correctly when shared on social media platforms like Facebook, LinkedIn, and Pinterest.

On Squarespace

  1. Squarespace automatically generates og:title from your page's SEO title. To set it: in the Pages panel, hover over the page → click the gear icon (Settings) → click the 'SEO' tab → fill in the 'SEO Title' field.
  2. For product pages: go to your Commerce section → Products → click a product → click the gear icon → SEO tab → fill in the SEO Title.
  3. For blog posts: open the post editor → click the gear icon → SEO tab → fill in the SEO Title.
  4. Squarespace does not currently allow fully custom og: meta tag injection per page via the UI for standard plans; the SEO Title field is the primary lever. On Business plans and above you can inject custom code: go to Settings → Advanced → Code Injection → paste your og:title tag in the Header section (this applies site-wide).
  5. Verify using the Facebook Sharing Debugger after publishing your changes.
Code · Generic HTML (html)
<head>
  <!-- Other head tags -->
  <meta property="og:title" content="Amazing Product Name | Your Store Name" />
  <meta property="og:type" content="website" />
  <meta property="og:url" content="https://www.yourstore.com/page-url" />
  <meta property="og:description" content="Short description of this page for social sharing." />
  <!-- Other head tags -->
</head>

Place inside the <head> section of every HTML page. Replace the content value with your actual page title.

Missing titleQuick win

Add a unique, descriptive title tag (30–60 characters) to every page that is missing one.

On Squarespace

  1. For a regular page: open the Pages panel → hover over the page → click the gear icon (Settings) → go to the 'SEO' tab → fill in the 'SEO Title' field.
  2. For a product: go to Commerce → Inventory → select the product → click the 'SEO' tab → fill in 'SEO Title'.
  3. For the homepage: Pages → hover over the homepage → gear icon → SEO tab → SEO Title.
  4. If the SEO Title field is left blank, Squarespace falls back to the page/product title — make sure at least the page title is set even if you don't customise the SEO title separately.
  5. Click Save.
Code · Generic HTML (html)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Slim Bifold Leather Wallet | BrandName</title>
</head>
<body>
  <!-- page content -->
</body>
</html>

Place this inside the <head> element of every HTML page. Keep the text between 30–60 characters.

Multiple h1Moderate effort

Remove all but one H1 tag from each page so every page has exactly one clear, descriptive primary heading.

On Squarespace

  1. Open Pages and click Edit on the affected page.
  2. Click each text block. In Squarespace, text style options (Heading 1, Heading 2, etc.) are set via the text formatting toolbar that appears when you highlight text.
  3. Ensure only the primary page title or main heading is set to Heading 1. Change all other headings to Heading 2 or Heading 3.
  4. For product pages in Squarespace Commerce, the product title is automatically rendered as H1 by the template — do not add a second H1 in the product description.
  5. For blog posts, the post title is the H1 — do not use Heading 1 style inside the post body; use Heading 2 onward.
  6. Use browser DevTools to confirm the rendered markup after saving.
Code · Generic HTML (html)
<!-- CORRECT: One H1 per page -->
<h1>Blue Running Shoes – Men's Lightweight Trainers</h1>

<!-- Major sections use H2 -->
<h2>Product Details</h2>
<p>Breathable mesh upper, responsive foam midsole...</p>

<h2>Customer Reviews</h2>
<!-- Sub-sections within a major section use H3 -->
<h3>Top Review: 5 Stars</h3>
<p>Best shoes I've ever bought!</p>

<!-- WRONG: Multiple H1 tags — do NOT do this -->
<!--
<h1>Blue Running Shoes</h1>
<h1>Product Details</h1>
<h1>Customer Reviews</h1>
-->

Correct semantic heading structure for an ecommerce page — one H1, everything else H2 or lower.

Noindex detectedQuick win

Remove or replace the noindex directive on any page you want to appear in Google search results.

On Squarespace

  1. Global setting (site visibility): Go to Settings → Site Availability and confirm it is set to 'Public'. 'Private' or 'Password Protected' causes Squarespace to add noindex headers to the entire site.
  2. Per-page setting: Open Pages, hover over the page, click the gear icon (Page Settings) → SEO tab. Look for a 'Hide Page from Search Engines' or 'Disable indexing' checkbox and make sure it is UNCHECKED.
  3. Blog posts: Open the blog post editor → click the gear icon → SEO tab → confirm indexing is not disabled.
  4. Code injection: Go to Settings → Advanced → Code Injection and check the Header section for any hardcoded <meta name="robots" content="noindex"> tag and remove it.
  5. After saving, submit the URL in Google Search Console → URL Inspection → Request Indexing.
Code · Generic HTML (html)
<meta name="robots" content="index,follow">

Place inside <head>. This is the CORRECT tag that allows indexing and link-following.

Non self canonicalQuick win

Audit every page whose canonical tag points to a different URL, then either correct it to self-reference or confirm the cross-reference is intentional and correct.

On Squarespace

  1. Squarespace automatically outputs self-canonical tags on all pages — manual overrides are only possible via Code Injection.
  2. Go to your Squarespace admin, navigate to Settings → Advanced → Code Injection.
  3. Check the 'Header' code injection area for any <link rel="canonical" ...> tag that was manually added. If found and incorrect, either remove it entirely (to restore Squarespace's automatic canonical) or update the href to the correct self-referencing URL.
  4. Also check individual pages: open the affected page in the Pages panel, click the gear icon (Page Settings), select the 'Advanced' tab, and inspect the 'Page Header Code Injection' field for any hardcoded canonical tag — remove or correct it.
  5. Save changes and view-source the live page to confirm only one canonical tag exists and it matches the page URL.
Code · Generic HTML (html)
<link rel="canonical" href="https://www.example.com/your-page-url/">

Place this tag inside the <head> element of every page. The href must exactly match the page's own preferred URL.

Og url mismatchModerate effort

Set a unique, page-specific og:url meta tag on every page that exactly matches that page's canonical URL.

On Squarespace

  1. In Squarespace, go to Pages → click the gear icon (⚙) next to any page → SEO tab → scroll to 'SEO Description'. Squarespace automatically sets og:url to the page's canonical URL — you cannot manually override it per-page without custom code.
  2. If your og:url is wrong site-wide, the most common cause is a custom code injection: go to Settings → Advanced → Code Injection and look for any hardcoded og:url tags in the Header section. Remove or correct them.
  3. For per-page code injection overrides, go to Pages → gear icon → Advanced → Page Header Code Injection and remove any conflicting og:url lines.
  4. Squarespace Business/Commerce plans allow Header code injection; if a developer has added a static og:url here, it will override Squarespace's automatic value — that line must be removed or made dynamic.
  5. After removing any conflicting injection, use the Facebook Sharing Debugger to verify the og:url for multiple page types.
Code · Generic HTML (html)
<meta property="og:url" content="https://www.example.com/exact-page-path/" />
<link rel="canonical" href="https://www.example.com/exact-page-path/" />

Place inside the <head> element. The og:url value must be the absolute canonical URL of the current page.

Page not foundModerate effort

Fix broken internal links pointing to pages that return a 404 error by either removing those links or setting up a 301 redirect from the missing URL to the correct replacement page.

On Squarespace

  1. In the Squarespace dashboard, go to Settings → Advanced → URL Mappings (for code-based redirects) OR go to Settings → URL Redirects (available in some Squarespace plans) and add a new 301 redirect from the old path to the new destination.
  2. For URL Mappings, enter the rule in the format: /old-url -> /new-url 301 — one rule per line. Save.
  3. To fix internal links in page content, open the Pages panel, click on the affected page, enter Edit mode, click the broken link, and update or delete it using the link toolbar.
  4. For navigation links, go to Pages → (the navigation item) and update the URL or remove the link.
  5. Squarespace does not expose server configuration files, so all redirects must go through URL Mappings or URL Redirects.
  6. Verify by visiting the old URL — you should be redirected to the correct page automatically.
Code · Squarespace (html)
/old-page-url -> /new-page-url 301
/old-products/discontinued-item -> /products/replacement-item 301
/old-category -> /new-category 301

Add a 301 redirect rule in Settings → Advanced → URL Mappings. One rule per line, no quotes.

Page speed warningModerate effort

Reduce your page load time to under 1.5 seconds by optimizing images, eliminating render-blocking resources, and enabling caching and compression.

On Squarespace

  1. Images: In the Squarespace editor, click any image block and in Image Settings choose the correct focal point and reduce the image file size before uploading by using Squarespace's built-in 'Compress images on upload' setting (Settings > Advanced > Image Compression). Squarespace serves images via Fastly CDN and converts to WebP automatically.
  2. Video backgrounds: In the Pages panel, click any section that uses a video background and replace it with a high-quality static image — video backgrounds are the biggest single Squarespace speed issue.
  3. Code injection: Go to Settings > Advanced > Code Injection and audit any custom HTML/CSS/JS you or a developer has added. Remove or defer any third-party scripts that are not business-critical.
  4. Fonts: In Design > Fonts, reduce the number of font styles you use. Each distinct font weight or style is a separate HTTP request. Choose two fonts maximum and limit to the weights you actually use.
  5. Extensions: Go to Extensions in your Squarespace dashboard and remove any extension (third-party app) you are not actively using.
  6. Squarespace does not allow server-level caching configuration — it is handled automatically — so focus on asset optimization (images, video, scripts) and reducing page complexity.
Redirect chainModerate effort

Update every internal link that passes through a redirect chain to point directly at the final destination URL, eliminating all intermediate hops.

On Squarespace

  1. Run Screaming Frog or a similar crawler against your published Squarespace URL to export all redirect chains; note each final destination URL.
  2. For links inside page content blocks: open Pages in the Squarespace Editor, click Edit on the affected page, click the linked text or button, select 'Edit Link', and replace the URL with the final destination. Save and publish.
  3. For navigation links: go to Pages in the left panel, hover over the page or folder whose URL is a chain, click the gear icon (Settings), and correct the URL or slug. Alternatively, if the item is an External Link in the nav, click the three dots and update the URL.
  4. Review URL Redirects under Settings → Advanced → URL Redirects; if any redirect target is itself a redirecting URL, update it to point to the true final destination.
  5. For links inside footers or header announcement bars: open the footer/header via Design → Site Styles or the footer editing area, find the linked element, and update its href to the final URL.
  6. Re-crawl the published site after saving to confirm all chains are eliminated.
Code · Generic HTML (html)
<!-- BEFORE: link points to an intermediate URL that itself redirects -->
<a href="https://example.com/old-page">Our Story</a>

<!-- AFTER: link points directly to the final destination URL -->
<a href="https://example.com/about-us">Our Story</a>

Replace every intermediate redirect URL in your anchor href with the final destination URL — the one that returns HTTP 200 with no further redirects.

Search results indexableModerate effort

Add a noindex robots meta tag to all internal search result pages and block the search URL path in robots.txt to prevent Google from crawling and indexing thin, duplicate search results.

On Squarespace

  1. In your Squarespace Admin, go to Pages → find your Search Page (if it exists as a standalone page) → click the gear icon → SEO tab → check 'Hide Page from Search Engines'. This adds noindex to that page.
  2. If your search results appear at a path like /search?q=, inject the noindex tag site-wide for search pages by going to Settings → Advanced → Code Injection → paste the following into the 'Page Header' field with a URL-condition check: <script>if(window.location.pathname.startsWith('/search')){document.head.insertAdjacentHTML('beforeend','<meta name="robots" content="noindex,follow">')}</script>
  3. For robots.txt: Squarespace does not allow direct robots.txt editing. Instead, rely on the noindex tag approach above — Googlebot will honor noindex even without a robots.txt Disallow.
  4. Verify with Google Search Console URL Inspection.
Code · Generic HTML (html)
<meta name="robots" content="noindex,follow">

Place this tag inside the <head> element of every search results page template.

Seo category description missingModerate effort

Write a 100–200 word description for every category page explaining what products it contains and who they are for, so Google can rank it for category-level keywords.

On Squarespace

  1. In Squarespace, category pages in Commerce are filtered product pages, not standalone pages with a dedicated description field.
  2. The recommended approach is to add a Text Block at the top of your main Shop page (above the product grid) that describes the category — or to create separate Squarespace Pages for major categories and embed the product list filtered by category using a Products Block.
  3. To add a description to a full dedicated category page: go to Pages → (your Shop page) → Edit, click '+' at the top of the content area, choose 'Text', and type your 100–200 word description.
  4. For stores using the built-in category filter (sidebar/dropdown), consider adding category-specific descriptions to a Text Block that updates based on context, or use Squarespace's Announcement Bar or intro section for the most prominent category text.
  5. Save and publish.
Code · Generic HTML (html)
<section class="category-description">
  <h1>Women's Waterproof Hiking Boots</h1>
  <p>
    Our women's waterproof hiking boots are built for trail runners, weekend
    trekkers, and serious mountaineers who refuse to let wet weather slow them
    down. Every pair in this collection features a fully sealed waterproof
    membrane, aggressive rubber outsoles for grip on loose or muddy terrain,
    and reinforced ankle support to protect against sprains on uneven ground.
    Whether you're day-hiking a local forest trail or taking on a multi-day
    alpine route, you'll find boots here rated for every conditions and
    experience level. Lightweight options keep pack weight low on fast-and-light
    adventures, while insulated models keep feet warm below freezing. Browse the
    full range below to find your perfect fit.
  </p>
</section>

Place this block near the top of your category page, above the product grid.

Seo category description thinModerate effort

Expand your category page description to at least 100 words of genuinely helpful, keyword-rich content that explains what shoppers will find in that category.

On Squarespace

  1. In Squarespace, category-level descriptions depend on your store version. Go to Commerce > Inventory, click on a category, and look for a 'Description' field if available in your version.
  2. If your version does not support native category descriptions, navigate to the Category page in Pages, click Edit, and add a Text Block above or below the product grid.
  3. Type your 100+ word description in the Text Block, using Squarespace's text formatting tools for headings and bullets.
  4. For Squarespace 7.1, you can also use the Page Description field (Settings > SEO > Page Description) for the meta description, but make sure visible on-page text also exists.
  5. Save and preview on mobile to confirm the layout looks correct, then publish.
Code · Generic HTML (html)
<section class="category-description">
  <h2>Shop Our Women's Running Shoes</h2>
  <p>
    Discover our curated collection of women's running shoes, designed for every
    type of runner — from casual joggers to marathon enthusiasts. Whether you
    need extra cushioning for long-distance road running, a lightweight racer
    for speed training, or a grippy trail shoe for off-road adventures, you'll
    find the perfect fit here.
  </p>
  <p>
    We stock top brands including Brooks, ASICS, New Balance, and Hoka, all
    rigorously tested for comfort, durability, and performance. Each pair is
    available in a wide range of widths and sizes, so you never have to
    compromise on fit. Browse by surface type, cushion level, or pronation
    support to narrow down your ideal shoe in seconds.
  </p>
  <p>
    Not sure where to start? Check out our
    <a href="/guides/running-shoe-guide">Running Shoe Buying Guide</a> or
    explore our <a href="/collections/running-accessories">Running Accessories</a>
    collection to complete your kit.
  </p>
</section>

Paste this pattern into any category page template. Replace placeholder text with your real content.

Seo category emptyQuick win

Either populate the empty category with products, or add a noindex tag and remove it from your navigation so Google does not waste crawl budget on a page with no content.

On Squarespace

  1. Open Pages in the Squarespace editor and locate your empty category page (usually a tagged or filtered Shop page).
  2. Option A — Add products: Go to Commerce → Products and either create new products tagged with this category, or edit existing products and add the relevant tag/category.
  3. Option B — Noindex: Click the page settings (gear icon), go to SEO → Page Settings, and under 'SEO Description / Advanced' look for 'Enable' toggle or use the Header Code Injection (available on Business plan and above): paste <meta name='robots' content='noindex, follow'> in the 'Header' code injection field for that page. Save.
  4. Option B (Site-wide code injection for a specific path): Go to Settings → Advanced → Code Injection → Header, and conditionally target the category URL if your template supports it.
  5. Option C — Delete & redirect: Remove the category page. Go to Settings → Advanced → URL Mappings and add a 301 redirect: /old-category-url -> /parent-category-url 301.
  6. Remove the category link from your navigation under Pages by dragging it to 'Not Linked' or deleting it.
Code · Generic HTML (html)
<meta name="robots" content="noindex, follow">

Place inside the <head> element of an empty category page to prevent Google from indexing it.

Seo category sparseModerate effort

Add more products to sparse category pages, or consolidate very thin categories into broader, related ones so every indexed category page delivers genuine value to shoppers and search engines.

On Squarespace

  1. In your Squarespace admin, go to Pages and open your Store.
  2. To add products to a sparse category: open each product → scroll to 'Categories & Tags' → add the appropriate category tag.
  3. Squarespace uses tags/categories on product pages rather than separate collection pages. Enrich the store landing page or a dedicated blog/content page that links to the filtered view.
  4. To add descriptive text: on the Store page, use a Text Block above the product grid (Edit page → Add Block → Text) to provide category context.
  5. To noindex a sparse category filter page: go to Pages → (gear icon next to the page) → SEO tab → check 'Hide Page from Search Engines' or paste a robots noindex tag in the Header Code Injection field under Advanced.
Code · Generic HTML (html)
<meta name="robots" content="noindex, follow">

Add inside <head> of any sparse category page you want excluded from Google's index while still being followable by crawlers.

Seo facet url not canonicalizedModerate effort

Add a canonical tag to every filtered, sorted, and paginated collection/category URL pointing back to the clean (unfiltered) category URL, so Google consolidates duplicate pages and focuses crawl budget on your real content.

On Squarespace

  1. Squarespace automatically adds canonical tags to all pages and does not natively expose faceted filter URLs as separate indexable pages in the same way as custom platforms.
  2. If you are using Squarespace Commerce and have filter URLs appearing in Google Search Console as separate indexed pages, go to Pages → [Your Shop Page] → SEO (gear icon) → and set the canonical URL explicitly to the clean shop/category URL.
  3. For tag or category filter URLs (e.g. /shop?tag=red), use Squarespace's URL slug settings to ensure only the primary shop page is indexable. There is no native query-parameter canonical override — use the 'noindex' robots meta as an alternative for heavily filtered URLs via Pages → SEO → Page Settings → Disable indexing for that specific tag page.
  4. Check Settings → SEO → Crawlers & Indexing to configure what Squarespace exposes to search engines.
Code · Generic HTML (html)
<head>
  <!-- All other head tags -->
  <link rel="canonical" href="https://www.example.com/collections/hoops">
</head>

Place this inside the <head> of every filtered/sorted/paginated category page. The href must be the full, absolute clean URL (no query parameters).

Seo product content client renderedLarger project

Server-render your product descriptions in the initial HTML so that all crawlers — including Google, AI search bots, and social media scrapers — can read your content without executing JavaScript.

On Squarespace

  1. Squarespace renders product pages server-side; descriptions entered in the Product editor are included in the initial HTML.
  2. Go to Pages → [Your Shop] → click a product → Edit. Enter your full product description in the Description field. Squarespace outputs this server-side automatically.
  3. For JSON-LD: Squarespace automatically adds Product structured data to store product pages. To verify: Pages → [Product Page] → SEO tab — check the preview. Use Google Rich Results Test with your product URL to confirm.
  4. If you are using Code Injection (Settings → Advanced → Code Injection) to load descriptions via JavaScript, move the content into the native Squarespace Description field instead — JS-injected content is not server-rendered.
  5. To add enriched JSON-LD (e.g., adding a description field Squarespace omits), go to the product page → Edit → Settings → Advanced → Page Header Code Injection and paste a complete <script type='application/ld+json'> block. Squarespace injects this in the server-rendered HTML.
  6. Validate at search.google.com/test/rich-results using your live product URL.
Seo product description minimalModerate effort

Expand your product descriptions to at least 300 words by adding specifications, use cases, and benefits so search engines have enough content to rank and shoppers have enough information to buy.

On Squarespace

  1. Go to Squarespace Admin → Commerce → Inventory (or Pages → your store page).
  2. Click the product to open the product editor.
  3. Select the 'Description' text area.
  4. Write a structured 300+ word description. Use the text toolbar to add bullet lists for specs and bold text for key benefits.
  5. Click 'Save'. Squarespace will update the live page automatically; verify with Google Search Console.
Code · Generic HTML (html)
<section class="product-description">
  <h2>About the [Product Name]</h2>
  <p>
    The [Product Name] is a [category] designed for [target audience]. Whether you need
    [use case 1] or [use case 2], this [product] delivers [core benefit] without
    [common pain point].
  </p>

  <h3>Key Features &amp; Specifications</h3>
  <ul>
    <li><strong>Material:</strong> [e.g. 100% organic cotton, BPA-free polypropylene]</li>
    <li><strong>Dimensions:</strong> [W × H × D] / Weight: [X kg / X lbs]</li>
    <li><strong>Colour options:</strong> [Colour 1], [Colour 2], [Colour 3]</li>
    <li><strong>Compatibility:</strong> [e.g. Works with iOS 14+ and Android 10+]</li>
    <li><strong>Warranty:</strong> [X-year manufacturer warranty]</li>
  </ul>

  <h3>Why Shoppers Choose [Product Name]</h3>
  <p>
    Unlike [generic alternatives], the [Product Name] [specific differentiator]. This means
    [tangible benefit for the shopper], saving you [time / money / effort].
  </p>
  <p>
    Ideal for [persona / scenario], the [Product Name] has been tested to [standard or
    certification] and ships ready to use — no assembly required.
  </p>

  <h3>How to Use</h3>
  <p>
    [Step-by-step or scenario-based usage instructions in 2–4 sentences. Include any
    important setup, safety, or care notes here.]
  </p>

  <h3>In the Box</h3>
  <ul>
    <li>1 × [Product Name]</li>
    <li>1 × [Accessory or manual]</li>
    <li>1 × [Charging cable / carry bag / etc.]</li>
  </ul>
</section>

Structural template for a product description section — paste inside your product page's main content area.

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 Squarespace

  1. In your Squarespace admin, go to Commerce (or Pages if using a product block) → Products.
  2. Click the product to open the product editor.
  3. In the 'Basic' tab, click into the 'Description' field and write or paste your 200–400 word description. Use the formatting toolbar for paragraphs and bullet points.
  4. To set SEO metadata: click the 'SEO' tab within the product editor, and fill in the 'SEO Description' field (155–160 characters).
  5. Click 'Save' and preview the live product page.
Code · Generic HTML (html)
<section class="product-description">
  <h2>About This Product</h2>
  <p>
    The <strong>Trailblazer 500 Waterproof Hiking Boot</strong> is a lightweight,
    full-grain leather boot built for all-day comfort on rugged mountain trails.
    Its Gore-Tex membrane keeps feet dry in rain and creek crossings while the
    Vibram outsole delivers confident grip on wet rock and loose scree.
  </p>
  <p>
    Designed for day hikers and weekend backpackers who want reliable protection
    without the weight of a mountaineering boot, the Trailblazer 500 strikes the
    ideal balance between support and agility. The padded collar and gusseted
    tongue prevent trail debris from entering the boot, and the cushioned EVA
    midsole absorbs impact mile after mile.
  </p>
  <h3>Key Specifications</h3>
  <ul>
    <li><strong>Upper:</strong> Full-grain leather with Gore-Tex waterproof lining</li>
    <li><strong>Outsole:</strong> Vibram Megagrip rubber</li>
    <li><strong>Weight:</strong> 680 g / pair (size UK 9)</li>
    <li><strong>Shaft height:</strong> Mid (ankle) cut</li>
    <li><strong>Available widths:</strong> Standard and Wide</li>
  </ul>
  <h3>How to Use</h3>
  <p>
    Lace firmly for ankle support on uneven terrain. Break the boot in over two
    or three shorter walks before a full-day hike. Apply a water-repellent spray
    to the leather upper every 20–30 hours of trail use to maintain waterproofing.
  </p>
</section>

Minimum viable product description markup — paste inside your product page's <main> or article element.

Seo product description thinModerate effort

Expand every product description to at least 300 words of unique, keyword-rich content that answers real shopper questions and gives Google enough text to understand and rank the page.

On Squarespace

  1. Go to Pages → [your store page] → click the product to open it in the product panel.
  2. Select the 'Description' tab; click into the text area and use Squarespace's rich-text editor to write or expand the description.
  3. Use the '+' block icon to insert Text, Bullet List, or Quote blocks for well-structured content.
  4. Click 'Save' and then 'Done'; submit the URL in Google Search Console for faster re-indexing.
Code · Generic HTML (html)
<section class="product-description" aria-label="Product description">
  <h2>About This Product</h2>
  <p>
    Write your opening paragraph here (2–3 sentences introducing the product,
    its primary benefit, and who it is for). Aim for a natural, engaging tone
    that mirrors how your customers talk about this type of product.
  </p>

  <h3>Key Features</h3>
  <ul>
    <li><strong>Feature One:</strong> Explain the benefit, not just the spec.</li>
    <li><strong>Feature Two:</strong> Include the detail a shopper needs to decide.</li>
    <li><strong>Feature Three:</strong> Use the words your customers actually search for.</li>
    <li><strong>Feature Four:</strong> Keep each bullet to one clear point.</li>
  </ul>

  <h3>Materials &amp; Specifications</h3>
  <p>
    Describe materials, dimensions, weight, compatibility, or other technical
    details relevant to your product category. Specificity builds trust and
    captures long-tail searches (e.g. "100% organic cotton", "fits 13-inch laptops").
  </p>

  <h3>How to Use</h3>
  <p>
    Walk the customer through setup, application, or use in plain language.
    Answer the most common pre-purchase questions here so shoppers feel confident.
  </p>

  <h3>Why Our Customers Love It</h3>
  <p>
    Reinforce with a sentence or two of social proof context or a unique selling
    point that differentiates this product from generic alternatives.
  </p>
</section>

Ideal semantic structure for a product description section on any platform's product page template.

Seo product image alt filenameModerate effort

Replace auto-generated filename-based alt text on product images with short, descriptive phrases that accurately describe what the image shows.

On Squarespace

  1. For product images: go to Commerce → Inventory, open a product, and click an image in the product editor.
  2. In the image editing panel that opens, locate the 'Filename' or 'Alt Text' field (labeled 'Alt Text' in Squarespace 7.1+) and enter your descriptive text.
  3. Click Apply and then Save.
  4. For non-product images: click the image block on any page, click the pencil/Edit icon, and fill in the 'Alt Text' field in the Image Settings panel.
Code · Generic HTML (html)
<!-- BAD: filename-based alt text -->
<img src="/images/IMG_4823_blue_v2.webp" alt="IMG_4823_blue_v2.webp">

<!-- BAD: empty alt text -->
<img src="/images/blue-sweater.webp" alt="">

<!-- GOOD: descriptive alt text -->
<img src="/images/blue-sweater.webp" alt="Blue cotton crew-neck sweater, front view">

The correct pattern for a product image alt attribute — descriptive, specific, keyword-natural.

Seo product missing brandModerate effort

Add a `brand` property to your Product schema markup so search engines can match your listings to brand-specific queries.

On Squarespace

  1. Squarespace Commerce auto-generates some Product schema but does not natively expose a brand field in the admin UI.
  2. Go to Squarespace Admin → Settings → Advanced → Code Injection (available on Business plan and above) to inject a custom JSON-LD block into the site-wide header — note this applies globally, so use JavaScript to conditionally run it only on product pages.
  3. Alternatively, use the 'Page Header Code Injection' under each specific product page (Pages → click gear icon on page → Advanced → Page Header Code Injection) to add a `<script type='application/ld+json'>` block with the brand property hardcoded or templated.
  4. For dynamic brand values across many products, consider a Squarespace Developer platform solution or a third-party SEO app integration.
  5. Validate the output with Google's Rich Results Test on a live product URL.
Seo product missing gtinModerate effort

Add a GTIN (and/or MPN) field to your Product structured data so Google can match your listings to its product knowledge graph for rich results and Google Shopping.

On Squarespace

  1. Go to Pages → Shop → [select a product] → Edit.
  2. In the product editor, find the 'Additional Details' section. Enter the GTIN in a custom text block labeled 'GTIN' — note that Squarespace does NOT natively inject barcode fields into Product schema.
  3. To add proper schema, use Squarespace's 'Code Injection' feature: Settings → Advanced → Code Injection → Footer. Paste a complete Product JSON-LD script block (see code snippet below) with the GTIN hardcoded or dynamically injected.
  4. For a catalog-wide solution on Squarespace 7.1, install a third-party SEO app from the Squarespace Extensions marketplace (e.g. 'SEOSpace' or 'Semrush') that adds product schema fields including GTIN.
  5. Alternatively, use per-product page code injection: in the product page editor, add a Code Block containing the JSON-LD with the GTIN value for that specific product.
Seo product missing stock statusModerate effort

Add a visible stock availability label and an `availability` property to your Product structured data so Google can display rich results and shoppers know immediately whether a product is in stock.

On Squarespace

  1. Squarespace (version 7.1 Commerce) outputs Product structured data automatically but the `availability` field depends on your inventory settings.
  2. Go to your Squarespace Dashboard → Commerce → Inventory → select a product → ensure 'Track inventory' is on and quantity is set, OR set the product to 'In Stock' manually if you don't track inventory.
  3. Squarespace does not allow direct JSON-LD editing natively. To inject a custom or supplementary JSON-LD block, go to Pages → select the product page → Page Settings (gear icon) → Advanced → Code Injection, and paste a complete `<script type='application/ld+json'>` block (see Generic HTML snippet below) that reflects the correct availability.
  4. For a visible stock label, add a Text block near your product description using the page editor and update it manually, or use a Code Block with a static HTML label. Dynamic labels require a custom developer integration.
  5. Validate the page in the Rich Results Test.
Code · Generic HTML (html)
<!-- Product structured data with availability -->
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Your Product Name",
  "description": "A short description of your product.",
  "sku": "YOUR-SKU-123",
  "image": "https://www.example.com/images/product.jpg",
  "brand": {
    "@type": "Brand",
    "name": "Your Brand Name"
  },
  "offers": {
    "@type": "Offer",
    "url": "https://www.example.com/products/your-product",
    "priceCurrency": "USD",
    "price": "29.99",
    "availability": "https://schema.org/InStock",
    "itemCondition": "https://schema.org/NewCondition"
  }
}
</script>

<!-- Visible stock label near Add-to-Cart button -->
<p class="stock-status" style="font-weight:bold; color:#2a7a2a;">&#10003; In Stock</p>

Paste the complete block into the <head> section of your product page HTML. Change availability value to OutOfStock or PreOrder as needed.

Seo product no imagesModerate effort

Add at least one high-quality image to every product page so shoppers can see what they're buying and Google can surface your products in Image Search.

On Squarespace

  1. In your Squarespace admin, go to Commerce → Inventory (or Pages → your Store page, then click the product).
  2. Click the product that is missing images to open the product editor.
  3. In the 'Images' section, click the '+' icon or drag and drop image files to upload them.
  4. Click on each uploaded image and use the 'Filename' or image caption field to add a descriptive name; for alt text, click the image, then the pencil icon, and fill in the 'Alt Text' field.
  5. Click 'Save' and view the live product page to confirm images are displaying.
Code · Generic HTML (html)
<figure class="product-gallery">
  <img
    src="/images/products/black-leather-wallet-front.jpg"
    alt="Black leather wallet with RFID blocking, front view"
    width="800"
    height="800"
    loading="eager"
  />
  <img
    src="/images/products/black-leather-wallet-open.jpg"
    alt="Black leather wallet open showing card slots and cash pocket"
    width="800"
    height="800"
    loading="lazy"
  />
</figure>

Basic responsive product image with descriptive alt text — place inside your product page HTML where the gallery/main image appears.

Seo product no spec tableModerate effort

Add a structured specifications table or list to every product page so shoppers, search engines, and AI tools can instantly find and use key product details.

On Squarespace

  1. Open the product in your Squarespace store editor (Commerce → Inventory → select product).
  2. In the product editor, click into the description area and place your cursor where you want the spec table.
  3. Click the '+' block inserter → choose 'Markdown' or 'Code' block and paste your HTML table markup directly.
  4. Alternatively, use the built-in table option if your Squarespace version supports it: click '+' → 'Table', then fill in rows for each spec.
  5. For consistent branding, add custom CSS via Website → Pages → Website Tools → Custom CSS to style the table (e.g. alternating row colours).
  6. Save the product and preview on mobile using Squarespace's device preview toggle.
Seo product price not in htmlModerate effort

Render your product price in the server-generated HTML so Google and other crawlers can read it directly — without executing JavaScript.

On Squarespace

  1. Squarespace Commerce product pages are server-rendered and prices are output in static HTML by default. If the price is missing from source, a custom code block or third-party script is likely replacing it.
  2. Go to Pages → your product page → Edit. Remove or inspect any Custom Code blocks (Insert Point → Code Block) that manipulate the price element via JavaScript.
  3. For structured data, Squarespace automatically generates JSON-LD Product markup including price for Commerce product pages. Confirm by using Google's Rich Results Test on a live product URL.
  4. If you have injected custom code via Settings → Advanced → Code Injection, review that code to ensure it does not defer or replace price rendering.
Seo product single imageModerate effort

Add at least 4 product images (multiple angles, detail shots, and lifestyle/in-use photos) to every product page to improve click-through rates, conversions, and Google Images visibility.

On Squarespace

  1. Go to Commerce → Inventory (or Pages → [your shop page]) → [select your product].
  2. In the product editor, click the image area and then the '+' icon to add more images to the gallery.
  3. Upload your additional product images — Squarespace supports multiple images per product as a carousel.
  4. To add alt text: hover over any image in the editor → click the pencil icon → click 'Edit' → enter alt text in the 'Alt Text' field.
  5. Click 'Save' to publish the updated product gallery.
Code · Generic HTML (html)
<figure class="product-gallery">
  <!-- Main hero image -->
  <img
    src="/images/red-leather-wallet-front.webp"
    alt="Red leather bifold wallet — front view"
    width="2000"
    height="2000"
    loading="eager"
    fetchpriority="high"
  />
</figure>

<!-- Thumbnail strip -->
<ul class="product-thumbnails" role="list">
  <li>
    <img
      src="/images/red-leather-wallet-front-thumb.webp"
      alt="Red leather bifold wallet — front view"
      width="200"
      height="200"
      loading="lazy"
    />
  </li>
  <li>
    <img
      src="/images/red-leather-wallet-back-thumb.webp"
      alt="Red leather bifold wallet — back view"
      width="200"
      height="200"
      loading="lazy"
    />
  </li>
  <li>
    <img
      src="/images/red-leather-wallet-interior-thumb.webp"
      alt="Red leather bifold wallet — interior card slots"
      width="200"
      height="200"
      loading="lazy"
    />
  </li>
  <li>
    <img
      src="/images/red-leather-wallet-lifestyle-thumb.webp"
      alt="Red leather bifold wallet shown in a shirt pocket"
      width="200"
      height="200"
      loading="lazy"
    />
  </li>
</ul>

Basic accessible product image gallery markup. Place inside your product detail page template.

Seo product title genericModerate effort

Rewrite every product page title tag to include the specific product name plus at least one differentiating attribute (variant, material, brand, or model) so Google and shoppers can instantly tell what the page is about.

On Squarespace

  1. Open your Squarespace dashboard and go to Commerce → Products (or Pages → [Your Shop Page]).
  2. Click the product you want to edit.
  3. Select the 'SEO' tab within the product editor panel.
  4. Update the 'SEO Title' field with your descriptive title.
  5. Click Save. Squarespace does not currently offer a bulk product SEO title editor, so each product must be updated individually or via the Squarespace API.
  6. To verify, preview the page and check the browser tab or use a browser extension to inspect the <title> tag.
Code · Generic HTML (html)
<head>
  <title>Magnetic Card Holder Phone Mount – MagSafe Compatible – BrandName</title>
  <meta name="description" content="Attach your cards securely to any MagSafe-compatible iPhone with BrandName's slim magnetic card holder mount. Holds 1–3 cards. Available in black and white.">
</head>

Place inside the <head> section of every product page. Follow the pattern: Product Name – Key Attribute – Brand.

Seo variant urls in sitemapModerate effort

Remove product variant URLs (e.g. ?variant= or ?sku= query strings) from your XML sitemap and keep only the canonical base product URL for each product.

On Squarespace

  1. Squarespace automatically generates a sitemap at yoursite.com/sitemap.xml and controls its contents — you cannot manually edit it.
  2. Go to Pages → click the gear icon on each product page → SEO tab → ensure 'SEO Visibility' is enabled (not hidden), which lets the canonical page appear in the sitemap.
  3. Squarespace Commerce variant URLs (e.g. ?variant=) are not included in the native sitemap — if you see them, a third-party integration or script may be injecting them.
  4. Check any connected marketing or SEO apps in Extensions and disable sitemap customization features that add query-string URLs.
  5. Re-submit your sitemap in Google Search Console to trigger a fresh crawl.
Code · Generic HTML (xml)
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">

  <!-- CORRECT: canonical base product URL -->
  <url>
    <loc>https://www.example.com/products/blue-sneaker</loc>
    <lastmod>2024-06-01</lastmod>
    <changefreq>weekly</changefreq>
    <priority>0.8</priority>
  </url>

  <!-- WRONG — never include variant query strings:
  <url>
    <loc>https://www.example.com/products/blue-sneaker?variant=12345</loc>
  </url>
  <url>
    <loc>https://www.example.com/products/blue-sneaker?sku=blue-large</loc>
  </url>
  -->

</urlset>

Correct sitemap entry — clean base product URL only, no query parameters.

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 on one URL instead of splitting them across hundreds of duplicates.

On Squarespace

  1. Squarespace automatically outputs canonical tags on product pages pointing to the base product URL. Native product variants (size, colour, etc.) do not generate separate URLs in Squarespace — they are selected client-side, so canonical fragmentation is rare.
  2. If you have added custom URL parameters via scripts or third-party integrations, go to Pages → your product page → gear icon (Page Settings) → Advanced → Page Header Code Injection and add a manual canonical tag: <link rel="canonical" href="https://www.yourdomain.com/shop/your-product-slug">
  3. Squarespace does not allow full theme-file editing, so the code injection box is the correct location for any custom canonical overrides.
  4. Verify by using View Source on the product page and searching for 'canonical' to confirm only one canonical tag is present and it points to the correct base URL.
Code · Squarespace (html)
<head>
  <!-- Squarespace Product Page: override canonical if custom params are being used -->
  <link rel="canonical" href="https://www.example.com/shop/your-product-slug">
</head>

Paste into the individual product page → Page Settings → Advanced → Page Header Code Injection. Replace the URL with your actual product URL.

Server errorModerate effort

Identify and fix every page returning an HTTP 5xx server error so search engines can crawl and index those URLs again.

On Squarespace

  1. Squarespace manages all server infrastructure, so a true 5xx on a native page is a platform issue — contact Squarespace Support via Help > Contact Us immediately, providing the exact URL and time of the error.
  2. If the error is on a page with a Code Block or Code Injection, go to Pages > [Page] > Edit > click the code block and remove or correct the custom HTML/JS/CSS — bad injected code can cause rendering failures.
  3. Check Settings > Advanced > Code Injection for any site-wide injected scripts that might be causing conflicts and temporarily remove them to test.
  4. For pages connected to external APIs via Squarespace Extensions, go to Extensions > [Extension] and check its connection status.
  5. After the fix, submit the URL via Google Search Console > URL Inspection > Request Indexing.
Code · Generic HTML (html)
# Run this in your terminal to check the HTTP status code of any URL
curl -o /dev/null -s -w "HTTP Status: %{http_code}\n" https://www.example.com/your-page

# A healthy page returns:
# HTTP Status: 200

# A broken page returns (example):
# HTTP Status: 500

This is the correct HTTP 200 response header your server should return for a healthy page. Use curl on the command line to verify any URL's status code before and after your fix.

Slow pageModerate effort

Reduce your page load time to under 3 seconds by compressing images, eliminating render-blocking scripts and styles, and improving server response speed.

On Squarespace

  1. Go to Pages → select a page → click the gear icon → SEO tab — review page-level settings, then run the page through Google PageSpeed Insights for specific guidance.
  2. Images: When uploading images, pre-compress them to under 500 KB using a tool like Squoosh (squoosh.app) before uploading — Squarespace does not allow post-upload compression. Use Squarespace's built-in lazy loading (enabled by default on 7.1).
  3. In Design → Custom CSS, remove any unused CSS rules you or a designer have added.
  4. Extensions: Go to Extensions in your Squarespace dashboard and uninstall any extension not in active use.
  5. Remove third-party embed codes (Settings → Advanced → Code Injection) that are no longer needed — each external script is a network request.
  6. Squarespace handles CDN, GZIP, and HTTP/2 automatically. Your primary levers are image sizes, custom code injections, and page-level content complexity.
Code · Squarespace (html)
<!-- Defer a third-party script to prevent it blocking render -->
<script>
  window.addEventListener('load', function() {
    var s = document.createElement('script');
    s.src = 'https://third-party-service.com/widget.js';
    s.async = true;
    document.head.appendChild(s);
  });
</script>

Paste into Settings → Advanced → Code Injection → Header to defer a third-party script. Replace the src value with your actual script URL.

Thin contentModerate effort

Add meaningful, original written content to pages that contain fewer than 300 words so Google has enough substance to rank and display them confidently.

On Squarespace

  1. Open Squarespace and navigate to the page you want to edit. Click 'Edit' to enter the page editor.
  2. Click on an existing text block or click the '+' insert point to add a new Text block. Write your expanded content here — for product pages this should include detailed descriptions, features, specs, and FAQs.
  3. For Squarespace Commerce product pages: Commerce → Products → click the product → expand the 'Description' tab and write a full description in the rich-text editor. You can also add additional content blocks below the product form using the page layout editor.
  4. For category/tag landing pages in Squarespace, navigate to that page in the editor and add a text block at the top or bottom of the product list.
  5. Save and preview on desktop and mobile to confirm text is visible.
Code · Generic HTML (html)
<section class="product-description">
  <h2>About This Product</h2>
  <p>
    The Merino Wool Crew-Neck Sweater is crafted from 100% ethically sourced
    Grade-A Merino wool, making it naturally temperature-regulating, moisture-
    wicking, and soft enough to wear directly against the skin. Perfect for
    layering in autumn and winter, or as a standalone piece during mild spring
    evenings.
  </p>

  <h3>Key Features</h3>
  <ul>
    <li>100% Merino wool — no synthetic blends</li>
    <li>Available in sizes XS–3XL with a relaxed, unisex fit</li>
    <li>12 colours, each piece individually yarn-dyed for depth</li>
    <li>Ribbed cuffs and hem for a tailored finish</li>
    <li>Machine washable on a gentle 30°C wool cycle</li>
    <li>Certified by the Responsible Wool Standard (RWS)</li>
  </ul>

  <h3>Sizing &amp; Fit</h3>
  <p>
    This sweater is cut with a relaxed, slightly oversized silhouette. If you
    prefer a closer fit, we recommend sizing down. See our full <a href="/size-guide">size guide</a>
    for chest, waist, and sleeve measurements.
  </p>

  <h3>Care Instructions</h3>
  <p>
    Machine wash cold on a gentle/wool cycle. Lay flat to dry — do not tumble
    dry, iron at high heat, or dry-clean. With proper care, Merino wool retains
    its shape and softness for years.
  </p>

  <h3>Frequently Asked Questions</h3>
  <dl>
    <dt>Is Merino wool itchy?</dt>
    <dd>
      No. Merino fibres are finer than standard wool (under 19.5 microns),
      which means they bend against the skin rather than prick it, making this
      sweater comfortable even for people who normally find wool irritating.
    </dd>
    <dt>How does Merino wool compare to cashmere?</dt>
    <dd>
      Merino is more durable and easier to care for than cashmere, while still
      offering exceptional softness. It's an ideal everyday choice for those
      who want luxury without high maintenance.
    </dd>
    <dt>Can I return or exchange this item?</dt>
    <dd>
      Yes. We accept returns and exchanges within 30 days of delivery, provided
      the item is unworn and in its original packaging. See our
      <a href="/returns">returns policy</a> for full details.
    </dd>
  </dl>
</section>

Example of a well-structured, content-rich product description section with FAQ — paste into any HTML page template.

Title too longQuick win

Shorten your page title tag to 60 characters or fewer so it displays fully — without truncation — in Google search results.

On Squarespace

  1. For regular pages: in the Pages panel, hover over the page, click the gear icon (⚙) to open Page Settings, select the 'SEO' tab, and edit the 'SEO Title' field.
  2. For products (Squarespace Commerce): go to Commerce → Inventory (or your Products page), open the product, click the 'SEO' tab in the product editor, and edit 'SEO Title'.
  3. For the homepage: go to Pages → Homepage → gear icon → SEO tab → SEO Title.
  4. Keep titles ≤60 characters and click Save.
Code · Generic HTML (html)
<head>
  <meta charset="UTF-8">
  <title>Running Shoes for Men | YourBrand</title>
</head>

Place inside the <head> element of every HTML page. Keep the total character count at or under 60.

Title too shortQuick win

Expand your page title to between 30 and 60 characters so Google displays it fully in search results and shoppers can immediately understand what the page is about.

On Squarespace

  1. For a regular page: open the Pages panel → hover over the page → click the gear icon (Page Settings) → select the 'SEO' tab → update the 'SEO Title' field.
  2. For a product page: go to Commerce → Inventory → select the product → click the 'SEO' tab in the product editor → update the 'SEO Title'.
  3. For the homepage: go to Pages → hover over the homepage → gear icon → SEO tab → update 'SEO Title'. If left blank, Squarespace uses the page title — so always fill in the SEO Title explicitly.
  4. For blog posts: open the blog post → click the gear icon → SEO tab → update 'SEO Title'.
  5. Squarespace does not show a live character counter in the editor; use an external title-preview tool to check length before saving.
Code · Generic HTML (html)
<head>
  <meta charset="UTF-8">
  <title>Men's Merino Wool Beanies – BrandName</title>
</head>

Place inside the <head> element of every page. Replace the example with your actual descriptive title (30–60 chars).

Answer Engine Optimization · 17 fixes

Aeo schema client renderedModerate effort

Move your JSON-LD structured data from client-side JavaScript injection to server-rendered HTML so that AI crawlers and search engines can read it in the raw page source.

On Squarespace

  1. In your Squarespace admin go to Settings → Advanced → Code Injection.
  2. Paste your complete <script type="application/ld+json">…</script> block into the 'Header' field — this is injected server-side into the <head> of every page.
  3. For page-specific schema (e.g., individual product pages), use a Code Block injected into that page's content area — note this is also server-rendered HTML, not JavaScript.
  4. Squarespace Commerce automatically outputs some Product schema server-side; to extend or replace it, use Code Injection rather than any third-party JavaScript snippet.
  5. View page source to confirm the JSON-LD block appears without needing to run JavaScript.
Code · Squarespace (html)
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Store",
  "name": "Your Store Name",
  "url": "https://www.example.com",
  "description": "A short description of your store.",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "123 Main St",
    "addressLocality": "Your City",
    "addressRegion": "CA",
    "postalCode": "90210",
    "addressCountry": "US"
  },
  "contactPoint": {
    "@type": "ContactPoint",
    "contactType": "customer service",
    "email": "hello@example.com"
  }
}
</script>

Paste into Settings → Advanced → Code Injection → Header. This is rendered server-side by Squarespace for every page. For page-specific schema, add a Code Block to that page.

Article missing authorQuick win

Add a structured-data author field (schema.org Person) to every article or blog post so AI engines and Google can identify and trust who wrote the content.

On Squarespace

  1. Squarespace automatically outputs some Article structured data for Blog posts using the post author's display name.
  2. To enrich author data: go to Settings → Permissions → click the author → ensure their display name and bio are complete.
  3. To add sameAs or a full Person block, inject custom JSON-LD via Settings → Advanced → Code Injection → Page Header (note: this applies globally; for per-post injection you need a Business plan or higher).
  4. On Business/Commerce plans, you can also add a Code Block to individual blog posts and paste the JSON-LD there, though a <script> tag in a code block may be stripped — use the Header Code Injection field per page instead.
  5. Validate with the Rich Results Test.
Code · Generic HTML (html)
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  "headline": "How to Choose the Best Running Shoes",
  "datePublished": "2024-03-10T09:00:00+00:00",
  "dateModified": "2024-06-20T14:00:00+00:00",
  "author": {
    "@type": "Person",
    "name": "Alex Johnson",
    "url": "https://www.yourstore.com/about/alex-johnson",
    "sameAs": [
      "https://www.linkedin.com/in/alexjohnson",
      "https://twitter.com/alexjohnson"
    ]
  },
  "publisher": {
    "@type": "Organization",
    "name": "Your Store Name",
    "logo": {
      "@type": "ImageObject",
      "url": "https://www.yourstore.com/assets/logo.png",
      "width": 300,
      "height": 60
    }
  },
  "mainEntityOfPage": {
    "@type": "WebPage",
    "@id": "https://www.yourstore.com/blog/how-to-choose-running-shoes"
  }
}
</script>

For any static site or custom CMS: paste inside the <head> of each article page and fill in real values.

Faq schema not visibleModerate effort

Render all FAQ answers in the server-delivered HTML so that both Google and your FAQ structured data can see every question and answer — not just the one currently open in a JavaScript accordion.

On Squarespace

  1. In your Squarespace dashboard, go to Pages → your FAQ page → Edit.
  2. If you are using an Accordion block, note that Squarespace Accordion blocks render all panel content in the HTML (they use CSS to show/hide) — confirm by checking page source for the answer text. If it is present, the visibility issue is already resolved.
  3. For FAQ structured data, go to Pages → FAQ page → Page Settings (gear icon) → Advanced → Page Header Code Injection and paste your FAQPage JSON-LD <script> block there.
  4. Ensure every question/answer in the JSON-LD exactly matches the text in the Accordion blocks on the page.
  5. Validate with the Rich Results Test.
Code · Squarespace (html)
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "What is your return policy?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "We accept returns within 30 days of purchase. Items must be unused and in original packaging."
      }
    },
    {
      "@type": "Question",
      "name": "How long does shipping take?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Standard shipping takes 3–5 business days. Express shipping (1–2 business days) is available at checkout."
      }
    },
    {
      "@type": "Question",
      "name": "Do you ship internationally?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Yes, we ship to over 40 countries. International orders typically arrive within 7–14 business days."
      }
    },
    {
      "@type": "Question",
      "name": "Can I change or cancel my order?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Orders can be changed or cancelled within 1 hour of placement. After that, please use our return process."
      }
    }
  ]
}
</script>

Paste into Pages → FAQ page → Page Settings → Advanced → Page Header Code Injection. Update question/answer text to match your Accordion blocks exactly.

Invalid rating valueModerate effort

Fix the AggregateRating.ratingValue in your structured data so it is a valid number between 1 and 5 (or your declared scale's minimum and maximum).

On Squarespace

  1. Squarespace automatically generates product structured data including AggregateRating. If you see an invalid ratingValue it is most likely caused by a Code Injection block containing custom JSON-LD that overrides or conflicts with Squarespace's native output.
  2. Go to Settings → Advanced → Code Injection (site-wide) and Pages → (individual page) → Advanced → Page Header Code Injection. Search for any JSON-LD blocks containing 'ratingValue' and correct or remove them.
  3. If you have a third-party reviews block or app embedded on product pages, check its documentation for a 'rich snippets' or 'structured data' setting — disable it if Squarespace's native schema is already active.
  4. Squarespace's native AggregateRating is only output when there are actual published reviews on the product; no fix is needed beyond ensuring reviews are present and approved.
  5. After any code injection changes, use the Google Rich Results Test on the product URL to confirm the structured data is valid.
Low answer first scoreModerate effort

Restructure page content to lead with a direct, concise answer, use question-format headings, and add FAQ structured data so search engines and AI assistants can surface your answers prominently.

On Squarespace

  1. Pages → click the page → hover over the first content block and click Edit.
  2. Write the 160-character answer summary as the first Text block and move it to the very top of the page layout if needed (drag the block handle).
  3. For subheadings: in each Text block, highlight the heading text, change the style to Heading 2 or Heading 3, and rewrite the copy as a question.
  4. Add FAQ schema: go to Pages → select the page → click the gear icon (Page Settings) → Advanced → Code Injection → paste the FAQPage JSON-LD script into the 'Page Header' or 'Footer' box.
  5. Squarespace 7.1 also supports the built-in Accordion block (Add Block → Accordion) which visually renders a Q&A section; you still need to add JSON-LD via Code Injection manually.
  6. Verify by entering your page URL in Google's Rich Results Test.
Code · Generic HTML (html)
<!-- Answer-first page structure template -->

<!-- 1. Direct-answer summary (≤160 characters) -->
<p class="answer-summary">
  [Product Name] does [core benefit] by [key mechanism] — ideal for [target customer].
</p>

<!-- 2. Question-format H2 subheading -->
<h2>What does [Product Name] do?</h2>
<p>Direct 1–2 sentence answer here. Then expand with supporting detail below.</p>

<!-- 3. Another question-format heading -->
<h2>Who is [Product Name] designed for?</h2>
<p>Direct answer. Then elaborate.</p>

<!-- 4. FAQ section (visible on page — required for FAQPage schema) -->
<section id="faq">
  <h2>Frequently Asked Questions</h2>

  <h3>How long does shipping take?</h3>
  <p>Standard shipping takes 3–5 business days. Express options are available at checkout.</p>

  <h3>What is your return policy?</h3>
  <p>We accept returns within 30 days of delivery on unused items in original packaging.</p>

  <h3>Is [Product Name] compatible with [common concern]?</h3>
  <p>Yes. [One-sentence direct answer with any important caveats.]</p>
</section>

<!-- 5. FAQPage JSON-LD (copy the JSON-LD snippet above and paste here or in <head>) -->

Page content structure template — place this as the opening content block on any product, category, or landing page.

Low review countModerate effort

Collect at least 5 published reviews so Google will display star ratings in search results alongside your product listings.

On Squarespace

  1. Squarespace Commerce has a built-in product review feature. Enable it under Pages → [your product page] → product settings → Reviews tab → toggle 'Accept Reviews' on.
  2. To prompt customers automatically, go to Commerce → Customer Notifications and enable the 'Review Request' email, setting the delay after fulfilment.
  3. Squarespace automatically adds AggregateRating schema to product pages once reviews are present — no manual coding required.
  4. Because Squarespace does not natively support review imports, collect reviews organically or use a third-party review widget (e.g. Elfsight Reviews) that injects its own structured data.
  5. After reaching 5 reviews, validate with Google's Rich Results Test to confirm the 'aggregateRating' block is visible.
Code · Generic HTML (html)
<!-- Product structured data with AggregateRating -->
<!-- Note: Google will only show review stars when reviewCount >= 5 -->
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Your Product Name",
  "image": [
    "https://example.com/images/product-front.jpg",
    "https://example.com/images/product-side.jpg"
  ],
  "description": "A clear, accurate description of your product.",
  "sku": "SKU-12345",
  "mpn": "MPN-12345",
  "brand": {
    "@type": "Brand",
    "name": "Your Brand"
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.5",
    "reviewCount": "12",
    "bestRating": "5",
    "worstRating": "1"
  },
  "offers": {
    "@type": "Offer",
    "url": "https://example.com/products/your-product",
    "priceCurrency": "USD",
    "price": "49.99",
    "priceValidUntil": "2026-12-31",
    "itemCondition": "https://schema.org/NewCondition",
    "availability": "https://schema.org/InStock",
    "seller": {
      "@type": "Organization",
      "name": "Your Store Name"
    }
  }
}
</script>

Drop this complete block into the <head> section of any product page. Swap in your real values for name, image, SKU, price, ratingValue, and reviewCount.

Missing schema articleModerate effort

Add Article schema markup (JSON-LD) to every blog post and editorial page so Google can identify and rich-result-enhance your content in search.

On Squarespace

  1. Go to Settings → Advanced → Code Injection → 'Page Header' section — note this injects into ALL pages, so you will need conditional logic or use per-page injection instead.
  2. For per-post injection: open the Blog page, click a specific post to edit it, then go to the post Settings (gear icon) → Advanced → 'Post Header Code Injection', and paste the JSON-LD script block there with values filled in for that post.
  3. For a sitewide automated approach, Squarespace 7.1 injects some Article schema automatically for blog posts; verify by running a blog post URL through the Rich Results Test — if it is missing or incomplete, use the per-post injection method above.
  4. Validate with the Rich Results Test after saving.
Code · Generic HTML (html)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>How to Choose the Right Running Shoes</title>
  <script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "BlogPosting",
    "headline": "How to Choose the Right Running Shoes",
    "description": "A complete guide to selecting running shoes based on your gait, terrain, and training goals.",
    "image": {
      "@type": "ImageObject",
      "url": "https://www.example.com/images/running-shoes-guide.jpg",
      "width": 1200,
      "height": 630
    },
    "author": {
      "@type": "Person",
      "name": "Jane Smith",
      "url": "https://www.example.com/authors/jane-smith"
    },
    "publisher": {
      "@type": "Organization",
      "name": "Example Store",
      "logo": {
        "@type": "ImageObject",
        "url": "https://www.example.com/logo.png",
        "width": 250,
        "height": 60
      }
    },
    "datePublished": "2024-03-15",
    "dateModified": "2024-06-01",
    "mainEntityOfPage": {
      "@type": "WebPage",
      "@id": "https://www.example.com/blog/how-to-choose-running-shoes"
    },
    "url": "https://www.example.com/blog/how-to-choose-running-shoes"
  }
  </script>
</head>
<body>
  <!-- page content -->
</body>
</html>

Place this entire block inside the <head> element of any article or blog-post page. Fill in all values before publishing.

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 Squarespace

  1. In the Squarespace admin, go to Website › Pages › select the page, then click the gear icon › Advanced › Page Header Code Injection.
  2. Paste the complete JSON-LD script block into the Code Injection field — Squarespace inserts this into the <head> for that specific page.
  3. For site-wide injection, go to Settings › Advanced › Code Injection and paste the JSON-LD in the Header field (this adds it to every page; use conditional JavaScript to render the correct breadcrumb per page type).
  4. Squarespace 7.1 Commerce pages: use the store's built-in SEO fields where available, or rely on the Code Injection method above for product and category pages.
  5. Validate with Google's Rich Results Test.
Code · Generic HTML (json)
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    {
      "@type": "ListItem",
      "position": 1,
      "name": "Home",
      "item": "https://www.example.com/"
    },
    {
      "@type": "ListItem",
      "position": 2,
      "name": "Women's Clothing",
      "item": "https://www.example.com/womens-clothing/"
    },
    {
      "@type": "ListItem",
      "position": 3,
      "name": "Dresses",
      "item": "https://www.example.com/womens-clothing/dresses/"
    },
    {
      "@type": "ListItem",
      "position": 4,
      "name": "Blue Wrap Dress",
      "item": "https://www.example.com/womens-clothing/dresses/blue-wrap-dress/"
    }
  ]
}
</script>

Place this <script> block inside <head> or anywhere in <body> on any page with a breadcrumb trail. Extend itemListElement with one ListItem per level.

Missing schema faqpageQuick win

Add FAQPage schema markup to any page that contains a Frequently Asked Questions section so Google can display your answers as rich results directly in search.

On Squarespace

  1. In your Squarespace dashboard, go to Settings → Advanced → Code Injection.
  2. Paste your JSON-LD <script> block into the 'Header' field for site-wide injection — OR, for a single page, open the page editor, click the gear icon (Page Settings) → Advanced tab → paste the script into the 'Page Header Code Injection' field (available on Business plan and above).
  3. Click Save and publish.
  4. Note: Per-page code injection requires a Business or Commerce plan; if on Personal plan, the site-wide Header injection is the only option.
  5. Validate with Google's Rich Results Test.
Code · Generic HTML (html)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Frequently Asked Questions | Your Store</title>
  <script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "FAQPage",
    "mainEntity": [
      {
        "@type": "Question",
        "name": "What is your return policy?",
        "acceptedAnswer": {
          "@type": "Answer",
          "text": "We accept returns within 30 days of purchase. Items must be unused and in their original packaging."
        }
      },
      {
        "@type": "Question",
        "name": "How long does shipping take?",
        "acceptedAnswer": {
          "@type": "Answer",
          "text": "Standard shipping takes 5–7 business days. Expedited options are available at checkout."
        }
      }
    ]
  }
  </script>
</head>
<body>
  <h1>Frequently Asked Questions</h1>
  <h2>What is your return policy?</h2>
  <p>We accept returns within 30 days of purchase. Items must be unused and in their original packaging.</p>
  <h2>How long does shipping take?</h2>
  <p>Standard shipping takes 5–7 business days. Expedited options are available at checkout.</p>
</body>
</html>

Full HTML page example showing exactly where to place the FAQPage script block inside the <head>.

Missing schema howtoModerate effort

Add HowTo structured data (JSON-LD) to any page that walks customers through a multi-step process, so Google can display your instructions as rich results in search.

On Squarespace

  1. In your Squarespace admin, go to Settings > Advanced > Code Injection for site-wide injection, OR open the specific page > Page Settings > Advanced > Page Header Code Injection for page-level injection (preferred).
  2. Paste your complete <script type='application/ld+json'> HowTo block into the Header Code Injection box for that page.
  3. Save and publish, then validate the live URL with Google's Rich Results Test.
  4. Note: Code Injection is available on Business plan and above.
Code · Generic HTML (html)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>How to Complete Your Task | Your Store</title>
  <script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "HowTo",
    "name": "How to Complete Your Task",
    "description": "Follow these steps to complete your task easily.",
    "totalTime": "PT10M",
    "step": [
      {
        "@type": "HowToStep",
        "position": 1,
        "name": "Prepare your materials",
        "text": "Gather everything you need before you start: list materials here."
      },
      {
        "@type": "HowToStep",
        "position": 2,
        "name": "Complete the main action",
        "text": "Describe exactly what the user should do in this core step."
      },
      {
        "@type": "HowToStep",
        "position": 3,
        "name": "Verify the result",
        "text": "Explain how the user confirms the task was completed successfully."
      }
    ]
  }
  </script>
</head>
<body>
  <!-- Your how-to page content -->
</body>
</html>

Place this block inside the <head> element of any static HTML page that contains step-by-step instructions.

Missing schema localbusinessQuick win

Add LocalBusiness JSON-LD structured data to your store so search engines and AI answer engines can surface your business name, address, phone number, and hours in rich results and direct answers.

On Squarespace

  1. In your Squarespace admin, go to Settings → Advanced → Code Injection.
  2. Paste your complete JSON-LD <script> block into the 'Header' field — this injects it site-wide into the <head> on every page.
  3. Click 'Save'.
  4. For page-specific injection (e.g. homepage only), open the Pages panel, click the gear icon on the target page, go to Advanced → Page Header Code Injection, and paste the block there.
  5. Publish and validate with Google's Rich Results Test.
Code · Generic HTML (html)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Your Store</title>
  <script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "Store",
    "name": "Your Business Name",
    "url": "https://www.yourdomain.com",
    "logo": "https://www.yourdomain.com/logo.png",
    "address": {
      "@type": "PostalAddress",
      "streetAddress": "123 Main Street",
      "addressLocality": "Springfield",
      "addressRegion": "IL",
      "postalCode": "62701",
      "addressCountry": "US"
    },
    "telephone": "+1-217-555-0100",
    "openingHoursSpecification": [
      {
        "@type": "OpeningHoursSpecification",
        "dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
        "opens": "09:00",
        "closes": "18:00"
      }
    ]
  }
  </script>
</head>
<body>
  <!-- page content -->
</body>
</html>

Paste this block anywhere inside the <head> element of your HTML page. Replace all placeholder values before deploying.

Missing schema organizationQuick win

Add an Organization schema markup block to your store's homepage (and/or sitewide template) so search engines and AI assistants can definitively identify your brand.

On Squarespace

  1. In your Squarespace dashboard, go to Settings → Advanced → Code Injection.
  2. Paste your complete <script type='application/ld+json'>…</script> Organization block into the 'Header' field.
  3. Click Save. Squarespace injects this into the <head> of every page sitewide.
  4. Verify using the Rich Results Test on your live site URL.
Code · Generic HTML (html)
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Organization",
  "name": "Acme Store",
  "url": "https://www.acmestore.com",
  "logo": {
    "@type": "ImageObject",
    "url": "https://www.acmestore.com/images/logo.png",
    "width": 250,
    "height": 250
  },
  "sameAs": [
    "https://www.facebook.com/acmestore",
    "https://www.instagram.com/acmestore",
    "https://twitter.com/acmestore",
    "https://www.linkedin.com/company/acmestore",
    "https://www.youtube.com/c/acmestore"
  ],
  "contactPoint": {
    "@type": "ContactPoint",
    "contactType": "customer service",
    "email": "hello@acmestore.com"
  }
}
</script>

Drop this complete block inside your <head>…</head> section on every page. Replace all placeholder values.

Missing schema productModerate effort

Add Product schema markup (JSON-LD) to every product page so search engines can display rich results — including price, availability, and ratings — directly in search.

On Squarespace

  1. Squarespace Commerce automatically outputs basic Product schema for store products — confirm this is present using Google's Rich Results Test on a product URL.
  2. To inject enhanced or additional schema fields not natively supported, go to your Page Settings for the product page → Advanced → 'Page Header Code Injection' and paste your custom JSON-LD block there.
  3. For site-wide product schema injection on all product pages, go to Settings → Advanced → 'Code Injection' → Header, and use a conditional approach if your template supports it.
  4. Validate with Google's Rich Results Test after saving.
Missing schema webpageModerate effort

Add WebPage schema markup to every page so search engines and AI answer engines can precisely understand and describe your content.

On Squarespace

  1. In your Squarespace dashboard, go to Settings → Advanced → Code Injection.
  2. Paste your WebPage JSON-LD <script> block into the 'Header' injection field — this applies it site-wide to every page.
  3. To make the schema dynamic (different title/description per page), you'll need to use a static fallback or consider a per-page approach: on individual pages, go to Pages → click the gear icon for a specific page → Advanced → Page Header Code Injection, and paste the page-specific JSON-LD there.
  4. Squarespace does not natively support Liquid/Handlebars variables in code injection fields, so either use static JSON-LD per page or use a third-party SEO app from the Squarespace Extensions marketplace (e.g., 'SEOSpace') that automates schema generation.
  5. Validate injected schema using the Rich Results Test on your live Squarespace domain.
Code · Generic HTML (html)
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "WebPage",
  "name": "About Us | Acme Store",
  "description": "Learn about Acme Store, our mission, and the team behind our products.",
  "url": "https://www.example.com/about/",
  "inLanguage": "en-US",
  "datePublished": "2022-01-15",
  "dateModified": "2024-06-01",
  "isPartOf": {
    "@type": "WebSite",
    "name": "Acme Store",
    "url": "https://www.example.com/"
  },
  "breadcrumb": {
    "@type": "BreadcrumbList",
    "itemListElement": [
      {
        "@type": "ListItem",
        "position": 1,
        "name": "Home",
        "item": "https://www.example.com/"
      },
      {
        "@type": "ListItem",
        "position": 2,
        "name": "About Us",
        "item": "https://www.example.com/about/"
      }
    ]
  }
}
</script>

Paste this inside the <head> element of any HTML page. Replace all placeholder values with real page data.

Non iso dateQuick win

Change every datePublished (and dateModified) value in your structured data from a human-readable string to a strict ISO-8601 date — formatted as YYYY-MM-DD or YYYY-MM-DDThh:mm:ss+hh:mm — so search engines can reliably parse your content's freshness.

On Squarespace

  1. Squarespace auto-generates schema for Blog Posts with ISO-8601 dates from the post's publish date — verify the post's publish date is set correctly in the blog post editor (Posts → click post → gear icon → Publish Date).
  2. If you have injected custom JSON-LD via Settings → Advanced → Code Injection (site-wide header) or a Page Header Code Injection block, locate the date fields in that code.
  3. Update any non-ISO date strings to YYYY-MM-DD or YYYY-MM-DDThh:mm:ss+hh:mm format.
  4. Squarespace does not expose Liquid/template variables in Code Injection, so dates in custom JSON-LD blocks must be updated manually or via a connected tool.
  5. Save changes and validate the page with Google's Rich Results Test.
Code · Generic HTML (html)
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "Your Article Headline",
  "datePublished": "2025-03-12",
  "dateModified": "2025-03-12",
  "author": {
    "@type": "Person",
    "name": "Author Name"
  }
}
</script>

Minimum viable JSON-LD block to paste into any HTML <head> — replace values with your own.

Org missing sameasQuick win

Add a `sameAs` array to your Organization schema, linking to your verified social profiles, Wikipedia page, LinkedIn, and other authoritative sources so search engines can confidently identify your brand as a known entity.

On Squarespace

  1. In the Squarespace Admin, go to Settings → Advanced → Code Injection.
  2. Paste the Organization JSON-LD block (with sameAs) into the Header code injection field.
  3. Click Save. This injects the schema into the <head> of every page site-wide.
  4. View your live site's source to confirm sameAs is present, then validate with Google's Rich Results Test.
Code · Generic HTML (html)
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Organization",
  "name": "Your Brand Name",
  "url": "https://www.yourdomain.com",
  "logo": "https://www.yourdomain.com/images/logo.png",
  "sameAs": [
    "https://www.linkedin.com/company/your-company",
    "https://www.facebook.com/yourpage",
    "https://twitter.com/yourhandle",
    "https://www.instagram.com/yourhandle",
    "https://www.youtube.com/@yourchannel",
    "https://en.wikipedia.org/wiki/Your_Brand",
    "https://www.wikidata.org/wiki/QXXXXXXX"
  ]
}
</script>

Paste this directly before the closing </head> tag in your HTML template. Remove any sameAs entries for platforms your brand does not have a presence on.

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 Squarespace

  1. In the Squarespace Pages panel, confirm the page is not in 'Draft' mode — click the page, look for the Draft badge, and click 'Publish'.
  2. Check Pages → (page) → Settings → SEO → ensure 'Hide page from search engines' (noindex) is NOT enabled.
  3. For store pages, go to Commerce → Inventory and confirm the product is set to 'Active' and not hidden.
  4. For 404 errors from old URLs, go to Settings → Developer Tools → URL Redirects (or Settings → Advanced → URL Mappings) and add a 301 redirect mapping the broken URL to the correct live page.
  5. To add custom structured data (JSON-LD), go to Pages → (page) → Settings → Advanced → Page Header Code Injection and paste your <script type='application/ld+json'> block. Note: Squarespace already generates some Product schema for Commerce products automatically.
  6. Re-test with Google Search Console URL Inspection and the Rich Results Test.

Accessibility (WCAG) · 66 fixes

Aria allowed attrModerate effort

Audit every element that uses ARIA attributes and ensure each attribute is permitted for that element's role — removing or correcting any mismatched aria-* attributes.

On Squarespace

  1. In the Squarespace editor, open Pages → click the page containing the flagged element.
  2. If the violation is in a Code Block or Code Injection (Settings → Advanced → Code Injection), locate the raw HTML you or a developer added and correct the aria-* attribute there.
  3. If the violation is in a Squarespace native section or block, it may be a platform bug; report it via Squarespace support with the exact element and attribute.
  4. For custom code added via Developer Mode or a custom template, open the template file in your code editor via the Developer Platform, find the flagged attribute, and correct it.
  5. Publish and re-run axe DevTools in the browser to verify the fix is live.
Code · Generic HTML (html)
<!-- WRONG: aria-checked is not allowed on role="button" -->
<div role="button" aria-checked="true">Toggle</div>

<!-- CORRECT option A: use a role that supports aria-checked -->
<div role="checkbox" aria-checked="true" tabindex="0">Toggle</div>

<!-- CORRECT option B: remove the unsupported attribute and use a native element -->
<button type="button" aria-pressed="true">Toggle</button>


<!-- WRONG: aria-expanded is not allowed on a <li> with no interactive role -->
<li aria-expanded="true">Menu Item</li>

<!-- CORRECT: put aria-expanded on the button that controls the submenu -->
<li>
  <button type="button" aria-expanded="true" aria-controls="submenu-1">Menu Item</button>
  <ul id="submenu-1">
    <li><a href="/page">Sub-page</a></li>
  </ul>
</li>


<!-- WRONG: aria-required on a <div> with no form-field role -->
<div aria-required="true">Enter your email</div>

<!-- CORRECT: aria-required belongs on the actual input, or use the native required attribute -->
<label for="email">Email <span aria-hidden="true">*</span></label>
<input type="email" id="email" name="email" required aria-required="true" />

Examples of invalid vs. corrected ARIA attribute usage for common patterns.

Aria allowed roleQuick win

Remove or replace any ARIA `role` attribute that is not permitted on the HTML element it is applied to — in particular, do not add `role="textbox"` (or other interactive roles) to elements that already have a native semantic role which conflicts with it.

On Squarespace

  1. Go to Pages → (your page) → Edit, and click on the block containing the flagged element.
  2. Squarespace blocks do not expose raw HTML for most native widgets. If the element is in a Code Block (Insert Block → Code), click Edit on that block and fix the `role` attribute directly in the HTML source.
  3. If the invalid role is in a Squarespace-generated widget (e.g. its built-in form or navigation), you can attempt to override it via Website → Pages → (page) → Advanced → Page Header Code Injection using JavaScript to remove the attribute after page load, or file a report with Squarespace support.
  4. Save and re-audit with WAVE or axe DevTools.
Code · Generic HTML (html)
<!-- ❌ WRONG: role="textbox" is not permitted on <select> -->
<select role="textbox" name="country">
  <option value="us">United States</option>
</select>

<!-- ✅ FIX A: Remove the invalid role — <select> already has the correct native semantics -->
<select name="country">
  <option value="us">United States</option>
</select>


<!-- ❌ WRONG: role="textbox" on a <div> with no keyboard/input handling -->
<div role="textbox" class="fake-input">Enter your name</div>

<!-- ✅ FIX B: Replace with a real <input> element -->
<label for="name">Your name</label>
<input type="text" id="name" name="name" placeholder="Enter your name">


<!-- ❌ WRONG: role="textbox" on a <p> element -->
<p role="textbox">Some editable text</p>

<!-- ✅ FIX C: If you need an editable region, use contenteditable + the permitted role -->
<!-- role="textbox" IS permitted on elements with contenteditable, like a <div> -->
<div role="textbox"
     contenteditable="true"
     aria-multiline="false"
     aria-label="Your name">
</div>

Common patterns: wrong role on the left, correct fix on the right (as comments).

Aria command nameModerate effort

Give every button, link, and menuitem a clear, accessible name so screen readers can announce what it does.

On Squarespace

  1. Log in to your Squarespace account and go to Website → Pages or Design → Custom CSS.
  2. For icon-only buttons built with Squarespace blocks (e.g., social icons, navigation buttons), Squarespace auto-generates some labels but may miss custom icon blocks.
  3. Go to Pages → select the page → click Edit → click the flagged block/element → open its block settings and fill in the 'Description', 'Alt text', or 'Button label' field if available.
  4. For site-wide elements like the cart icon or mobile nav toggle that are part of the theme and not directly editable in the block editor, go to Design → Custom CSS and inject a CSS-based visually-hidden label workaround, OR use Settings → Advanced → Code Injection to add a small JavaScript snippet that sets `aria-label` on those elements after the page loads (see code snippet below).
  5. Re-publish and test with axe to confirm the label appears.
Code · Squarespace (html)
<script>
// Squarespace: add aria-labels to icon-only controls after page load.
// Adjust selectors to match your specific theme's generated HTML.
document.addEventListener('DOMContentLoaded', function () {

  // Mobile navigation toggle
  var menuToggle = document.querySelector('.burger-inner, .Mobile-bar-menu-icon, [data-controller="MobileNavFoldController"]');
  if (menuToggle) {
    var btn = menuToggle.closest('button') || menuToggle;
    if (!btn.getAttribute('aria-label')) {
      btn.setAttribute('aria-label', 'Open main menu');
    }
  }

  // Cart icon link
  var cartLink = document.querySelector('.sqs-cart-button, a[href*="/cart"]');
  if (cartLink && !cartLink.getAttribute('aria-label') && !cartLink.textContent.trim()) {
    cartLink.setAttribute('aria-label', 'View shopping cart');
  }

  // Search button
  var searchBtn = document.querySelector('.header-search-icon button, .search-input-toggle');
  if (searchBtn && !searchBtn.getAttribute('aria-label')) {
    searchBtn.setAttribute('aria-label', 'Open search');
  }

});
</script>

Paste into Settings → Advanced → Code Injection → Footer. Targets Squarespace's generated cart and menu toggle buttons that cannot be edited through the visual editor.

Aria dialog nameModerate effort

Add a visible or programmatic accessible name to every dialog element so screen readers can announce what the dialog is about when it opens.

On Squarespace

  1. Squarespace popups (Promotional Pop-Ups and Quick View panels) are generated by the platform. Go to Pages → Not Linked → Promotional Pop-Up (or Marketing → Promotional Pop-Up) to configure your popup content.
  2. Add a descriptive heading block as the first element inside the popup so it serves as a visible title.
  3. To inject the ARIA attribute, go to Settings → Advanced → Code Injection and add a small JavaScript snippet that runs after page load to set aria-labelledby or aria-label on the dialog element (see code snippet below).
  4. For Quick View dialogs on product pages, use the same Code Injection approach targeting the Quick View modal's role="dialog" element.
  5. After publishing, verify with the axe DevTools browser extension in a real browser.
Code · Squarespace (html)
<script>
(function () {
  function labelDialogs() {
    document.querySelectorAll('[role="dialog"]:not([aria-label]):not([aria-labelledby])').forEach(function (dialog) {
      // Try to find a heading inside the dialog to use as the label
      var heading = dialog.querySelector('h1, h2, h3, h4, h5, h6');
      if (heading) {
        if (!heading.id) {
          heading.id = 'dialog-label-' + Math.random().toString(36).slice(2, 9);
        }
        dialog.setAttribute('aria-labelledby', heading.id);
      } else {
        // Fallback: use a generic label — replace with a name meaningful to your dialogs
        dialog.setAttribute('aria-label', 'Site dialog');
      }
    });
  }
  // Run on initial load
  labelDialogs();
  // Re-run when new dialogs are dynamically injected
  var observer = new MutationObserver(labelDialogs);
  observer.observe(document.body, { childList: true, subtree: true });
})();
</script>

Paste into Settings → Advanced → Code Injection → Footer. This script runs after page load and patches any unlabelled dialogs.

Aria hidden focusModerate effort

Remove `aria-hidden="true"` from any element that contains focusable children (links, buttons, inputs), or remove those focusable children from the keyboard tab order so they cannot receive focus while hidden from assistive technology.

On Squarespace

  1. Squarespace generates most HTML automatically, so direct template editing is limited. Go to Website → Pages → select the affected page → Edit.
  2. If the flagged element is a Squarespace built-in block (slideshow, navigation, announcement bar), check the block's settings for any visibility or accessibility options.
  3. For a custom workaround, go to Website → Website Tools → Code Injection → Footer and inject a small JavaScript snippet that selects the aria-hidden container and sets tabindex='-1' on its focusable children (see code snippet below). This runs on every page load.
  4. If you have a Developer plan with template access, you can edit template files directly to correct the ARIA markup at the source.
  5. After adding the Code Injection snippet, publish, then re-run the axe scan to confirm the fix.
Aria input field nameModerate effort

Add a descriptive accessible name (aria-label, aria-labelledby, or a visible <label>) to every ARIA input field so assistive technologies can identify it.

On Squarespace

  1. In Squarespace, go to Pages → select the page with the form → click Edit, then click on the Form Block.
  2. Click the pencil/edit icon on the form. For each field, ensure the 'Label' field is filled in and 'Show Label' is toggled ON — Squarespace uses the visible label as the accessible name automatically.
  3. Do not rely solely on placeholder text; always enable the visible label.
  4. For search blocks, Squarespace typically injects an accessible label automatically, but if flagged, add a Code Injection snippet: go to Settings → Advanced → Code Injection → Footer and add a small JavaScript snippet: document.querySelectorAll('input[type="search"]:not([aria-label])').forEach(el => el.setAttribute('aria-label', 'Search'));
  5. Save and verify with the WAVE browser extension.
Code · Generic HTML (html)
<label for="customer-email">Email address</label>
<input type="email" id="customer-email" name="email" autocomplete="email">

Option 1 (preferred): Visible label associated via 'for' + 'id'. Use this whenever a visible label fits the design.

Aria meter nameQuick win

Add a descriptive accessible name (via aria-label, aria-labelledby, or a visible <label>) to every element with role="meter" so screen readers can announce what the meter represents.

On Squarespace

  1. Squarespace does not expose ARIA attributes through its visual editor for most built-in blocks.
  2. If the meter is inside a Code Block (Insert → Code), edit the HTML directly and add aria-label="[Descriptive label]" plus aria-valuenow, aria-valuemin, and aria-valuemax to the <meter> or role="meter" element.
  3. If the meter is rendered by a built-in Squarespace block (e.g., a rating widget), inject a fix via Settings → Advanced → Code Injection (Footer): add a small <script> snippet that locates the element by selector and sets setAttribute('aria-label', 'Average customer rating').
  4. Test the page with the axe DevTools browser extension to confirm the fix is applied after injection.
Code · Squarespace (html)
<!-- Place in a Squarespace Code Block where the meter should appear -->
<meter
  role="meter"
  aria-label="Average customer rating"
  aria-valuenow="4.2"
  aria-valuemin="0"
  aria-valuemax="5"
  value="4.2"
  min="0"
  max="5"
  style="width:100%;">
  4.2 out of 5
</meter>

<!-- OR: Code Injection (Footer) script to patch an existing unlabeled meter -->
<script>
  document.addEventListener('DOMContentLoaded', function () {
    document.querySelectorAll('[role="meter"], meter').forEach(function (el) {
      if (!el.getAttribute('aria-label') && !el.getAttribute('aria-labelledby')) {
        el.setAttribute('aria-label', 'Average customer rating');
      }
    });
  });
</script>

Paste into a Code Block on the page, or into Settings → Advanced → Code Injection (Footer) for a site-wide script fix.

Aria progressbar nameQuick win

Add an accessible name (aria-label or aria-labelledby) to every progress bar element so screen readers can announce its purpose.

On Squarespace

  1. Progress bars in Squarespace appear mainly in: product review sections (Business/Commerce plans), donation goal trackers, and any progress bars added via Code Blocks.
  2. For Code Block-based progress bars: go to the page in the Pages panel → click Edit → click the Code Block containing the progress bar → add aria-label='…' to the HTML element.
  3. For review/rating bars generated by Squarespace's built-in product reviews: these are rendered by Squarespace's own system. Go to Settings → Advanced → Code Injection → Footer and inject a small script: document.querySelectorAll('[role="progressbar"]').forEach(el => { if (!el.getAttribute('aria-label')) el.setAttribute('aria-label', 'Product rating'); });
  4. For third-party blocks or extensions that render bars, contact the extension developer about adding aria-label support.
  5. Squarespace does not provide direct template file editing for most users; the Code Injection approach is the recommended path for injecting ARIA attributes into system-generated elements.
  6. Verify with the axe DevTools browser extension after publishing.
Code · Squarespace (html)
<script>
document.addEventListener('DOMContentLoaded', function () {
  // Label all role=progressbar elements that lack an accessible name
  document.querySelectorAll('[role="progressbar"], progress').forEach(function (el) {
    if (!el.getAttribute('aria-label') && !el.getAttribute('aria-labelledby')) {
      // Attempt to derive a label from a preceding sibling or parent heading
      var prev = el.previousElementSibling;
      if (prev && prev.textContent.trim()) {
        var id = 'sq-pb-label-' + Math.random().toString(36).slice(2, 7);
        prev.setAttribute('id', id);
        el.setAttribute('aria-labelledby', id);
      } else {
        el.setAttribute('aria-label', 'Progress');
      }
    }
  });
});
</script>

Paste in Settings → Advanced → Code Injection → Footer to label any system-generated progress bars that cannot be edited directly.

Aria prohibited attrModerate effort

Remove or replace any ARIA attributes that are prohibited for the role assigned to each HTML element, so assistive technologies receive accurate, unambiguous information.

On Squarespace

  1. In the Squarespace Pages panel, navigate to the page containing the flagged element.
  2. If the element is inside a Code Block or a custom HTML injection (Settings → Advanced → Code Injection), open that block and search for the prohibited ARIA attribute, then correct it.
  3. If the attribute is on a native Squarespace component (e.g. a navigation or gallery widget), you may need to override it via Custom CSS or a JavaScript snippet injected through Settings → Advanced → Code Injection — add JavaScript that removes/corrects the attribute after page load.
  4. Save and preview, then validate with the axe browser extension.
Code · Generic HTML (html)
<!-- ❌ WRONG: aria-checked is prohibited on role='heading' -->
<div role="heading" aria-level="2" aria-checked="false">Product Title</div>

<!-- ✅ CORRECT: remove the prohibited aria-checked attribute -->
<div role="heading" aria-level="2">Product Title</div>


<!-- ❌ WRONG: aria-label is prohibited on role='none' / role='presentation' -->
<div role="none" aria-label="Decorative banner"></div>

<!-- ✅ CORRECT: role='none' means purely decorative — remove all ARIA attributes -->
<div role="none"></div>


<!-- ❌ WRONG: aria-expanded is prohibited on a static <p> (implicit role='paragraph') -->
<p aria-expanded="true">Read more about our returns policy.</p>

<!-- ✅ CORRECT: move aria-expanded to the interactive control that actually toggles content -->
<button aria-expanded="true" aria-controls="returns-detail">Read more about our returns policy</button>
<div id="returns-detail">Full returns policy text here.</div>


<!-- ❌ WRONG: aria-required is prohibited on a <div role='alert'> -->
<div role="alert" aria-required="true">Please fill in all fields.</div>

<!-- ✅ CORRECT: remove aria-required; it belongs only on form inputs -->
<div role="alert">Please fill in all fields.</div>

Examples of prohibited-attribute violations and their correct fixes.

Aria required attrModerate effort

Add all required ARIA attributes (such as aria-expanded and aria-controls) to every interactive element that uses an ARIA role, so assistive technologies can communicate widget state to users.

On Squarespace

  1. Squarespace does not allow direct editing of most core HTML. Go to Website → Pages → (your page) → Edit, and check if the component has any built-in accessibility options in its block settings.
  2. For nav dropdowns, go to Design → Navigation and confirm you are using Squarespace's native navigation, which should include ARIA attributes — if it does not, your template version may be outdated; check for template updates under Design → Template.
  3. For custom-coded blocks (Code Blocks or Custom HTML injection): go to Settings → Advanced → Code Injection, or open the Code Block directly, and manually add aria-expanded and aria-controls to your markup, plus a small <script> tag to toggle the value.
  4. If you use a third-party Squarespace plugin for accordions or menus, check that plugin's documentation for ARIA support or contact the plugin vendor.
  5. Test the result with the WAVE browser extension.
Code · Generic HTML (html)
<!-- Trigger button (e.g. accordion header or dropdown toggle) -->
<button
  id="section1-toggle"
  aria-expanded="false"
  aria-controls="section1-panel"
>
  Product Details
</button>

<!-- Controlled panel -->
<div
  id="section1-panel"
  role="region"
  aria-labelledby="section1-toggle"
  hidden
>
  <p>Panel content goes here.</p>
</div>

<script>
  const toggle = document.getElementById('section1-toggle');
  const panel  = document.getElementById('section1-panel');

  toggle.addEventListener('click', function () {
    const isExpanded = this.getAttribute('aria-expanded') === 'true';
    this.setAttribute('aria-expanded', String(!isExpanded));
    panel.hidden = isExpanded;
  });
</script>

Place on any trigger element that opens/closes a collapsible section. Update aria-expanded via JS on each toggle.

Aria required childrenModerate effort

Add the required child ARIA roles (e.g. `role="option"` inside `role="listbox"`, or `role="group"`/`role="option"` inside `role="combobox"`) so every composite ARIA widget contains the child roles the ARIA specification demands.

On Squarespace

  1. Squarespace does not expose direct HTML editing for its built-in blocks; go to Website → Pages → select the page → Edit.
  2. For built-in widgets (dropdowns, navigation) that generate the violation, the only option is to report it to Squarespace Support, as the platform controls that HTML output.
  3. For custom content areas: go to the block where the issue appears → Edit → switch to a Code Block, and write the widget markup manually with the correct ARIA role tree.
  4. In Settings → Advanced → Code Injection you can add a small JavaScript snippet that post-processes the DOM on DOMContentLoaded to add missing role attributes to children of a specific container — use this as a last resort when the source cannot be changed.
  5. Test with axe DevTools after publishing.
Aria required parentModerate effort

Wrap every ARIA role that requires a parent container (e.g. `menuitem`, `option`, `listitem`) inside the correct parent element carrying the matching ARIA role (e.g. `menu`/`menubar`, `listbox`, `list`).

On Squarespace

  1. In Squarespace, go to Settings → Advanced → Code Injection and add a JavaScript snippet to the Footer section that dynamically wraps the orphaned child-role elements in the correct parent role after page load.
  2. For navigation menus specifically, check Settings → Navigation and see if the menu style can be changed to one that produces better semantic HTML.
  3. If the issue is in a Code Block (a custom HTML embed on a page), open that block and add the wrapping parent element directly in the HTML.
  4. Test with the axe DevTools browser extension after saving.
Code · Generic HTML (html)
<!-- INCORRECT: menuitem with no required parent -->
<nav>
  <a href="/shop" role="menuitem">Shop</a>
  <a href="/about" role="menuitem">About</a>
  <a href="/contact" role="menuitem">Contact</a>
</nav>

<!-- CORRECT: menuitem children wrapped in role="menubar" -->
<nav>
  <ul role="menubar">
    <li role="none"><a href="/shop" role="menuitem">Shop</a></li>
    <li role="none"><a href="/about" role="menuitem">About</a></li>
    <li role="none"><a href="/contact" role="menuitem">Contact</a></li>
  </ul>
</nav>

<!-- CORRECT: option children wrapped in role="listbox" -->
<div role="listbox" aria-label="Select a size">
  <div role="option" aria-selected="false">Small</div>
  <div role="option" aria-selected="true">Medium</div>
  <div role="option" aria-selected="false">Large</div>
</div>

<!-- CORRECT: tab children wrapped in role="tablist" -->
<div role="tablist" aria-label="Product details">
  <button role="tab" aria-selected="true" aria-controls="panel-desc">Description</button>
  <button role="tab" aria-selected="false" aria-controls="panel-reviews">Reviews</button>
</div>
<div id="panel-desc" role="tabpanel">Description content here.</div>
<div id="panel-reviews" role="tabpanel" hidden>Reviews content here.</div>

Correct pattern: child roles (menuitem) wrapped in the required parent role (menu/menubar). Apply the same principle to other role pairs.

Aria rolesQuick win

Audit every element that has a `role` attribute and replace any invalid or misspelled role value with a valid WAI-ARIA role from the official specification.

On Squarespace

  1. Squarespace does not allow direct HTML editing of structural templates; invalid roles in core blocks must be reported to Squarespace Support.
  2. For roles inside Code Blocks or custom HTML you added yourself: in the Page Editor, click the Code Block, select Edit, find the `role=` attribute in your markup, correct it, and save.
  3. For site-wide custom code (e.g. injected via Settings → Advanced → Code Injection): go to Settings → Advanced → Code Injection, locate the snippet containing the invalid role, correct it, and save.
  4. Republish and verify with an axe browser extension on the live page.
Code · Generic HTML (html)
<!-- INVALID: typo -->
<!-- <div role="buton">Add to Cart</div> -->

<!-- FIXED: correct spelling -->
<div role="button" tabindex="0">Add to Cart</div>

<!-- BETTER: use native HTML instead of ARIA role wherever possible -->
<button type="button">Add to Cart</button>

<!-- INVALID: invented role -->
<!-- <section role="product-card"> -->

<!-- FIXED: remove non-existent role; let native <section> semantics apply -->
<section aria-label="Product card">

<!-- INVALID: abstract/structural-only role used on a concrete element -->
<!-- <ul role="list widget"> -->

<!-- FIXED: 'list' is valid; 'widget' is abstract and not allowed -->
<ul role="list">

<!-- INVALID: deprecated presentational role used incorrectly -->
<!-- <img role="presentation" alt="Red sneaker"> -->

<!-- FIXED: use role="presentation" only for decorative images with empty alt -->
<img role="presentation" alt="">

Replace invalid or misspelled role values with the correct WAI-ARIA role. Examples of common corrections:

Aria toggle field nameQuick win

Add a visible or programmatic accessible name to every toggle control (checkbox, switch, or button with role="switch") so screen readers can announce what the control does.

On Squarespace

  1. In your Squarespace Pages panel, open the page containing the toggle and click the block to edit it.
  2. For native Form blocks with checkboxes, click the checkbox field → Edit, and ensure the 'Label' field is filled in with descriptive text — this text becomes the accessible name.
  3. For icon-only toggle buttons in navigation or custom sections, go to Website → Pages → select the page → click Edit, then use a Code Block to inject a small JavaScript snippet that adds aria-label attributes to the toggle elements (see code snippet below).
  4. For site-wide toggles (e.g. in the header or footer), go to Website → Website Tools → Code Injection and add a JavaScript snippet in the Footer section that selects the toggle elements and adds aria-label values.
  5. Preview the page, open browser DevTools → Accessibility tab, and verify each toggle has an accessible name.
Code · Squarespace (javascript)
<script>
// Squarespace Code Injection — Footer
// Adds aria-label to icon-only toggle buttons that lack an accessible name.
// Adjust the selector and label text to match your actual elements.
document.addEventListener('DOMContentLoaded', function () {
  var toggleMappings = [
    { selector: '.mobile-overlay-toggle',    label: 'Open mobile menu' },
    { selector: '.sqs-search-ui-close',      label: 'Close search' },
    { selector: '.wishlist-toggle-btn',      label: 'Add to wishlist' }
  ];
  toggleMappings.forEach(function (mapping) {
    document.querySelectorAll(mapping.selector).forEach(function (el) {
      if (!el.getAttribute('aria-label') && !el.getAttribute('aria-labelledby')) {
        el.setAttribute('aria-label', mapping.label);
      }
    });
  });
});
</script>

Paste into Website → Website Tools → Code Injection → Footer to add aria-labels to any icon-only toggles site-wide.

Aria tooltip nameModerate effort

Give every tooltip element an accessible name so screen readers can announce its content to users who cannot see the screen.

On Squarespace

  1. In the Squarespace editor, navigate to the page containing the tooltip and click the block or section that generates it.
  2. If the tooltip is a native Squarespace feature (e.g., form field tooltip or image caption), use the block's Content settings to add or update the label/description text — Squarespace uses this as the accessible name.
  3. For custom-coded blocks (Code Block or Inject Code), go to Pages → (page) → Edit → add a Code Block, then edit the HTML to include descriptive inner text or aria-label on the tooltip element.
  4. To inject a global fix, go to Settings → Advanced → Code Injection → Footer and add a small <script> that finds all role="tooltip" elements and sets their aria-label if missing.
  5. Preview the page and confirm with the axe browser extension that no aria-tooltip-name violations appear.
Code · Generic HTML (html)
<!-- Trigger element references the tooltip via aria-describedby -->
<button type="button" aria-describedby="shipping-tip">
  Shipping info
  <span class="icon-help" aria-hidden="true">?</span>
</button>

<!-- Tooltip element: inner text IS the accessible name -->
<div id="shipping-tip" role="tooltip">
  Standard shipping takes 2–3 business days. Express options available at checkout.
</div>

Place this pattern anywhere a tooltip is needed. The button triggers the tooltip; aria-describedby links them.

Aria valid attrQuick win

Find and replace every misspelled or non-existent ARIA attribute name (e.g. `aria-labeledby`) with the correct, spec-defined name (e.g. `aria-labelledby`) across your entire site's HTML and templates.

On Squarespace

  1. In your Squarespace admin, go to Website → Pages and navigate to the affected page.
  2. If the invalid ARIA attribute is in a Code Block or Embed Block, click to edit that block and correct the attribute name in the HTML.
  3. If it is in site-wide custom code, go to Settings → Advanced → Code Injection and search the Header or Footer injection fields for the misspelled attribute.
  4. For theme-level customisation (available on Business plan and above), go to Design → Custom CSS — note that CSS cannot fix an invalid HTML attribute name; you must find the HTML source.
  5. Squarespace's own native components cannot be directly edited for ARIA attributes — if the violation is inside a Squarespace-native block, report it to Squarespace Support.
  6. After saving and publishing, verify with the axe DevTools browser extension.
Code · Generic HTML (html)
<!-- WRONG: aria-labeledby is not a valid ARIA attribute (one 'l' is a typo) -->
<input type="search" aria-labeledby="search-heading">

<!-- CORRECT: aria-labelledby (double 'l') is the valid ARIA attribute -->
<input type="search" aria-labelledby="search-heading">
<h2 id="search-heading">Search our store</h2>

<!-- Other common invalid → valid corrections:
  aria-role        → role  (not an ARIA attribute at all; 'role' is a plain HTML attribute)
  aria-labeledby   → aria-labelledby
  aria-describeby  → aria-describedby
  aria-owns-id     → aria-owns
-->

Before/after comparison showing the most common misspelling corrected. Apply the same principle to any other invalid ARIA attribute name.

Aria valid attr valueModerate effort

Audit every ARIA attribute on your pages and correct any that have invalid or mismatched values so assistive technologies can interpret them correctly.

On Squarespace

  1. In the Squarespace editor, go to Pages → select the page → click 'Edit'.
  2. Click the block containing the flagged element and open its block settings.
  3. For Code Blocks (Insert Point → Code): edit the raw HTML directly and correct the ARIA attribute value.
  4. For built-in Squarespace blocks (e.g. navigation, accordion), ARIA is auto-generated by Squarespace — go to Website → Website Tools → Custom CSS or inject a fix via Settings → Advanced → Code Injection (Header) using JavaScript to correct the attribute at runtime.
  5. For theme-level fixes, go to Design → Custom CSS or use a Developer platform site with Git integration to edit template files.
  6. Verify with Lighthouse (Chrome DevTools) or the axe browser extension after publishing.
Code · Generic HTML (html)
<!-- WRONG: aria-expanded with a number instead of boolean string -->
<button aria-expanded="1">Menu</button>

<!-- CORRECT: must be exactly the string "true" or "false" -->
<button aria-expanded="false">Menu</button>

<!-- WRONG: aria-describedby pointing to an ID that doesn't exist -->
<input type="email" aria-describedby="email-hint" />
<!-- (no element with id="email-hint" on the page) -->

<!-- CORRECT: the referenced element must exist in the DOM -->
<input type="email" aria-describedby="email-hint" />
<p id="email-hint">We'll never share your email with anyone.</p>

<!-- WRONG: aria-checked with a non-standard value -->
<div role="checkbox" aria-checked="yes">Subscribe</div>

<!-- CORRECT: aria-checked accepts "true", "false", or "mixed" -->
<div role="checkbox" aria-checked="false">Subscribe</div>

<!-- WRONG: aria-hidden with an invalid value -->
<span aria-hidden="hidden">decorative icon</span>

<!-- CORRECT: aria-hidden accepts only "true" or "false" -->
<span aria-hidden="true">decorative icon</span>

Correct examples for the most commonly mis-valued ARIA attributes. Copy the pattern that matches your flagged element.

Autocomplete validModerate effort

Add valid `autocomplete` attribute values to every form field that collects personal information, using the exact tokens specified by the HTML standard.

On Squarespace

  1. Squarespace does not provide direct HTML editing of built-in form blocks or checkout fields.
  2. For built-in Form Blocks (contact, newsletter), Squarespace injects its own markup. You can inject additional attributes via Settings → Advanced → Code Injection (available on Business plan and above) using a JavaScript snippet that sets `autocomplete` on matching inputs after DOM load (see code snippet).
  3. For Squarespace Commerce checkout, Squarespace controls the checkout page HTML — contact Squarespace Support to report missing autocomplete attributes on checkout fields.
  4. For any custom HTML blocks containing `<form>` markup (Insert Block → Code), you have full control — add the correct `autocomplete` attribute directly to each `<input>` in your HTML block.
  5. After injecting JavaScript, publish and verify with the axe browser extension that the violation is resolved.
Code · Squarespace (html)
<script>
  document.addEventListener('DOMContentLoaded', function () {
    // Map Squarespace form field titles/placeholders to autocomplete tokens.
    // Adjust the selector strings to match your actual field labels or IDs.
    var fieldMap = [
      { selector: 'input[placeholder*="First name" i], input[id*="fname" i]', autocomplete: 'given-name' },
      { selector: 'input[placeholder*="Last name" i], input[id*="lname" i]', autocomplete: 'family-name' },
      { selector: 'input[type="email"], input[placeholder*="Email" i]', autocomplete: 'email' },
      { selector: 'input[type="tel"], input[placeholder*="Phone" i]', autocomplete: 'tel' },
      { selector: 'input[placeholder*="Address" i]', autocomplete: 'street-address' },
      { selector: 'input[placeholder*="Postcode" i], input[placeholder*="Zip" i]', autocomplete: 'postal-code' },
    ];

    fieldMap.forEach(function (item) {
      document.querySelectorAll(item.selector).forEach(function (el) {
        if (!el.getAttribute('autocomplete')) {
          el.setAttribute('autocomplete', item.autocomplete);
        }
      });
    });
  });
</script>

Paste into Settings → Advanced → Code Injection → Footer to add autocomplete attributes to Squarespace Form Block inputs via JavaScript.

Avoid inline spacingModerate effort

Remove hard-coded text-spacing CSS values from inline `style` attributes so users can override them with their own stylesheets or browser settings.

On Squarespace

  1. In the Squarespace editor, go to Design → Custom CSS (available on Business plan and above).
  2. Identify which block or section is outputting the inline spacing — use browser DevTools to find the element and its selector.
  3. Write a CSS rule in the Custom CSS panel that targets that element using its class or selector, setting the spacing properties you need (e.g. `.product-description p { line-height: 1.6; }`). This creates a stylesheet-level rule users can override.
  4. In the page editor, avoid using the 'Design' panel sliders for line-height/letter-spacing if they output as `style=` attributes — prefer Custom CSS for fine-grained spacing.
  5. If a third-party block or Code Block is injecting inline styles, edit the Code Block's HTML directly and move the spacing into a `<style>` tag or your Custom CSS.
  6. Save and verify with the axe browser extension.
Code · Generic HTML (html)
<!-- BEFORE (fails WCAG 1.4.12 — inline style blocks user overrides) -->
<p style="line-height: 1.6; letter-spacing: 0.05em; word-spacing: 0.1em;">
  Product description text here.
</p>

<!-- AFTER (passes — spacing is in a stylesheet class) -->
<p class="product-description">
  Product description text here.
</p>

<!-- In your <head> or external .css file -->
<style>
  .product-description {
    line-height: 1.6;
    letter-spacing: 0.05em;
    word-spacing: 0.1em;
  }
</style>

Before: inline style locks spacing. After: class-based style allows user overrides.

Button nameModerate effort

Add a descriptive, screen-reader-accessible name to every button on your site so assistive technology users know what each button does.

On Squarespace

  1. In the Squarespace Editor, go to Pages → select the page, then click Edit. For site-wide elements like the navigation or cart button, go to Design → Site Styles or the Header/Footer settings.
  2. Squarespace does not expose aria-label fields in its visual editor. To add aria-labels to icon buttons, inject custom code: go to Settings → Advanced → Code Injection (available on Business plan and above) and add a JavaScript snippet that programmatically sets aria-label on the target buttons after the page loads.
  3. Alternatively, for page-specific buttons, use a Code Block (Insert Point → Code) and write the button in raw HTML with the aria-label included.
  4. For the cart icon, search icon, and hamburger menu (rendered by Squarespace's system), use Code Injection to run a small script: document.querySelector('.header-burger-btn').setAttribute('aria-label', 'Open menu'); — adapt the CSS selector to match your template's actual class names (inspect with browser DevTools).
  5. If you have a Developer-mode-enabled (version 7.0) template, edit the template files directly via the Template Editor to add aria-label attributes in the source markup.
  6. Test with VoiceOver or NVDA after publishing to verify the injected labels are announced.
Code · Squarespace (html)
<script>
(function() {
  function labelButtons() {
    // Hamburger / mobile menu button
    var burger = document.querySelector(
      '.header-burger-btn, .mobile-bar-menu-icon, [data-controller="MobileBarController"] button'
    );
    if (burger && !burger.getAttribute('aria-label')) {
      burger.setAttribute('aria-label', 'Open navigation menu');
    }

    // Search icon button
    var search = document.querySelector(
      '.header-search-btn, [data-test="header-search-button"], .sqs-search-ui-open-btn'
    );
    if (search && !search.getAttribute('aria-label')) {
      search.setAttribute('aria-label', 'Open search');
    }

    // Cart icon button / link
    var cart = document.querySelector(
      '.header-cart-btn, [data-test="header-cart-button"], .sqs-cart-icon'
    );
    if (cart && !cart.getAttribute('aria-label')) {
      cart.setAttribute('aria-label', 'View shopping cart');
    }

    // Close / dismiss buttons
    document.querySelectorAll('.close-btn, [data-action="close"]').forEach(function(btn) {
      if (!btn.getAttribute('aria-label') && !btn.textContent.trim()) {
        btn.setAttribute('aria-label', 'Close');
      }
    });
  }

  // Run on initial load
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', labelButtons);
  } else {
    labelButtons();
  }
})();
</script>

Paste this into Settings → Advanced → Code Injection → Footer (Business plan+). The script runs after page load and labels Squarespace's built-in icon buttons. Adjust CSS selectors to match your template version using browser DevTools.

Color contrastQuick win

Increase the contrast ratio between your text color and its background color to meet the WCAG 4.5:1 minimum, so all users — including those with low vision — can read your content clearly.

On Squarespace

  1. Go to Website → Pages → click Edit on the relevant page, then click on the failing text element and use the inline toolbar to change the text color.
  2. For global changes, go to Design → Styles (or the 'paintbrush' icon in the editor) and find the Body Text or Secondary Text color. Update it to an accessible value.
  3. In Squarespace 7.1 you can also go to Design → Custom CSS and add an override rule (see snippet below).
  4. Save and preview.
Code · Squarespace (css)
/* Squarespace: fix low-contrast body or secondary text */
p,
.sqs-block-content p,
.summary-excerpt {
  color: #595959 !important; /* was #777777 — 7.0:1 on white */
}

Paste into Design → Custom CSS in Squarespace 7.1.

Definition listModerate effort

Ensure every `<dl>` (definition list) element contains only properly nested `<dt>` and `<dd>` children, with no stray text, divs, or other elements placed directly inside it.

On Squarespace

  1. Squarespace does not expose raw HTML for most blocks. If the malformed `<dl>` is inside a Code Block, go to the page in the Editor, click the Code Block, and edit the HTML directly.
  2. If the `<dl>` is generated by a Squarespace built-in block (e.g. a product page), you cannot edit it directly — inject corrective CSS or report it to Squarespace Support.
  3. For custom injected code, go to Settings → Advanced → Code Injection and locate any `<dl>` markup in the header/footer injection fields; correct it there.
  4. Publish and verify with the axe DevTools browser extension.
Code · Generic HTML (html)
<!-- ✅ CORRECT: only <dt> and <dd> as direct children -->
<dl>
  <dt>Material</dt>
  <dd>100% Organic Cotton</dd>

  <dt>Weight</dt>
  <dd>180 GSM</dd>

  <dt>Care Instructions</dt>
  <dd>Machine wash cold</dd>
  <dd>Tumble dry low</dd>
</dl>

<!-- ✅ ALSO CORRECT: <div> wrappers for layout/styling -->
<dl>
  <div>
    <dt>Material</dt>
    <dd>100% Organic Cotton</dd>
  </div>
  <div>
    <dt>Weight</dt>
    <dd>180 GSM</dd>
  </div>
</dl>

<!-- ❌ WRONG: stray <p>, <span>, or plain text directly inside <dl> -->
<!-- <dl>
  <p>Product Details</p>
  <dt>Material</dt>
  <dd>Cotton</dd>
</dl> -->

Correct `<dl>` structure — use this pattern for all product specs, FAQs, and paired term/value content.

DlitemModerate effort

Wrap every `<dt>` (term) and `<dd>` (description) element inside a parent `<dl>` element so description list items have their required container.

On Squarespace

  1. In your Squarespace admin, go to the page with the issue and open the page editor.
  2. If the offending markup is in a 'Code Block': click the block → Edit → find any `<dt>` or `<dd>` tags and wrap them in `<dl>` … `</dl>`.
  3. For site-wide code injected via Settings → Advanced → Code Injection (Header/Footer): review that code for orphaned `<dt>`/`<dd>` elements and add `<dl>` wrappers.
  4. If the issue is in theme-generated output (e.g., product detail pages), you may need to add CSS to restyle a different semantic element, or use a Code Block with correctly structured `<dl>` markup to replace the problematic content.
  5. Save changes, preview the page, and inspect the DOM with browser DevTools to confirm the fix.
Code · Generic HTML (html)
<!-- CORRECT: dt and dd are direct children of dl -->
<dl>
  <dt>Shipping time</dt>
  <dd>3–5 business days</dd>

  <dt>Return policy</dt>
  <dd>30-day free returns</dd>

  <dt>Material</dt>
  <dd>100% organic cotton</dd>
</dl>

<!-- ALSO CORRECT: grouping pairs with div inside dl (HTML5 spec allows this) -->
<dl>
  <div>
    <dt>Shipping time</dt>
    <dd>3–5 business days</dd>
  </div>
  <div>
    <dt>Return policy</dt>
    <dd>30-day free returns</dd>
  </div>
</dl>

<!-- INCORRECT — do NOT do this: dt/dd outside a dl -->
<!-- <div>
  <dt>Shipping time</dt>
  <dd>3–5 business days</dd>
</div> -->

The correct structure: every <dt> and <dd> must be a direct child of a <dl> element.

Document titleQuick win

Add a descriptive, non-empty `<title>` element to every page so browsers, screen readers, and search engines can identify it.

On Squarespace

  1. For the site-wide title pattern: Settings → SEO → 'SEO Site Title' — this is used as the suffix across all pages.
  2. For individual pages: Pages → click the gear icon (⚙) next to the page name → SEO tab → 'SEO Title' field.
  3. For product pages in Squarespace Commerce: Pages → your Store page → click a product → SEO tab → 'SEO Title'.
  4. For blog posts: Pages → Blog → click a post → Settings → SEO tab → 'SEO Title'.
  5. If the SEO Title field is left blank, Squarespace falls back to the page title — ensure every page has at least a page title set.
Code · Generic HTML (html)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Women's Running Shoes – Acme Sports</title>
</head>
<body>
  <!-- page content -->
</body>
</html>

Place this inside the <head> section of every HTML page. Replace the text with the actual page and store name.

Empty headingQuick win

Find every empty heading tag on your store and add visible, descriptive text (or remove the tag entirely) so screen readers and search engines can interpret your page structure.

On Squarespace

  1. Open the Pages panel and edit the page containing the empty heading.
  2. In the page editor, click the block that contains the empty heading text (it will appear as a blank Text or Markdown block).
  3. Type meaningful text into the block, or change the heading style to 'Normal' / 'Paragraph' in the text formatting toolbar if a heading is not appropriate.
  4. If using Code Blocks with raw HTML: click the block → Edit → find empty `<h*>` tags and add text or remove the tags.
  5. Delete the block entirely if it serves no structural purpose.
  6. After saving, validate the page with the axe DevTools browser extension in your browser.
Code · Generic HTML (html)
<!-- ❌ WRONG: empty heading — announced as 'heading' with no label -->
<h2></h2>

<!-- ✅ CORRECT option 1: add visible, descriptive text -->
<h2>Featured Products</h2>

<!-- ✅ CORRECT option 2: visually-hidden text (visible to screen readers, hidden on screen) -->
<!-- Add this CSS once in your stylesheet: -->
<!--
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
-->
<h2><span class="sr-only">Featured Products</span></h2>

<!-- ✅ CORRECT option 3: aria-label when removing the tag is not possible -->
<h2 aria-label="Featured Products"></h2>

<!-- ✅ CORRECT option 4: not a heading at all — use a div instead -->
<div class="decorative-divider"></div>

The wrong pattern and the two correct alternatives — visible text, or visually-hidden text for screen readers only.

Empty table headerQuick win

Add visible or screen-reader-accessible text to every empty `<th>` table header cell so assistive technology users can understand what each column or row represents.

On Squarespace

  1. In the Squarespace Pages panel, open the page containing the table and click Edit.
  2. Click the Table block to edit it; click each empty header cell in the top row and type a descriptive label.
  3. If the table was added as a Code Block (Insert Point → Code), click the Code Block to open the HTML editor and add text or `aria-label` to any empty `<th>` elements.
  4. For Squarespace Commerce product tables, check Settings → Inventory or the product page editor for column label options.
  5. Save, then verify with axe DevTools or WAVE extension.
Code · Generic HTML (html)
<!-- OPTION 1: Add visible text (best for most cases) -->
<table>
  <thead>
    <tr>
      <th>Feature</th>
      <th>Basic Plan</th>
      <th>Pro Plan</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Storage</td>
      <td>5 GB</td>
      <td>50 GB</td>
    </tr>
  </tbody>
</table>

<!-- OPTION 2: Visually hidden text (for top-left corner cells) -->
<style>
  .sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
</style>
<table>
  <thead>
    <tr>
      <th><span class="sr-only">Feature name</span></th>
      <th>Basic Plan</th>
      <th>Pro Plan</th>
    </tr>
  </thead>
</table>

<!-- OPTION 3: aria-label directly on the th element -->
<table>
  <thead>
    <tr>
      <th aria-label="Feature name"></th>
      <th>Basic Plan</th>
      <th>Pro Plan</th>
    </tr>
  </thead>
</table>

Option 1 — visible text in the header cell (preferred). Option 2 — visually hidden text via a span. Option 3 — aria-label on the th element.

Error not associatedModerate effort

Add `aria-invalid="true"` and a linked `aria-describedby` error message to every form field that fails validation, so screen reader users are told exactly what went wrong.

On Squarespace

  1. Log in to your Squarespace dashboard and open the page containing the form block.
  2. Click the form block → Edit → Form tab: ensure every required field has a meaningful field label (this becomes the error reference).
  3. Squarespace's native form blocks have limited ARIA customisation. To inject aria-invalid and aria-describedby, go to Website → Pages → select the page → click the </> icon (Page Header Code Injection) or use Settings → Advanced → Code Injection (site-wide).
  4. In the Code Injection footer, add a <script> block that listens for the form's submit event, validates fields, and programmatically sets aria-invalid and inserts/updates a sibling <span id="FIELDNAME-error"> with the error text.
  5. Alternatively, embed a fully accessible third-party form (e.g. Tally, Typeform accessible mode, or a hand-coded HTML form) via an Embed Block for complete control over ARIA markup.
  6. Save and test with a screen reader.
Code · Generic HTML (html)
<div class="field-wrapper">
  <label for="user-email">Email address <span aria-hidden="true">*</span></label>
  <input
    type="email"
    id="user-email"
    name="email"
    autocomplete="email"
    aria-required="true"
    aria-describedby="user-email-error"
  />
  <span
    id="user-email-error"
    class="field-error"
    role="alert"
    hidden
  ></span>
</div>

Place this markup in any HTML form. The error span is always in the DOM; JS toggles visibility and sets aria-invalid.

Focus not visibleQuick win

Add a clearly visible focus indicator to every interactive element so keyboard users can always see which element is currently selected.

On Squarespace

  1. In your Squarespace dashboard, go to Design → Custom CSS (or Website → Pages → Website Tools → Custom CSS).
  2. Paste the universal `:focus` / `:focus-visible` CSS rule from the snippet below into the Custom CSS editor.
  3. Click Save. Open your live site, press Tab, and confirm the ring is visible on links, buttons, and form fields.
  4. If using Squarespace 7.1, also check the Site Styles panel to ensure no individual button or link style is overriding outline to none.
Code · Squarespace (css)
/* Visible focus indicator fix — WCAG 2.4.7 */

*:focus-visible {
  outline: 3px solid #005FCC !important;
  outline-offset: 2px !important;
  border-radius: 2px;
}

*:focus {
  outline: 3px solid #005FCC !important;
  outline-offset: 2px !important;
}

*:focus:not(:focus-visible) {
  outline: none !important;
}

Paste into Design → Custom CSS. Squarespace injects this into the <head> automatically.

Frame titleQuick win

Add a descriptive `title` attribute to every `<iframe>` and `<frame>` element on your store so screen-reader users know what each embedded frame contains before entering it.

On Squarespace

  1. In your Squarespace editor, navigate to the page containing the iframe. If the iframe was inserted via a Code Block (Insert → Code), click Edit on that block.
  2. Find the <iframe> tag in the code block and add title="…" directly to it, then save.
  3. For Squarespace extensions or third-party embed codes that inject iframes, edit the embed code in the relevant Code Block or Footer/Header injection area (Settings → Advanced → Code Injection) and add the title attribute.
  4. For iframes Squarespace itself generates (e.g. for Maps blocks, Form blocks), there is no direct title override available in the editor — submit a feature/accessibility request to Squarespace support, or replace the built-in block with a custom Code Block containing your own iframe with a title attribute.
Code · Generic HTML (html)
<!-- Good: descriptive title -->
<iframe
  src="https://www.google.com/maps/embed?pb=..."
  title="Google Map showing our store location at 123 Main St"
  width="600"
  height="450"
  loading="lazy"
  referrerpolicy="no-referrer-when-downgrade"
></iframe>

<!-- Good: product video embed -->
<iframe
  src="https://www.youtube.com/embed/VIDEO_ID"
  title="Product demo video: how to use the XYZ Widget"
  width="560"
  height="315"
  allowfullscreen
></iframe>

<!-- Good: decorative / empty frame — hide from assistive tech -->
<iframe
  src="blank.html"
  title=""
  aria-hidden="true"
  tabindex="-1"
></iframe>

Add a descriptive title attribute directly to any iframe element.

Heading orderModerate effort

Restructure your page headings so they follow a logical, sequential order (H1 → H2 → H3) with no levels skipped.

On Squarespace

  1. Open the Pages panel and click 'Edit' on the page you want to fix.
  2. Click any text block that contains a heading. In the rich-text toolbar, use the text-style dropdown (showing 'Heading 1', 'Heading 2', 'Heading 3') to assign the correct heading level — Squarespace maps these directly to H1, H2, and H3 HTML tags.
  3. For blocks where the heading level is hard-coded by the template (e.g., section titles in certain blocks), go to Website → Pages → click the gear icon next to the page → Advanced, and add custom CSS to reassign visual styling without changing your heading markup (or use a Code Block to insert a manually tagged heading).
  4. If you need heading levels beyond H3, insert a Code Block and write the HTML heading tag directly: e.g., <h4>Sub-section title</h4>.
  5. After saving, use the axe DevTools or HeadingsMap browser extension to verify the heading outline.
Code · Generic HTML (html)
<!-- ONE H1 per page: the primary page title -->
<h1>Women's Running Shoes</h1>

<!-- H2 for major page sections -->
<h2>Filter by Category</h2>

  <!-- H3 for sub-sections within an H2 -->
  <h3>Shoe Type</h3>
  <h3>Brand</h3>

<h2>Featured Products</h2>

  <!-- H3 for individual product titles within the H2 section -->
  <h3>UltraRun Pro 5</h3>
  <h3>TrailBlaze X2</h3>

<h2>Customer Reviews</h2>

  <h3>Top Rated This Month</h3>

    <!-- H4 for sub-items within an H3 — only go deeper when content genuinely nests -->
    <h4>Review by Sarah M.</h4>
    <h4>Review by James T.</h4>

Correct heading hierarchy pattern for a typical ecommerce product or category page.

Html has langQuick win

Add a valid `lang` attribute to the `<html>` element so browsers, screen readers, and search engines know what language your page is written in.

On Squarespace

  1. Squarespace automatically sets the `lang` attribute based on your region/language settings.
  2. Go to Settings → Region & Language and ensure the correct language is selected.
  3. Squarespace will inject `<html lang="xx">` accordingly on all pages.
  4. If you need to override this (e.g., for a specific language not in the list), go to Settings → Advanced → Code Injection and add a small JavaScript snippet: `document.documentElement.lang = 'fr';` (replace `fr` with your code) — this is a workaround only.
  5. Verify with View Source after saving.
Code · Generic HTML (html)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Your Page Title</title>
</head>
<body>
  <!-- page content -->
</body>
</html>

Add the lang attribute to the opening <html> tag of every HTML page. Use a valid BCP 47 language tag.

Html lang validQuick win

Add a valid BCP 47 language code to the `lang` attribute on your site's `<html>` element so browsers and assistive technologies know what language your content is written in.

On Squarespace

  1. Squarespace automatically adds a `lang` attribute to the `<html>` tag based on the site's language setting.
  2. Go to Settings → Language & Region → Site Language and select the correct language from the dropdown.
  3. Save and publish. Squarespace will update the rendered `<html lang="...">` attribute automatically.
  4. Confirm by visiting your live site and inspecting the page source or using a browser developer tool to view the `<html>` tag.
  5. Note: Squarespace does not allow direct editing of the `<html>` tag via custom code; the language setting is the only lever available to store owners.
Code · Generic HTML (html)
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Page Title</title>
  </head>
  <body>
    <!-- page content -->
  </body>
</html>

Place this as the very first tag in your HTML document. Replace 'en' with your actual BCP 47 language code.

Image altModerate effort

Add descriptive alt text to every meaningful image, and mark purely decorative images with an empty alt attribute or role="presentation".

On Squarespace

  1. Click any image block on your page → click the pencil/edit icon → in the image editing panel, click the 'Accessibility' tab (or scroll to the 'Alt Text' field) → type your description → Apply.
  2. For product images: Commerce → Inventory → [Product] → click an image in the Media section → the 'Alt Text' field appears on the right side of the Media Library.
  3. For gallery blocks: click the gallery → Edit (pencil) → click any individual image → edit the 'Alt Text' field in the image detail view.
  4. Squarespace does not auto-populate alt text from image filenames, so every image needs a manual entry unless you use a third-party SEO tool.
Code · Generic HTML (html)
<!-- Meaningful image: describe the content -->
<img src="red-leather-bag.jpg" alt="Red leather crossbody bag with gold clasp" width="600" height="400">

<!-- Image used as a link: describe the destination/action -->
<a href="/sale">
  <img src="summer-sale-banner.jpg" alt="Shop our summer sale — up to 40% off">
</a>

<!-- Decorative image: empty alt, screen readers skip it -->
<img src="decorative-swoosh.svg" alt="" role="presentation">

<!-- WRONG — never omit alt entirely on an <img> -->
<!-- <img src="product.jpg"> -->

<!-- WRONG — never use filename or generic words -->
<!-- <img src="IMG_4821.jpg" alt="image"> -->

Correct patterns for meaningful, linked, and decorative images.

Image redundant altQuick win

Remove or clear the alt text on images whose description is already provided by visible text immediately surrounding them, so screen readers don't read the same information twice.

On Squarespace

  1. In the Squarespace editor, click the image block or gallery item that is flagged.
  2. Click the pencil/edit icon to open image settings.
  3. In the 'Filename' or 'Alt Text' field (labeled 'Alt Text' in most templates), clear any text that duplicates the surrounding visible caption or title.
  4. Leave the Alt Text field empty for decorative or redundant images — Squarespace will output alt="".
  5. For product images in Squarespace Commerce, go to the Products panel → click the product → click the image → clear the Alt Text field.
  6. Save and publish, then verify with axe DevTools.
Code · Generic HTML (html)
<!-- CORRECT: image inside a link that also has visible text -->
<a href="/products/red-sneakers">
  <img src="red-sneakers.jpg" alt="" width="300" height="300">
  <span>Red Sneakers</span>
</a>

<!-- INCORRECT: alt repeats the visible link text -->
<a href="/products/red-sneakers">
  <img src="red-sneakers.jpg" alt="Red Sneakers" width="300" height="300">
  <span>Red Sneakers</span>
</a>

<!-- INCORRECT: alt attribute missing entirely (screen reader reads filename) -->
<a href="/products/red-sneakers">
  <img src="red-sneakers.jpg" width="300" height="300">
  <span>Red Sneakers</span>
</a>

Use alt="" (empty string) when the image is inside or adjacent to visible text that already describes it. Never omit the alt attribute entirely.

Input button nameQuick win

Add a visible label or accessible name to every input button so assistive technologies can announce what the button does.

On Squarespace

  1. Squarespace manages most button markup automatically; empty-value input buttons most often appear inside Code Blocks or custom Form Blocks.
  2. In the Pages panel, click the page containing the button, then double-click the Code Block or Form Block.
  3. For a Code Block: find the `<input type="submit">` or `<input type="button">` element and add `value="Subscribe"` (or appropriate label).
  4. For a Form Block: open Form settings → Storage & Submission → edit the Submit Button label field to ensure it is not blank.
  5. If you injected HTML via Settings → Advanced → Code Injection, locate it there and add the `value` attribute.
  6. Save/Publish and verify with the axe browser extension.
Code · Generic HTML (html)
<!-- CORRECT: Submit button with descriptive value -->
<input type="submit" value="Place Order">

<!-- CORRECT: Button with descriptive value -->
<input type="button" value="Add to Cart">

<!-- CORRECT: Reset button with descriptive value -->
<input type="reset" value="Clear Form">

<!-- CORRECT: Icon-only button — use aria-label when no visible text is possible -->
<input type="submit" value="" aria-label="Search products">

<!-- WRONG: Empty value — screen readers cannot announce purpose -->
<!-- <input type="submit" value=""> -->

Use a descriptive value attribute on every input button type. Never leave value empty.

Input image altQuick win

Add a descriptive `alt` attribute to every `<input type="image">` element so screen readers can announce its purpose to visually impaired shoppers.

On Squarespace

  1. Squarespace restricts direct HTML editing for most elements, but `<input type="image">` buttons typically appear in Code Blocks or in injected code.
  2. Go to Pages → select the relevant page → click the Code Block containing the image button → Edit, and add `alt="[action text]"` to the `<input>` tag.
  3. For site-wide injections (e.g. in the header/footer), go to Settings → Advanced → Code Injection, locate the relevant `<input type="image">` snippet, and add the `alt` attribute.
  4. Save and preview, then verify with axe DevTools.
Code · Generic HTML (html)
<!-- BEFORE (broken): -->
<input type="image" src="buy-now.png">

<!-- AFTER (fixed): -->
<input type="image" src="buy-now.png" alt="Buy now">

<!-- Search button example: -->
<input type="image" src="search-icon.png" alt="Search products">

<!-- Custom checkout submit example: -->
<input type="image" src="checkout-btn.png" alt="Proceed to checkout">

Replace the `alt` value with a short, action-oriented description of what the button does.

LabelQuick win

Add a visible or programmatic label to every form input so assistive technologies can identify it for users.

On Squarespace

  1. For Squarespace Form Blocks: click Edit on the form block, then click the pencil icon on each field. In the field settings, ensure 'Label' is filled in — Squarespace renders this as a `<label>` tag.
  2. If you want to hide labels visually while keeping them accessible, go to Design → Custom CSS and add: `.field-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; }` — this hides labels visually but keeps them in the DOM for screen readers.
  3. For the Search Block (header/footer), Squarespace automatically provides an `aria-label` on the input; if a custom header overrides this, add the fix via Settings → Advanced → Code Injection (header code) to inject a small script that sets `aria-label` on the element.
  4. For Newsletter Blocks, open the block editor, ensure the Email field has a label entered in the form settings.
  5. Save and verify with the axe browser extension.
Code · Generic HTML (html)
<!-- Method 1: Explicit label (recommended) -->
<label for="user-email">Email address</label>
<input type="email" id="user-email" name="email" autocomplete="email">

<!-- Method 2: Implicit (wrapped) label -->
<label>
  Email address
  <input type="email" name="email" autocomplete="email">
</label>

<!-- Method 3: aria-label (use when no visible label is desired, e.g. icon-only search) -->
<input type="search" name="q" aria-label="Search products">

<!-- Method 4: aria-labelledby (point to existing visible text on the page) -->
<h2 id="newsletter-heading">Subscribe to our newsletter</h2>
<input type="email" name="subscribe" aria-labelledby="newsletter-heading">

<!-- Visually hidden label (visible to screen readers, hidden on screen) -->
<style>
  .visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
</style>
<label for="search-input" class="visually-hidden">Search products</label>
<input type="search" id="search-input" name="q" placeholder="Search...">

Preferred method: explicit label linked by for/id. Place immediately before the input.

Label title onlyModerate effort

Add a visible text label to every form field so it is not labeled only by a hidden tooltip (title attribute) or supplementary description (aria-describedby).

On Squarespace

  1. In the Squarespace editor, click the form block you want to fix → Edit → click on an individual field.
  2. Ensure the 'Label' option is enabled and contains meaningful text (not just a placeholder). Squarespace renders enabled labels as visible <label> elements in the HTML.
  3. For the site search block, Squarespace injects an aria-label automatically in most templates — test with axe to confirm. If it is missing, add a Code Block above the search block with a visually-hidden label, or use Custom CSS with a ::before pseudo-element workaround (limited).
  4. For advanced fixes, go to Pages → (page) → Edit → click any block → … → Edit Custom CSS, or use the global Design → Custom CSS panel to add a .visually-hidden utility class, then inject the label via Settings → Advanced → Code Injection (note: Code Injection is available on Business plan and above).
  5. After changes, publish and validate with axe DevTools.
Code · Generic HTML (html)
<!-- CORRECT: Visible label paired to input -->
<div class="form-field">
  <label for="customer-email">Email address</label>
  <input
    type="email"
    id="customer-email"
    name="email"
    autocomplete="email"
  />
</div>

<!-- CORRECT: Visually-hidden label (readable by screen readers, invisible to sighted users) -->
<style>
  .visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
</style>
<div class="form-field">
  <label for="site-search" class="visually-hidden">Search the store</label>
  <input
    type="search"
    id="site-search"
    name="q"
    placeholder="Search..."
  />
</div>

<!-- CORRECT: aria-label as alternative when no <label> element is possible -->
<input
  type="search"
  name="q"
  aria-label="Search the store"
  placeholder="Search..."
/>

<!-- WRONG: title only — do NOT rely on this -->
<!-- <input type="search" name="q" title="Search the store" /> -->

<!-- WRONG: placeholder only — do NOT rely on this -->
<!-- <input type="email" name="email" placeholder="Email address" /> -->

The correct pattern: a visible <label> paired to an input via matching for/id attributes.

Landmark banner is top levelModerate effort

Move your site's `<header>` element (or `role="banner"` landmark) so it is a direct child of `<body>`, not nested inside another landmark region.

On Squarespace

  1. Squarespace controls page structure. Go to Pages → Website Tools → Custom CSS and Custom Code (Business plan or higher required for header injection).
  2. If you have injected custom HTML into the header via Settings → Advanced → Code Injection, review that injected code and remove any wrapping landmark elements (e.g., `<main>`, `<section>`) around the `<header>` content.
  3. Squarespace's native `<header>` is already top-level; the issue most commonly arises from custom code injection — audit and remove any wrapping landmarks there.
  4. Test the published site with axe DevTools.
Code · Generic HTML (html)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>My Store</title>
</head>
<body>

  <!-- CORRECT: <header> is a direct child of <body> -->
  <header>
    <a href="/"><img src="/logo.svg" alt="My Store home"></a>
    <nav aria-label="Primary">
      <ul>
        <li><a href="/shop">Shop</a></li>
        <li><a href="/about">About</a></li>
      </ul>
    </nav>
  </header>

  <main id="main-content">
    <!-- page content here -->
  </main>

  <footer>
    <!-- footer content here -->
  </footer>

</body>
</html>

Correct top-level structure: <header> is a direct child of <body>, not nested in any landmark.

Landmark complementary is top levelModerate effort

Move your <aside> element (or role="complementary") to the top level of the page so it is not nested inside another landmark region.

On Squarespace

  1. Squarespace controls most landmark HTML automatically; your best lever is Custom CSS and Code Injection.
  2. Go to Website → Pages, open the page containing the sidebar, and check whether it uses a sidebar layout (available in some templates like Brine, Avenue).
  3. If you have injected a custom `<aside>` via Settings → Advanced → Code Injection or via a Code Block, ensure that code block is placed in its own layout row/section rather than inside a block that renders within the `<main>` content area.
  4. If your template's theme wraps the sidebar inside `<main>`, add a CSS-only fix: use 'Custom CSS' (Design → Custom CSS) to apply `display: flex` or `display: grid` on the page wrapper so `<main>` and any sibling `<aside>` appear side by side without DOM nesting changes — contact Squarespace support or switch to a template that renders the sidebar outside `<main>` if the template's structure is the root cause.
  5. For Developer Platform (Squarespace 7.1 Developer mode) templates, edit the JSON-T template files directly to move the `<aside>` outside the `<main>` block.
  6. Validate the final output with axe DevTools on the live URL.
Code · Generic HTML (html)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Page Title</title>
</head>
<body>
  <header>
    <nav aria-label="Main navigation">
      <!-- navigation links -->
    </nav>
  </header>

  <!-- Correct: <main> and <aside> are siblings, both top-level landmarks -->
  <div class="page-layout">
    <main id="main-content">
      <!-- primary page content -->
    </main>

    <aside aria-label="Related products">
      <!-- complementary / sidebar content -->
    </aside>
  </div>

  <footer>
    <!-- footer content -->
  </footer>
</body>
</html>

Correct top-level landmark structure — <aside> is a sibling of <main>, both direct children of the page wrapper.

Landmark contentinfo is top levelQuick win

Move your site's footer element (or role="contentinfo") so it is a direct child of the page body, not nested inside another landmark region.

On Squarespace

  1. Squarespace manages its HTML output automatically. In most Squarespace templates, the footer is already rendered as a top-level landmark — but custom code injections can break this.
  2. Go to Website → Pages → scroll to the Footer section and ensure your footer content is placed in the native Footer area, not injected into a page section or content block.
  3. Check Settings → Advanced → Code Injection (Footer field): if you have custom HTML here that wraps content in a <footer> or role="contentinfo" element, make sure it does not duplicate or nest a footer landmark inside another one.
  4. If using custom CSS/JavaScript or third-party widgets that inject a second <footer>, remove the duplicate or remove the role from the inner element.
  5. Use axe DevTools on your live site to verify only one top-level contentinfo landmark exists.
Code · Generic HTML (html)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Store Page</title>
</head>
<body>

  <header>
    <!-- Site logo, main navigation -->
  </header>

  <nav aria-label="Main navigation">
    <!-- Primary nav links -->
  </nav>

  <main>
    <!-- All primary page content goes here -->
    <h1>Page Title</h1>
    <p>Page content...</p>
  </main>

  <!-- CORRECT: <footer> is a direct child of <body>, after </main> -->
  <footer>
    <p>&copy; 2024 My Store. All rights reserved.</p>
    <nav aria-label="Footer navigation">
      <a href="/privacy">Privacy Policy</a>
      <a href="/contact">Contact</a>
    </nav>
  </footer>

</body>
</html>

Correct top-level landmark structure — <footer> is a direct child of <body>, not nested inside <main> or any other landmark.

Landmark main is top levelQuick win

Move the `<main>` element (or `role="main"`) so it is a direct child of `<body>`, not nested inside any other landmark element such as `<header>`, `<nav>`, `<aside>`, or `<footer>`.

On Squarespace

  1. Squarespace controls its own HTML landmark structure; you cannot directly reorder `<main>` vs. `<header>` through the visual editor.
  2. Go to Pages → select a page → click Edit, and ensure your main content sections/blocks are not placed inside a Header or Footer content area.
  3. Navigate to Website → Pages → Website Tools → Custom CSS or inject code via Settings → Advanced → Code Injection: add a diagnostic script only (you cannot rewrite landmark tags via CSS injection).
  4. If the violation originates from a Squarespace template bug (some older templates wrap content inside header regions), switch to a newer Fluid Engine template, which has improved semantic structure.
  5. For code blocks, avoid adding `role` attributes that could create extra landmarks wrapping your content.
  6. Report persistent template-level violations to Squarespace support, referencing the landmark-main-is-top-level WCAG rule.
Code · Generic HTML (html)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>My Store</title>
</head>
<body>

  <header>
    <nav aria-label="Primary navigation">
      <ul>
        <li><a href="/">Home</a></li>
        <li><a href="/shop">Shop</a></li>
      </ul>
    </nav>
  </header>

  <!-- CORRECT: <main> is a direct child of <body>, NOT inside <header> or any other landmark -->
  <main id="main-content">
    <h1>Welcome to My Store</h1>
    <p>Browse our latest products below.</p>
  </main>

  <footer>
    <p>&copy; 2024 My Store</p>
  </footer>

</body>
</html>

Correct top-level landmark structure — <main> is a direct child of <body>, sibling to <header> and <footer>.

Landmark no duplicate bannerModerate effort

Ensure your page has only one banner landmark (one `<header>` or `role="banner"` element that is not nested inside another landmark), so screen reader users can navigate your site reliably.

On Squarespace

  1. Squarespace generates the `<header>` element automatically from the site Header section. You cannot change its HTML tag directly in the GUI.
  2. Go to Pages → open any page → click the pencil icon on the Header block to ensure only one header exists site-wide.
  3. If a Section block inside a page uses a `<header>` tag (rare in default templates), go to Website → Pages → select the page → edit the section's Custom CSS or inject code via Settings → Advanced → Code Injection.
  4. Use Settings → Advanced → Code Injection (Footer) to add a JavaScript snippet that renames rogue `<header>` elements to `<div>` at runtime — or contact a Squarespace developer to override via custom code.
  5. Note: deeply modifying semantic HTML in Squarespace may require a Developer Mode (Squarespace 7.0) or custom code injection approach.
Code · Generic HTML (html)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Store Page</title>
</head>
<body>

  <!-- CORRECT: Single top-level <header> = one banner landmark -->
  <header>
    <a href="/"><img src="logo.svg" alt="Acme Store"></a>
    <nav aria-label="Main navigation">
      <ul>
        <li><a href="/shop">Shop</a></li>
        <li><a href="/about">About</a></li>
        <li><a href="/contact">Contact</a></li>
      </ul>
    </nav>
  </header>

  <main>
    <article>
      <!-- CORRECT: <header> nested inside <article> is NOT a banner landmark -->
      <header>
        <h1>Product Name</h1>
        <p>Posted: <time datetime="2024-01-01">January 1, 2024</time></p>
      </header>
      <p>Product description goes here.</p>
    </article>

    <!-- CORRECT: promotional strip uses <div>, not <header> -->
    <div class="promo-bar" role="region" aria-label="Promotional offer">
      <p>Free shipping on orders over $50!</p>
    </div>
  </main>

  <footer>
    <p>&copy; 2024 Acme Store</p>
  </footer>

</body>
</html>

Correct page structure: one top-level <header> as the banner, inner content sections use <div> or are wrapped in a sectioning element.

Landmark no duplicate contentinfoModerate effort

Ensure your page has only one footer/contentinfo landmark by removing or re-marking any duplicate `<footer>` elements or `role="contentinfo"` attributes.

On Squarespace

  1. In your Squarespace admin, go to Pages → scroll to the Footer section. Squarespace renders this as the single <footer> landmark automatically.
  2. Go to Settings → Advanced → Code Injection. Check the Footer code injection box for any HTML that contains a <footer> tag or role="contentinfo" — remove or change those to <div>.
  3. In the page editor, if you have added a Code Block (Insert Point → Code) anywhere on the page that outputs a <footer> element, click the block, edit the HTML, and replace <footer> with <div>.
  4. If a third-party extension or Squarespace Extension is injecting a duplicate, check its settings or contact the developer to request a fix.
  5. Publish the site and verify with the WAVE or axe DevTools browser extension on the live URL.
Code · Generic HTML (html)
<!-- CORRECT: One site-wide footer landmark -->
<body>
  <header><!-- site header --></header>
  <main><!-- page content --></main>

  <!-- Secondary informational section — NOT a footer landmark -->
  <div class="promo-bar" aria-label="Promotional offers">
    <p>Free shipping on orders over $50!</p>
  </div>

  <!-- The ONE true contentinfo landmark -->
  <footer>
    <nav aria-label="Footer navigation">
      <ul>
        <li><a href="/privacy">Privacy Policy</a></li>
        <li><a href="/terms">Terms of Service</a></li>
        <li><a href="/contact">Contact Us</a></li>
      </ul>
    </nav>
    <p>&copy; 2024 My Store. All rights reserved.</p>
  </footer>
</body>

Correct pattern: exactly one top-level <footer> per page. Any secondary footer-like section uses <div> with a descriptive aria-label.

Landmark no duplicate mainQuick win

Find and remove every duplicate `<main>` element or `role="main"` attribute so that exactly one main landmark exists on each page.

On Squarespace

  1. Squarespace generates most landmark HTML automatically; duplicate `<main>` issues usually come from custom code injections. Go to Settings → Advanced → Code Injection and check the Header, Footer, and Page Header/Footer injection fields for any '<main>' or 'role="main"' in your custom HTML.
  2. Also check individual pages: Pages → (select page) → gear icon → Advanced → Page Header Code Injection.
  3. Remove any '<main>' tags from injected code; replace with '<div>' or '<section>'.
  4. If you have a Developer Platform (Squarespace 7.0) site with custom templates, open the relevant .region or .block files and search for duplicate '<main>' usage.
  5. Verify with the axe browser extension on the live page.
Code · Generic HTML (html)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Page Title</title>
</head>
<body>

  <header>
    <nav aria-label="Primary navigation">
      <!-- site-wide navigation -->
    </nav>
  </header>

  <!-- ✅ Only ONE <main> element per page -->
  <main id="main-content">
    <h1>Page Heading</h1>
    <!-- primary page content goes here -->
  </main>

  <footer>
    <!-- footer content -->
  </footer>

</body>
</html>

Correct page structure: exactly one <main> element wrapping the primary content, with header and footer outside it.

Landmark one mainQuick win

Add a single `<main>` landmark element (or `role="main"`) to every page so assistive technologies can identify and navigate directly to the primary content.

On Squarespace

  1. Squarespace does not allow direct HTML structural edits to its layout. Go to Website → Pages, and for each page open the page settings.
  2. In the Design tab of your page, look for a 'Page Section' with an Advanced or Custom CSS/Code block option.
  3. Use Settings → Advanced → Code Injection (available on Business plan and above) to inject a small JavaScript snippet into the page footer that programmatically adds `role="main"` to the primary content wrapper (commonly `#page` or `#content`).
  4. Test the injected role using the axe DevTools extension on the live published page.
  5. Note: Squarespace 7.1 templates are not fully editable at the HTML level; if you need full landmark control, consider migrating critical content to a supported custom-code block or contacting Squarespace support about their built-in accessibility roadmap.
Code · Squarespace (html)
<script>
(function () {
  // Squarespace wraps main content in #page or #content — adjust selector if needed
  var selectors = ['#page', '#content', '.sqs-layout', '[data-page-sections]'];
  for (var i = 0; i < selectors.length; i++) {
    var el = document.querySelector(selectors[i]);
    if (el && !document.querySelector('[role="main"]') && !document.querySelector('main')) {
      el.setAttribute('role', 'main');
      el.setAttribute('id', 'main-content');
      break;
    }
  }
})();
</script>

Inject in Settings → Advanced → Code Injection → Footer. Adds role='main' to Squarespace's primary content wrapper via JavaScript.

Landmark uniqueModerate effort

Add a unique aria-label (or aria-labelledby) to every repeated landmark role on the page so screen-reader users can tell them apart.

On Squarespace

  1. Squarespace does not expose direct HTML landmark editing through its standard editor. You will need to use the Code Injection feature.
  2. Go to Settings → Advanced → Code Injection → Footer. Paste a small JavaScript snippet that selects the duplicate landmark elements by class or position and adds aria-label attributes to each.
  3. Alternatively, if you have a Business or Commerce plan, go to Pages → (your page) → Edit → add a Code Block, then use JavaScript to target and label the landmarks on that specific page.
  4. The most reliable approach is to inject JS in the site-wide footer: document.querySelectorAll('nav')[0].setAttribute('aria-label','Main navigation'); document.querySelectorAll('nav')[1].setAttribute('aria-label','Footer navigation'); — adjusted for your actual landmark count and structure.
  5. Save and preview, then confirm with the axe DevTools extension that landmark-unique violations are resolved.
Code · Squarespace (html)
<script>
  (function () {
    // Label all <nav> elements on the page uniquely.
    // Adjust the labels to match your actual navigation regions.
    var navs = document.querySelectorAll('nav');
    var labels = [
      'Main navigation',
      'Footer navigation',
      'Breadcrumb'
    ];
    navs.forEach(function (nav, index) {
      if (!nav.getAttribute('aria-label') && labels[index]) {
        nav.setAttribute('aria-label', labels[index]);
      }
    });

    // Label repeated <section> or <aside> elements if needed.
    var asides = document.querySelectorAll('aside');
    var asideLabels = ['Related posts', 'Newsletter signup'];
    asides.forEach(function (aside, index) {
      if (!aside.getAttribute('aria-label') && asideLabels[index]) {
        aside.setAttribute('aria-label', asideLabels[index]);
      }
    });
  })();
</script>

Paste this JavaScript into Settings → Advanced → Code Injection → Footer. Adjust indices and labels to match your actual page structure.

Link in text blockQuick win

Increase the color contrast between inline links and their surrounding body text to at least 3:1, or add a non-color visual distinction (such as underline) so links are identifiable without relying on color alone.

On Squarespace

  1. In the Squarespace editor, go to Design → Fonts (or Styles, depending on your version).
  2. Scroll to the Link Style section and update the link color to a compliant value using the color picker (enter the hex code directly).
  3. Also confirm that 'Underline' is toggled on for links inside text blocks — this satisfies the non-color distinction requirement even if contrast is borderline.
  4. For Squarespace 7.1 with custom CSS: Design → Custom CSS, add: .sqs-block-content a { color: #YOUR_COLOR; text-decoration: underline; }
  5. Save and preview on a page with body text containing links to verify.
Code · Squarespace (css)
/* Squarespace: target links inside standard text blocks */
.sqs-block-content a {
  color: #0057d8; /* update to your chosen compliant color */
  text-decoration: underline;
}

Paste into Design → Custom CSS in the Squarespace editor.

Link nameQuick win

Add a descriptive, screen-reader-accessible text label to every link on your store so assistive technology can announce its purpose.

On Squarespace

  1. Squarespace has limited direct code access. Go to Website → Pages → click the relevant page → Edit, then locate the block containing the problematic link.
  2. For image blocks used as links: click the image block → Edit → Link, then add alt text in the 'Image Alt Text' field — Squarespace uses this as the accessible name for linked images.
  3. For social icon blocks: Squarespace automatically adds aria-labels to its built-in social links block based on the network name — ensure you are using the native Social Links block, not a custom code block with raw icon HTML.
  4. For custom code blocks (HTML/CSS/JS): go to the block → Edit → paste your code with proper aria-label attributes on all <a> tags.
  5. For header/navigation icon buttons (cart, search): go to Design → Site Styles or the header settings — Squarespace's native icons are typically labelled, but if you've added a custom icon via Code Injection (Settings → Advanced → Code Injection → Header), add aria-label to those elements.
  6. Publish and test with WAVE.
ListModerate effort

Fix all HTML lists so that only valid child elements appear directly inside `<ul>` and `<ol>` tags, and only `<ul>` or `<ol>` elements wrap `<li>` items.

On Squarespace

  1. In Squarespace, go to Pages → select the affected page → click Edit.
  2. For navigation: Squarespace auto-generates nav HTML — if errors appear here, go to Design → Navigation Styles and switch to a different nav style, or use the Footer editor to rebuild footer links using the built-in Link Block rather than a Code Block.
  3. For body content lists: click on the text block containing the list → highlight the items → use the text editor toolbar's List button (bulleted or numbered) to convert them to a proper Squarespace list, which outputs correct `<ul>`/`<li>` markup.
  4. For custom Code Blocks (Settings → Advanced → Code Injection or a Code Block on a page): open the code block and manually correct the `<ul>`/`<ol>` HTML to ensure only `<li>` children are used.
  5. Save and re-publish the page, then re-test with axe.
Code · Generic HTML (html)
<!-- CORRECT: <ul> or <ol> with only <li> children -->
<ul>
  <li>First item</li>
  <li>Second item</li>
  <li>Third item
    <!-- CORRECT: nested list lives INSIDE an <li> -->
    <ul>
      <li>Nested item A</li>
      <li>Nested item B</li>
    </ul>
  </li>
</ul>

<!-- WRONG: <div> as a direct child of <ul> -->
<!-- <ul>
  <div>This breaks the list</div>
  <li>Item</li>
</ul> -->

<!-- WRONG: <li> with no list parent -->
<!-- <li>Orphaned item</li> -->

Correct list structure — all platforms. Use this as a reference for what valid markup looks like.

ListitemModerate effort

Ensure every `<li>` element is a direct child of a `<ul>` or `<ol>` element (or an element explicitly given `role="list"`), so that screen readers can correctly announce list structure to users.

On Squarespace

  1. Log in to your Squarespace account and open the affected page in the Pages panel.
  2. If the broken list is inside a text block: click Edit on the block, select your list text, and use the Squarespace text toolbar to apply 'Bulleted List' or 'Numbered List' formatting — this generates proper `<ul><li>` or `<ol><li>` HTML.
  3. If the broken list is in a custom Code Block (Add Block → Code), click to edit the block and rewrite the markup so `<li>` elements are wrapped in `<ul>` or `<ol>`.
  4. For list markup injected via Settings → Advanced → Code Injection (site-wide header/footer scripts), find the relevant script and correct the HTML structure there.
  5. If the issue originates in a Squarespace built-in navigation or summary block and you cannot change the markup, contact Squarespace support or use custom CSS combined with ARIA overrides only as a last resort.
  6. Save and preview the page. Use axe DevTools browser extension to verify the fix.
Code · Generic HTML (html)
<!-- CORRECT: unordered list -->
<ul>
  <li>Free shipping on orders over $50</li>
  <li>30-day returns</li>
  <li>2-year warranty</li>
</ul>

<!-- CORRECT: ordered list (e.g. steps) -->
<ol>
  <li>Add item to cart</li>
  <li>Enter shipping address</li>
  <li>Complete payment</li>
</ol>

<!-- CORRECT: list inside a <nav> (navigation pattern) -->
<nav aria-label="Main navigation">
  <ul>
    <li><a href="/shop">Shop</a></li>
    <li><a href="/about">About</a></li>
    <li><a href="/contact">Contact</a></li>
  </ul>
</nav>

<!-- WRONG: <li> inside a <div> — do NOT do this -->
<!--
<div>
  <li>Item one</li>
  <li>Item two</li>
</div>
-->

<!-- LAST RESORT only: if the parent HTML tag truly cannot be changed,
     add role="list" to the parent element -->
<div role="list">
  <div role="listitem">Item one</div>
  <div role="listitem">Item two</div>
</div>

Correct structure: every <li> must be a direct child of <ul> or <ol>.

Meta refreshQuick win

Remove or disable the `<meta http-equiv="refresh">` tag that forces an automatic page reload, or replace any redirect use-case with a server-side redirect instead.

On Squarespace

  1. Go to Website → Pages → select the affected page → click the gear icon (Page Settings) → Advanced → Page Header Code Injection.
  2. Remove any `<meta http-equiv="refresh" ...>` tag pasted there.
  3. Also check Settings → Advanced → Code Injection (site-wide header) for the same tag.
  4. For redirects, use Squarespace's URL Mapping tool: Settings → Advanced → URL Mappings. Add a line like `/ -> /new-page 301` following Squarespace's syntax.
  5. Save and publish, then verify via View Source that the meta-refresh is gone.
Code · Generic HTML (html)
<!-- REMOVE — self-refresh every 30 seconds (WCAG fail) -->
<!-- <meta http-equiv="refresh" content="30"> -->

<!-- REMOVE — redirect to another URL after 5 seconds (WCAG fail) -->
<!-- <meta http-equiv="refresh" content="5; url=https://example.com/new-page"> -->

<!-- ALLOWED — 0-second instant redirect (no time limit imposed on user) -->
<!-- Only use this as a fallback alongside a server-side redirect -->
<meta http-equiv="refresh" content="0; url=https://example.com/new-page">

REMOVE this tag from your page's <head>. Both forms below are problematic (self-refresh and timed redirect).

Meta viewportQuick win

Remove `user-scalable=no` (and any `maximum-scale` below 5) from your site's `<meta name="viewport">` tag so visitors can pinch-to-zoom on mobile devices.

On Squarespace

  1. Squarespace injects the viewport tag at the platform level and does not expose it for direct editing.
  2. Go to Website → Pages → select any page → gear icon → Advanced → Page Header Code Injection.
  3. You can inject a corrected viewport tag here to override the platform default: <meta name="viewport" content="width=device-width, initial-scale=1"> — browsers use the last valid viewport tag, but browser behaviour varies; test carefully.
  4. Alternatively, contact Squarespace Support and report the accessibility issue so they can fix it platform-wide.
  5. Check your version: Squarespace 7.1 templates are more likely to have addressed this; 7.0 legacy templates may still include zoom-blocking attributes.
Code · Squarespace (html)
<meta name="viewport" content="width=device-width, initial-scale=1">

Inject this into Website → Pages → [page] → Advanced → Page Header Code Injection to attempt an override of the platform viewport tag. Test on multiple browsers.

Meta viewport largeQuick win

Remove or raise the `maximum-scale` value in your meta viewport tag so users can pinch-zoom on mobile devices.

On Squarespace

  1. Squarespace controls the viewport tag internally and generally does not block zoom.
  2. To add or override the tag, go to Website → Pages → click the gear icon on any page → Advanced → Page Header Code Injection, and paste a corrected <meta name="viewport"> tag.
  3. For a sitewide fix, go to Settings → Advanced → Code Injection → Header and add the corrected tag there.
  4. Note: injecting a second viewport tag may cause duplicate-tag warnings — confirm via DevTools that the correct tag takes effect.
Code · Squarespace (html)
<meta name="viewport" content="width=device-width, initial-scale=1">

In Settings → Advanced → Code Injection → Header, paste this snippet sitewide.

Nested interactiveModerate effort

Remove or restructure nested interactive elements so that no focusable control (button, link, input, etc.) is placed inside another interactive control, and never rely on tabindex="-1" or aria-hidden="true" to hide an inner interactive element from assistive technologies.

On Squarespace

  1. In your Squarespace admin, go to Pages → [affected page] → Edit. Identify the block containing the nested interactive element.
  2. If the issue is in a Button block inside a Clickable element block, remove the clickable behavior from the outer container — keep only the Button block as the interactive control.
  3. For custom code injected via Settings → Advanced → Code Injection or a Code Block, edit the HTML directly: remove the nested interactive tag and replace it with a `<span>` or style the remaining single element as needed.
  4. If the nesting comes from a third-party Squarespace plugin/extension, contact the developer or replace it with a custom Code Block where you control the markup.
  5. Save and preview. Use the axe browser extension to confirm the violation is resolved.
Code · Generic HTML (html)
<!-- ❌ WRONG: button nested inside a link (invalid HTML, unpredictable in screen readers) -->
<a href="/products/widget">
  <button type="button">View Product</button>
</a>

<!-- ✅ CORRECT: single interactive element styled as a button -->
<a href="/products/widget" class="btn btn-primary">View Product</a>


<!-- ❌ WRONG: link nested inside a button -->
<button type="button">
  <a href="/cart">Add to Cart</a>
</button>

<!-- ✅ CORRECT: use only the element that matches the action -->
<!-- If it navigates → use <a>; if it performs an action on the page → use <button> -->
<a href="/cart" class="btn btn-primary">Add to Cart</a>


<!-- ❌ WRONG: relying on tabindex or aria-hidden to suppress inner element -->
<a href="/products/widget">
  <button type="button" tabindex="-1" aria-hidden="true">View Product</button>
</a>

<!-- ✅ CORRECT: icons and decorative content inside interactive elements must be non-interactive -->
<button type="button">
  <svg aria-hidden="true" focusable="false" width="20" height="20">
    <use href="#icon-cart"></use>
  </svg>
  <span>Add to Cart</span>
</button>

The WRONG pattern and the correct fix side by side.

Object altQuick win

Add a meaningful text alternative (via `title` attribute or `aria-label`) to every `<object>` element so screen readers can describe its content to users who cannot see it.

On Squarespace

  1. In the Squarespace Editor, navigate to the page containing the embedded object.
  2. If the <object> is inside a Code Block, click the block to edit it, then find the <object> tag in the code and add `title='Descriptive label here'`.
  3. If it is in a Markdown Block with embedded HTML, switch to the HTML view and add the `title` attribute.
  4. For site-wide code injected via Settings → Advanced → Code Injection, edit the relevant script/HTML snippet there.
  5. Save the block or injection, then publish and verify with the axe DevTools browser extension.
Code · Generic HTML (html)
<!-- BEFORE (fails accessibility check) -->
<object data="product-catalog.pdf" type="application/pdf" width="600" height="400">
  <p>Your browser does not support PDFs.</p>
</object>

<!-- AFTER: Option 1 — title attribute (preferred for <object>) -->
<object
  data="product-catalog.pdf"
  type="application/pdf"
  width="600"
  height="400"
  title="Winter 2024 Product Catalog (PDF)">
  <p>Your browser does not support PDFs.
    <a href="product-catalog.pdf">Download the catalog</a>.
  </p>
</object>

<!-- AFTER: Option 2 — aria-label (acceptable alternative) -->
<object
  data="product-catalog.pdf"
  type="application/pdf"
  width="600"
  height="400"
  aria-label="Winter 2024 Product Catalog (PDF)">
  <p>Your browser does not support PDFs.
    <a href="product-catalog.pdf">Download the catalog</a>.
  </p>
</object>

<!-- AFTER: Option 3 — purely decorative, hide from AT -->
<object
  data="decorative-animation.svg"
  type="image/svg+xml"
  width="200"
  height="200"
  aria-hidden="true">
</object>

Add a `title` attribute to any <object> element — this is the primary fix. Use aria-label as an alternative if ARIA is already in use on the element.

Page has heading oneQuick win

Add a single, descriptive `<h1>` heading to every page so assistive technologies and search engines can identify the page's main topic.

On Squarespace

  1. Open the page in the Squarespace editor and click on the text block that represents the main page title.
  2. Highlight the title text, then click the text-format toolbar and select 'Heading 1' (the style marked with a single '#' or labeled 'H1').
  3. If the page uses a cover page or banner section whose title is output by Squarespace automatically, check Site Styles to confirm the Page Title style maps to an <h1> — Squarespace 7.1 themes do this by default for page and collection titles.
  4. For blog posts and product pages, Squarespace automatically renders the post/product title as <h1> — verify by viewing page source.
  5. After saving, view source (Ctrl+U) and search for '<h1' to confirm exactly one exists, then re-run your accessibility checker.
Code · Generic HTML (html)
<main>
  <h1>Women's Running Shoes</h1>
  <!-- rest of page content -->
</main>

Place this after your site navigation, as the first element inside <main>. Style it with CSS as needed — the visual size is independent of the semantic tag.

Presentation role conflictModerate effort

Remove conflicting ARIA attributes (global ARIA properties and tabindex) from any element that has been marked as purely presentational with role="presentation" or role="none".

On Squarespace

  1. In Squarespace, direct HTML editing is limited. Start by identifying which element triggers the issue using Chrome DevTools → Elements panel.
  2. If the element is a built-in Squarespace block (e.g. a decorative image or spacer block), check whether a custom Code Block or CSS injection is adding ARIA attributes — go to Pages → (your page) and look for any Code Blocks, or check Design → Custom CSS.
  3. Remove or correct any custom ARIA attributes in the offending Code Block or Custom CSS/JS injection under Settings → Advanced → Code Injection (header/footer).
  4. If the issue is in Squarespace's own theme output and you cannot edit it directly, document the element and submit a support request to Squarespace, or use the Code Injection area to inject a small corrective JavaScript snippet that removes the conflicting attribute after DOM load (see code snippet below).
  5. Republish and re-scan with axe DevTools.
Code · Squarespace (html)
<script>
(function () {
  var CONFLICTING = [
    'aria-label','aria-labelledby','aria-describedby',
    'aria-live','aria-atomic','aria-relevant','aria-busy',
    'aria-controls','aria-owns','aria-flowto',
    'aria-haspopup','aria-expanded','tabindex'
  ];
  function fixConflicts() {
    document.querySelectorAll('[role="presentation"],[role="none"]')
      .forEach(function(el) {
        CONFLICTING.forEach(function(a) { el.removeAttribute(a); });
      });
  }
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', fixConflicts);
  } else {
    fixConflicts();
  }
}());
</script>

Paste in Settings → Advanced → Code Injection → Footer to auto-correct conflicting presentational elements injected by blocks you cannot directly edit.

RegionModerate effort

Wrap all visible page content inside HTML landmark regions (e.g. `<header>`, `<main>`, `<nav>`, `<footer>`) so screen-reader users can navigate the page by section.

On Squarespace

  1. Squarespace renders its own landmark structure — the global header, footer, and page sections are automatically wrapped in semantic elements in most modern templates (7.1). Open your live site and run the axe extension to confirm which specific content is orphaned.
  2. In the Pages panel, if you are using 'Page Sections' (7.1 fluid engine), ensure all content blocks are placed inside a Section — do not use the 'Page Header' injection points for content that belongs in the body.
  3. Go to Settings → Advanced → Code Injection (available on Business plan and above). If you have injected raw HTML in the Header or Footer injection fields, ensure that injected content is wrapped with the correct landmark tags (e.g., `<div role='region' aria-label='Announcement'>` as a minimum).
  4. For content inside Custom Code blocks on a page, wrap the HTML in the appropriate landmark before pasting.
  5. Use Squarespace's 'Page Settings → SEO' description and title fields properly — these also improve overall page structure signals.
Role img altModerate effort

Add a meaningful aria-label (or aria-labelledby) to every element with role="img" so screen readers can announce what the image represents.

On Squarespace

  1. In Squarespace, go to Pages → select the page → click Edit.
  2. For an Icon Block, click the icon to open its settings; look for an 'Alt Text' or 'Accessible Label' field and fill it in.
  3. For SVG or Code Blocks containing role="img" HTML, click the block → Edit → and update the HTML directly to include aria-label="[description]" on the role="img" element.
  4. For template-level icon fonts (e.g. social icons in the footer), go to Design → Custom CSS and inject a JavaScript fix via Settings → Advanced → Code Injection (header or footer): add a <script> that finds each [role='img'] without aria-label and adds one.
  5. Squarespace does not expose direct theme file editing, so Code Injection is the primary route for template-controlled elements.
  6. Validate with the axe browser extension after saving.
Code · Generic HTML (html)
<!-- Pattern 1: Inline element (icon font, emoji, span) -->
<span role="img" aria-label="Free shipping available">🚚</span>

<!-- Pattern 2: SVG element — use <title> + aria-labelledby (most robust) -->
<svg role="img" aria-labelledby="icon-free-shipping" width="24" height="24" xmlns="http://www.w3.org/2000/svg">
  <title id="icon-free-shipping">Free shipping available</title>
  <use href="#icon-truck"></use>
</svg>

<!-- Pattern 3: SVG with aria-label only (simpler, slightly less support) -->
<svg role="img" aria-label="4.5 out of 5 stars" width="120" height="24" xmlns="http://www.w3.org/2000/svg">
  <!-- star paths here -->
</svg>

<!-- Pattern 4: div/section used as a decorative image — HIDE from screen readers -->
<div role="presentation" aria-hidden="true" class="decorative-banner"></div>

<!-- Pattern 5: referencing an existing visible caption -->
<figure>
  <div role="img" aria-labelledby="badge-caption" class="trust-badge"></div>
  <figcaption id="badge-caption">Verified Secure Checkout</figcaption>
</figure>

Apply to any HTML element using role="img" — choose the pattern that matches your element type.

Scrollable region focusableQuick win

Make every scrollable region on your site reachable by keyboard by adding tabindex="0" (or placing focusable content inside it) so keyboard and assistive-technology users can scroll it.

On Squarespace

  1. In Squarespace, go to Pages → select the relevant page → Edit.
  2. Click the scrollable content block. If it is a Code Block containing custom HTML, click Edit on the block and add tabindex="0" aria-label="[Region name]" to the scrollable element's HTML tag.
  3. For Squarespace-native blocks (e.g. a scrolling text section), inject a CSS override via Design → Custom CSS: .your-block-class { /* already has overflow:auto */ } .your-block-class:focus { outline: 2px solid #005fcc; } — and use a Code Injection (Settings → Advanced → Code Injection) with a small <script> snippet to add tabindex="0" to the element by its class or data attribute.
  4. Save and preview. Test keyboard navigation with Tab and arrow keys.
Code · Generic HTML (html)
<!-- BEFORE (inaccessible): -->
<div class="product-description" style="height: 200px; overflow-y: auto;">
  <p>This is a long product description that requires scrolling to read in full...</p>
</div>

<!-- AFTER (keyboard-accessible): -->
<div
  class="product-description"
  style="height: 200px; overflow-y: auto;"
  tabindex="0"
  aria-label="Product description"
  role="region"
>
  <p>This is a long product description that requires scrolling to read in full...</p>
</div>

Add tabindex="0" and aria-label to any scrollable container that holds only non-interactive content.

Select nameQuick win

Add a visible or programmatic label to every `<select>` dropdown so assistive technologies can announce its purpose to users.

On Squarespace

  1. Squarespace controls most form and product option HTML; you have limited direct access. Navigate to Pages → the page containing the dropdown, then open the block/section editor.
  2. For Squarespace Form blocks: click the form block → Edit → click the dropdown field → ensure the 'Label' field is filled in. Squarespace renders this as a visible label linked to the field.
  3. For product option dropdowns (Commerce), go to Commerce → your product → click 'Options' and ensure each option has a descriptive name (e.g., 'Size', 'Color'). Squarespace uses these names to build accessible labels automatically in most templates.
  4. For any remaining unlabeled selects, use Settings → Advanced → Code Injection (available on Business plan and above) to inject a JavaScript snippet that adds `aria-label` to the specific `<select>` element by its class or position. Example: `document.querySelector('.your-select-class').setAttribute('aria-label', 'Sort by');`
  5. Alternatively, add a Custom CSS / Custom Code block via a Code Block widget with the JavaScript above, scoped to the relevant page.
  6. Re-test with the axe extension after publishing.
Code · Squarespace (html)
<script>
  // Runs after page load to add aria-label to any select missing an accessible name.
  // Update the selector '.your-select-class' to match your specific dropdown.
  (function() {
    var selects = document.querySelectorAll('select:not([aria-label]):not([aria-labelledby]):not([id])');
    selects.forEach(function(sel) {
      // Try to infer a label from a sibling or data attribute, otherwise use a fallback.
      var sibling = sel.previousElementSibling;
      var labelText = (sibling && sibling.textContent.trim()) ? sibling.textContent.trim() : 'Select an option';
      sel.setAttribute('aria-label', labelText);
    });
  })();
</script>

Inject via Settings → Advanced → Code Injection → Footer, or add as a Code Block on the specific page. Targets an unlabeled select by its class; update the selector to match your theme's actual class.

Skip linkQuick win

Add a valid, focusable target element (with a matching `id`) for every "Skip to main content" link so keyboard and assistive-technology users can bypass repeated navigation.

On Squarespace

  1. In Squarespace, go to Website → Pages → select any page → click Edit, then open Settings → Advanced → Page Header Code Injection.
  2. Alternatively, use the site-wide injection: Settings → Advanced → Code Injection → Header.
  3. Paste the skip link `<a>` tag and accompanying `<style>` block into the Header injection field (see code snippet below). The skip link will be injected on every page.
  4. Squarespace's main content area uses the selector `#page` or `#content` depending on the template. Inspect your live page with browser DevTools to identify the correct `id` of the main content wrapper, then match the `href` fragment to that `id`.
  5. Because Squarespace does not let you modify core template markup, add `tabindex="-1"` to the target element via JavaScript in the Footer Code Injection: `document.querySelector('#page, #content, main').setAttribute('tabindex', '-1');`
  6. Publish and test with keyboard Tab on the live site.
Svg img altModerate effort

Add a meaningful text alternative to every SVG image so screen readers can describe it to visually impaired shoppers.

On Squarespace

  1. Squarespace renders most icons and logos as inline SVGs that you cannot directly edit in the visual editor. For your site logo: go to Pages > Website Tools (or Design) > Logo & Title and re-upload your logo as a PNG or SVG; Squarespace wraps it in an `<img>` tag where you can set alt text under Design > Logo.
  2. For SVGs embedded via a Code Block: Pages > (your page) > Edit > add or open a Code Block > edit the raw SVG HTML directly to include `role="img"` and `aria-label="Description"` on the `<svg>` tag, or nest `<title id="t1">Description</title>` inside it and reference it with `aria-labelledby="t1"`.
  3. For theme-generated SVG icons (social icons, navigation arrows), inject a CSS/JS fix via Settings > Advanced > Code Injection > Header: add a small JavaScript snippet that selects the SVGs by class and sets `setAttribute('aria-label', 'Description')` and `setAttribute('role', 'img')` for each.
  4. For decorative SVGs, use Code Injection to add a script that sets `setAttribute('aria-hidden', 'true')` on the relevant SVG elements.
  5. Test with Chrome's Accessibility panel after publishing.
Code · Generic HTML (html)
<!-- MEANINGFUL SVG — use title + aria-labelledby -->
<svg role="img" aria-labelledby="svg-logo-title" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
  <title id="svg-logo-title">Acme Co. logo — home</title>
  <!-- SVG path data here -->
  <circle cx="50" cy="50" r="50" fill="#e63946"/>
</svg>

<!-- MEANINGFUL SVG — simpler aria-label alternative -->
<svg role="img" aria-label="Free shipping badge" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  <!-- SVG path data here -->
  <path d="M1 3h15v13H1z" fill="#2a9d8f"/>
</svg>

<!-- DECORATIVE SVG — hide from assistive technology -->
<svg aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 10">
  <!-- decorative divider path -->
  <rect width="200" height="10" fill="#f0f0f0"/>
</svg>

Preferred pattern for a meaningful inline SVG: <title> as first child + aria-labelledby on the root element.

TabindexModerate effort

Remove or replace all positive tabindex values (tabindex="1" or higher) on your page elements, using tabindex="0" for focusable elements and tabindex="-1" only when programmatic focus is needed.

On Squarespace

  1. In your Squarespace admin, go to Website → Pages, then open the page in the editor.
  2. Squarespace does not allow direct HTML editing of most elements; however, you can inject custom HTML/CSS via Settings → Advanced → Code Injection (site-wide) or via a Code Block on a specific page.
  3. If you added a Code Block or Embed Block containing elements with positive tabindex values, click the block to edit it, find the tabindex attribute in your HTML, and change the value to '0' or remove it.
  4. If the issue comes from Squarespace's own theme components (not custom code you added), report it to Squarespace Support — you cannot directly edit their native template HTML.
  5. For developer-mode templates (legacy Squarespace 7.0 with Developer Mode enabled), edit the template files via SFTP and search for 'tabindex' in .html and .block files.
  6. After changes, reload your live site and test tab order with the keyboard.
Code · Generic HTML (html)
<!-- ❌ WRONG: positive tabindex breaks natural tab order -->
<button tabindex="3">Submit</button>
<a href="/shop" tabindex="1">Shop Now</a>
<div tabindex="2">Custom widget</div>

<!-- ✅ CORRECT: native elements use no tabindex (natural order) -->
<button>Submit</button>
<a href="/shop">Shop Now</a>

<!-- ✅ CORRECT: non-native element made focusable in natural order -->
<div tabindex="0" role="button" aria-label="Custom widget">Custom widget</div>

<!-- ✅ CORRECT: element only focused by JavaScript (e.g., modal), not in tab flow -->
<div tabindex="-1" id="modal-container" role="dialog" aria-modal="true">...</div>

Replace any positive tabindex value with 0 (or remove the attribute). Use -1 only for programmatic focus.

Valid langQuick win

Add or correct the `lang` attribute on every HTML element that contains content in a different language, using a valid BCP 47 language code.

On Squarespace

  1. Squarespace automatically sets the <html lang> attribute based on your site's language setting: go to Settings → Region & Language → Site Language and choose the correct language — Squarespace translates this to a valid BCP 47 code.
  2. For inline foreign-language text blocks, add a Code Block (Insert Point → Code) and write: <p lang="fr">Votre texte ici.</p>. This is the only way to attach a lang attribute to a specific passage in Squarespace.
  3. If you use Squarespace's built-in multilingual feature (Business plan and above), each language version will inherit the correct lang attribute automatically — verify by previewing the alternate locale and inspecting the <html> tag.
Code · Generic HTML (html)
<!-- Primary page language on the root element -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>My Store</title>
  </head>
  <body>
    <p>Welcome to our store. Free shipping on orders over $50.</p>

    <!-- Inline passage in a different language: add lang to the wrapping element -->
    <p lang="fr">Bienvenue dans notre boutique. Livraison gratuite dès 50 €.</p>

    <!-- Inline span for a short foreign-language phrase within an English sentence -->
    <p>Our slogan is <span lang="de">Qualität zuerst</span>, which means "Quality first".</p>
  </body>
</html>

Set the primary language on the <html> tag and mark inline foreign-language passages with their own lang attribute.

Security (OWASP) · 26 fixes

Dmarc policy noneModerate effort

Strengthen your DMARC policy from p=none (monitor-only) to p=quarantine, then p=reject, so that emails fraudulently sent from your domain are blocked rather than silently allowed through.

On Squarespace

  1. Go to your Squarespace Dashboard → Settings → Domains. If DNS is hosted by Squarespace, click on your domain → DNS Settings → Custom Records.
  2. Find the existing _dmarc TXT record and edit the p= value from none to quarantine. If no DMARC record exists, add a TXT record with Host = _dmarc and the updated value.
  3. If Squarespace Email Campaigns is in use, ensure the sending domain is verified (Squarespace guides you through SPF/DKIM in Settings → Email Campaigns → Sender Email).
  4. After monitoring rua reports for a few weeks, return and change p=quarantine to p=reject.
Code · Squarespace (dns)
v=DMARC1; p=quarantine; sp=quarantine; pct=100; rua=mailto:dmarc-reports@yourdomain.com; ri=86400; aspf=r; adkim=r; fo=1;

In Squarespace Dashboard → Settings → Domains → DNS Settings → Custom Records. Host: _dmarc | Type: TXT | Data: the string below.

Hsts disabledQuick win

Set a valid HTTP Strict-Transport-Security (HSTS) header with a max-age of at least 31536000 (one year) and includeSubDomains to force browsers to always use HTTPS for your store.

On Squarespace

  1. Squarespace automatically enables HTTPS and sets an HSTS header for all custom domains — there is no manual header configuration panel in the Squarespace admin.
  2. Ensure SSL is active: go to Settings → Domains → click your domain → confirm the SSL badge shows 'Active'.
  3. If your domain was recently connected, wait up to 72 hours for SSL provisioning and HSTS to propagate.
  4. Verify using DevTools (F12 → Network → your domain → Response Headers) that Strict-Transport-Security is present.
Code · Generic HTML (html)
Strict-Transport-Security: max-age=31536000; includeSubDomains

This is an HTTP response header — it cannot be set in HTML meta tags. It must be set by your server, CDN, or platform. Shown here for reference only.

Hsts max age too shortQuick win

Increase your HSTS max-age directive to at least 31536000 seconds (1 year) so browsers enforce HTTPS connections for a meaningful period.

On Squarespace

  1. Squarespace provides automatic SSL and controls HSTS at the infrastructure level — you cannot set custom HTTP headers from the Squarespace admin panel.
  2. Confirm SSL is enabled: Squarespace Admin → Settings → Security & SSL → ensure 'Secure (preferred)' mode is selected and 'HSTS' is toggled on if that option is available in your plan.
  3. If a scanner reports a short max-age, this is a Squarespace platform-level setting. Contact Squarespace Support with the specific header value and request they update it to max-age=31536000.
  4. For Squarespace Developer Platform sites or external domains proxied through Cloudflare in front of Squarespace, you can override/supplement the HSTS header at the Cloudflare level using a Transform Rule.
Code · Generic HTML (http)
Strict-Transport-Security: max-age=31536000; includeSubDomains

This is an HTTP response header — it must be sent by your server, NOT as an HTML meta tag. The meta tag is not supported for HSTS.

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 Squarespace

  1. Squarespace automatically issues and renews a free SSL certificate for all sites on a paid plan.
  2. In your Squarespace Admin panel, go to Settings → Domains.
  3. Click your custom domain and confirm 'SSL' shows as Active.
  4. Go to Settings → Advanced → SSL and set the Security preference to 'Secure (HTTPS)' and enable 'HSTS' if the option is available in your plan.
  5. Squarespace automatically redirects HTTP to HTTPS; no manual redirect rules are required.
Info disclosure serverQuick win

Remove or suppress the HTTP `Server` response header so your web server no longer advertises its software name and version number to the public internet.

On Squarespace

  1. Squarespace is a fully managed SaaS platform — `Server` headers are set by Squarespace's infrastructure and are not configurable from the Pages, Design, or Settings panels.
  2. Contact Squarespace Support via the Help Center to report the finding and ask for documentation confirming their infrastructure-level header policy for compliance purposes.
  3. To gain control over headers, proxy your Squarespace site through *Cloudflare*: in your domain registrar (or Squarespace Domains panel), update nameservers to Cloudflare, enable the proxy, and add a Transform Rule to remove or overwrite the `Server` response header.
Code · Generic HTML (html)
<!-- The Server header cannot be controlled from HTML.
     Apply the fix at your web server, CDN, or hosting control panel
     using one of the platform-specific configurations shown below. -->

There is no HTML tag to set or suppress the Server header — it is purely a server/CDN-level configuration. Use the server-specific snippets below.

Info disclosure x powered byQuick win

Remove or suppress the X-Powered-By HTTP response header so your server stops advertising which technology stack, hosting platform, or software version powers your store.

On Squarespace

  1. Squarespace is a fully hosted SaaS platform; store owners cannot modify server response headers directly.
  2. Squarespace does not expose an X-Powered-By header on standard storefronts.
  3. If a third-party integration or code injection block is adding this header, remove or update that integration.
  4. Contact Squarespace support if the platform itself is emitting the header unexpectedly.
Code · Generic HTML (html)
<!-- X-Powered-By is an HTTP response header set by the server, not in HTML markup.
     Use the server-side code snippets below for your specific platform. -->

There is no HTML tag for this — it is a server-side HTTP response header. Use the server/framework snippets below.

Insecure cookieModerate effort

Set the HttpOnly, Secure, and SameSite flags on all session and authentication cookies to prevent them from being stolen or misused by attackers.

On Squarespace

  1. Squarespace manages all core session cookies at the platform level — you cannot modify their Set-Cookie headers directly. If core cookies are flagged, raise the issue with Squarespace support.
  2. For any custom cookies set via Code Injection (Settings → Advanced → Code Injection) or page-specific JavaScript blocks, refactor those cookies to be set server-side instead. Because Squarespace does not offer server-side scripting, move cookie logic to an external serverless function (Netlify Functions, Vercel, Cloudflare Workers) and proxy the response.
  3. Audit third-party scripts added via Code Injection and remove or replace those that set insecure cookies.
Code · Generic HTML (http)
Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=Strict

Correct Set-Cookie HTTP response header — all three flags present. Your server must emit this header, not JavaScript.

Missing content security policyModerate effort

Add a Content-Security-Policy (CSP) HTTP response header to every page to block unauthorized scripts, styles, and resources from loading in your visitors' browsers.

On Squarespace

  1. Squarespace does not allow custom HTTP response headers.
  2. Add a partial CSP via Settings → Advanced → Code Injection → Header field: paste a <meta http-equiv='Content-Security-Policy' content='default-src self; object-src none;'> tag. This only covers HTML pages, not all resource types, and some directives are ignored in meta-tag mode.
  3. For stronger enforcement, route your Squarespace site through Cloudflare and add the CSP as a Cloudflare Transform Rule on HTTP responses.
Missing dmarcQuick win

Add a DMARC DNS TXT record at _dmarc.yourdomain.com to tell receiving mail servers how to handle emails that fail authentication checks for your domain.

On Squarespace

  1. If your domain is registered with Squarespace: go to Squarespace Dashboard → Domains → click your domain → DNS Settings → Add Record → Type: TXT, Host: _dmarc, Data: v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com, TTL: 3600 → Save.
  2. If your domain DNS is managed outside Squarespace (e.g. at GoDaddy), add the TXT record there.
  3. Squarespace Commerce sends transactional email (order confirmations etc.) via Squarespace's own servers, so SPF/DKIM for that path is managed by Squarespace. If you use Google Workspace or another external mail provider for your From: address, add that provider's DKIM record first.
  4. After publishing the DMARC record at p=none, monitor reports for 2–4 weeks before tightening the policy.
Code · Generic HTML (dns)
_dmarc.yourdomain.com. 3600 IN TXT "v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com; ruf=mailto:dmarc-forensic@yourdomain.com; sp=none; adkim=r; aspf=r"

Add this as a DNS TXT record at your domain registrar or DNS provider. Replace yourdomain.com and the rua address with your actual domain.

Missing permissions policyQuick win

Add a Permissions-Policy HTTP response header to your store to explicitly restrict which browser features (camera, microphone, geolocation, etc.) pages and embedded third-party scripts are allowed to access.

On Squarespace

  1. Squarespace does not provide a native interface for setting custom HTTP response headers.
  2. Use Cloudflare as your DNS proxy: In Cloudflare → Rules → Transform Rules → Modify Response Header → add 'Permissions-Policy' header with value 'camera=(), microphone=(), geolocation=(), payment=(), usb=(), interest-cohort=()'.
  3. Verify in browser DevTools → Network → Response Headers.
Code · Generic HTML (meta tag — limited support) (html)
<!-- NOT recommended — use a real HTTP header instead. Shown for reference only. -->
<meta http-equiv="Permissions-Policy" content="camera=(), microphone=(), geolocation=(), payment=(), usb=(), interest-cohort=()">

Meta tag delivery is not recommended — use HTTP headers instead. Included for reference only; browser support is partial.

Missing referrer policyQuick win

Add a Referrer-Policy HTTP response header set to strict-origin-when-cross-origin to control what URL information browsers send when users navigate away from your store.

On Squarespace

  1. Squarespace does not expose HTTP response header configuration to store owners.
  2. Inject the meta tag via Website → Pages → select any page → Edit → click the gear icon (Page Settings) → Advanced → Header Code Injection. Add: <meta name="referrer" content="strict-origin-when-cross-origin">
  3. For site-wide injection, go to Settings → Advanced → Code Injection → Header and paste the same <meta> tag — this applies it to all pages globally.
  4. For a true HTTP header (stronger), proxy Squarespace through Cloudflare and use a Transform Rule to add the header.
Code · Generic HTML (html)
<meta name="referrer" content="strict-origin-when-cross-origin">

Add inside the <head> element of every HTML page as a fallback when HTTP header control is unavailable.

Missing security txtQuick win

Create and publish a /.well-known/security.txt file with at least a Contact: line so security researchers know how to report vulnerabilities responsibly.

On Squarespace

  1. Squarespace does not allow files to be placed at /.well-known/ directly.
  2. Use a Cloudflare Worker (if your domain is proxied through Cloudflare) to serve the security.txt content at that path before the request reaches Squarespace.
  3. Alternatively, contact Squarespace support to enquire about custom file hosting for /.well-known/ — this is not natively supported as of 2024.
  4. Verify by visiting https://yourdomain.com/.well-known/security.txt after configuring the worker.
Code · Generic HTML (text)
Contact: mailto:security@yourdomain.com
Expires: 2026-12-31T23:59:00.000Z
Preferred-Languages: en
Policy: https://yourdomain.com/security-policy
Acknowledgments: https://yourdomain.com/security-acknowledgments

Save this as security.txt and place it at /.well-known/security.txt on your web server. Update all placeholder values before publishing.

Missing spfQuick win

Add a DNS TXT record containing a valid SPF policy to your domain so that email receivers can verify which servers are authorised to send mail on your behalf.

On Squarespace

  1. If your domain is registered with Squarespace: Squarespace Dashboard → Domains → click your domain → DNS Settings → Custom Records.
  2. Click 'Add record', set Type = TXT, Host = '@', Data = your SPF string (e.g. v=spf1 include:_spf.google.com -all). Save.
  3. If your domain is registered elsewhere, log in to that registrar and add the TXT record there.
  4. Squarespace transactional (order) emails are sent by Squarespace's infrastructure. Squarespace automatically adds required authentication records for domains registered with them; verify by checking Squarespace's Help Center article on email authentication for the current recommended SPF include.
  5. If you send marketing email via Mailchimp, Klaviyo, or another tool, add those services' include: entries to the same record.
  6. Verify with MXToolbox SPF Lookup.
Code · Generic HTML (dns)
v=spf1 include:_spf.google.com include:sendgrid.net include:spf.mailgun.org -all

Add this as a DNS TXT record at your domain apex ('@'). Replace the include: values with the exact hostnames from each of your email providers' SPF documentation. Only one SPF TXT record is allowed per domain — combine all providers into one record.

Missing strict transport securityQuick win

Add the Strict-Transport-Security (HSTS) response header to every HTTPS page so browsers always use an encrypted connection to your store.

On Squarespace

  1. Squarespace automatically provisions SSL and enforces HTTPS for all sites — HSTS is intended to be managed at the platform level.
  2. Verify the header is present on your live domain with browser DevTools or securityheaders.com.
  3. If missing, contact Squarespace Support referencing the Strict-Transport-Security header. There is no in-dashboard toggle for HSTS.
  4. If your domain routes through Cloudflare, enable HSTS in Cloudflare → SSL/TLS → Edge Certificates → HTTP Strict Transport Security (HSTS).
Code · Generic HTML (html)
<!-- HSTS cannot be set via an HTML meta tag. It MUST be sent as an HTTP response header. Use the server-level examples below. -->
<!-- Correct header value -->
<!-- Strict-Transport-Security: max-age=31536000; includeSubDomains -->

Meta tags cannot set HSTS — it must be a real HTTP response header. This is a reminder of the correct header value to use at the server level.

Missing x content type optionsQuick win

Add the `X-Content-Type-Options: nosniff` HTTP response header to every page and asset your store serves.

On Squarespace

  1. Squarespace does not allow direct HTTP response header configuration from the admin panel.
  2. Route your custom domain through Cloudflare: add your domain to Cloudflare (free plan), point your domain's nameservers to Cloudflare, then go to Rules → Transform Rules → Modify Response Header → Create Rule → Add header `X-Content-Type-Options` with value `nosniff` → deploy.
  3. Verify in browser DevTools after Cloudflare propagates (usually within minutes).
Code · Generic HTML (http)
X-Content-Type-Options: nosniff

This is an HTTP response header — it is sent by the server, not placed in HTML markup. The examples below show where and how to set it.

Missing x frame optionsQuick win

Add the X-Frame-Options HTTP response header set to DENY or SAMEORIGIN to prevent your store's pages from being embedded in iframes on other sites.

On Squarespace

  1. Squarespace does not allow direct HTTP response header customization from the admin panel.
  2. Place your Squarespace site behind Cloudflare by pointing your domain's nameservers or DNS A/CNAME records to Cloudflare (in 'DNS only' mode if full proxy is preferred).
  3. In Cloudflare: Rules → Transform Rules → Response Header Modification → Add header: X-Frame-Options = SAMEORIGIN for all requests → Deploy.
  4. Verify by loading any Squarespace page and checking Response Headers in browser DevTools.
Code · Generic HTML (http)
X-Frame-Options: SAMEORIGIN

This is an HTTP response header — it must be sent by the server, not a meta tag. It should appear in the HTTP response headers for every page.

Passive scan onlyModerate effort

Set up regular active security testing (DAST) on a staging copy of your store to catch vulnerabilities that passive header/cookie/TLS scans cannot find.

On Squarespace

  1. Squarespace is a fully managed SaaS platform with no self-hosted staging; create a free trial store as a staging proxy: squarespace.com → Get Started → use the same template.
  2. On the trial site, use Settings → Permissions → set Site Visibility to 'Password Protected' to prevent public indexing.
  3. Run OWASP ZAP in Spider/Passive mode against the trial URL to inventory pages and identify any exposed sensitive endpoints or missing security headers (Squarespace controls headers centrally).
  4. Active injection testing on Squarespace core is not applicable (Squarespace manages the backend); focus DAST efforts on any custom JavaScript injected via Settings → Advanced → Code Injection.
  5. Review all custom code blocks and third-party embed scripts for XSS risks — remove or sanitise any that accept user input.
  6. Report infrastructure-level findings to Squarespace Support; keep all Squarespace Extensions updated via the Extensions marketplace.
Code · Generic HTML (html)
<meta name="robots" content="noindex, nofollow">

Add this meta tag to your staging site's <head> to prevent search engines from indexing it while DAST scanning is in progress.

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 Squarespace

  1. Squarespace automatically provisions free SSL certificates via Let's Encrypt for all Squarespace-hosted domains and auto-renews them.
  2. To check: go to Squarespace Dashboard → Settings → Domains. A green lock icon next to each domain indicates active SSL.
  3. If a domain shows SSL as inactive or pending, navigate to Settings → Domains → click the affected domain → select 'Use Squarespace Nameservers' or verify your external DNS is correctly pointed. Squarespace cannot issue a certificate if DNS is misconfigured.
  4. If SSL remains inactive after 72 hours of correct DNS configuration, contact Squarespace Support via Help → Contact Us.
Code · Generic HTML (html)
<!-- Place this in your maintenance/holding page only if HTTPS is temporarily unavailable -->
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

Meta-refresh redirect for maintenance: not applicable to SSL renewal. Instead, use this HTML to display a temporary notice if your cert has lapsed and you need to redirect HTTP traffic while fixing HTTPS.

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 Squarespace

  1. Squarespace automatically provisions and renews free SSL certificates for all sites and connected custom domains.
  2. Go to Home Menu → Settings → Domains. Click your custom domain and confirm it shows 'Active' with SSL enabled.
  3. If SSL is listed as 'Pending' or 'Not Secure', the issue is almost always a DNS misconfiguration. Ensure your domain registrar has the exact DNS records Squarespace requires: an A record pointing to 198.185.159.144 / 198.185.159.145 and CNAME www pointing to ext-cust.squarespace.com.
  4. After correcting DNS, SSL provisioning can take up to 72 hours for DNS propagation. Squarespace handles renewal automatically.
  5. Squarespace does not support uploading custom SSL certificates.
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 Squarespace

  1. Squarespace automatically provisions free SSL certificates (via Let's Encrypt) for all sites, including custom domains.
  2. Go to: Squarespace Admin → Settings → Domains (or Website → Pages → Website Tools on older navigation).
  3. Click your custom domain and confirm it is 'Active' with SSL enabled.
  4. If SSL shows as unavailable, the most common cause is incorrect DNS — ensure your domain's CNAME record points to ext-cust.squarespace.com (for subdomains/www) and/or the A record is pointed to Squarespace's correct IP.
  5. Toggle 'HTTPS Encryption' on under Settings → Advanced → SSL if it appears disabled.
  6. Allow up to 72 hours after DNS correction for the certificate to be issued. Contact Squarespace Support if the issue persists.
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 Squarespace

  1. Squarespace automatically provisions a free SSL certificate (via Comodo/Sectigo) for all sites and keeps port 443 open — firewall configuration is not in your control.
  2. Go to Home Menu → Settings → Security & SSL.
  3. Ensure 'Secure (HTTPS)' is selected (not 'Insecure (HTTP)'). Toggle 'HTTPS Encryption' to ON.
  4. Enable 'Automatic SSL Renewal' to prevent future certificate expiry.
  5. For custom domains, confirm DNS is pointed to Squarespace per Settings → Domains. Certificate provisioning happens automatically within 72 hours of DNS propagation.
  6. If the SSL status shows an error, click 'Troubleshoot SSL' on the same page or contact Squarespace Support.
Vulnerable component axiosModerate effort

Update the Axios JavaScript library to its latest stable release to eliminate known security vulnerabilities in your storefront code.

On Squarespace

  1. Squarespace has limited custom code access. Go to Website → Pages → select any page → click Edit → insert a Code Block, or go to Settings → Advanced → Code Injection to find any manually added Axios <script> tags.
  2. If you added a CDN script tag for Axios yourself, update it to point to the latest version URL in the same Code Injection / Code Block location.
  3. If the vulnerable Axios is loaded by a Squarespace Extension or third-party embed, contact the extension provider for a patched version — you cannot modify extension internals.
  4. If you use a custom Developer template (Squarespace Developer Platform), open your local project, run `npm install axios@latest`, rebuild, and redeploy.
Code · Generic HTML (html)
<!-- Load the latest Axios from jsDelivr CDN (always points to newest stable release) -->
<script src="https://cdn.jsdelivr.net/npm/axios@latest/dist/axios.min.js" integrity="" crossorigin="anonymous"></script>

<!-- OR pin to a specific safe version (recommended for production stability) -->
<script src="https://cdn.jsdelivr.net/npm/axios@1.7.9/dist/axios.min.js" crossorigin="anonymous"></script>

Replace any hardcoded Axios CDN script tag in your HTML templates with this — always uses the latest stable version.

Vulnerable component jqueryModerate effort

Update jQuery to the latest stable version (3.7+) to eliminate known cross-site scripting (XSS) and prototype-pollution vulnerabilities that attackers actively exploit.

On Squarespace

  1. Squarespace manages its own jQuery version internally and updates it as part of platform releases — you cannot directly override it. Keep your Squarespace plan active and up to date.
  2. Navigate to Website → Pages → select any page → Edit, then go to Settings (gear icon) → Advanced → Page Header Code Injection. Check for any manually added jQuery <script> tags and update their CDN URLs to 'https://code.jquery.com/jquery-3.7.1.min.js'.
  3. Also check Settings → Advanced → Code Injection (global header/footer) for any outdated jQuery script tags and update them.
  4. For third-party Squarespace plugins (blocks from external vendors), contact the vendor and request a version that loads current jQuery, or remove the block.
  5. Publish changes and use DevTools → Network to audit which jQuery version(s) are loaded.
Code · Generic HTML (html)
<!-- Remove your old jQuery script tag and replace with this -->
<script
  src="https://code.jquery.com/jquery-3.7.1.min.js"
  integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo="
  crossorigin="anonymous"></script>

Replace any old jQuery <script> tag in your HTML <head> with this. Get the current SRI hash from https://code.jquery.com/

Weak spfQuick win

Add a hard-fail (-all) or soft-fail (~all) terminator to your SPF DNS record so that mail servers reject or flag email sent from servers not explicitly authorized by your domain.

On Squarespace

  1. In Squarespace, go to the Home Menu → Settings → Domains → click your domain → DNS Settings.
  2. Under 'Custom Records', find the TXT record starting with `v=spf1`.
  3. Click Edit and update the record value to include `-all` or `~all` at the end.
  4. Click Save.
  5. If your domain's nameservers are pointed away from Squarespace (e.g., to Cloudflare), you must edit the record at whichever provider is authoritative for your DNS.
Code · Generic HTML (dns)
v=spf1 include:_spf.google.com include:sendgrid.net -all

DNS TXT record value for your root domain (@). Replace the include/redirect mechanisms with the ones your email service provider specifies, and always end with -all or ~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 Squarespace

  1. Squarespace automatically sets `X-Content-Type-Options: nosniff` on all hosted stores — no manual configuration is available or needed within the Squarespace UI.
  2. If a duplicate header is detected, audit any Cloudflare or CDN layer connected to your custom domain: Cloudflare Dashboard → Rules → Transform Rules → Modify Response Headers — remove any rule setting this header.
  3. Contact Squarespace Support if the platform itself is emitting a malformed or repeated value.
X frame options weakQuick win

Replace the weak X-Frame-Options header value with DENY or SAMEORIGIN to prevent clickjacking attacks on your store.

On Squarespace

  1. Squarespace manages HTTP headers at the infrastructure level — there is no admin UI to set custom response headers.
  2. Squarespace already sends X-Frame-Options: SAMEORIGIN on most page responses. If a scan reports a weak value (e.g. ALLOW-FROM from an integrated third-party service), the issue is in that third-party service's configuration, not Squarespace itself.
  3. Contact Squarespace Support (Help → Contact Us) to report the specific header issue and request an update.
  4. If the offending header comes from a third-party embed (e.g. a CMS preview iframe), contact that vendor to update their response headers to use Content-Security-Policy frame-ancestors instead of ALLOW-FROM.
Code · Generic HTML (html)
<!-- X-Frame-Options MUST be sent as an HTTP response header, not a meta tag. -->
<!-- Use the server-side or platform snippets below instead. -->

<!-- The modern equivalent you CAN set via meta tag (limited support): -->
<meta http-equiv="Content-Security-Policy" content="frame-ancestors 'none';">

If you cannot set server-level headers, use this meta-equivalent only as a last resort — note that X-Frame-Options via meta tag is NOT supported by browsers (it must be an HTTP header). This snippet is shown for illustration only; use server-side headers.

Site Lifecycle · 12 fixes

Cms versionModerate effort

Update your CMS and ecommerce platform to the latest stable version immediately to close known security vulnerabilities and maintain vendor support.

On Squarespace

  1. Squarespace is fully SaaS — core platform updates are automatic and you cannot control them.
  2. If you are on an older Squarespace template version (7.0 vs 7.1), Squarespace recommends migrating to 7.1 for ongoing feature and security support. Go to your Squarespace account dashboard to start a new 7.1 site if you are still on 7.0.
  3. Third-party code blocks and custom scripts injected via Settings > Advanced > Code Injection or individual page headers should be audited periodically — update any CDN-linked libraries to their latest versions.
Code · Generic HTML (html)
<!-- REMOVE or suppress this tag from your <head> — it advertises your CMS version to attackers -->
<!-- <meta name="generator" content="WordPress 5.8.1" /> -->

<!-- In WordPress, add this to your theme's functions.php to remove it: -->
<!-- remove_action('wp_head', 'wp_generator'); -->

If your site injects a generator meta tag exposing your CMS version publicly, remove it to reduce information exposure to attackers. This does not replace upgrading — it is a secondary hardening step.

Domain expiryQuick win

Log in to your domain registrar, confirm your domain's expiry date, and enable auto-renew so your store never goes offline due to an expired domain.

On Squarespace

  1. For domains purchased through Squarespace: go to the Squarespace Dashboard → Domains. Click the domain → 'Domain Settings'. Scroll to 'Auto-Renew' and make sure it is toggled ON.
  2. Confirm the billing card linked to your Squarespace account is valid: Account Menu → Billing → Payment Methods.
  3. For externally registered domains pointed to Squarespace: manage auto-renew at your registrar (e.g. GoDaddy, Namecheap).
Code · Generic HTML (html)
<!-- No HTML change required. Domain renewal is managed at your domain registrar's dashboard (e.g. GoDaddy, Namecheap, Cloudflare Registrar). Log in, find the domain, enable auto-renew, and confirm a valid payment method is on file. -->

No code change is needed on your website — this fix is completed entirely in your registrar's dashboard. There is no markup or configuration file involved.

Gtm auditModerate effort

Install Google Tag Manager on your store and configure it to fire GA4 with full ecommerce event tracking (view_item, add_to_cart, purchase, and more).

On Squarespace

  1. Go to Settings › Developer Tools › Code Injection (on Business plan or higher).
  2. Paste the GTM <script> snippet into the 'Header' field and the <noscript> snippet into the 'Footer' field. Save.
  3. For GA4, also go to Settings › Analytics › Google Analytics and enter your GA4 Measurement ID for Squarespace's native ecommerce events (purchase tracking).
  4. For richer events (view_item, add_to_cart), you will need custom code injections or the Littledata connector for Squarespace Commerce.
  5. Verify with GTM Preview mode.
Code · Generic HTML (html)
<!-- Google Tag Manager (paste in <head>) -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXXX');</script>
<!-- End Google Tag Manager -->

<!-- Google Tag Manager (noscript) (paste immediately after <body>) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXXXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->

Replace GTM-XXXXXXX with your real Container ID. First snippet goes in <head>, second immediately after <body>.

Html langQuick win

Add a lang attribute to your site's <html> tag that matches the primary language of your store's content.

On Squarespace

  1. Squarespace automatically sets the lang attribute based on your site's language setting.
  2. To change it: go to Settings → Language & Region → Site Language and choose the correct language.
  3. Squarespace injects the lang attribute into <html> automatically — you do not edit it directly in a template file.
  4. If you use Code Injection (Settings → Advanced → Code Injection), do not add a duplicate <html> tag there; only adjust the language in Settings.
Code · Generic HTML (html)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Your Store</title>
</head>
<body>
  <!-- page content -->
</body>
</html>

Place this as the very first tag in your HTML document, before <head>.

Lifecycle oos schema not updatedModerate effort

Update the `offers.availability` value in your Product structured data from `InStock` to `OutOfStock` (or `PreOrder`) whenever a product sells out, so Google's records always match your actual inventory.

On Squarespace

  1. Squarespace Commerce automatically outputs Product schema and syncs availability with your inventory settings.
  2. In your Squarespace admin, go to Commerce (or Selling) → Inventory. Find each sold-out product and confirm its stock quantity is set to 0 or that 'Sold Out' is indicated.
  3. Navigate to the product's page in the Pages panel, click to edit the product block, and under Inventory set the quantity to 0 and ensure 'Allow purchases when out of stock' is unchecked — this ensures the schema signals `OutOfStock`.
  4. Squarespace does not expose the JSON-LD template for direct editing; availability in schema is derived purely from inventory data, so correct stock settings are the only lever.
  5. Validate with Google's Rich Results Test after saving.
Code · Generic HTML (json)
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Your Product Name",
  "image": "https://example.com/images/product.jpg",
  "description": "Short product description.",
  "sku": "YOUR-SKU-123",
  "brand": {
    "@type": "Brand",
    "name": "Your Brand"
  },
  "offers": {
    "@type": "Offer",
    "url": "https://example.com/product-page",
    "priceCurrency": "USD",
    "price": "29.99",
    "availability": "https://schema.org/OutOfStock",
    "itemCondition": "https://schema.org/NewCondition"
  }
}
</script>

Place this inside a <script type='application/ld+json'> tag in the <head> or <body> of your product page. Replace placeholder values with real data. Use OutOfStock when sold out.

Lifecycle orphaned productsModerate effort

Add internal links pointing to every orphaned product page from relevant category pages, collection pages, or other on-site content so search crawlers and shoppers can discover them.

On Squarespace

  1. In Squarespace, go to Commerce → Inventory and open each orphaned product.
  2. In the product editor, use the 'Categories' field to assign the product to one or more relevant categories. Save.
  3. Go to Pages and ensure the Shop page (or the relevant Category page) is included in your main navigation — if not, drag it into the Navigation section in the Pages panel.
  4. To add cross-links, open a related product page → scroll to the bottom → add a Related Products block or a Products block filtered to the same category.
  5. For editorial cross-links, open a relevant Blog post or regular page, add a Products block, and filter it to feature the orphaned product.
Code · Generic HTML (html)
<!-- Add this inside a relevant category page, blog post, or 'Featured Products' section -->
<a href="/products/your-orphaned-product-slug">Product Display Name</a>

Add a simple text link from any existing page (category, homepage, blog post) pointing directly to the orphaned product URL.

Lifecycle products missing from sitemapQuick win

Add all canonical product URLs to your XML sitemap so search engines discover and index every product page quickly.

On Squarespace

  1. Squarespace auto-generates a sitemap at yourdomain.com/sitemap.xml — only published pages and products are included.
  2. Go to your Squarespace Admin → Pages panel and confirm all product pages/stores are Published (not Draft or Password-protected at the page level).
  3. Check that the Store page itself is not disabled: in Pages, click the gear icon next to your store page → SEO tab → ensure 'Hide page from search engines' is NOT checked.
  4. For individual products: open the product in the Commerce panel, click the SEO tab for that product, and confirm 'Enable search engine indexing' is on (Squarespace 7.1).
  5. Submit the sitemap in Google Search Console → Indexing → Sitemaps → enter 'sitemap.xml' → Submit.
Code · Generic HTML (xml)
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">

  <!-- Example product page entry -->
  <url>
    <loc>https://www.example.com/products/blue-running-shoes</loc>
    <lastmod>2024-06-01</lastmod>
    <changefreq>weekly</changefreq>
    <priority>0.8</priority>
  </url>

  <!-- Repeat one <url> block per canonical product page -->
  <url>
    <loc>https://www.example.com/products/red-yoga-mat</loc>
    <lastmod>2024-05-20</lastmod>
    <changefreq>weekly</changefreq>
    <priority>0.8</priority>
  </url>

</urlset>

Standard XML sitemap structure. Place this at yourdomain.com/sitemap.xml (or reference it from a sitemap index file).

Lifecycle products too deepModerate effort

Move deeply buried product pages closer to the homepage by flattening your site's navigation structure so every product is reachable within 4 clicks (ideally 3) from the homepage.

On Squarespace

  1. Go to Pages in the Squarespace panel. Your page hierarchy is visible here; pages nested under folders add click depth.
  2. Drag nested pages out of deep folder hierarchies and place them directly under a top-level folder, or ungroup them as standalone navigation pages.
  3. For Squarespace Commerce: go to Commerce → Inventory, select the affected products, and add them to a top-level or second-level category tag. Then create a dedicated Store page filtered by that category and link it in your main navigation.
  4. On your homepage, add a 'Products' block (Insert Point → Commerce → Products) filtered to show the previously buried products, creating a direct 1-click path.
  5. Review your main navigation in the Pages panel to confirm no Store section is more than one folder deep.
Code · Generic HTML (html)
<!-- Featured Products section on homepage or top category page -->
<section aria-label="Featured Products">
  <h2>Featured Products</h2>
  <ul>
    <li><a href="/products/product-name-1">Product Name 1</a></li>
    <li><a href="/products/product-name-2">Product Name 2</a></li>
    <li><a href="/products/product-name-3">Product Name 3</a></li>
  </ul>
</section>

Add direct internal links to deep products from your homepage or top-level category pages. Place this markup in a 'Featured Products' or 'Quick Links' section.

Mixed contentModerate effort

Ensure every resource (images, scripts, stylesheets, fonts, iframes) on your store is loaded over HTTPS, never HTTP, so browsers never block or warn about mixed content.

On Squarespace

  1. Squarespace hosts all its own assets over HTTPS. Mixed content comes from Code Blocks or custom CSS/JS injections.
  2. Go to Pages → click the page → Edit → find any Code Block components. Click each to edit and replace 'http://' URLs with 'https://'.
  3. Go to Settings → Advanced → Code Injection. Check the Header and Footer injection areas for any 'http://' src or href values and update them to 'https://'.
  4. Go to Design → Custom CSS and look for any url('http://...') references — update to 'https://'.
  5. Re-test using browser DevTools Console.
Code · Generic HTML (html)
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

Add this meta tag inside <head> to instruct browsers to automatically upgrade HTTP sub-requests to HTTPS. This is a safety net — fix the root URLs too.

Mobile viewportQuick win

Add a responsive viewport meta tag to every page so mobile browsers render your site at the correct width and scale.

On Squarespace

  1. Squarespace injects the viewport meta tag automatically on all templates — no manual action is required.
  2. If you use Code Injection (Settings → Advanced → Code Injection → Header), verify you have not accidentally added a second conflicting viewport tag.
  3. Remove any duplicate or restrictive viewport meta tags from the Header code injection box.
  4. Save and verify on a mobile device.
Code · Generic HTML (html)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Page Title</title>
</head>
<body>
  <!-- page content -->
</body>
</html>

Place the viewport meta tag as early as possible in <head>, before any CSS or other meta tags.

Server versionQuick win

Remove or suppress HTTP response headers that advertise your server software name and version to the public internet.

On Squarespace

  1. Squarespace manages its own infrastructure; 'Server' and 'X-Powered-By' headers are not configurable from the admin panel.
  2. Route traffic through Cloudflare (point your nameservers to Cloudflare in 'orange-cloud' / proxy mode), then use a Transform Rule to delete 'X-Powered-By' and set 'Server' to a neutral value.
  3. Navigate to Cloudflare: Rules → Transform Rules → Modify Response Header → Create Rule → Remove header → 'X-Powered-By'. Repeat for any other disclosing headers.
  4. Verify the fix by checking response headers in DevTools after Cloudflare propagation (may take a few minutes).
Code · Generic HTML (html)
<!-- HTTP response headers cannot be set via HTML meta tags.
     Use the server-side or CDN configuration snippets below. -->

Meta tags cannot suppress HTTP response headers — this must be done at the server/CDN layer. The snippets below cover the most common server/framework approaches.

Ssl expiryQuick win

Renew your TLS/SSL certificate before it expires and enable automatic renewal so your store never goes offline or shows security warnings.

On Squarespace

  1. Squarespace automatically provisions and renews SSL for all sites — no manual action is needed.
  2. To confirm: go to Pages (or Website) → Website Tools → SSL, and verify the toggle is set to 'Secure' (HTTPS).
  3. Also enable the 'HSTS' option in the same panel to enforce HTTPS at the browser level.
  4. If your domain is registered elsewhere, ensure your DNS records still point to Squarespace, as a misconfigured DNS prevents renewal.
Code · Generic HTML (html)
<!-- SERVER-SIDE redirect is strongly preferred. Example nginx config snippet below. -->
<!-- nginx: force HTTPS -->
<!-- server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
} -->

Verify your HTTPS redirect is in place at the server/app level. This meta-refresh is a last-resort fallback only — implement a proper server-side 301 redirect instead.

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 Squarespace

  1. Squarespace generates robots.txt automatically and does not allow direct editing.
  2. Make sure you have NOT enabled any setting that hides the site from search engines (Settings > Crawlers / 'Discourage search engines').
  3. Because per-bot robots rules aren't editable, lean on the other GEO levers (llms.txt, schema, sameAs) to maximise AI visibility.
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 Squarespace

  1. Squarespace generates robots.txt automatically and does not allow direct editing.
  2. Make sure you have NOT enabled any setting that hides the site from search engines (Settings > Crawlers / 'Discourage search engines').
  3. Because per-bot robots rules aren't editable, lean on the other GEO levers (llms.txt, schema, sameAs) to maximise AI visibility.
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 Squarespace

  1. Squarespace emits some commerce schema automatically; add or extend JSON-LD via Settings > Advanced > Code Injection (or per-page code injection) for Organization sameAs and any missing Product fields.
  2. Fill in Business Information (Settings) so name/logo/social links are available.
  3. Validate with 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 Squarespace

  1. Squarespace emits some commerce schema automatically; add or extend JSON-LD via Settings > Advanced > Code Injection (or per-page code injection) for Organization sameAs and any missing Product fields.
  2. Fill in Business Information (Settings) so name/logo/social links are available.
  3. Validate with 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 Squarespace

  1. Squarespace emits some commerce schema automatically; add or extend JSON-LD via Settings > Advanced > Code Injection (or per-page code injection) for Organization sameAs and any missing Product fields.
  2. Fill in Business Information (Settings) so name/logo/social links are available.
  3. Validate with 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 Squarespace

  1. Squarespace emits some commerce schema automatically; add or extend JSON-LD via Settings > Advanced > Code Injection (or per-page code injection) for Organization sameAs and any missing Product fields.
  2. Fill in Business Information (Settings) so name/logo/social links are available.
  3. Validate with 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 Squarespace

  1. Squarespace emits some commerce schema automatically; add or extend JSON-LD via Settings > Advanced > Code Injection (or per-page code injection) for Organization sameAs and any missing Product fields.
  2. Fill in Business Information (Settings) so name/logo/social links are available.
  3. Validate with 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 Squarespace

  1. Squarespace emits some commerce schema automatically; add or extend JSON-LD via Settings > Advanced > Code Injection (or per-page code injection) for Organization sameAs and any missing Product fields.
  2. Fill in Business Information (Settings) so name/logo/social links are available.
  3. Validate with 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 Squarespace

  1. Squarespace doesn't allow arbitrary root files; use a URL redirect or a Code Block page and map /llms.txt where possible, or host the file on a subdomain/CDN you control.
  2. Verify the URL resolves to the generated content.