From shopify
Creates and manages Shopify products via GraphQL Admin API or CSV imports. Bulk import/update variants, inventory, images, assign to collections.
npx claudepluginhub jezweb/claude-skills --plugin shopifyThis skill uses the workspace's default tool permissions.
Create, update, and bulk-import Shopify products. Produces live products in the store via the GraphQL Admin API or CSV import.
Guides Payload CMS config (payload.config.ts), collections, fields, hooks, access control, APIs. Debugs validation errors, security, relationships, queries, transactions, hook behavior.
Builds scalable data pipelines, modern data warehouses, and real-time streaming architectures using Spark, dbt, Airflow, Kafka, and cloud platforms like Snowflake, BigQuery.
Builds production Apache Airflow DAGs with best practices for operators, sensors, testing, and deployment. For data pipelines, workflow orchestration, and batch job scheduling.
Create, update, and bulk-import Shopify products. Produces live products in the store via the GraphQL Admin API or CSV import.
shopify.config.json or .dev.varsDetermine what the user wants to create or update:
Accept data from:
| Scenario | Method |
|---|---|
| 1-5 products | GraphQL mutations |
| 6-20 products | GraphQL with batching |
| 20+ products | CSV import via admin |
| Updates to existing | GraphQL mutations |
| Inventory adjustments | inventorySetQuantities mutation |
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).
mutation productUpdate($input: ProductInput!) {
productUpdate(input: $input) {
product { id title }
userErrors { field message }
}
}
Variables include id (required) plus any fields to update.
mutation productDelete($input: ProductDeleteInput!) {
productDelete(input: $input) {
deletedProductId
userErrors { field message }
}
}
Add variants to an existing product:
mutation productVariantsBulkCreate($productId: ID!, $variants: [ProductVariantsBulkInput!]!) {
productVariantsBulkCreate(productId: $productId, variants: $variants) {
productVariants { id title price }
userErrors { field message }
}
}
mutation productVariantsBulkUpdate($productId: ID!, $variants: [ProductVariantsBulkInput!]!) {
productVariantsBulkUpdate(productId: $productId, variants: $variants) {
productVariants { id title price }
userErrors { field message }
}
}
For 20+ products, generate a CSV and import through Shopify admin.
Required columns:
| Column | Description | Example |
|---|---|---|
Handle | URL slug (unique per product) | classic-tshirt |
Title | Product name (first row per product) | Classic T-Shirt |
Body (HTML) | Description in HTML | <p>Premium cotton</p> |
Vendor | Brand or manufacturer | My Brand |
Product Category | Shopify standard taxonomy | Apparel & Accessories > Clothing > Shirts & Tops |
Type | Custom product type | T-Shirts |
Tags | Comma-separated tags | summer, cotton, casual |
Published | Whether product is visible | TRUE or FALSE |
Variant columns:
| Column | Description | Example |
|---|---|---|
Option1 Name | First option name | Size |
Option1 Value | First option value | Medium |
Option2 Name | Second option name | Colour |
Option2 Value | Second option value | Black |
Option3 Name | Third option name | Material |
Option3 Value | Third option value | Cotton |
Variant SKU | Stock keeping unit | TSHIRT-M-BLK |
Variant Grams | Weight in grams | 200 |
Variant Inventory Qty | Stock quantity | 50 |
Variant Price | Variant price | 29.95 |
Variant Compare At Price | Original price (for sales) | 39.95 |
Variant Requires Shipping | Physical product | TRUE |
Variant Taxable | Subject to tax | TRUE |
Image columns:
| Column | Description | Example |
|---|---|---|
Image Src | Image URL | https://example.com/img.jpg |
Image Position | Display order (1-based) | 1 |
Image Alt Text | Alt text for accessibility | Classic T-Shirt front view |
SEO columns:
| Column | Description | Example |
|---|---|---|
SEO Title | Page title tag | `Classic T-Shirt |
SEO Description | Meta description | Premium cotton tee in 5 colours |
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,
Published = TRUE makes the product immediately visibleassets/product-csv-template.csv if availablehttps://{store}.myshopify.com/admin/products/importUse browser automation to assist with the upload if needed.
Images require a two-step process -- staged upload then attach.
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:
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" }
]
}
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 }
}
}
}
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 }
}
}
}
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
New products default to DRAFT. To make them visible:
{ "status": "ACTIVE" }
Always confirm with the user before setting status to ACTIVE.
Shopify allows max 100 variants per product and 3 options (e.g. Size, Colour, Material). If you need more, split into separate products.
Prices are strings, not numbers. Always quote them: "price": "29.95" not "price": 29.95.
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 insteadFor 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.
assets/product-csv-template.csv -- Blank CSV template with Shopify import headers