Shopify Products

by jezweb64965d9d9fc7No license1K starsListed Oct 8, 2026Updated Oct 8, 2026Repository updated 3 days ago

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.

AI-generated overview

Creates, updates and bulk-imports Shopify products through the Admin GraphQL API or CSV import.

What it does
This skill guides an agent through creating, updating and bulk-importing Shopify products using the Admin GraphQL API or a CSV import through the Shopify admin. It covers gathering product data, choosing between GraphQL mutations and CSV, uploading images, assigning products to collections, setting inventory quantities, and verifying the results. It produces live or draft products in a Shopify store and provides the admin URL for review.
When to use it
Use it when a user wants to add products to Shopify, bulk-import a catalog from CSV, spreadsheet or URL, update variants or prices, manage inventory quantities, upload product images, or assign products to collections.
Requirements
A Shopify Admin API access token, store URL and API version from shopify.config.json or .dev.vars, plus network access to the Shopify Admin GraphQL API. It ships a blank CSV template asset and is marked claude-code-only; no scripts are included.

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
graphql
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:

json
{  "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:

bash
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
graphql
mutation productUpdate($input: ProductInput!) {  productUpdate(input: $input) {    product { id title }    userErrors { field message }  }}

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

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

Add variants to an existing product:

graphql
mutation productVariantsBulkCreate($productId: ID!, $variants: [ProductVariantsBulkInput!]!) {  productVariantsBulkCreate(productId: $productId, variants: $variants) {    productVariants { id title price }    userErrors { field message }  }}
productVariantsBulkUpdate
graphql
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:

csv
Handle,Title,Body (HTML),Vendor,Type,Tags,Published,Option1 Name,Option1 Value,Variant SKU,Variant Price,Variant Inventory Qty,Image Srcclassic-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.jpgclassic-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
graphql
mutation stagedUploadsCreate($input: [StagedUploadInput!]!) {  stagedUploadsCreate(input: $input) {    stagedTargets {      url      resourceUrl      parameters { name value }    }    userErrors { field message }  }}

Input per file:

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

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

productCreateMedia
graphql
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:

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

Step 5: Assign to Collections

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

To find collection IDs:

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

Step 6: Set Inventory

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

Input:

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

To find location IDs:

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

Step 7: Verify

Query back the created products to confirm:

graphql
{  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:

json
{ "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:

graphql
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

Source and attribution

Source:jezweb/claude-skillsinplugins/shopify/skills/shopify-productsat commit64965d9

License: No license

Content belongs to its original authors. SourceWeft indexes it from a public repository.

Report or request removal