# Shopify Admin Bulk Price Adjustment

> Query products by collection or tag and update all variant prices by a percentage or fixed amount, with optional floor/ceiling constraints.

- **Type:** Skill
- **Install:** `agentstack add skill-40rty-ai-shopify-admin-skills-shopify-admin-bulk-price-adjustment`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [40RTY-ai](https://agentstack.voostack.com/s/40rty-ai)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [40RTY-ai](https://github.com/40RTY-ai)
- **Source:** https://github.com/40RTY-ai/shopify-admin-skills/tree/main/skills/merchandising/shopify-admin-bulk-price-adjustment
- **Website:** http://skills.40rty.ai

## Install

```sh
agentstack add skill-40rty-ai-shopify-admin-skills-shopify-admin-bulk-price-adjustment
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

## Purpose
Applies a percentage or fixed price adjustment to every variant across a Shopify collection or tag in a single automated workflow — without manually navigating products in the admin UI, exporting CSVs, editing them, and re-importing. Use this skill when you need to run a storewide or collection-level sale, revert prices after a promotion ends, pass through a supplier cost increase, or align pricing across a segment of products.

## Prerequisites
- Authenticated Shopify CLI session: `shopify auth login --store `
- API scopes: `read_products`, `write_products`

## Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| store | string | yes | — | Store domain (e.g., mystore.myshopify.com) |
| format | string | no | human | Output format: `human` or `json` |
| dry_run | bool | no | false | Preview operations without executing mutations |
| collection_id | string | no* | — | GID of collection to target (e.g., `gid://shopify/Collection/123`) |
| tag | string | no* | — | Product tag to filter by (alternative to collection_id) |
| adjustment_type | string | yes | — | `percent` or `fixed` |
| adjustment_value | float | yes | — | Amount to adjust. Positive = increase, negative = decrease. For percent: `-10` = 10% discount. |
| min_price | float | no | 0 | Floor price — no variant will be set below this value |
| max_price | float | no | — | Ceiling price — no variant will be set above this value (optional) |

*One of `collection_id` or `tag` is required.

## Safety

> ⚠️ Step 2 executes `productVariantsBulkUpdate` mutations that change live prices immediately. Price changes cannot be undone in bulk via API — each variant must be reverted individually. Always run with `dry_run: true` first to review the full change set before committing. Verify the CSV output from dry_run against your expected results before proceeding.

## Workflow Steps

1. **OPERATION:** `products` — query
   **Inputs:** `first: 250`, `query: "collection_id:''"` or `query: "tag:''"`, pagination cursor
   **Expected output:** List of products with all variant IDs, current prices, SKUs; paginate until `hasNextPage: false`

2. **OPERATION:** `productVariantsBulkUpdate` — mutation
   **Inputs:** For each product: `productId` + array of `{id, price}` with computed new prices (respecting min_price/max_price constraints)
   **Expected output:** Updated `price` per variant, `userErrors` array; collect all errors across batches

## GraphQL Operations

```graphql
# products:query — validated against api_version 2025-01
query ProductsForPriceAdjustment($first: Int!, $after: String, $query: String) {
  products(first: $first, after: $after, query: $query) {
    edges {
      node {
        id
        title
        tags
        variants(first: 100) {
          edges {
            node {
              id
              title
              price
              compareAtPrice
              sku
            }
          }
        }
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}
```

```graphql
# productVariantsBulkUpdate:mutation — validated against api_version 2025-01
mutation ProductVariantsBulkUpdate($productId: ID!, $variants: [ProductVariantsBulkInput!]!) {
  productVariantsBulkUpdate(productId: $productId, variants: $variants) {
    productVariants {
      id
      price
      compareAtPrice
    }
    userErrors {
      field
      message
    }
  }
}
```

## Session Tracking

**Claude MUST emit the following output at each stage. This is mandatory.**

**On start**, emit:
```
╔══════════════════════════════════════════════╗
║  SKILL: bulk-price-adjustment                ║
║  Store:                        ║
║  Started:              ║
╚══════════════════════════════════════════════╝
```

**After each step**, emit:
```
[N/TOTAL]   
          → Params: 
          → Result: 
```

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
  :   
  ...
  Errors:           
  Output:           
══════════════════════════════════════════════
```

For `format: json`, emit a JSON object with this schema:
```json
{
  "skill": "bulk-price-adjustment",
  "store": "",
  "started_at": "",
  "completed_at": "",
  "dry_run": false,
  "steps": [
    {
      "step": 1,
      "operation": "",
      "type": "query|mutation",
      "params_summary": "",
      "result_summary": "",
      "skipped": false
    }
  ],
  "outcome": {
    "": "",
    "errors": 0,
    "output_file": ""
  }
}
```

## Output Format
CSV file `price_changes_.csv` with columns: `product_id`, `variant_id`, `sku`, `title`, `old_price`, `new_price`. For dry_run, the CSV is still generated but no mutations are executed.

## Error Handling
| Error | Cause | Recovery |
|-------|-------|----------|
| `Neither collection_id nor tag provided` | Both parameters are empty | Provide one of `collection_id` or `tag` |
| `userErrors` in mutation response | Invalid price, variant not found | Log error per variant, continue with remaining variants, report in outcome |
| `Product not found in collection` | collection_id is wrong or collection is empty | Verify collection GID in Shopify admin |
| Rate limit (429) | Too many mutations in rapid succession | Reduce batch size; retry with exponential backoff |

## Best Practices
1. Always run `dry_run: true` first — review the CSV to confirm prices before committing. There is no bulk undo.
2. Set `min_price` to your cost floor to prevent pricing variants below cost during percentage discounts.
3. For collections with more than 250 products, the skill paginates automatically — the CSV will contain all variants regardless of page count.
4. Use `adjustment_type: percent` with a negative value for sales (e.g., `-15` for 15% off). Use `adjustment_type: fixed` for flat adjustments (e.g., `-5` to drop every variant by $5).
5. After committing, verify a sample of prices in the Shopify admin before announcing a sale — `userErrors` are logged but do not halt execution.

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [40RTY-ai](https://github.com/40RTY-ai)
- **Source:** [40RTY-ai/shopify-admin-skills](https://github.com/40RTY-ai/shopify-admin-skills)
- **License:** MIT
- **Homepage:** http://skills.40rty.ai

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-40rty-ai-shopify-admin-skills-shopify-admin-bulk-price-adjustment
- Seller: https://agentstack.voostack.com/s/40rty-ai
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
