Generate Shopify add-to-cart permalinks from a store's public products.json.
Project description
Shopify-ATC
A command-line tool that turns any Shopify storefront into a list of direct add-to-cart permalinks.
Point it at a store and it reads the shop's public catalog, then prints a ready-to-click …/cart/add?id=… link for every product variant — so you can drop an item straight into your cart instead of clicking through the product page. Output comes in human-readable text, JSON, or CSV.
How it works
Shopify exposes two public, documented features this tool builds on:
/products.json— every Shopify store publishes its catalog (products, variants, prices, stock) as JSON. No API key required./cart/add?id=<variant_id>permalinks — Shopify's built-in cart permalink format adds a specific variant to the cart in one request.
Shopify-ATC fetches the first, then generates the second for each variant.
Features
- Add-to-cart links for every variant — resolves each product's variants and builds a
/cart/addpermalink with a configurable quantity. - In-stock filtering —
--in-stock-onlydrops sold-out variants so you only see what you can actually buy. - Three output formats —
textfor reading,jsonfor piping into other tools,csvfor spreadsheets. - Clear failure modes — a non-Shopify URL, an unreachable host, and an HTTP error each produce a distinct message and a distinct exit code, rather than one catch-all "something went wrong".
Tech Stack
- Language: Python 3.9+
- HTTP:
requests - CLI:
argparse(standard library) - Tests:
pytest(HTTP mocked — the suite runs fully offline) - CI: GitHub Actions, matrix across Python 3.9–3.13
Getting Started
Prerequisites
- Python 3.9 or newer
Installation
# From PyPI (recommended)
pip install shopify-atc
# …or isolated with pipx
pipx install shopify-atc
This installs a shopify-atc command. The package is published on PyPI at
pypi.org/project/shopify-atc.
Runnable examples (CLI and library) live in examples/.
For local development from a clone:
# Editable install with test deps
pip install -e ".[dev]"
Usage
shopify-atc <store-url> [--limit N] [--in-stock-only] [--quantity N] [--format text|json|csv]
| Flag | Default | Description |
|---|---|---|
store_url |
— | Store URL, e.g. https://www.allbirds.com (scheme optional) |
--limit |
250 |
Max products to fetch (Shopify's page maximum) |
--in-stock-only |
off | Only include available variants |
--quantity |
1 |
Quantity placed in each cart link |
--format |
text |
text, json, or csv |
Examples
# Human-readable, in-stock only
shopify-atc https://www.allbirds.com --in-stock-only
# JSON for scripting
shopify-atc https://www.allbirds.com --limit 50 --format json > catalog.json
# CSV for a spreadsheet
shopify-atc https://www.allbirds.com --format csv > catalog.csv
Text output looks like:
Trino® Cozy Crew - Heathered Onyx
https://www.allbirds.com/products/trino-cozy-crew-heathered-onyx
S (W5-7) — $24.00
https://www.allbirds.com/cart/add?id=39574630924368&quantity=1
Exit codes: 0 success · 2 bad arguments or unreachable host · 3 HTTP error from the store · 4 not a Shopify storefront.
Use as a Python library
Everything the CLI does is available programmatically. The key names are re-exported from the top-level package:
import shopify_atc
base = shopify_atc.normalize_url("www.allbirds.com") # -> https://www.allbirds.com
try:
products = shopify_atc.fetch_products(base, limit=5)
except shopify_atc.ShopifyError as exc:
raise SystemExit(str(exc))
products = shopify_atc.filter_in_stock(products) # optional: drop sold-out variants
# Render to any format the CLI supports:
print(shopify_atc.render(products, "json", base, quantity=1))
# …or work with the dataclasses directly:
for product in products:
for variant in product.variants:
print(variant.title, variant.price, f"{base}/cart/add?id={variant.id}&quantity=1")
API at a glance
| Name | Description |
|---|---|
fetch_products(url, limit=250, *, timeout=15) |
Fetch + parse a store's products.json into Product objects. Raises a ShopifyError subclass on failure. |
filter_in_stock(products) |
Return products keeping only available variants; drops products left empty. |
normalize_url(url) |
Trim whitespace/trailing slash and default to https:// if no scheme. |
render(products, fmt, base_url, quantity) |
Render products as "text", "json", or "csv". |
Product, Variant |
Dataclasses describing a product and its variants. |
ShopifyError |
Base exception; subclasses NetworkError (exit 2), HTTPError (exit 3), NotShopifyError (exit 4). |
Development
# Install with dev dependencies
pip install -e ".[dev]"
# Run the test suite
pytest
Project Structure
Shopify-ATC/
├── shopify_atc/
│ ├── client.py # fetch + parse products.json into typed dataclasses; typed errors
│ ├── formatters.py # pure text / json / csv renderers
│ └── cli.py # argparse + error→exit-code wiring
├── tests/ # offline tests (HTTP mocked)
├── pyproject.toml # packaging + `shopify-atc` console entry point
└── .github/workflows/ # CI
Responsible use
Shopify-ATC reads only public endpoints and generates links — it does not log in, store payment details, or complete checkouts. It is not affiliated with Shopify. Respect each store's Terms of Service and avoid hammering a storefront with rapid repeated requests.
License
MIT
Author
Jacob Kanfer — GitHub
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file shopify_atc-1.0.1.tar.gz.
File metadata
- Download URL: shopify_atc-1.0.1.tar.gz
- Upload date:
- Size: 13.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7f135f56d426d83257295a15532d0ed6384899dca18afb52cc2abc3bab049333
|
|
| MD5 |
7fef6e357095009291c3ec4bc7b4714d
|
|
| BLAKE2b-256 |
f2560df473fc203293884c3f97275bb80135509576d4e57859f431d3a4697253
|
Provenance
The following attestation bundles were made for shopify_atc-1.0.1.tar.gz:
Publisher:
publish.yml on Technical-1/Shopify-ATC
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
shopify_atc-1.0.1.tar.gz -
Subject digest:
7f135f56d426d83257295a15532d0ed6384899dca18afb52cc2abc3bab049333 - Sigstore transparency entry: 1690357750
- Sigstore integration time:
-
Permalink:
Technical-1/Shopify-ATC@ed9576d8b2da8f52e0c41b29c9094fe85f938f1c -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/Technical-1
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ed9576d8b2da8f52e0c41b29c9094fe85f938f1c -
Trigger Event:
release
-
Statement type:
File details
Details for the file shopify_atc-1.0.1-py3-none-any.whl.
File metadata
- Download URL: shopify_atc-1.0.1-py3-none-any.whl
- Upload date:
- Size: 9.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
847771e15d8b39bb5638e5e30c56e7b46cc3fe06c555a1617bbe942aa16be4b9
|
|
| MD5 |
89aa4d5dae0e3b583526eadd63410bd9
|
|
| BLAKE2b-256 |
322e61e1225af25c4f14ce3b13a24976d86a1602d5fd1af8bddb1287dea57b5e
|
Provenance
The following attestation bundles were made for shopify_atc-1.0.1-py3-none-any.whl:
Publisher:
publish.yml on Technical-1/Shopify-ATC
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
shopify_atc-1.0.1-py3-none-any.whl -
Subject digest:
847771e15d8b39bb5638e5e30c56e7b46cc3fe06c555a1617bbe942aa16be4b9 - Sigstore transparency entry: 1690357775
- Sigstore integration time:
-
Permalink:
Technical-1/Shopify-ATC@ed9576d8b2da8f52e0c41b29c9094fe85f938f1c -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/Technical-1
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ed9576d8b2da8f52e0c41b29c9094fe85f938f1c -
Trigger Event:
release
-
Statement type: