Skip to Content
Preview & sample data

Preview & sample data

You can preview any template in your theme without a live store. The platform renders your Liquid over the dummy fixtures you ship in sample-data/*.json - the same render path used in production, so what you see in preview is what a real store gets.

Sample-data fixtures

Ship dummy data under sample-data/. These fixtures are not optional decoration

  • the automated review gate renders every template over them, so a bundle whose fixtures are missing or misnamed fails review.

The filenames are exact. The loader looks for these keys and nothing else:

sample-data/ ├── shop.json # REQUIRED - the shop object. No shop, no preview. ├── products.json # array of products; products[0] powers the PDP preview ├── collections.json # array of collections; collections[0] powers the │ # collection preview, and each entry is also exposed │ # as collections['<handle>'] globally ├── menus.json # object keyed by handle: "main-menu", "footer-menu" ├── search.json # { "terms": "...", "results": [ ...products ] } ├── page.json # { "title", "handle", "content" } for the page preview ├── cart.json # a populated cart (defaults to an empty cart) ├── customer.json # a customer object, or literally `null` ├── settings.json # sample merchant setting overrides (optional) └── globals.json # global section settings (optional)

shop.json is mandatory, and the plural filenames matter. A fixture named product.json or collection.json (singular) is simply not read - your preview renders with no products and the gate reports empty pages. And with no sample-data/shop.json at all, every template in the gate fails with “Missing sample-data/shop.json preview fixture” - the single most common first-submission failure.

shop.json must include at least a string name and a string currency.

Each fixture matches the shape documented in the Liquid context reference. For example, each entry in products.json follows the product object - title, handle, price (in paise), options[], variants[], and so on.

Keep fixtures realistic but small. Each sample-data/*.json is capped at 512 KB, and the whole sample-data/ directory at 2 MB; exceeding either fails the parse.

The standalone preview endpoint

The platform renders a preview via a public, unauthenticated endpoint:

GET /public/themes/:slug/preview/:template?version=<semver>
  • :slug - your theme’s slug.
  • :template - the template to render (index, product, collection, search, page, wishlist, 404, …).
  • version - optional; pins a specific published version. Omit for the latest.

It returns text/html rendered from your bundle over the dummy sample-data fixtures. No tenant, no database, no customer data is involved - so previewing is always safe and side-effect free.

The preview’s bundle assets (CSS / JS / fonts / images) are served from /assets/:slug/:version/*, which is exactly what the asset_url filter emits - so a preview renders fully styled.

Local preview via the CLI

During development, qm theme dev runs the same render library locally against your sample-data fixtures, so you get an instant local preview loop without publishing anything.

qm theme dev # renders each template over sample-data and serves them locally

Because the CLI local preview, the marketplace preview, and the automated review gate all share the identical render path, a template that renders correctly in qm theme dev renders correctly everywhere.

What to preview

At minimum, preview and read every template at all three breakpoints (1440 / 768 / 375 px):

  • Home (index)
  • Product (product) - including sold-out and unavailable-combination states
  • Collection (collection) - with filters applied and an empty result
  • Search (search) - a hit and the empty state
  • A content page (page)
  • Wishlist (wishlist) - populated and empty
  • 404

Do not pattern-match on “looks right.” Exercise sort, filter, pagination, search, and add-to-cart - broken interactions do not show in a static screenshot.