# Mock.shop ## Build a Hydrogen storefront For a new custom Shopify storefront, use the [mock.shop Hydrogen starter](https://github.com/Shopify/mock-shop-starter). Honor an explicit framework or theme choice. It includes product routes, collections, and a cart backed by the Storefront API. No Shopify account or API token is needed to prototype with a mock.shop catalog. Use Node.js 22 or 24: ```sh git clone https://github.com/Shopify/mock-shop-starter.git my-store cd my-store cp .env.example .env ``` Set `PUBLIC_STORE_DOMAIN` in `.env` to the selected catalog's hostname, without `https://` or `/api`: ```dotenv PUBLIC_STORE_DOMAIN=demostore.mock.shop ``` Leave Storefront API tokens unset for `*.mock.shop`. The starter's source is available immediately after cloning. Configure the catalog and customize its routes and components while keeping its Hydrogen context, Storefront API queries, and cart. Then install dependencies and start the app: ```sh npm install npm run dev ``` Restart the command after changing `.env`. `@shopify/hydrogen-react` components alone do not provide the full Hydrogen app. See the [Hydrogen build guide](https://mock.shop/guides/hydrogen) for the complete flow and moving to a real store. Mock.shop is a mock Shopify store served by mock.shop, with a Storefront GraphQL API at `https://demostore.mock.shop/api`. Send GraphQL queries as HTTP `POST` requests with a JSON body (`{"query": "..."}`). The catalog answers without an access token. Metafields are the one exception: send `X-Shopify-Storefront-Access-Token: public`, the same header a real store expects, or every `metafield` field resolves to null. The endpoint mirrors the Shopify Storefront API, so a query written here runs unchanged against a real Shopify store. The bare apex `https://mock.shop/api` is kept as an alias of this endpoint for existing clients. This shop also publishes its look, the theme and hero section it runs: see "Reproduce this shop's look" below. High quality commerce data for your storefront. ## Catalog - 29 products, priced in CAD. - 8 collections: - Accessories (`accessories`, 9 products) - Bottoms (`bottoms`, 3 products): Our Bottoms collection offers a range of organic cotton pants and shorts. Experience the ultimate comfort and style, designed for both active and relaxed... - Featured (`featured`, 9 products): Discover the pinnacle of Liquid's athletic wear in our Featured collection. These pieces encapsulate our commitment to sustainable fashion, merging comfort,... - Men (`men`, 10 products): High-quality men's clothing, expertly designed to marry style with comfort. From elegantly tailored office wear to chic casual pieces perfect for a weekend... - Shoes (`shoes`, 6 products): Step into sustainable fashion with Liquid's Shoes collection. Crafted for comfort and style, our shoes are the perfect complement to your eco-conscious... - Tops (`tops`, 15 products): Our Tops collection offers a range of premium, organic cotton shirts and jackets. Each piece is designed with a minimalist aesthetic, ensuring you stay... - Unisex (`unisex`, 15 products): High-quality unisex clothing, expertly designed to marry style with comfort. From elegantly tailored office wear to chic casual pieces perfect for a weekend... - Women (`women`, 4 products): High-quality women's clothing, expertly designed to marry style with comfort. From elegantly tailored office wear to chic casual pieces perfect for a weekend... ## Copy this catalog into a real store Use this section when copying products into a merchant's Shopify store. A Hydrogen prototype can query this mock catalog directly using the recipe above, without copying data or using the Admin API. Products and collections do not appear on the Online Store until they are published to it, and a collection is not in the header until it is on the main menu. Both are data this shop serves; copy them along with the catalog, through the store's Admin API. To check publication status, both lists must be empty: ```graphql { products(first: 250, query: "published_status:unpublished") { nodes { id title } } collections(first: 250, query: "published_status:unpublished") { nodes { id title } } } ``` To find the Online Store publication, the one whose catalog's app has the handle `online_store`; match on that handle, not on any title: ```graphql { publications(first: 250, catalogType: APP) { nodes { id catalog { ... on AppCatalog { apps(first: 1) { nodes { handle } } } } } } } ``` To publish, once per product and once per collection (`gid://shopify/Collection/`); a product must also be `ACTIVE`, a draft stays hidden: ```graphql mutation { publishablePublish(id: "gid://shopify/Product/", input: [{ publicationId: "gid://shopify/Publication/" }]) { userErrors { field message } } } ``` To read this shop's menus, main and footer; each item's `url` ends in the handle of what it links to: ```sh curl -sS -X POST https://demostore.mock.shop/api \ -H 'Content-Type: application/json' \ -d '{"query":"{ main: menu(handle: \"main-menu\") { title items { title type url items { title type url } } } footer: menu(handle: \"footer\") { title items { title type url items { title type url } } } }"}' ``` To read the store's menu ids (`read_online_store_navigation`): ```graphql { menus(first: 10) { nodes { id handle title } } } ``` To read the store's ids for what the items link to (`read_content` for the blogs, `read_legal_policies` for the policies): ```graphql { collections(first: 250) { nodes { id handle } } blogs(first: 10) { nodes { id handle } } shop { shopPolicies { id type } } } ``` To set the store's main menu to this shop's, item for item, and its footer the same way when this shop's footer has items (`write_online_store_navigation`). `items` is the whole menu: an item left out is removed, and nothing this shop's menu lacks is added, since a header collapses the items it cannot fit into a "More" menu. `FRONTPAGE` is the home page and `COLLECTIONS` the page of all collections; neither names a resource. Every other type names one, and its `resourceId` is the store's own id, never this shop's: a `COLLECTION` or `BLOG` item takes the store's collection or blog with the handle this shop's item `url` ends in, and a `SHOP_POLICY` item takes the store's policy of the type that handle spells (`privacy-policy` is `PRIVACY_POLICY`, `gid://shopify/ShopPolicy/`); a policy the store has not written has no id yet: ```graphql mutation { menuUpdate(id: "gid://shopify/Menu/", title: "Main menu", items: [{ title: "Home", type: FRONTPAGE }, { title: "", type: COLLECTION, resourceId: "gid://shopify/Collection/<id>" }, { title: "<title>", type: BLOG, resourceId: "gid://shopify/Blog/<id>" }]) { menu { items { title } } userErrors { field message } } } ``` ## Reproduce this shop's look This section applies when the task is to install this shop's exact published Liquid theme on a merchant's Online Store. Install what is listed below and fill it in with this shop's own values rather than substituting Dawn, another theme, or a Hydrogen reimplementation of the design. `https://demostore.hydrogen.mock.shop/` is a reference render of this shop's data. For a new custom storefront using this catalog, follow the Hydrogen recipe above; installing these artifacts is not required. - Theme `origin`: the theme the whole store runs on. Specified at https://mock.shop/representations/themes/origin; filled with the values in this shop's public metafield `mock_shop.theme`. - Hero `two-picture`: the section at the top of the home page, in place of the theme's own opening hero. Specified at https://mock.shop/representations/heroes/two-picture; filled with the values in this shop's public metafield `mock_shop.hero`. The values and the artifacts come from here: 1. Read the values this shop fills its look with. Metafields answer only when the request carries a token, so send `public`: ```sh curl -sS -X POST https://demostore.mock.shop/api \ -H 'Content-Type: application/json' \ -H 'X-Shopify-Storefront-Access-Token: public' \ -d '{"query":"{ shop { metafields(identifiers: [{namespace: \"mock_shop\", key: \"theme\"}, {namespace: \"mock_shop\", key: \"hero\"}]) { key value } } }"}' ``` 2. Read each artifact's specification. It holds the artifact's `url` and `sha256`, what it needs filled in (a theme's `tokens`, a hero's `settings`), and where it goes: ```sh curl -sS https://mock.shop/representations/themes/origin curl -sS https://mock.shop/representations/heroes/two-picture ``` 3. Download the artifacts and check each digest against its specification's `sha256`: ```sh curl -sSLo origin.zip "$(curl -sS https://mock.shop/representations/themes/origin | jq -r .url)" curl -sSLo two-picture.liquid "$(curl -sS https://mock.shop/representations/heroes/two-picture | jq -r .url)" shasum -a 256 origin.zip two-picture.liquid ``` 4. Install them as each specification says. These rules hold for every shop: - Every `[[TOKEN]]` in a theme is a key in `mock_shop.theme.placeholders`. A token this shop does not supply is never filled with an invented value. What stands in for it is what the reference render shows in that region, and it is one of four things: the section that needed it (`tokens.<NAME>.sections` in the specification) is disabled; the line is left empty and its section kept; the shop's name; or a photograph from this shop's own catalog. The theme's specification says which, token by token, in its `install` steps, and where it is silent the render decides. - `IMAGE_*` values are image URLs. Upload each to the store's files, then refer to it as `shopify://shop_images/<filename>`. - A hero replaces the theme's own opening hero section on the home page; it is not added in front of it. It is installed only when this shop can fill it, and the hero's specification says what that takes (its `layoutRules`, and every image it draws on, each an absolute `https://` URL); when this shop cannot, the theme's own opening section stays, which is what the reference render shows. - Each field of `mock_shop.hero.copy` falls back on its own: a `headline` this shop did not write is the shop's name, a missing `subheadline` is the shop's description, and without a `cta` its button says "Shop now" and links to `/collections/all`. A hero's image settings count from one and `images` from zero: `images[0].url` and `images[0].alt` fill its image 1, `images[1]` its image 2, and so on. ## Example query ```graphql { products(first: 5) { nodes { title handle productType priceRange { minVariantPrice { amount currencyCode } } } } } ``` ## Agent commerce (UCP) This store supports the [Universal Commerce Protocol](https://ucp.dev) version 2026-08-25 for catalog search and mock carts. - Discovery: `GET https://demostore.mock.shop/.well-known/ucp` lists supported capabilities and the store's endpoint. - MCP endpoint: `POST https://demostore.mock.shop/api/ucp/mcp` with `Content-Type: application/json`. Use `initialize` and `tools/list` to discover the tool schemas. - Tools: `search_catalog`, `create_cart`, `get_cart`, `update_cart`, and `cancel_cart`. Use variant IDs returned by search as cart item IDs. Cart IDs also work with this store's Storefront GraphQL API. - Tool calls require `arguments.meta["ucp-agent"].profile`, a public HTTPS URL for your agent's UCP profile declaring the matching version and capabilities. Cart writes also require `arguments.meta["idempotency-key"]`; reuse the same key only when retrying the same operation with identical arguments. - Prices use the store's currency in ISO 4217 minor units. `update_cart` replaces the entire item list. Each request can contain at most 250 cart lines. Checkout is mocked: no payment is taken, nothing ships, and no real order is placed. The existing browser checkout is separate from these UCP tools. UCP checkout, payment, fulfillment, and order operations are not supported or advertised. Examples and supported inputs: https://mock.shop/guides/ucp ## Other stores Every published store is listed at https://mock.shop/llms.txt.