Shopify skill

Build and customize Shopify stores — themes with Liquid, Storefront API, custom apps, and headless commerce with Hydrogen.

by TerminalSkills·Apache-2.0 license·GitHub ↗

★ 157 Stars on the repo·Checked

npx degit TerminalSkills/skills/skills/shopify#main ~/.claude/skills/shopify-2

SKILL.md · 11.4 KB · names 5 other files — download is this file only · installs the whole folder to ~/.claude/skills/shopify-2

Files of Shopify

Files 1 file
Show the full text366 lines

Shopify

Overview

Shopify is the leading e-commerce platform — from simple stores to enterprise. Build custom themes with Liquid templating (no backend needed, employees can edit content through the admin panel), extend functionality with custom apps via the Admin and Storefront APIs, or go fully headless with Hydrogen (React/Remix). Covers the full spectrum: zero-code store setup, theme customization, API integrations, and custom headless storefronts.

When to Use

  • Building an online store (products, cart, checkout, payments)
  • Customizing Shopify themes (layout, design, sections)
  • Building custom functionality (apps, integrations, webhooks)
  • Headless commerce (custom frontend, Shopify as backend)
  • Staff-manageable stores where non-technical people update products and content

Instructions

Theme Development with Liquid
# Install Shopify CLI
npm install -g @shopify/cli @shopify/theme
shopify theme init my-theme
cd my-theme
shopify theme dev  # Local development with hot reload
Theme Structure
my-theme/
├── layout/
│   └── theme.liquid          # Main layout (wraps all pages)
├── templates/
│   ├── index.json            # Homepage (JSON template)
│   ├── product.liquid        # Product page
│   ├── collection.liquid     # Collection page
│   ├── cart.liquid            # Cart page
│   └── page.liquid            # Generic page
├── sections/
│   ├── header.liquid          # Header section (customizable in admin)
│   ├── hero-banner.liquid     # Hero banner section
│   ├── featured-products.liquid
│   └── footer.liquid
├── snippets/
│   ├── product-card.liquid    # Reusable product card
│   └── price.liquid           # Price display with compare-at
├── assets/
│   ├── theme.css
│   └── theme.js
├── config/
│   └── settings_schema.json   # Theme settings (colors, fonts, etc.)
└── locales/
    └── en.default.json        # Translations
Liquid Templates
{% comment %} sections/hero-banner.liquid — Customizable hero section {% endcomment %}
{% comment %}
  Staff can change the heading, text, image, and button
  through the Shopify admin without touching code.
{% endcomment %}

<section class="hero" style="background-image: url('{{ section.settings.image | image_url: width: 1920 }}')">
  <div class="hero__content">
    <h1>{{ section.settings.heading }}</h1>
    <p>{{ section.settings.text }}</p>
    {% if section.settings.button_text != blank %}
      <a href="{{ section.settings.button_link }}" class="btn">
        {{ section.settings.button_text }}
      </a>
    {% endif %}
  </div>
</section>

{% schema %}
{
  "name": "Hero Banner",
  "settings": [
    {
      "type": "image_picker",
      "id": "image",
      "label": "Background Image"
    },
    {
      "type": "text",
      "id": "heading",
      "label": "Heading",
      "default": "Welcome to our store"
    },
    {
      "type": "richtext",
      "id": "text",
      "label": "Description"
    },
    {
      "type": "text",
      "id": "button_text",
      "label": "Button Text"
    },
    {
      "type": "url",
      "id": "button_link",
      "label": "Button Link"
    }
  ],
  "presets": [
    {
      "name": "Hero Banner"
    }
  ]
}
{% endschema %}
{% comment %} sections/featured-products.liquid — Dynamic product grid {% endcomment %}

<section class="featured-products">
  <h2>{{ section.settings.title }}</h2>
  <div class="product-grid">
    {% for product in section.settings.collection.products limit: section.settings.limit %}
      {% render 'product-card', product: product %}
    {% endfor %}
  </div>
</section>

{% schema %}
{
  "name": "Featured Products",
  "settings": [
    { "type": "text", "id": "title", "label": "Section Title", "default": "Featured Products" },
    { "type": "collection", "id": "collection", "label": "Collection" },
    { "type": "range", "id": "limit", "label": "Products to show", "min": 2, "max": 12, "step": 1, "default": 4 }
  ],
  "presets": [{ "name": "Featured Products" }]
}
{% endschema %}
{% comment %} snippets/product-card.liquid — Reusable product card {% endcomment %}

<div class="product-card">
  <a href="{{ product.url }}">
    <img
      src="{{ product.featured_image | image_url: width: 400 }}"
      alt="{{ product.featured_image.alt | escape }}"
      loading="lazy"
      width="400"
      height="400"
    >
    <h3>{{ product.title }}</h3>
    <div class="product-card__price">
      {% if product.compare_at_price > product.price %}
        <span class="price--sale">{{ product.price | money }}</span>
        <span class="price--compare">{{ product.compare_at_price | money }}</span>
      {% else %}
        <span>{{ product.price | money }}</span>
      {% endif %}
    </div>
  </a>
  <button class="btn" data-product-id="{{ product.variants.first.id }}">
    {% if product.available %}
      Add to Cart
    {% else %}
      Sold Out
    {% endif %}
  </button>
</div>
Theme Settings (Staff-Editable)
// config/settings_schema.json — Theme customization panel
[
  {
    "name": "Colors",
    "settings": [
      { "type": "color", "id": "color_primary", "label": "Primary Color", "default": "#000000" },
      { "type": "color", "id": "color_secondary", "label": "Secondary Color", "default": "#333333" },
      { "type": "color", "id": "color_accent", "label": "Accent Color", "default": "#0066cc" }
    ]
  },
  {
    "name": "Typography",
    "settings": [
      { "type": "font_picker", "id": "font_heading", "label": "Heading Font", "default": "helvetica_n7" },
      { "type": "font_picker", "id": "font_body", "label": "Body Font", "default": "helvetica_n4" }
    ]
  },
  {
    "name": "Social Media",
    "settings": [
      { "type": "text", "id": "social_instagram", "label": "Instagram URL" },
      { "type": "text", "id": "social_facebook", "label": "Facebook URL" },
      { "type": "text", "id": "social_tiktok", "label": "TikTok URL" }
    ]
  }
]
Storefront API (Headless)
// lib/shopify.ts — Query Shopify Storefront API
const SHOPIFY_DOMAIN = "my-store.myshopify.com";
const STOREFRONT_TOKEN = process.env.SHOPIFY_STOREFRONT_TOKEN;

async function shopifyQuery(query: string, variables?: Record<string, any>) {
  const res = await fetch(`https://${SHOPIFY_DOMAIN}/api/2024-10/graphql.json`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-Shopify-Storefront-Access-Token": STOREFRONT_TOKEN!,
    },
    body: JSON.stringify({ query, variables }),
  });
  return res.json();
}

// Get products
const { data } = await shopifyQuery(`
  query GetProducts($first: Int!) {
    products(first: $first) {
      edges {
        node {
          id
          title
          handle
          priceRange {
            minVariantPrice { amount currencyCode }
          }
          images(first: 1) {
            edges { node { url altText } }
          }
        }
      }
    }
  }
`, { first: 12 });
Admin API (Backend/Apps)
// admin/products.ts — Manage products via Admin API
const ADMIN_TOKEN = process.env.SHOPIFY_ADMIN_TOKEN;

async function adminQuery(query: string, variables?: Record<string, any>) {
  const res = await fetch(`https://${SHOPIFY_DOMAIN}/admin/api/2024-10/graphql.json`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-Shopify-Access-Token": ADMIN_TOKEN!,
    },
    body: JSON.stringify({ query, variables }),
  });
  return res.json();
}

// Create a product
await adminQuery(`
  mutation CreateProduct($input: ProductInput!) {
    productCreate(input: $input) {
      product { id title }
      userErrors { field message }
    }
  }
`, {
  input: {
    title: "New Product",
    bodyHtml: "<p>Product description</p>",
    vendor: "My Brand",
    productType: "Accessories",
    tags: ["new", "featured"],
  },
});
Cart with JavaScript (Ajax API)
// assets/theme.js — Cart functionality (no page reload)
async function addToCart(variantId, quantity = 1) {
  const res = await fetch("/cart/add.js", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ items: [{ id: variantId, quantity }] }),
  });
  const cart = await res.json();
  updateCartUI(cart);
}

async function updateQuantity(lineItemKey, quantity) {
  const res = await fetch("/cart/change.js", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ id: lineItemKey, quantity }),
  });
  const cart = await res.json();
  updateCartUI(cart);
}

async function getCart() {
  const res = await fetch("/cart.js");
  return res.json();
}

Examples

Example 1: Build a custom Shopify theme

User prompt: "Create a Shopify theme for a clothing store with customizable hero, product grid, and newsletter sections that staff can edit."

The agent will create Liquid sections with schema blocks, theme settings for colors/fonts, product card snippets, and Ajax cart — all editable by non-technical staff through the Shopify admin panel.

Example 2: Integrate external service with Shopify

User prompt: "When an order is placed, send the details to our warehouse API and update inventory."

The agent will create a Shopify webhook listener for order creation, call the warehouse API, and update inventory via the Admin API.

Example 3: Headless Shopify with React

User prompt: "Build a custom React storefront using Shopify as the backend."

The agent will set up Storefront API queries for products/collections/cart, handle checkout creation, and implement product search.

Guidelines

  • Sections for customizability — anything staff should edit goes in a section with {% schema %}
  • JSON templates — use templates/*.json for drag-and-drop section ordering
  • Snippets for reusability — {% render 'product-card', product: product %}
  • Ajax API for cart — /cart/add.js, /cart/change.js, /cart.js for no-reload cart
  • Storefront API for headless — GraphQL, read-only, public token
  • Admin API for apps — GraphQL/REST, private token, full CRUD
  • Image optimization — always use | image_url: width: X filter
  • Metafields for custom data — extend products/pages with custom fields
  • Theme settings for global config — colors, fonts, social links in settings_schema.json
  • shopify theme dev for local development — hot reload, sync with store
  • Checkout is managed by Shopify — customize only via checkout extensions (Shopify Plus)
  • Staff training — sections + settings make themes self-service for non-devs
1---
2name: shopify
3description: >-
4 Build and customize Shopify stores — themes with Liquid, Storefront API,
5 custom apps, and headless commerce with Hydrogen. Use when someone asks to
6 "build a Shopify store", "Shopify theme", "Liquid templates", "Shopify API",
7 "Shopify app", "headless Shopify", "Hydrogen storefront", "customize Shopify",
8 "Shopify product management", or "e-commerce with Shopify". Covers Liquid
9 templating, theme development, Storefront/Admin APIs, custom apps, checkout
10 extensions, and Hydrogen (React-based headless).
11license: Apache-2.0
12compatibility: "Liquid (themes). Node.js/Ruby (apps). React/Remix (Hydrogen). Shopify CLI."
13metadata:
14 author: terminal-skills
15 version: "1.0.0"
16 category: business
17 tags: ["shopify", "ecommerce", "liquid", "storefront", "hydrogen", "themes"]
18---
19 
20# Shopify
21 
22## Overview
23 
24Shopify is the leading e-commerce platform — from simple stores to enterprise. Build custom themes with Liquid templating (no backend needed, employees can edit content through the admin panel), extend functionality with custom apps via the Admin and Storefront APIs, or go fully headless with Hydrogen (React/Remix). Covers the full spectrum: zero-code store setup, theme customization, API integrations, and custom headless storefronts.
25 
26## When to Use
27 
28- Building an online store (products, cart, checkout, payments)
29- Customizing Shopify themes (layout, design, sections)
30- Building custom functionality (apps, integrations, webhooks)
31- Headless commerce (custom frontend, Shopify as backend)
32- Staff-manageable stores where non-technical people update products and content
33 
34## Instructions
35 
36### Theme Development with Liquid
37 
38```bash
39# Install Shopify CLI
40npm install -g @shopify/cli @shopify/theme
41shopify theme init my-theme
42cd my-theme
43shopify theme dev # Local development with hot reload
44```
45 
46#### Theme Structure
47 
48```
49my-theme/
50├── layout/
51│ └── theme.liquid # Main layout (wraps all pages)
52├── templates/
53│ ├── index.json # Homepage (JSON template)
54│ ├── product.liquid # Product page
55│ ├── collection.liquid # Collection page
56│ ├── cart.liquid # Cart page
57│ └── page.liquid # Generic page
58├── sections/
59│ ├── header.liquid # Header section (customizable in admin)
60│ ├── hero-banner.liquid # Hero banner section
61│ ├── featured-products.liquid
62│ └── footer.liquid
63├── snippets/
64│ ├── product-card.liquid # Reusable product card
65│ └── price.liquid # Price display with compare-at
66├── assets/
67│ ├── theme.css
68│ └── theme.js
69├── config/
70│ └── settings_schema.json # Theme settings (colors, fonts, etc.)
71└── locales/
72 └── en.default.json # Translations
73```
74 
75#### Liquid Templates
76 
77```liquid
78{% comment %} sections/hero-banner.liquid — Customizable hero section {% endcomment %}
79{% comment %}
80 Staff can change the heading, text, image, and button
81 through the Shopify admin without touching code.
82{% endcomment %}
83 
84<section class="hero" style="background-image: url('{{ section.settings.image | image_url: width: 1920 }}')">
85 <div class="hero__content">
86 <h1>{{ section.settings.heading }}</h1>
87 <p>{{ section.settings.text }}</p>
88 {% if section.settings.button_text != blank %}
89 <a href="{{ section.settings.button_link }}" class="btn">
90 {{ section.settings.button_text }}
91 </a>
92 {% endif %}
93 </div>
94</section>
95 
96{% schema %}
97{
98 "name": "Hero Banner",
99 "settings": [
100 {
101 "type": "image_picker",
102 "id": "image",
103 "label": "Background Image"
104 },
105 {
106 "type": "text",
107 "id": "heading",
108 "label": "Heading",
109 "default": "Welcome to our store"
110 },
111 {
112 "type": "richtext",
113 "id": "text",
114 "label": "Description"
115 },
116 {
117 "type": "text",
118 "id": "button_text",
119 "label": "Button Text"
120 },
121 {
122 "type": "url",
123 "id": "button_link",
124 "label": "Button Link"
125 }
126 ],
127 "presets": [
128 {
129 "name": "Hero Banner"
130 }
131 ]
132}
133{% endschema %}
134```
135 
136```liquid
137{% comment %} sections/featured-products.liquid — Dynamic product grid {% endcomment %}
138 
139<section class="featured-products">
140 <h2>{{ section.settings.title }}</h2>
141 <div class="product-grid">
142 {% for product in section.settings.collection.products limit: section.settings.limit %}
143 {% render 'product-card', product: product %}
144 {% endfor %}
145 </div>
146</section>
147 
148{% schema %}
149{
150 "name": "Featured Products",
151 "settings": [
152 { "type": "text", "id": "title", "label": "Section Title", "default": "Featured Products" },
153 { "type": "collection", "id": "collection", "label": "Collection" },
154 { "type": "range", "id": "limit", "label": "Products to show", "min": 2, "max": 12, "step": 1, "default": 4 }
155 ],
156 "presets": [{ "name": "Featured Products" }]
157}
158{% endschema %}
159```
160 
161```liquid
162{% comment %} snippets/product-card.liquid — Reusable product card {% endcomment %}
163 
164<div class="product-card">
165 <a href="{{ product.url }}">
166 <img
167 src="{{ product.featured_image | image_url: width: 400 }}"
168 alt="{{ product.featured_image.alt | escape }}"
169 loading="lazy"
170 width="400"
171 height="400"
172 >
173 <h3>{{ product.title }}</h3>
174 <div class="product-card__price">
175 {% if product.compare_at_price > product.price %}
176 <span class="price--sale">{{ product.price | money }}</span>
177 <span class="price--compare">{{ product.compare_at_price | money }}</span>
178 {% else %}
179 <span>{{ product.price | money }}</span>
180 {% endif %}
181 </div>
182 </a>
183 <button class="btn" data-product-id="{{ product.variants.first.id }}">
184 {% if product.available %}
185 Add to Cart
186 {% else %}
187 Sold Out
188 {% endif %}
189 </button>
190</div>
191```
192 
193#### Theme Settings (Staff-Editable)
194 
195```json
196// config/settings_schema.json — Theme customization panel
197[
198 {
199 "name": "Colors",
200 "settings": [
201 { "type": "color", "id": "color_primary", "label": "Primary Color", "default": "#000000" },
202 { "type": "color", "id": "color_secondary", "label": "Secondary Color", "default": "#333333" },
203 { "type": "color", "id": "color_accent", "label": "Accent Color", "default": "#0066cc" }
204 ]
205 },
206 {
207 "name": "Typography",
208 "settings": [
209 { "type": "font_picker", "id": "font_heading", "label": "Heading Font", "default": "helvetica_n7" },
210 { "type": "font_picker", "id": "font_body", "label": "Body Font", "default": "helvetica_n4" }
211 ]
212 },
213 {
214 "name": "Social Media",
215 "settings": [
216 { "type": "text", "id": "social_instagram", "label": "Instagram URL" },
217 { "type": "text", "id": "social_facebook", "label": "Facebook URL" },
218 { "type": "text", "id": "social_tiktok", "label": "TikTok URL" }
219 ]
220 }
221]
222```
223 
224### Storefront API (Headless)
225 
226```typescript
227// lib/shopify.ts — Query Shopify Storefront API
228const SHOPIFY_DOMAIN = "my-store.myshopify.com";
229const STOREFRONT_TOKEN = process.env.SHOPIFY_STOREFRONT_TOKEN;
230 
231async function shopifyQuery(query: string, variables?: Record<string, any>) {
232 const res = await fetch(`https://${SHOPIFY_DOMAIN}/api/2024-10/graphql.json`, {
233 method: "POST",
234 headers: {
235 "Content-Type": "application/json",
236 "X-Shopify-Storefront-Access-Token": STOREFRONT_TOKEN!,
237 },
238 body: JSON.stringify({ query, variables }),
239 });
240 return res.json();
241}
242 
243// Get products
244const { data } = await shopifyQuery(`
245 query GetProducts($first: Int!) {
246 products(first: $first) {
247 edges {
248 node {
249 id
250 title
251 handle
252 priceRange {
253 minVariantPrice { amount currencyCode }
254 }
255 images(first: 1) {
256 edges { node { url altText } }
257 }
258 }
259 }
260 }
261 }
262`, { first: 12 });
263```
264 
265### Admin API (Backend/Apps)
266 
267```typescript
268// admin/products.ts — Manage products via Admin API
269const ADMIN_TOKEN = process.env.SHOPIFY_ADMIN_TOKEN;
270 
271async function adminQuery(query: string, variables?: Record<string, any>) {
272 const res = await fetch(`https://${SHOPIFY_DOMAIN}/admin/api/2024-10/graphql.json`, {
273 method: "POST",
274 headers: {
275 "Content-Type": "application/json",
276 "X-Shopify-Access-Token": ADMIN_TOKEN!,
277 },
278 body: JSON.stringify({ query, variables }),
279 });
280 return res.json();
281}
282 
283// Create a product
284await adminQuery(`
285 mutation CreateProduct($input: ProductInput!) {
286 productCreate(input: $input) {
287 product { id title }
288 userErrors { field message }
289 }
290 }
291`, {
292 input: {
293 title: "New Product",
294 bodyHtml: "<p>Product description</p>",
295 vendor: "My Brand",
296 productType: "Accessories",
297 tags: ["new", "featured"],
298 },
299});
300```
301 
302### Cart with JavaScript (Ajax API)
303 
304```javascript
305// assets/theme.js — Cart functionality (no page reload)
306async function addToCart(variantId, quantity = 1) {
307 const res = await fetch("/cart/add.js", {
308 method: "POST",
309 headers: { "Content-Type": "application/json" },
310 body: JSON.stringify({ items: [{ id: variantId, quantity }] }),
311 });
312 const cart = await res.json();
313 updateCartUI(cart);
314}
315 
316async function updateQuantity(lineItemKey, quantity) {
317 const res = await fetch("/cart/change.js", {
318 method: "POST",
319 headers: { "Content-Type": "application/json" },
320 body: JSON.stringify({ id: lineItemKey, quantity }),
321 });
322 const cart = await res.json();
323 updateCartUI(cart);
324}
325 
326async function getCart() {
327 const res = await fetch("/cart.js");
328 return res.json();
329}
330```
331 
332## Examples
333 
334### Example 1: Build a custom Shopify theme
335 
336**User prompt:** "Create a Shopify theme for a clothing store with customizable hero, product grid, and newsletter sections that staff can edit."
337 
338The agent will create Liquid sections with schema blocks, theme settings for colors/fonts, product card snippets, and Ajax cart — all editable by non-technical staff through the Shopify admin panel.
339 
340### Example 2: Integrate external service with Shopify
341 
342**User prompt:** "When an order is placed, send the details to our warehouse API and update inventory."
343 
344The agent will create a Shopify webhook listener for order creation, call the warehouse API, and update inventory via the Admin API.
345 
346### Example 3: Headless Shopify with React
347 
348**User prompt:** "Build a custom React storefront using Shopify as the backend."
349 
350The agent will set up Storefront API queries for products/collections/cart, handle checkout creation, and implement product search.
351 
352## Guidelines
353 
354- **Sections for customizability** — anything staff should edit goes in a section with `{% schema %}`
355- **JSON templates** — use `templates/*.json` for drag-and-drop section ordering
356- **Snippets for reusability** — `{% render 'product-card', product: product %}`
357- **Ajax API for cart** — `/cart/add.js`, `/cart/change.js`, `/cart.js` for no-reload cart
358- **Storefront API for headless** — GraphQL, read-only, public token
359- **Admin API for apps** — GraphQL/REST, private token, full CRUD
360- **Image optimization** — always use `| image_url: width: X` filter
361- **Metafields for custom data** — extend products/pages with custom fields
362- **Theme settings for global config** — colors, fonts, social links in `settings_schema.json`
363- **`shopify theme dev` for local development** — hot reload, sync with store
364- **Checkout is managed by Shopify** — customize only via checkout extensions (Shopify Plus)
365- **Staff training** — sections + settings make themes self-service for non-devs
366 

Discussion

Alternatives

Also in Storefront & listingsSee all 136 in Sales →