From shopify-admin-skills
Bulk adds or removes tags on Shopify products matching a collection, existing tag, or search query. Use for campaign setup/teardown and catalog organization.
npx claudepluginhub 40rty-ai/shopify-admin-skills --plugin shopify-admin-skillsThis skill uses the workspace's default tool permissions.
Adds or removes one or more tags across a set of products in bulk — replacing manual product-by-product editing in the Shopify admin. Use for campaign setup (add `summer-sale` to a collection before launch), campaign teardown (remove `flash-sale` after it ends), or catalog reorganization (retag products moving between categories). Tags drive collection rules, marketing segments, and reporting f...
Bulk adds/removes tags to Shopify customers filtered by query (e.g., total_spent:>=500, tag:newsletter) or ID list; supports dry-run previews, merge/replace modes for migrations and segment updates.
Manages Shopify products, variants, collections, and inventory with GraphQL Admin API. Handles CRUD for catalog integrations, including product options and inventory quantities.
Creates and manages Shopify products via GraphQL Admin API or CSV imports. Bulk import/update variants, inventory, images, assign to collections.
Share bugs, ideas, or general feedback.
Adds or removes one or more tags across a set of products in bulk — replacing manual product-by-product editing in the Shopify admin. Use for campaign setup (add summer-sale to a collection before launch), campaign teardown (remove flash-sale after it ends), or catalog reorganization (retag products moving between categories). Tags drive collection rules, marketing segments, and reporting filters, so bulk accuracy matters. Replaces manual Shopify admin bulk editing and CSV import/export workflows.
shopify auth login --store <domain>read_products, write_productsUniversal (store, format, dry_run) + skill-specific:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| action | string | yes | — | add or remove |
| tags | array | yes | — | One or more tag strings to add or remove (e.g., ["summer-sale", "clearance"]) |
| collection_id | string | no* | — | GID of a collection — target all products in this collection |
| filter_tag | string | no* | — | Target all products that currently have this tag |
| query_filter | string | no* | — | Shopify product search query (e.g., "product_type:Apparel") |
*One of collection_id, filter_tag, or query_filter is required.
⚠️ Step 2 executes bulk tag mutations.
tagsRemoveis irreversible — if you remove the wrong tag, you must re-add it manually or run this skill again withaction: add. Run withdry_run: trueto see the full product list before committing. For large catalogs (1000+ products), dry_run is strongly recommended before any removal operation.
OPERATION: products — query
Inputs: first: 250, query built from collection_id, filter_tag, or query_filter; paginate until all matching products fetched
Expected output: List of product GIDs and current tag arrays; confirm target set before proceeding
OPERATION: tagsAdd — mutation (if action: add)
Inputs: id: <productId>, tags: <tags array> per product
Expected output: Updated node.id with userErrors
OR
OPERATION: tagsRemove — mutation (if action: remove)
Inputs: id: <productId>, tags: <tags array> per product
Expected output: Updated node with userErrors
# products:query — validated against api_version 2025-01
query ProductsForTagUpdate($first: Int!, $after: String, $query: String) {
products(first: $first, after: $after, query: $query) {
edges {
node {
id
title
tags
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
# tagsAdd:mutation — validated against api_version 2025-01
mutation TagsAdd($id: ID!, $tags: [String!]!) {
tagsAdd(id: $id, tags: $tags) {
node {
id
}
userErrors {
field
message
}
}
}
# tagsRemove:mutation — validated against api_version 2025-01
mutation TagsRemove($id: ID!, $tags: [String!]!) {
tagsRemove(id: $id, tags: $tags) {
node {
id
}
userErrors {
field
message
}
}
}
Claude MUST emit the following output at each stage. This is mandatory.
On start, emit:
╔══════════════════════════════════════════════╗
║ SKILL: product-tag-bulk-update ║
║ Store: <store domain> ║
║ Started: <YYYY-MM-DD HH:MM UTC> ║
╚══════════════════════════════════════════════╝
After each step, emit:
[N/TOTAL] <QUERY|MUTATION> <OperationName>
→ Params: <brief summary of key inputs>
→ Result: <count or outcome, e.g., "143 records returned">
If dry_run: true, prefix every mutation step with [DRY RUN] and do not execute it.
On completion, emit:
For format: human (default):
══════════════════════════════════════════════
OUTCOME SUMMARY
Products targeted: <count>
Tags added/removed: <tags list>
Action: <add|remove>
Errors: <count, 0 if none>
Output: <filename or "none">
══════════════════════════════════════════════
For format: json, emit a JSON object with this schema:
{
"skill": "product-tag-bulk-update",
"store": "<domain>",
"started_at": "<ISO8601>",
"completed_at": "<ISO8601>",
"dry_run": false,
"steps": [
{
"step": 1,
"operation": "<OperationName>",
"type": "query|mutation",
"params_summary": "<string>",
"result_summary": "<string>",
"skipped": false
}
],
"outcome": {
"action": "<add|remove>",
"tags": ["<tag1>", "<tag2>"],
"products_targeted": 0,
"mutations_succeeded": 0,
"errors": 0,
"output_file": "<filename|null>"
}
}
CSV file tag-update-<YYYY-MM-DD>.csv with columns: product_id, product_title, action, tags_changed, previous_tags, result.
| Error | Cause | Recovery |
|---|---|---|
| No products returned | Filter matches nothing | Check collection GID or filter_tag spelling |
userErrors from tagsAdd/tagsRemove | Tag string too long or invalid characters | Shopify tag max length is 255 characters; no commas allowed |
| Large product count (1000+) | Many API calls needed for pagination | Expected — the skill paginates automatically; may take longer |
| Tag not present (on remove) | Product doesn't have the tag you're removing | Silently skips — tagsRemove on a non-existent tag is a no-op |
dry_run: true before any action: remove — the CSV preview shows exactly which products will lose the tag.action: add at launch and action: remove at the end — keeping your product tags tidy prevents collection rule drift.query_filter: "tag:old-campaign-name" for teardown — it will find exactly the products tagged from the previous run.tags: ["sale", "homepage-featured", "clearance"] to apply all three atomically.Sale and sale.