Shopify at your fingertips with shell automation
Learning Shopify has been on my bucket list for a few years now. Plenty of people in my circle — friends, colleagues, and fellow devs — are all somehow involved with Shopify in one way or the other. Earlier this year, I finally had some breathing room between projects, so I figured it was the perfect time to give Shopify a proper look.
I started exploring the platform by setting up a dev store, poking around the admin, and skimming through the API manual. While this was a quick and easy start, it didn’t give me a deeper understanding of the platform. Plus, clicking my way through the UI felt repetitive and tedious.
That got me thinking: is there a more efficient, developer-centric way to manage a store? Something that I could run in a terminal, plug into a CI/CD pipeline, or script my way out of those mundane tasks.
Meet ShopCTL
Simply put, it’s like a Swiss Army knife for your Shopify store — giving you quick, scriptable commands to query and modify products, customers, and more (upcoming).
Quick Feature Highlights
ShopCTL currently comes with product and customer-related commands. The tool is POSIX-compliant, giving you a familiarity with standard Unix command-line operations. The CLI flags are designed such that you can combine available flags in any order to create a unique query. For instance, the command below will give you all gift-cards on status DRAFT that were created after January 2025 and have tags on-sale and premium.
shopctl product list --gift-card -sDRAFT --tags on-sale,premium --created ">=2025–01–01"
The list commands also accept queries in a Shopify Search query syntax as the first argument. That means you can build a complex search query as needed for your use case.
# List products using combination of raw query and available flags
shopctl product list "(title:Caramel Apple) OR (inventory_total:>500 inventory_total:<=1000)" --tags premium
In addition to advanced searching, you can create, update, delete, export, and import products — including their options, variants, and media — and most of these features also apply to customers. A handy peek command is available to give you a quick glance at product details right from your terminal. Support for other resources might be added in the future as needed.
Automation and Scripting Use-cases
Let’s explore some possible real-life use cases.
True power in scripting isn’t just about automating tasks — it’s the belief that even the simplest code can create wonders. — Not me
Seasonal pricing updates
Seasonal sales are great for business, but updating prices for a whole collection can be tedious. A CLI tool could make it easy to script bulk price adjustments. For example, suppose you want to apply a 30% discount to all products tagged with “summer-sale” for a summer sale:
#!/usr/bin/env bash
for product_id in $(shopctl product list --tags summer-sale --columns=id --plain --no-headers); do
shopctl product variant list "$product_id" --columns=id,price --plain --no-headers | \
while read variant_id price; do
new_price=$(echo "$price * 0.7" | bc)
shopctl product variant edit "$product_id" --id "$variant_id" --price "$new_price"
done
done
Automated Inventory Discounts for Clearance
Ever have excess inventory you want to clear out? With
#!/usr/bin/env bash
for product_id in $(shopctl product list "inventory_total:>=100" --columns=id --plain --no-headers); do
shopctl product variant list "$product_id" --columns=id,price --plain --no-headers | \
while read variant_id price; do
new_price=$(echo "$price * 0.8" | bc) # 20% discount
shopctl product variant edit "$product_id" --id "$variant_id" --price "$new_price"
done
shopctl product update "$product_id" --tags "clearance" # Add clearance tag
done
Data Cleanup & Dynamic Tagging
Data cleanup is another area where scripting shines. As your product catalog grows, keeping track of what’s selling and what’s just sitting in inventory becomes harder. Why not tag these products based on specific conditions, like high inventory and older creation dates, and act upon it without manually digging through product listings?
# Add 'slow-moving' tag to products with high inventory created before 2025
shopctl product list "inventory_total:>=500" --created "<2025-01-01" --columns=id --plain --no-headers \
| xargs -I{} shopctl product update {} --tags slow-moving
Another use-case could be to archive products with missing SKUs. Suppose you want to find any products that have missing SKUs (perhaps products that were created without proper variant SKUs) and archive them so they don’t clutter your active catalog. You can search for products with empty SKU fields and update their status in bulk with some simple bash scripts:
#!/usr/bin/env bash
for product_id in $(shopctl product list --sku "" --columns=id --plain --no-headers); do
shopctl product update "$product_id" --status archived
done
How about something as simple as quickly finding and deleting stale DRAFT products to keep your catalog clean?
# Remove all drafts older than 90 days
shopctl product list -sDRAFT — created “<=$(date -v -90d +%Y-%m-%d)” \
| xargs -I{} shopctl product delete {}
Attaching Media to Products via CSV Attaching images or other media to products in bulk can be cumbersome through the web UI. Let’s say a client provides you a CSV file with relevant columns like a product ID/handle and a URL to an image that needs to be attached to that product. You can perform media attachments in bulk with a simple bash script.
# Sample csv
product_id,image_url,alt,media_type
12345,https://example.com/image1.jpg,Front view,image
12345,https://example.com/video1.mp4,Demo video,video
56789,https://example.com/image1.jpg,Front view,image
#!/usr/bin/env bash
# Skip the CSV header and process each row
tail -n +2 images.csv | while IFS=, read -r product_id image_url alt media_type; do
media_type_upper=${media_type^^} # Convert media_type to uppercase
shopctl product media attach "$product_id" --url "$image_url" --alt "$alt" --media-type "$media_type_upper"
done
Exporting and Importing Customer Data
Last but not least, consider the task of exporting customer data for a marketing campaign or migrating customers to a new store. ShopCTL has you covered with built-in export/import for customers as well. For example, to export all customers from one store and import them into another:
shopctl export -c store1 -r customer="created:>2025-01-01 AND created:<2025-04-01" -o /backups -n customers_this_quarter
shopctl import -c store2 -r customer -f /backups/customers_this_quarter.tar.gz
Wrapping Up
The possibilities with scripting are endless — you can shape it to fit your own workflows and solve unique use cases. The examples above are just the start. As the tool matures, it will open the door to some advanced automation and workflows.
Learn more
Check out
Your suggestions and feedback are highly appreciated. Feel free to