Table of contents
A store that is not on Shopify gets no UCP profile by default. Shopify serves one for its merchants. WooCommerce, BigCommerce, and hand-built carts publish one only if somebody puts a JSON file at /.well-known/ucp. This guide shows two ways to do that, how to serve the file so an agent will accept it, and how to check the result. It is current as of 13 October 2026, against UCP version 2026-08-25.
Quick summary
| Question | Answer | Source |
|---|---|---|
| What does AIScan check? | check:M1: whether /.well-known/ucp answers. It is a bonus check, so a miss never lowers your score | AIScan commerce docs |
| What must the file contain? | A top-level ucp object with version, services and payment_handlers. The last two must exist even when empty | UCP specification |
| How must it be served? | HTTPS, no redirects, Cache-Control with public and max-age of at least 60 | Same page, Hosting section |
| Fastest route on WooCommerce | A plugin that serves the profile and the endpoints behind it | Path 1 |
| Fastest route on a custom cart | A static or generated file, honest about what you support | Path 2 |
| Who should skip it? | Stores with a handful of plans and no catalogue. UCP is a catalogue standard | AIScan check guidance |
Fastest fix: run npx aiscan-cli yourstore.com, read the M1 row, then pick a path below.
What the check sees, and what an agent needs
AIScan requests /.well-known/ucp and records the status code. On aiscan.site it records HTTP 404, and the row shows as informational. Our adoption study found that M1 decides on the status code alone, so an empty page or an HTML page that returns 200 passes the check and helps no agent.
An agent needs more. According to the UCP specification, a profile is "a JSON object with a required ucp member". The ucp member carries version, services and payment_handlers, all required, and "the services and payment_handlers registries MUST be present even when empty." capabilities is optional.
Each entry under services names a transport (rest, mcp, a2a or embedded) and a version and spec URL. REST and MCP entries also need a schema, and the endpoint is where the agent will send calls. That endpoint is the part that costs real work. A profile is a promise that something answers there.
Decide what you can honestly promise
There are three levels, and only the third needs engineering.
- A valid placeholder.
servicesandpayment_handlersempty. It satisfies the spec and turns M1 green, and it advertises nothing. Treat it as a marker, not as agent readiness. - A profile served by software that also serves the endpoints. The plugin or platform owns both halves, so the promise is kept.
- A profile you write, pointing at endpoints you built. You implement the UCP REST or MCP surface from the spec, then declare it.
Never copy a Shopify store's profile and change the domain. We read one live on 13 October 2026 (Allbirds). It declares an MCP service at a myshopify.com address, a checkout capability, and a fulfillment extension. Declaring capabilities your store does not run sends agents to endpoints that do not exist.
Path 1: WooCommerce, with a plugin
WooCommerce has no native UCP support in core. The feature-request thread on woocommerce.com was still marked Open when we looked on 13 October 2026. Two plugins on WordPress.org describe themselves as UCP implementations. We read their listings and have not installed either one:
| Plugin | Version | Last updated | Active installs | What the listing says |
|---|---|---|---|---|
| Universal Commerce Protocol (UCP) for WooCommerce | 1.0.4 | 9 Mar 2026 | about 30 | Serves /.well-known/ucp, with REST, MCP and embedded bindings |
| WebToffee Universal Commerce Protocol Enabler | 1.0.5 | 1 Oct 2026 | about 10 | Implements UCP 2026-08-25, serves the profile, REST and MCP endpoints, and an A2A agent card |
Both are tiny installs, so read the code and test on staging first. Steps:
- Clone the store to staging and back up the database.
- Install one plugin from Plugins, then Add New, and search for "Universal Commerce Protocol".
- Activate it and open
https://staging.example.com/.well-known/ucpin a browser. You should see JSON. - Read
ucp.version. The first plugin was last updated before2026-08-25existed, so confirm which version it declares before you rely on it. - Run the verifier below against staging, then the AIScan scan after you go live.
If the profile renders as a 404 page, flush permalinks (Settings, Permalinks, Save) and check that no cache or security plugin rewrites /.well-known/.
ThinkRank is the WordPress plugin we recommend for the layer around the profile: Product schema, robots.txt, and llms.txt from one plugin, with migration from Rank Math, Yoast, AIOSEO and SEOPress. We have not tested whether it serves a UCP profile, so treat the profile as its own job. Yoast and Rank Math also handle schema; the UCP profile is a separate task for any of them.
Path 2: write the file yourself
This fits a custom cart, a headless build, or any platform with no plugin.
- Create
ucp.jsonwith the placeholder below. It is valid and claims nothing.
{
"ucp": {
"version": "2026-08-25",
"services": {},
"payment_handlers": {}
}
}
- Serve it at exactly
/.well-known/ucp, with no.jsonextension. The next section covers headers. - Run the verifier. Confirm the placeholder passes.
- Build the surface you want to declare. Read the UCP specification and the REST or MCP schema it links. Start with one transport.
- Add one
servicesentry per working transport. The shape, from the spec, is:
"services": {
"dev.ucp.shopping": [{
"version": "2026-08-25",
"spec": "https://ucp.dev/2026-08-25/specification/overview/",
"transport": "rest",
"endpoint": "https://shop.example.com/ucp/v1",
"schema": "https://ucp.dev/2026-08-25/services/shopping/rest.openapi.json"
}]
}
- Add
capabilitiesonly for what the endpoint implements. Each needsversion,specandschema. Extensions such as fulfillment useextends. - Declare
payment_handlersthat match your real processor. Leave it empty if checkout stays on your own site. - Redeploy and rerun the verifier after every change.
Versions: dated, and exact
UCP versions are dates, not semantic numbers. The profile declares ucp.version, and every service and capability inside it carries its own version. According to the spec, a business that selects version D must declare D on every dev.ucp.* entry. Mixing 2026-08-25 at the top with 2026-04-08 inside a service is an inconsistent profile.
Businesses that still support older releases add a supported_versions object mapping each older date to its own profile URL. The Allbirds profile does this for 2026-04-08 and 2026-01-23. If you start on the current date and have no older clients, you need no such object. Copy the date from the spec page, not from a plugin readme, and update the profile when you move to a newer release.
Serve it so an agent will take it
The specification's Hosting section sets three rules. Published artifacts must be served over HTTPS. Profile endpoints "MUST NOT use redirects (3xx)". And they must send Cache-Control with public and a max-age of at least 60 seconds, never private, no-store or no-cache. An ETag or Last-Modified header is recommended.
The redirect rule bites people who force www to apex or http to https at the app layer. Fetch the profile on the exact host agents will use. Our canonical host guide covers the redirect side.
Extensionless files need a content type. On nginx, a location block does it (we did not run nginx here, so test it):
location = /.well-known/ucp {
default_type application/json;
add_header Cache-Control "public, max-age=300";
try_files /ucp.json =404;
}
On a Next.js app, a route handler at app/.well-known/ucp/route.ts can return the JSON with the same two headers. We did not run that one either. For the same reason, a catch-all route that returns the app shell for unknown paths will give you a soft 200 here, so test with curl.
Verify
Start with the scan, because it is free and needs no account:
npx aiscan-cli yourstore.com
Or paste the address at aiscan.site. Read the M1 row. HTTP 200 is a pass and HTTP 404 means nothing is published. The scan covers M1 only for the status code, so M4 (machine-readable pricing) and P2 (MCP server card) are separate rows, and AIScan cannot tell you whether your profile is valid or your endpoints work.
If you would rather check by hand, this script uses only the standard library and applies the spec's hosting and shape rules:
import http.client, json, re, sys
from urllib.parse import urlsplit
def main(base):
u = urlsplit(base if "//" in base else "https://" + base)
cls = http.client.HTTPSConnection if u.scheme == "https" else http.client.HTTPConnection
c = cls(u.netloc, timeout=15)
c.request("GET", "/.well-known/ucp", headers={"User-Agent": "Mozilla/5.0"})
r = c.getresponse()
h = {k.lower(): v for k, v in r.getheaders()}
body = r.read()
bad = []
if r.status != 200:
bad.append(f"status {r.status}, want 200 with no redirect")
if "json" not in h.get("content-type", ""):
bad.append("content-type is not JSON")
cc = h.get("cache-control", "")
m = re.search(r"max-age=(\d+)", cc)
if "public" not in cc or not m or int(m.group(1)) < 60 or re.search(r"no-store|no-cache|private", cc):
bad.append(f"cache-control {cc!r}")
try:
ucp = json.loads(body)["ucp"]
if not re.fullmatch(r"\d{4}-\d{2}-\d{2}", str(ucp.get("version", ""))):
bad.append("ucp.version missing")
for k in ("services", "payment_handlers"):
if not isinstance(ucp.get(k), dict):
bad.append(f"ucp.{k} must exist, even when empty")
except Exception:
bad.append("body is not JSON with a ucp object")
print("\n".join(bad) or "PASS")
return 1 if bad else 0
sys.exit(main(sys.argv[1]))
We ran it on 13 October 2026 against four cases. A local server with the placeholder profile passed. A catch-all server that returns an HTML page with status 200 failed on content type, caching and body. A server that redirected /.well-known/ucp with a 301 failed on the status. Allbirds passed: JSON, Cache-Control: public, max-age=60, version 2026-08-25. It does not check that your endpoints work. Test those by calling them.
BigCommerce and other platforms
Commerce, the parent company of BigCommerce, announced its endorsement of UCP and plans to offer buying inside Google's AI surfaces. We found no merchant documentation for publishing a profile, for it, so this guide makes no claim about BigCommerce's tooling. Check your admin and the platform's developer docs. Where nothing exists, Path 2 works on any host that lets you serve a file.
When something goes wrong
- 404 after a plugin install: permalinks or a rewrite rule. Flush permalinks and test the URL with curl, not a browser.
- 200 but HTML: a catch-all route. Serve the file before the app handler.
- 301 or 302 on the profile: remove the redirect for this path. Agents are told not to follow it.
- Valid file, M1 still 404: you tested a different host. Scan the exact hostname customers use.
403from your own scan: a bot-protection rule or WAF is blocking the path. Allow/.well-known/and rescan.
On Shopify you do not publish the file. Check that it still answers after a theme or proxy change, and use StoreSEO for the llms.txt and schema layer that makes the catalogue legible. For the protocols themselves, read agentic commerce protocols explained; for pricing markup, machine-readable pricing schema.
Next step
Scan your store with npx aiscan-cli yourstore.com and look at M1, M4 and P2. Fix M4 first if your pricing is only in prose, since that check affects your score and M1 does not. Then browse the guide library and the commerce checks page. The task works without us: a text editor and curl are enough.
Frequently asked questions
Do I need a UCP profile to pass AIScan?
No. M1 is a bonus check, so a missing profile shows as informational and never lowers your score. Publish one if you sell a catalogue and want agents to find a way in.
What is the smallest valid UCP profile?
A JSON object with a ucp member holding version, services and payment_handlers. The last two must exist even when empty. It is valid and advertises nothing, so treat it as a placeholder.
My /.well-known/ucp returns 404 after I added the file. What now?
The server is not routing that path to your file. Check the exact location rule or plugin rewrite, flush WordPress permalinks, and test with curl on the exact host customers use.
The URL returns 200 but the body is an HTML page. Does that pass?
AIScan reads the status code for M1, so it can pass, but no agent can use it. A catch-all route is serving your app shell. Serve the profile before that handler and rerun the verifier.
Why does the profile redirect to a different URL?
Something forces www, http or a trailing slash at the app layer. The UCP spec says profile endpoints must not redirect and platforms must not follow redirects, so serve the file directly on the final host.
Can I copy a Shopify store's profile and change the domain?
No. It declares services and capabilities that your store does not run. Agents would call endpoints that do not exist. Declare only what you serve.
Does WooCommerce support UCP natively?
Not in core, as of 13 October 2026. The feature request on woocommerce.com was still open. Third-party plugins on WordPress.org describe UCP support, so test them on staging first.
Which UCP version should I put in the file?
Use the current dated release from ucp.dev, which was 2026-08-25 on 13 October 2026. Every service and capability entry must carry the same version as the profile.
Related guides
Platform League Table: WordPress, Next.js, Astro and Shopify Across 728 Sites
Every few weeks someone asks which platform produces the most agentready sites. WordPress, Next.js, Astro and Shopify all have fans, and a ranked table is the answer people expect. We have the data…
Redirect www and http to one canonical host, the way an agent needs it
Type http://www.example.com/pricing into a terminal and count the hops it takes to reach the page. On a clean setup the answer is one, a single 301 straight to the canonical address. On many sites it…
Declare your content-use policy to AI: Content Signals, ai.txt, TDMRep
Blocking or allowing a crawler answers one question: may it fetch this page. It says nothing about what the crawler may do afterwards. This guide covers the three places a site can state that second…
UCP profiles: Shopify serves one, most other stores don't
Shopify stores answer on /.wellknown/ucp. Almost nobody else does. We checked 238 commerceactive sites in the AIScan corpus on 10 October 2026: 12 of 17 Shopify catalogue stores pass check M1 the…
