shopify-admin-compare-at-price-cleanup
SkillCommerce & financeRemoves stale compareAtPrice values where current price >= compareAtPrice (no real discount) or compareAtPrice has been set for over a configurable age threshold.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the shopify-admin-compare-at-price-cleanup skill
What this skill tells your AI
The instructions your AI receives, as published by 40rty-ai/shopify-admin-skills in skills/merchandising/shopify-admin-compare-at-price-cleanup/SKILL.md and read by ahel’s review.
Purpose
Identifies variants with a compareAtPrice that no longer represents a genuine discount and clears it, so storefront strikethrough pricing reflects real savings rather than legacy noise. Two conditions are flagged: (a) compareAtPrice <= price (no discount, often left over from a price increase), and (b) compareAtPrice set for longer than max_age_days (stale "always on sale" optics that hurt long-term price perception and can violate advertising standards in some regions). Defaults to dry-run.
Prerequisites
- Authenticated Shopify CLI session:
shopify store auth --store <domain> --scopes read_products,write_products - API scopes:
read_products,write_products
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| store | string | yes | — | Store domain (e.g., mystore.myshopify.com) |
| dry_run | bool | no | true | Preview the cleanup without executing mutations |
| clean_no_discount | bool | no | true | Clear compareAtPrice when price >= compareAtPrice |
| clean_stale | bool | no | true | Clear compareAtPrice set longer than max_age_days |
| max_age_days | integer | no | 90 | Age threshold in days for the stale rule (uses variant updatedAt as proxy) |
| collection_id | string | no | — | Optional collection GID to scope the cleanup |
| tag_filter | string | no | — | Optional product tag to scope the cleanup |
| format | string | no | human | Output format: human or json |
Safety
⚠️ Step 2 executes
productVariantsBulkUpdatemutations that overwritecompareAtPriceto null. The original strikethrough value is not preserved server-side — record the dry-run CSV before committing if you want a restore path. Always start withdry_run: trueand review the CSV before running withdry_run: false.
Workflow Steps
-
OPERATION:
productVariants— query Inputs:first: 250,query: <built from collection_id or tag_filter>, selectprice,compareAtPrice,updatedAt,product { id, title, vendor },sku, pagination cursor Expected output: All variants in scope with current pricing; paginate untilhasNextPage: false -
Filter to variants meeting either rule:
clean_no_discountANDcompareAtPrice != nullANDparseFloat(compareAtPrice) <= parseFloat(price), ORclean_staleANDcompareAtPrice != nullAND(now - updatedAt) > max_age_days. Group byproduct.idfor batched mutation. -
OPERATION:
productVariantsBulkUpdate— mutation (skipped whendry_run: true) Inputs: Per product,productIdplus[{ id: variantId, compareAtPrice: null }]Expected output: Updated variants withcompareAtPriceset to null; collectuserErrorsper batch -
Write the CSV (always, even on dry run) for audit trail and revert capability.
GraphQL Operations
# productVariants:query — validated against api_version 2025-01
query VariantsForCompareAtCleanup($query: String, $after: String) {
productVariants(first: 250, after: $after, query: $query) {
edges {
node {
id
sku
price
compareAtPrice
updatedAt
product {
id
title
vendor
tags
}
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
# productVariantsBulkUpdate:mutation — validated against api_version 2025-01
mutation ClearCompareAtPrice($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: Compare-At Price Cleanup ║
║ 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>
If dry_run: true, prefix every mutation step with [DRY RUN] and do not execute it.
On completion, emit:
For format: human (default):
══════════════════════════════════════════════
COMPARE-AT PRICE CLEANUP (<dry-run|live>)
Variants inspected: <n>
No-discount cleared: <n>
Stale (>= <days>d): <n>
Total cleared: <n>
Errors: <n>
Output: compare_at_cleanup_<date>.csv
══════════════════════════════════════════════
For format: json, emit:
{
"skill": "compare-at-price-cleanup",
"store": "<domain>",
"dry_run": true,
"variants_inspected": 0,
"cleared_no_discount": 0,
"cleared_stale": 0,
"total_cleared": 0,
"errors": 0,
"output_file": "compare_at_cleanup_<date>.csv"
}
Output Format
CSV file compare_at_cleanup_<YYYY-MM-DD>.csv with columns:
variant_id, product_id, product_title, vendor, sku, price, original_compare_at_price, rule_matched, variant_updated_at, mutation_status
Error Handling
| Error | Cause | Recovery |
|---|---|---|
userErrors in mutation response | Variant locked or in active subscription contract | Log per-variant error, continue with remaining variants |
THROTTLED | API rate limit exceeded | Wait 2 seconds, retry up to 3 times |
compareAtPrice already null mid-run | Another process cleared it concurrently | Skip, count as no-op success |
updatedAt newer than expected | Concurrent edit during the audit | Re-query single variant before mutation; skip if rule no longer matches |
Best Practices
- Always run with
dry_run: truefirst and review the CSV. There is no bulk undo for compareAtPrice clearing. - Disable
clean_stale(setclean_stale: false) during long planned promotions — your "stale" sale is actually intentional. - Use
collection_idto scope the cleanup to evergreen products and exclude an active sale collection. - After running live, spot-check 5–10 variants in the storefront to confirm strikethrough pricing is gone.
- Schedule a quarterly run as part of catalog hygiene; combine with
seo-metadata-auditandproduct-data-completeness-scorefor an end-of-quarter merchandising sweep.
Signals
- GitHub stars
- 187
- Forks
- 18
- Last commit
- Aug 2026
ahel review
S4info
community integration — published by 40rty-ai, not shopify
Automated review, not a security audit. Ruleset v1.
Advanced
- Catalog kind
- skill
- Gateway key
shopify-admin-compare-at-price-cleanup- Source
- github.com/40rty-ai/shopify-admin-skills