Skip to main content
SiteShi p

Reference

Shopify E-commerce

The engine builds the Content Security Policy from site.yaml. Adding Shopify hosts to allowedDomains opens script-src, frame-src, and connect-src so the Storefront components can load and reach Shopify's APIs.

Add Shopify products and checkout to any page using Storefront Web Components. Shopify handles inventory, payments, and checkout — the site just displays products.

Setup

  1. Get store domain from the user (e.g. mystore.myshopify.com)
  2. Add domains to CSP in data/site.yaml:
    {
      "allowedDomains": ["cdn.shopify.com", "mystore.myshopify.com"]
    }
    
  3. Add the script to the page or layout:
    <script src="https://cdn.shopify.com/storefront/web-components.js"></script>
    
  4. Initialize the store (once per page, before any product components):
    <shopify-store id="store" store-domain="https://mystore.myshopify.com"></shopify-store>
    

Optional: add public-access-token="xxxxx" for inventory data or custom fields.

Display a Product

Use <shopify-context> with the product handle (the URL slug from Shopify admin):

<shopify-context type="product" handle="classic-leather-bag">
  <template>
    <div class="grid md:grid-cols-2 gap-8">
      <shopify-media query="product.selectedOrFirstAvailableVariant.image" width="600"></shopify-media>
      <div>
        <h2 class="text-2xl font-bold"><shopify-data query="product.title"></shopify-data></h2>
        <p class="text-xl font-semibold text-primary-600 mt-2">
          <shopify-money query="product.selectedOrFirstAvailableVariant.price"></shopify-money>
        </p>
        <div class="mt-4"><shopify-data query="product.descriptionHtml"></shopify-data></div>
        <shopify-variant-selector class="mt-4"></shopify-variant-selector>
        <button onclick="getElementById('store').buyNow(event)"
          shopify-attr--disabled="!product.selectedOrFirstAvailableVariant.availableForSale"
          class="mt-6 px-8 py-3 bg-primary-600 text-white font-semibold rounded-lg hover:bg-primary-700 transition-colors disabled:opacity-50">
          Buy now
        </button>
      </div>
    </div>
  </template>
</shopify-context>

Buy Now Button (single product → checkout)

The simplest pattern — one button that goes straight to Shopify checkout:

<shopify-context type="product" handle="product-handle">
  <template>
    <button onclick="getElementById('store').buyNow(event)"
      shopify-attr--disabled="!product.selectedOrFirstAvailableVariant.availableForSale"
      class="px-6 py-3 bg-primary-600 text-white rounded-lg font-semibold hover:bg-primary-700 disabled:opacity-50">
      Buy now — <shopify-money query="product.selectedOrFirstAvailableVariant.price"></shopify-money>
    </button>
  </template>
</shopify-context>

Add to Cart (multi-product shopping)

For stores with multiple products — customers add items to a cart, then check out:

<!-- Product card -->
<shopify-context type="product" handle="product-handle">
  <template>
    <shopify-media query="product.selectedOrFirstAvailableVariant.image" width="400"></shopify-media>
    <h3><shopify-data query="product.title"></shopify-data></h3>
    <shopify-money query="product.selectedOrFirstAvailableVariant.price"></shopify-money>
    <shopify-variant-selector></shopify-variant-selector>
    <button onclick="getElementById('cart').addLine(event).showModal()"
      shopify-attr--disabled="!product.selectedOrFirstAvailableVariant.availableForSale"
      class="px-4 py-2 bg-primary-600 text-white rounded-lg text-sm">
      Add to cart
    </button>
  </template>
</shopify-context>

<!-- Cart (one per page, renders as a dialog) -->
<shopify-cart id="cart"></shopify-cart>

Shop Pay Button (fastest checkout)

For a branded Shop Pay express checkout button:

<script src="https://cdn.shopify.com/shopifycloud/shop-js/modules/v2/loader.pay-button.esm.js" type="module"></script>
<shop-pay-button
  store-url="https://mystore.myshopify.com"
  variants="36607875587"
></shop-pay-button>

Multiple variants with quantities: variants="36607875587:2,36607875459:3"

Product Collection Grid

Display multiple products in a grid layout:

<div class="grid md:grid-cols-3 gap-6">
  <shopify-context type="product" handle="product-1">
    <template>
      <div class="border rounded-xl overflow-hidden">
        <shopify-media query="product.selectedOrFirstAvailableVariant.image" width="400" class="w-full"></shopify-media>
        <div class="p-4">
          <h3 class="font-semibold"><shopify-data query="product.title"></shopify-data></h3>
          <p class="text-primary-600 font-bold mt-1">
            <shopify-money query="product.selectedOrFirstAvailableVariant.price"></shopify-money>
          </p>
          <button onclick="getElementById('cart').addLine(event)"
            class="mt-3 w-full py-2 bg-primary-600 text-white rounded-lg text-sm">
            Add to cart
          </button>
        </div>
      </div>
    </template>
  </shopify-context>
  <!-- Repeat for each product -->
</div>

<shopify-cart id="cart"></shopify-cart>

Data Display Components

Component Purpose Example
<shopify-data> Text content query="product.title"
<shopify-money> Formatted price query="product.selectedOrFirstAvailableVariant.price"
<shopify-media> Product image query="product.selectedOrFirstAvailableVariant.image" width="400"
<shopify-variant-selector> Size/color picker No query needed
<shopify-cart> Shopping cart dialog Add id="cart" for JS access

Rules

  • Always ask for the store domain — never invent it. Product handles come from Shopify admin (the URL slug).
  • No access token is needed for basic product display — only for inventory or custom data.
  • Shopify handles checkout, inventory, and payment — the site just displays products.
  • Web components are client-side rendered — product content is NOT indexed by search engines. Add static SEO content (headings, descriptions) alongside the components.
  • Cart does NOT support mixing products from multiple Shopify stores.
  • Style components with regular CSS — they don't use Shadow DOM for most elements.
  • Place <shopify-store> and <shopify-cart> once per page, before product contexts.
  • The <template> inside <shopify-context> renders after data loads — content is hidden until ready.

Found something out of date? Open an issue. ← All docs