PluginBench
Skill
Fail
Audit score 45

shopify-products

jezweb/claude-skills

How to install shopify-products

npx skills add https://github.com/jezweb/claude-skills --skill shopify-products
Claude Code
Cursor
Windsurf
Cline
Full instructions (SKILL.md)

Source of truth, from jezweb/claude-skills.


name: shopify-products description: "Create and manage Shopify products via the Admin GraphQL API or CSV import. Workflow: gather data, choose method, execute, verify. Use whenever the user wants to add products to Shopify, bulk-import a catalog from CSV/spreadsheet/URL, update variants or prices, manage inventory quantities, upload product images, or assign products to collections." compatibility: claude-code-only

Shopify Products

Create, update, and bulk-import Shopify products. Produces live products in the store via the GraphQL Admin API or CSV import.

Prerequisites

  • Admin API access token (use the shopify-setup skill if not configured)
  • Store URL and API version from shopify.config.json or .dev.vars

Workflow

Step 1: Gather Product Data

Determine what the user wants to create or update:

  • Product basics: title, description (HTML), product type, vendor, tags
  • Variants: options (size, colour, material), prices, SKUs, inventory quantities
  • Images: URLs to upload, or local files
  • SEO: page title, meta description, URL handle
  • Organisation: collections, product type, tags

Accept data from:

  • Direct conversation (user describes products)
  • Spreadsheet/CSV file (user provides a file)
  • Website scraping (user provides a URL to extract from)

Step 2: Choose Method

ScenarioMethod
1-5 productsGraphQL mutations
6-20 productsGraphQL with batching
20+ productsCSV import via admin
Updates to existingGraphQL mutations
Inventory adjustmentsinventorySetQuantities mutation

Step 3a: Create via GraphQL (Recommended)

productCreate

mutation productCreate($product: ProductCreateInput!) {
  productCreate(product: $product) {
    product {
      id
      title
      handle
      status
      variants(first: 100) {
        edges {
          node { id title price sku inventoryQuantity }
        }
      }
    }
    userErrors { field message }
  }
}

Variables:

{
  "product": {
    "title": "Example T-Shirt",
    "descriptionHtml": "<p>Premium cotton tee</p>",
    "vendor": "My Brand",
    "productType": "T-Shirts",
    "tags": ["summer", "cotton"],
    "status": "DRAFT",
    "options": ["Size", "Colour"],
    "variants": [
      {
        "optionValues": [
          {"optionName": "Size", "name": "S"},
          {"optionName": "Colour", "name": "Black"}
        ],
        "price": "29.95",
        "sku": "TSHIRT-S-BLK",
        "inventoryPolicy": "DENY",
        "inventoryItem": { "tracked": true }
      },
      {
        "optionValues": [
          {"optionName": "Size", "name": "M"},
          {"optionName": "Colour", "name": "Black"}
        ],
        "price": "29.95",
        "sku": "TSHIRT-M-BLK"
      },
      {
        "optionValues": [
          {"optionName": "Size", "name": "L"},
          {"optionName": "Colour", "name": "Black"}
        ],
        "price": "29.95",
        "sku": "TSHIRT-L-BLK"
      }
    ],
    "seo": {
      "title": "Example T-Shirt | My Brand",
      "description": "Premium cotton tee in multiple sizes"
    }
  }
}

Curl example:

curl -s https://{store}/admin/api/2025-01/graphql.json \
  -H "Content-Type: application/json" \
  -H "X-Shopify-Access-Token: {token}" \
  -d '{"query": "mutation productCreate($product: ProductCreateInput!) { productCreate(product: $product) { product { id title } userErrors { field message } } }", "variables": { ... }}'

Batching multiple products: Create products sequentially with a short delay between each to respect rate limits (1,000 cost points/second).

productUpdate

mutation productUpdate($input: ProductInput!) {
  productUpdate(input: $input) {
    product { id title }
    userErrors { field message }
  }
}

Variables include id (required) plus any fields to update.

productDelete

mutation productDelete($input: ProductDeleteInput!) {
  productDelete(input: $input) {
    deletedProductId
    userErrors { field message }
  }
}

productVariantsBulkCreate

Add variants to an existing product:

mutation productVariantsBulkCreate($productId: ID!, $variants: [ProductVariantsBulkInput!]!) {
  productVariantsBulkCreate(productId: $productId, variants: $variants) {
    productVariants { id title price }
    userErrors { field message }
  }
}

productVariantsBulkUpdate

mutation productVariantsBulkUpdate($productId: ID!, $variants: [ProductVariantsBulkInput!]!) {
  productVariantsBulkUpdate(productId: $productId, variants: $variants) {
    productVariants { id title price }
    userErrors { field message }
  }
}

Step 3b: Bulk Import via CSV

For 20+ products, generate a CSV and import through Shopify admin.

CSV Column Reference

Required columns:

ColumnDescriptionExample
HandleURL slug (unique per product)classic-tshirt
TitleProduct name (first row per product)Classic T-Shirt
Body (HTML)Description in HTML<p>Premium cotton</p>
VendorBrand or manufacturerMy Brand
Product CategoryShopify standard taxonomyApparel & Accessories > Clothing > Shirts & Tops
TypeCustom product typeT-Shirts
TagsComma-separated tagssummer, cotton, casual
PublishedWhether product is visibleTRUE or FALSE

Variant columns:

ColumnDescriptionExample
Option1 NameFirst option nameSize
Option1 ValueFirst option valueMedium
Option2 NameSecond option nameColour
Option2 ValueSecond option valueBlack
Option3 NameThird option nameMaterial
Option3 ValueThird option valueCotton
Variant SKUStock keeping unitTSHIRT-M-BLK
Variant GramsWeight in grams200
Variant Inventory QtyStock quantity50
Variant PriceVariant price29.95
Variant Compare At PriceOriginal price (for sales)39.95
Variant Requires ShippingPhysical productTRUE
Variant TaxableSubject to taxTRUE

Image columns:

ColumnDescriptionExample
Image SrcImage URLhttps://example.com/img.jpg
Image PositionDisplay order (1-based)1
Image Alt TextAlt text for accessibilityClassic T-Shirt front view

SEO columns:

ColumnDescriptionExample
SEO TitlePage title tag`Classic T-Shirt
SEO DescriptionMeta descriptionPremium cotton tee in 5 colours

Multi-Variant Row Format

The first row has the product title and details. Subsequent rows for the same product have only the Handle and variant-specific columns:

Handle,Title,Body (HTML),Vendor,Type,Tags,Published,Option1 Name,Option1 Value,Variant SKU,Variant Price,Variant Inventory Qty,Image Src
classic-tshirt,Classic T-Shirt,<p>Premium cotton</p>,My Brand,T-Shirts,"summer,cotton",TRUE,Size,Small,TSH-S,29.95,50,https://example.com/tshirt.jpg
classic-tshirt,,,,,,,,Medium,TSH-M,29.95,75,
classic-tshirt,,,,,,,,Large,TSH-L,29.95,60,

CSV Rules

  • UTF-8 encoding required
  • Maximum 50MB file size
  • Handle must be unique per product -- duplicate handles update existing products
  • Leave variant columns blank on variant rows for fields that don't change
  • Images can be on any row -- they're associated by Handle
  • Published = TRUE makes the product immediately visible

Import Steps

  1. Generate CSV using the column format above
  2. Use the template from assets/product-csv-template.csv if available
  3. Navigate to https://{store}.myshopify.com/admin/products/import
  4. Upload the CSV file
  5. Review the preview and confirm import

Use browser automation to assist with the upload if needed.


Step 4: Upload Product Images

Images require a two-step process -- staged upload then attach.

stagedUploadsCreate

mutation stagedUploadsCreate($input: [StagedUploadInput!]!) {
  stagedUploadsCreate(input: $input) {
    stagedTargets {
      url
      resourceUrl
      parameters { name value }
    }
    userErrors { field message }
  }
}

Input per file:

{
  "filename": "product-image.jpg",
  "mimeType": "image/jpeg",
  "httpMethod": "POST",
  "resource": "IMAGE"
}

Then upload to the staged URL, and attach with productCreateMedia:

productCreateMedia

mutation productCreateMedia($productId: ID!, $media: [CreateMediaInput!]!) {
  productCreateMedia(productId: $productId, media: $media) {
    media { alt status }
    mediaUserErrors { field message }
  }
}

Shortcut: If images are already hosted at a public URL, pass src directly in the product creation:

{
  "images": [
    { "src": "https://example.com/image.jpg", "alt": "Product front view" }
  ]
}

Step 5: Assign to Collections

collectionAddProducts

mutation collectionAddProducts($id: ID!, $productIds: [ID!]!) {
  collectionAddProducts(id: $id, productIds: $productIds) {
    collection { title productsCount }
    userErrors { field message }
  }
}

To find collection IDs:

{
  collections(first: 50) {
    edges {
      node { id title handle productsCount }
    }
  }
}

Step 6: Set Inventory

inventorySetQuantities

mutation inventorySetQuantities($input: InventorySetQuantitiesInput!) {
  inventorySetQuantities(input: $input) {
    inventoryAdjustmentGroup { reason }
    userErrors { field message }
  }
}

Input:

{
  "reason": "correction",
  "name": "available",
  "quantities": [{
    "inventoryItemId": "gid://shopify/InventoryItem/123",
    "locationId": "gid://shopify/Location/456",
    "quantity": 50
  }]
}

To find location IDs:

{
  locations(first: 10) {
    edges {
      node { id name isActive }
    }
  }
}

Step 7: Verify

Query back the created products to confirm:

{
  products(first: 50) {
    edges {
      node {
        id title handle status productType vendor
        variants(first: 10) {
          edges { node { id title price sku inventoryQuantity } }
        }
        images(first: 3) { edges { node { url altText } } }
      }
    }
    pageInfo { hasNextPage endCursor }
  }
}

Provide the admin URL for the user to review: https://{store}.myshopify.com/admin/products


Critical Patterns

Product Status

New products default to DRAFT. To make them visible:

{ "status": "ACTIVE" }

Always confirm with the user before setting status to ACTIVE.

Variant Limits

Shopify allows max 100 variants per product and 3 options (e.g. Size, Colour, Material). If you need more, split into separate products.

Price Formatting

Prices are strings, not numbers. Always quote them: "price": "29.95" not "price": 29.95.

HTML Descriptions

Product descriptions accept HTML. Keep it simple -- Shopify's editor handles basic tags:

  • <p>, <strong>, <em>, <ul>, <ol>, <li>, <h2>-<h6>
  • <a href="..."> for links
  • <img> is stripped -- use product images instead

Bulk Operations for Large Imports

For 50+ products via API, use Shopify's bulk operation:

mutation {
  bulkOperationRunMutation(
    mutation: "mutation ($input: ProductInput!) { productCreate(input: $input) { product { id } userErrors { message } } }"
    stagedUploadPath: "tmp/bulk-products.jsonl"
  ) {
    bulkOperation { id status }
    userErrors { message }
  }
}

This accepts a JSONL file with one product per line, processed asynchronously.


Asset Files

  • assets/product-csv-template.csv -- Blank CSV template with Shopify import headers

Related skills

More from jezweb/claude-skills and the wider catalog.

SH

shadcn-ui

jezweb/claude-skills

Install and configure shadcn/ui components for React projects. Guides component selection, installation order, dependency management, customisation with semantic tokens, and common UI recipes (forms, data tables, navigation, modals). Use after tailwind-theme-builder has set up the theme infrastructure, when adding components, building forms, creating data tables, or setting up navigation.

3.0k installsAudited
TA

tailwind-v4-shadcn

jezweb/claude-skills

|

2.7k installsAudited
TA

tailwind-theme-builder

jezweb/claude-skills

Set up Tailwind v4 + shadcn/ui themed UI with dark mode. Install deps, configure CSS variables via @theme inline, wire dark mode toggle, verify. Use whenever the user mentions Tailwind v4, setting up Tailwind theming, shadcn/ui colours, dark mode, or troubleshooting colours not working, tw-animate-css errors, @theme inline conflicts, @apply breaking after upgrade, or v3 → v4 migration issues.

2.7k installs
TA

tanstack-query

jezweb/claude-skills

|

2.6k installsAudited
CO

color-palette

jezweb/claude-skills

Generate complete, accessible colour palettes from a single brand hex. Produces 11-shade scale (50-950), semantic tokens, dark mode variants, Tailwind v4 CSS output, WCAG contrast checks. Use whenever the user supplies a brand hex and asks for a palette, mentions setting up a design system, wants Tailwind theme colours from a brand colour, or asks to check colour accessibility / contrast.

2.4k installsAudited
FA

fastapi

jezweb/claude-skills

|

2.0k installsAudited