academy.com
Work at academy.com?Verify your @academy.com email to rescan on demand.
Agents can reach the site, but product data is thin or inconsistent.
Higher than 86% of 192 scanned stores
Pillars
- Access30.7/35
- Catalog legibility20.5/25
- Transactability9/25
- Trust & policy10/15
Checks
12 of 27 scored checks passed. Expand a row for the evidence behind it.
Access
30.7/35Catalog legibility
20.5/25Transactability
9/25Trust & policy
10/15How to fix it
15 fixes for academy.com, ready to paste into a ticket or hand to a coding agent.
Make site search work for agents
access.search-agents · partial
Your search results page (https://www.academy.com/search?q=gift) did not return usable content for every probe. Agents use site search to find a product when the user names it; a search page that is blocked or empty forces them to guess URLs or give up.
claude-user: challenge (200)
Typical causes and fixes:
- Results are rendered client-side. Third-party search (Algolia, Klevu, Searchspring, Nosto) often replaces the results grid with JavaScript. Keep the platform's server-rendered results as the HTML fallback, or render results on the server before enhancing them.
- A WAF rule treats query strings as scraping. Allow the shopping agents (see the homepage and product-page fixes) on the search path, and raise any rate limit on
?q=. - The search URL is hard to find. Expose a plain
<form action="/search">with aqinput in the header, and declare it inWebSiteJSON-LD so agents can jump straight to results:
{ "@context": "https://schema.org", "@type": "WebSite", "url": "https://www.example.com/", "potentialAction": { "@type": "SearchAction", "target": { "@type": "EntryPoint", "urlTemplate": "https://www.example.com/search?q={search_term_string}" }, "query-input": "required name=search_term_string" } }Add a Content-Signal directive
access.content-signal · partial
Your robots.txt has no Content-Signal directive. Content Signals (contentsignals.org) is a robots.txt extension that states, separately, whether your content may be used for search, as real-time AI input (which is what shopping agents do), and for training. An explicit signal scores fully; silence scores half.
You can welcome shopping agents while still declining training. Add to the
*group (or to each group you care about):User-agent: * Content-Signal: search=yes, ai-input=yes, ai-train=no Allow: /Keep
ai-input=yes; setai-trainhowever you like. If Cloudflare manages your robots.txt, the equivalent setting lives in AI Crawl Control → Content Signals.Edit the
robots.txtserved from your web root (or the CDN/edge rule that generates it) and redeploy. Crawlers cache robots.txt for up to 24 hours, so re-scan after a day.Publish a Web Bot Auth key directory
access.web-bot-auth · fail
Nothing usable was found at
/.well-known/http-message-signatures-directory(HTTP 404). Web Bot Auth is the IETF draft that lets agents sign requests with HTTP Message Signatures; parties that sign publish their Ed25519 public keys in this directory, and verifiers fetch it to check theSignatureandSignature-Inputheaders. Visa's Trusted Agent Protocol, Mastercard's Agent Pay, and Cloudflare's signed-agent verification are all built on it.Two steps matter for a storefront:
- Verify signatures at your edge so signed agents are let through bot management instead of challenged. On Cloudflare this is the Verified Bots / signed agents setting; other WAFs are adding the same.
- Publish your own directory for any requests you sign (your own agent, service-to-service calls, or a verifier that expects one to exist). Serve it with
Content-Type: application/http-message-signatures-directory+json:
{ "keys": [ { "kty": "OKP", "crv": "Ed25519", "kid": "2026-01", "x": "<base64url-encoded public key>", "nbf": 1767225600, "exp": 1798761600 } ] }Serve the file from the same origin as the storefront, with a long cache lifetime, and rotate keys by adding the new one before removing the old.
Add shipping, returns, and price validity to the Offer
catalog.offer-details · partial
Your
Offeris missingshippingDetails. Agents rank options by delivery time, delivery cost, return risk, and how confident they are in the price; these three fields are where they look.Add to the
offersobject:"priceValidUntil": "2026-12-31", "shippingDetails": { "@type": "OfferShippingDetails", "shippingRate": { "@type": "MonetaryAmount", "value": "0", "currency": "USD" }, "shippingDestination": { "@type": "DefinedRegion", "addressCountry": "US" }, "deliveryTime": { "@type": "ShippingDeliveryTime", "handlingTime": { "@type": "QuantitativeValue", "minValue": 0, "maxValue": 1, "unitCode": "DAY" }, "transitTime": { "@type": "QuantitativeValue", "minValue": 2, "maxValue": 5, "unitCode": "DAY" } } }, "hasMerchantReturnPolicy": { "@type": "MerchantReturnPolicy", "applicableCountry": "US", "returnPolicyCategory": "https://schema.org/MerchantReturnFiniteReturnWindow", "merchantReturnDays": 30, "returnMethod": "https://schema.org/ReturnByMail", "returnFees": "https://schema.org/FreeReturn" }Use your real values; one representative shipping rate and destination is enough. Set
priceValidUntilto a date you can honour (the end of the current season or year, regenerated as it passes).Many stores define the return policy once at the
Organizationlevel and reference it from eachOffer; either is fine as long as theOfferon the product page carries or links to it.List product URLs in your sitemap
catalog.sitemap-products · partial
Your sitemap (https://www.academy.com/sitemap.xml) is reachable and we sampled 679 URLs, but none looked like a product URL and no child sitemap was named after products. Agents use the sitemap to enumerate the catalog without crawling.
Make product entries recognisable: either keep product URLs on a conventional path (
/products/…,/product/…,/p/…,/item/…) or split products into a child sitemap whose filename contains "product" (for examplesitemap-products-1.xml). Compressed (.xml.gz) sitemaps are skipped; serve plain XML.Offer a Markdown version of product pages
catalog.markdown-negotiation · fail
Requesting https://www.academy.com/p/ruger-american-predator-20-308-winchester-bolt-action-rifle with
Accept: text/markdownreturned HTML. Agents that support content negotiation get a page that is a tenth of the size and needs no parsing. This is worth one point and is a nice-to-have.When the
Acceptheader preferstext/markdown, respond with a Markdown body andVary: Accept:GET /products/trail-runner-2 HTTP/1.1 Accept: text/markdown HTTP/1.1 200 OK Content-Type: text/markdown; charset=utf-8 Vary: Accept # Trail Runner 2 **$129.00** · In stock · SKU TR2-BLK-10 Lightweight waterproof trail shoe. Sizes 6–13. Free shipping over $75, 30-day returns.The simplest place to do this is edge middleware (a Cloudflare Worker, Vercel or Netlify middleware, or a Next.js route) that converts the rendered HTML or renders a dedicated template. If you are on Cloudflare, the "Markdown for Agents" option in AI Crawl Control does the conversion for you.
Publish /llms.txt
catalog.llms-txt · fail
/llms.txtreturned an HTML page (probably your 404 or homepage) instead of plain text.llms.txt (llmstxt.org) is a short Markdown file at the site root that tells language models what the site is and where the important pages are. For a store, point at the catalog, the policies, and any agent endpoints. Serve it as
text/plainortext/markdownwith a 200 status:# Example Outdoor > Example sells trail-running shoes and apparel, shipping to the US and Canada. Free 30-day returns. ## Shop - [All products](https://www.example.com/collections/all): the full catalog - [Product sitemap](https://www.example.com/sitemap_products_1.xml) ## Policies - [Shipping](https://www.example.com/policies/shipping-policy) - [Returns](https://www.example.com/policies/refund-policy) ## For agents - [UCP profile](https://www.example.com/.well-known/ucp) - [Storefront MCP](https://www.example.com/api/mcp)Answer tools/list on your UCP MCP endpoint
tx.ucp-mcp-endpoint · fail
https://www.academy.com/api/ucp/mcpdid not return a tool list (HTTP 401). The endpoint must speak MCP over Streamable HTTP: accept a JSON-RPC POST and answer with JSON or an SSE stream.Test it the way we do:
curl -sS -X POST https://www.academy.com/api/ucp/mcp \ -H 'Content-Type: application/json' \ -H 'Accept: application/json, text/event-stream' \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'tools/listmust work without authentication; require auth on the tool calls that need it, and advertise it through OAuth discovery (see that fix).- Return
200withContent-Type: application/json(ortext/event-stream), never a 405 for POST or an HTML page. - Make sure the URL in the UCP profile (
services → dev.ucp.shopping → mcp.endpoint) points at this endpoint exactly.
Any MCP server SDK (TypeScript, Python, Go) with the Streamable HTTP transport will do; mount it on the storefront origin so the profile, the endpoint, and the cookies share a domain.
Serve a Storefront MCP server at /api/mcp
tx.storefront-mcp · fail
No MCP server answered
tools/listat/api/mcp(HTTP 404). This is the conventional storefront endpoint (Shopify's Storefront MCP lives here) where an agent can search the catalog, read policies, and manage a cart without scraping.Expose an MCP server over Streamable HTTP at that path with tools such as
search_shop_catalog,get_product_details,search_shop_policies_and_faqs,get_cart, andupdate_cart.tools/listmust be callable without authentication.If you already run the UCP MCP endpoint, mounting the same server at
/api/mcpis enough.Publish an MCP server card
tx.mcp-server-card · fail
Nothing was found at
/.well-known/mcp/server-card.json. The server card is the MCP discovery document that lets an agent find your server, its transport endpoint, and how to authenticate, without reading documentation.Publish a JSON document describing the server (field names follow the current MCP server-card draft; adjust to the version you target):
{ "serverInfo": { "name": "example-storefront", "title": "Example Storefront", "version": "1.0.0" }, "description": "Search the Example catalog, read policies, and manage a cart.", "transport": { "type": "streamable-http", "endpoint": "https://www.example.com/api/mcp" }, "capabilities": { "tools": {} }, "authentication": { "required": false } }Serve it as
application/jsonwith CORS enabled, and keep the endpoint in sync with the one your UCP profile names.Publish an API catalog (RFC 9727)
tx.api-catalog · fail
No API catalog was found. RFC 9727 defines
/.well-known/api-catalog, a linkset that points agents at your APIs and their descriptions (OpenAPI, MCP, UCP) in one place.Serve this as
application/linkset+json:{ "linkset": [ { "anchor": "https://www.example.com/", "service-desc": [ { "href": "https://www.example.com/api/openapi.json", "type": "application/vnd.oai.openapi+json" } ], "service-doc": [ { "href": "https://www.example.com/developers", "type": "text/html" } ], "service-meta": [ { "href": "https://www.example.com/.well-known/ucp", "type": "application/json" }, { "href": "https://www.example.com/.well-known/mcp/server-card.json", "type": "application/json" } ] } ] }Also advertise it from the homepage with a
Linkheader, which we accept on its own:Link: </.well-known/api-catalog>; rel="api-catalog"Publish OAuth discovery metadata
tx.oauth-discovery · fail
None of
/.well-known/oauth-authorization-server,/.well-known/openid-configuration, and/.well-known/oauth-protected-resourcereturned a JSON document. Agents that need to act on a customer's account (order status, saved addresses, loyalty) look for OAuth 2.0 discovery before they will attempt authenticated calls; it is also what MCP clients use to authorise against your MCP server.If you run an authorization server on this origin, publish RFC 8414 metadata at
/.well-known/oauth-authorization-server:{ "issuer": "https://www.example.com", "authorization_endpoint": "https://www.example.com/oauth/authorize", "token_endpoint": "https://www.example.com/oauth/token", "registration_endpoint": "https://www.example.com/oauth/register", "scopes_supported": ["cart:write", "orders:read"], "response_types_supported": ["code"], "grant_types_supported": ["authorization_code", "refresh_token"], "code_challenge_methods_supported": ["S256"] }If authentication is handled by a separate identity provider, publish RFC 9728 protected-resource metadata at
/.well-known/oauth-protected-resourcepointing at it:{ "resource": "https://www.example.com/api/mcp", "authorization_servers": ["https://auth.example.com"], "scopes_supported": ["cart:write", "orders:read"], "bearer_methods_supported": ["header"] }Support PKCE and dynamic client registration (RFC 7591) so agents can onboard without a manual app review.
Publish an agent card or skills index
tx.agent-cards · fail
None of
/.well-known/agent-card.json,/.well-known/agent.json, and/.well-known/agent-skills/index.jsonwas found. An A2A agent card tells other agents that your store has an agent of its own and what it can do; an Agent Skills index lists reusable skill files. Either satisfies this one-point check.A minimal A2A agent card at
/.well-known/agent-card.json:{ "name": "Example Shopping Assistant", "description": "Find, compare, and buy Example products.", "url": "https://www.example.com/a2a", "version": "1.0.0", "protocolVersion": "0.3.0", "capabilities": { "streaming": true }, "defaultInputModes": ["text/plain"], "defaultOutputModes": ["text/plain", "application/json"], "skills": [ { "id": "find-products", "name": "Find products", "description": "Search the catalog by query, size, colour, and price.", "tags": ["shopping", "search"] } ] }Or, if you publish skills rather than an agent, serve
/.well-known/agent-skills/index.jsonlisting each skill's name, description, and the URL of itsSKILL.md. Only publish a card for an endpoint that actually answers.Add Organization structured data to the homepage
trust.org-jsonld · partial
Your homepage has Organization markup but it is missing
url,logo, andsameAs. Agents use these to confirm who is selling and to cross-check the brand against its official profiles.Add to the homepage (an
OnlineStoreis anOrganization, and is the better fit for a shop):{ "@context": "https://schema.org", "@type": "OnlineStore", "name": "Example Outdoor", "url": "https://www.example.com/", "logo": "https://www.example.com/images/logo.png", "sameAs": [ "https://www.instagram.com/example", "https://www.facebook.com/example", "https://en.wikipedia.org/wiki/Example_Outdoor" ], "contactPoint": { "@type": "ContactPoint", "contactType": "customer service", "email": "help@example.com" } }Enforce HTTPS with a redirect and HSTS
trust.https-hsts · partial
Agents will not hand payment or personal details to an origin that is not strictly HTTPS. Three things are checked:
- OK: the storefront is served over HTTPS.
- Missing: a plain
http://request redirects (301/308) tohttps://. - Missing: the
Strict-Transport-Securityheader is set.
Send this header on every HTTPS response:
Strict-Transport-Security: max-age=31536000; includeSubDomainsStart with a shorter
max-ageif you are unsure every subdomain supports HTTPS, then raise it.Configure the redirect at the edge or web server (nginx: a
serverblock on port 80 withreturn 301 https://$host$request_uri;; Apache: aRewriteRulein the port-80 virtual host; Cloudflare: SSL/TLS → Edge Certificates → Always Use HTTPS).If you are behind Cloudflare, the whole thing is three toggles: SSL/TLS mode Full (strict), Always Use HTTPS, and HSTS under Edge Certificates.
History
| Date | AUR | Level | Engine |
|---|---|---|---|
| Oct 20, 2026 | 59 | Visible | v1.0.1 |
| Oct 20, 2026 | 55 | Visible | v1.0.1 |