outdoorvoices.com
Audited 6 days ago· shopify
Agent-readiness across all five AI commerce surfaces.
Surfaces — click to filter
13 failing · 11 not checked · 24 shown
11 checks couldn't run on this store — each is listed below with the reason. Your score reflects only what we could verify.
Enforce HTTPS sitewide and ship a Strict-Transport-Security header with max-age ≥ 6 months
Why this matters: AI agents and payment flows refuse plain HTTP; weak HSTS is treated as effectively no HSTS by trust-and-safety scanners.
Findings (1)
Confirmed the homepage is HTTPS (status 200), probed http://outdoorvoices.com/ for redirect behaviour, and parsed the Strict-Transport-Security header (value: "max-age=7889238").
How: URL scheme + homepage status check, an http://host/ redirect probe through politeFetch, and a Strict-Transport-Security max-age parse (RFC 6797; ≥ 180-day threshold).
- HSTS max-age is below the 6-month minimumCRITICAL
/parsed max-age = 7889238s (need ≥ 15552000s = 180 days)
What we found
max-age=7889238What we expected
Strict-Transport-Security: max-age=31536000; includeSubDomainsBump
max-ageto at least 15552000 (180 days). 31536000 (1 year) is required for preload-list inclusion.
Emit a single Product JSON-LD node per PDP
Why this matters: Duplicate Product nodes on a single PDP cause Google's merchant scraper to drop the listing or pick the wrong variant.
Findings (20)
Sampled 20 PDP(s); 20 carried multiple Product JSON-LD nodes.
How: For each sampled PDP, count JSON-LD nodes whose @type is Product or whose @type array contains Product. Each PDP must expose at most one.
Coverage
0/20 · 0%
- PDP exposes 8 Product JSON-LD nodesHIGH× 10
Emit exactly one Product JSON-LD block per PDP; model variants via
hasVariantor multiple Offer children.Affected (10)
- /products/m-gridtek-breezy-shortsleeve-reservoir8 Product nodes detected
- /products/m-solarcool-camp-collar-rainstorm-blur8 Product nodes detected
- /products/megafleece-full-zip-conifer-navy8 Product nodes detected
- /products/m-rectrek-zip-off-pant-black8 Product nodes detected
- /products/w-the-volley-dress-reservoir8 Product nodes detected
- /products/w-the-exercise-dress-rainstorm-blur8 Product nodes detected
- /products/w-techsweat-move-free-dress-margarita8 Product nodes detected
- /products/w-the-exercise-3in-skort-evergreen8 Product nodes detected
- /products/w-cowgirl-jean-salt8 Product nodes detected
- /products/m-recreationalist-graphic-shortsleeve…8 Product nodes detected
…and 10 more
Populate gtin on every branded Product node
Why this matters: GTINs let agents match your product to the same item elsewhere; without them you lose cross-catalog matching.
Findings (11)
Checked 20 sampled product pages for a GTIN in the Product JSON-LD (0 carry a valid GTIN, 0%).
How: Extract gtin / gtin8 / gtin12 / gtin13 / gtin14 from the first Product JSON-LD node on each PDP; validate digit length.
Coverage
0/20 · 0%
- No valid GTIN on this product pageHIGH× 10
Populate gtin/gtin8/gtin12/gtin13/gtin14 with the manufacturer's barcode.
Affected (10)
- /products/m-gridtek-breezy-shortsleeve-reservoir
- /products/m-solarcool-camp-collar-rainstorm-blur
- /products/megafleece-full-zip-conifer-navy
- /products/m-rectrek-zip-off-pant-black
- /products/w-megafleece-cropped-pullover-oatmeal
- /products/w-superform-rib-longsleeve-jasmine
- /products/w-orbit-bra-yucca
- /products/w-the-volley-dress-reservoir
- /products/w-the-exercise-dress-rainstorm-blur
- /products/w-energy-dress-yucca-multi
…and 1 more
Make every MerchantReturnPolicy node satisfy Option A or Option B
Why this matters: A policy node missing both shapes is invisible to agents — they can't render it, link to it, or quote your return terms.
Findings (11)
Inspected 20 MerchantReturnPolicy nodes across 20 PDPs (0 satisfy Option A or B, 0%).
How: For each PDP, walk every hasMerchantReturnPolicy node (Product or Offer level) and require either (applicableCountry + returnPolicyCategory) OR a syntactically-valid merchantReturnLink URL.
Coverage
0/20 · 0%
- MerchantReturnPolicy node fails Option A and Option BHIGH× 10
Add (applicableCountry + returnPolicyCategory) or merchantReturnLink to this policy node.
Affected (10)
- /products/m-gridtek-breezy-shortsleeve-reservoirnode missing Option A or B (lacks: returnPolicyCategory, applicableCountry (ISO alpha-2), merchantReturnLink (URL))
- /products/m-solarcool-camp-collar-rainstorm-blurnode missing Option A or B (lacks: returnPolicyCategory, applicableCountry (ISO alpha-2), merchantReturnLink (URL))
- /products/megafleece-full-zip-conifer-navynode missing Option A or B (lacks: returnPolicyCategory, applicableCountry (ISO alpha-2), merchantReturnLink (URL))
- /products/m-rectrek-zip-off-pant-blacknode missing Option A or B (lacks: returnPolicyCategory, applicableCountry (ISO alpha-2), merchantReturnLink (URL))
- /products/w-megafleece-cropped-pullover-oatmealnode missing Option A or B (lacks: returnPolicyCategory, applicableCountry (ISO alpha-2), merchantReturnLink (URL))
- /products/w-superform-rib-longsleeve-jasminenode missing Option A or B (lacks: returnPolicyCategory, applicableCountry (ISO alpha-2), merchantReturnLink (URL))
- /products/w-orbit-bra-yuccanode missing Option A or B (lacks: returnPolicyCategory, applicableCountry (ISO alpha-2), merchantReturnLink (URL))
- /products/w-the-volley-dress-reservoirnode missing Option A or B (lacks: returnPolicyCategory, applicableCountry (ISO alpha-2), merchantReturnLink (URL))
- /products/w-the-exercise-dress-rainstorm-blurnode missing Option A or B (lacks: returnPolicyCategory, applicableCountry (ISO alpha-2), merchantReturnLink (URL))
- /products/w-energy-dress-yucca-multinode missing Option A or B (lacks: returnPolicyCategory, applicableCountry (ISO alpha-2), merchantReturnLink (URL))
…and 1 more
Add every required top-level key to the UCP profile
Why this matters: A profile missing one of the four required keys is treated as non-conformant — agent runtimes fall back to default behaviour and may skip the merchant.
Findings (1)
Profile is missing required key(s): signing_keys.
How: Read the profile root (or top-level ucp wrapper) and verify the presence of version, services, capabilities, and signing_keys keys.
- Required top-level key
signing_keysis missingHIGHWhat we expected
Add a top-level "signing_keys" field to the JSON document (empty array/object is fine).Set
signing_keysat the root of the JSON document.
Skipped — No MerchantReturnPolicy node used the MerchantReturnFiniteReturnWindow category, so the `merchantReturnDays` check has nothing to evaluate.
Context: AI agents quote your concrete return window in shopping cards. Without `merchantReturnDays`, your policy renders as 'has a return policy' without the headline number.
Why this was skipped
No MerchantReturnPolicy node used the MerchantReturnFiniteReturnWindow category, so the merchantReturnDays check has nothing to evaluate.
How: For each MerchantReturnPolicy node whose returnPolicyCategory normalizes to MerchantReturnFiniteReturnWindow, require merchantReturnDays to be a positive number (or a numeric string > 0).
Skipped — the runner did not surface transport metadata
Context: If your UCP profile says `no-cache`, agent runtimes re-fetch on every interaction — brittle at scale and prone to rate-limit failures.
Why this was skipped
Wanted to inspect the UCP profile's Cache-Control header, but the runner did not surface transport metadata.
How: Parse the Cache-Control header on the /.well-known/ucp response; require public, max-age ≥ 60, and no no-store/no-cache/private.
- Transport metadata not available — runner update pendingLOW
This check activates once the runner (Task I1) populates ctx.wellKnownUcp.cacheControl.
Skipped — Profile declares no signing_keys; JWK validation has no entries to evaluate.
Context: Malformed JWK entries are rejected silently by agents — signed payloads cannot be verified and the merchant loses trust signal.
Why this was skipped
Profile declares no signing_keys; JWK validation has no entries to evaluate.
How: Walk signing_keys[] and validate each entry per RFC 7517 §4.1 (kty required) + RFC 7518 §6 (kty-specific required parameters). kid is OPTIONAL per RFC 7517 §4.5 and not enforced here.
Add includeSubDomains to your Strict-Transport-Security header
Why this matters: Without includeSubDomains, an HTTP subdomain (staging, mail, …) can be used to attack the apex's cookies.
Findings (1)
Inspected the homepage Strict-Transport-Security header ("max-age=7889238") and the includeSubDomains directive is absent.
How: Parse the homepage Strict-Transport-Security header for the includeSubDomains directive (RFC 6797 §6.1.2).
- HSTS header is missing the includeSubDomains directiveMEDIUM
What we found
max-age=7889238What we expected
Strict-Transport-Security: max-age=31536000; includeSubDomainsAppend
; includeSubDomainsto your STS header once every subdomain you operate supports HTTPS.
Add an Organization (or OnlineStore) JSON-LD block to your homepage with a contactPoint
Why this matters: Organization markup with a contactPoint tells AI agents who you are and how a shopper can reach you for support.
Findings (1)
Found a homepage Organization node but its contactPoint is missing both email and telephone.
How: Parse homepage <script type="application/ld+json"> blocks, flatten @graph, and look for an Organization/OnlineStore/Store node with a contactPoint carrying email or telephone.
- Homepage Organization node has no contactPoint with email or telephoneMEDIUM
What we expected
"contactPoint": [{"@type":"ContactPoint","contactType":"customer service","email":"support@example.com","telephone":"+1-555-123-4567"}]Add a contactPoint object with at least one of
emailortelephone.
Keep every sitemap entry on the sitemap's own host
Why this matters: Cross-host sitemap entries are silently dropped, so the off-host product URLs effectively don't exist for the crawler.
Findings (5)
Compared 637 <loc> entries against their sitemap host across 7 resource(s); 6 cross-host entries found.
How: For each resolved sitemap resource, parse the sitemap URL's host and compare it against every parsed <loc> URL's host.
- Cross-host <loc> — sitemap host is outdoorvoices.com but entry is on www.outdoorvoices.comMEDIUM
/sitemap.xmlsitemap host: outdoorvoices.com; entry host: www.outdoorvoices.com
What we found
https://www.outdoorvoices.com/sitemap_agentic_discovery.xmlRemove the cross-host entry from this sitemap, or publish a separate sitemap on that host.
- Cross-host <loc> — sitemap host is outdoorvoices.com but entry is on www.outdoorvoices.comMEDIUM
/sitemap.xmlsitemap host: outdoorvoices.com; entry host: www.outdoorvoices.com
What we found
https://www.outdoorvoices.com/sitemap_products_1.xml?from=4868626251854&to=7917506363470Remove the cross-host entry from this sitemap, or publish a separate sitemap on that host.
- Cross-host <loc> — sitemap host is outdoorvoices.com but entry is on www.outdoorvoices.comMEDIUM
/sitemap.xmlsitemap host: outdoorvoices.com; entry host: www.outdoorvoices.com
What we found
https://www.outdoorvoices.com/sitemap_pages_1.xml?from=16699081&to=121846759502Remove the cross-host entry from this sitemap, or publish a separate sitemap on that host.
- Cross-host <loc> — sitemap host is outdoorvoices.com but entry is on www.outdoorvoices.comMEDIUM
/sitemap.xmlsitemap host: outdoorvoices.com; entry host: www.outdoorvoices.com
What we found
https://www.outdoorvoices.com/sitemap_collections_1.xml?from=8504559&to=308474904654Remove the cross-host entry from this sitemap, or publish a separate sitemap on that host.
- Cross-host <loc> — sitemap host is outdoorvoices.com but entry is on www.outdoorvoices.comMEDIUM
/sitemap.xmlsitemap host: outdoorvoices.com; entry host: www.outdoorvoices.com
What we found
https://www.outdoorvoices.com/sitemap_blogs_1.xmlRemove the cross-host entry from this sitemap, or publish a separate sitemap on that host.
Skipped — No MerchantReturnPolicy node carried a `merchantReturnLink` URL, so reachability has nothing to evaluate.
Context: A broken return-link makes Option B policies invisible — agents can't render or follow the link.
Why this was skipped
No MerchantReturnPolicy node carried a merchantReturnLink URL, so reachability has nothing to evaluate.
How: Collect every unique merchantReturnLink URL across all MerchantReturnPolicy nodes; probe each once via politeFetch (failSoft). 2xx counts as reachable.
Skipped — No MerchantReturnPolicy node carried `applicableCountry`, so the ISO-code check has nothing to evaluate.
Context: A non-ISO country is dropped silently; the policy looks present but never reaches the merchant-listing rich result.
Why this was skipped
No MerchantReturnPolicy node carried applicableCountry, so the ISO-code check has nothing to evaluate.
How: On each MerchantReturnPolicy node where applicableCountry is set, extract every candidate string and require every one to match /^[A-Z]{2}$/i.
Skipped — No MerchantReturnPolicy node carried `returnPolicyCategory`, so the enum check has nothing to evaluate.
Context: An invalid category is silently dropped — your policy looks present in the source but never renders in Google's return-policy rich result.
Why this was skipped
No MerchantReturnPolicy node carried returnPolicyCategory, so the enum check has nothing to evaluate.
How: On each MerchantReturnPolicy node where returnPolicyCategory is set, accept the bare enum name or the schema.org URL form; reject any other string.
Skipped — No OfferShippingDetails node carried `shippingDestination`, so the DefinedRegion check has nothing to evaluate.
Context: Without a valid destination region, your shipping rate has no scope — Google can't decide whether to render it for a given shopper's country.
Why this was skipped
No OfferShippingDetails node carried shippingDestination, so the DefinedRegion check has nothing to evaluate.
How: On each OfferShippingDetails node where shippingDestination is set, require it to be a DefinedRegion (or array) and every entry to carry addressCountry matching /^[A-Z]{2}$/i.
Skipped — No OfferShippingDetails node carried `shippingRate`, so the MonetaryAmount check has nothing to evaluate.
Context: An invalid rate object is silently dropped; agents can't quote your shipping cost in shopping cards.
Why this was skipped
No OfferShippingDetails node carried shippingRate, so the MonetaryAmount check has nothing to evaluate.
How: On each OfferShippingDetails node where shippingRate is set, require an object with numeric value/maxValue (typed or numeric string) and a 3-letter ISO 4217 currency.
Skipped — Profile declares no capabilities; required-field checks have nothing to evaluate.
Context: Capabilities missing version/spec/schema can't be matched against agent support tables — agents skip them silently.
Why this was skipped
Profile declares no capabilities; required-field checks have nothing to evaluate.
How: For each capabilities[] entry, require non-empty string values for version, spec, and schema.
Upload higher-resolution product images (area ≥ 50,000 pixels)
Why this matters: Tiny product images get dropped from Google’s shopping rich-result modules and are unhelpful to AI agents quoting your product visually.
Findings (11)
Inspected <img width=… height=…> attributes on 20 sampled product pages (0 have at least one image with area ≥ 50,000 px; dimensions absent from HTML are not HEAD-probed and count as indeterminate).
How: For every sampled PDP, parse <img> tags and read explicit width and height attributes; a PDP passes when at least one image has width × height ≥ 50,000. PDPs without any explicit-dimension <img> are marked indeterminate (this check does not HEAD image URLs).
Coverage
0/20 · 0%
- No <img> on this PDP carries explicit width+height attributesLOW× 10
Server-render explicit width and height attributes so crawlers can verify image area without fetching.
Affected (10)
- /products/m-gridtek-breezy-shortsleeve-reservoir27 <img> tags found, none with width+height
- /products/m-solarcool-camp-collar-rainstorm-blur38 <img> tags found, none with width+height
- /products/megafleece-full-zip-conifer-navy29 <img> tags found, none with width+height
- /products/m-rectrek-zip-off-pant-black40 <img> tags found, none with width+height
- /products/w-megafleece-cropped-pullover-oatmeal37 <img> tags found, none with width+height
- /products/w-superform-rib-longsleeve-jasmine21 <img> tags found, none with width+height
- /products/w-orbit-bra-yucca23 <img> tags found, none with width+height
- /products/w-the-volley-dress-reservoir31 <img> tags found, none with width+height
- /products/w-the-exercise-dress-rainstorm-blur46 <img> tags found, none with width+height
- /products/w-energy-dress-yucca-multi27 <img> tags found, none with width+height
…and 1 more
Add preload to your Strict-Transport-Security header and submit to hstspreload.org
Why this matters: HSTS preload-list inclusion is the strongest downgrade protection available — first-time visits are protected too.
Findings (1)
Inspected the homepage Strict-Transport-Security header ("max-age=7889238") and the preload directive is absent.
How: Parse the homepage Strict-Transport-Security header for the preload directive (hstspreload.org vendor extension to RFC 6797).
- HSTS header is missing the preload directiveLOW
What we found
max-age=7889238What we expected
Strict-Transport-Security: max-age=31536000; includeSubDomains; preloadAppend
; preloadafterincludeSubDomainsand submit your domain at https://hstspreload.org/.
Add descriptive alt text to product images (WCAG 2.x SC 1.1.1)
Why this matters: Alt text is the only text description AI agents and screen readers have for your product imagery.
Findings (11)
Parsed <img> alt attributes across 20 sampled product pages (0 have alt text on at least 80% of images).
How: Per PDP, count <img> tags via regex; a tag 'has alt text' when its alt attribute is present AND non-empty after trim. A PDP passes when it carries no <img> at all OR ≥80% of its <img> tags have non-empty alt.
Coverage
0/20 · 0%
- Most images on this product page lack alt textLOW× 10
What we expected
<img src="/img/sneaker.webp" alt="Red leather running shoe, side view" />Populate the alt attribute on each <img> with a description of what the image shows; use alt="" only for decorative images.
Affected (10)
- /products/m-gridtek-breezy-shortsleeve-reservoir14/27 <img> tags have non-empty alt (52%)
- /products/m-solarcool-camp-collar-rainstorm-blur4/38 <img> tags have non-empty alt (11%)
- /products/megafleece-full-zip-conifer-navy16/29 <img> tags have non-empty alt (55%)
- /products/m-rectrek-zip-off-pant-black25/40 <img> tags have non-empty alt (63%)
- /products/w-megafleece-cropped-pullover-oatmeal18/37 <img> tags have non-empty alt (49%)
- /products/w-superform-rib-longsleeve-jasmine6/21 <img> tags have non-empty alt (29%)
- /products/w-orbit-bra-yucca12/23 <img> tags have non-empty alt (52%)
- /products/w-the-volley-dress-reservoir17/31 <img> tags have non-empty alt (55%)
- /products/w-the-exercise-dress-rainstorm-blur4/46 <img> tags have non-empty alt (9%)
- /products/w-energy-dress-yucca-multi15/27 <img> tags have non-empty alt (56%)
…and 1 more
Skipped — No MerchantReturnPolicy node carried returnFees, returnMethod, or refundType, so the enum check has nothing to evaluate.
Context: Invalid enrichment values are dropped silently, leaving merchants confused about why their rendered policy is missing fields they configured.
Why this was skipped
No MerchantReturnPolicy node carried returnFees, returnMethod, or refundType, so the enum check has nothing to evaluate.
How: On each MerchantReturnPolicy node, inspect returnFees/returnMethod/refundType if set; require the bare name or schema.org URL form of a value in the corresponding Schema.org enum.
Skipped — No OfferShippingDetails node carried `deliveryTime`, so the ShippingDeliveryTime check has nothing to evaluate.
Context: Without populated handling/transit times, agents can't quote a delivery window in shopping cards.
Why this was skipped
No OfferShippingDetails node carried deliveryTime, so the ShippingDeliveryTime check has nothing to evaluate.
How: On each OfferShippingDetails node where deliveryTime is set, require an object with at least one of handlingTime / transitTime populated as a QuantitativeValue.
Enable Apple Pay through your payment processor (informational only)
Why this matters: Apple Pay is a checkout-quality signal for human shoppers — informational only, does not affect the agent-readiness score.
Findings (1)
Scanned the homepage and 20 sampled PDPs for Apple Pay markers; none matched.
How: Substring match on known Apple Pay SDK/markup signatures (ApplePaySession, apple-pay-button, /apple-developer-merchantid-domain-association) across the homepage and every sampled PDP HTML.
- No Apple Pay markers detected on the homepage or PDPsINFO
Enable Apple Pay in your payment processor's dashboard (Stripe / Adyen / Braintree). Informational only — does not affect the score.
Enable Google Pay through your payment processor (informational only)
Why this matters: Google Pay is a checkout-quality signal for human shoppers — informational only, does not affect the agent-readiness score.
Findings (1)
Scanned the homepage and 20 sampled PDPs for Google Pay markers; none matched.
How: Substring match on known Google Pay SDK/markup signatures (pay.google.com/gp/p/js/pay.js, google.payments.api, <google-pay-button) across the homepage and every sampled PDP HTML.
- No Google Pay markers detected on the homepage or PDPsINFO
Enable Google Pay in your payment processor's dashboard (Stripe / Adyen / Braintree). Informational only — does not affect the score.