Shopify Scraper
Pricing
from $3.00 / 1,000 product results
Shopify Scraper
Shopify products scraper and Shopify store scraper: export any store's products, prices, SKUs, stock and theme. Shopify catalog scraper, Shopify product data scraper, Shopify store catalog, Shopify products JSON. Shopify price monitor, Shopify price tracker, Shopify stock monitor: get only changes.
Pricing
from $3.00 / 1,000 product results
Rating
5.0
(2)
Developer
Flash Scrape
Maintained by CommunityActor stats
0
Bookmarked
17
Total users
2
Monthly active users
9 days ago
Last modified
Categories
Features
Share
Shopify Store Scraper exports any Shopify store's full catalog and watches its prices and stock, in one Actor for $0.003 per result ($3 per 1,000 rows), the same flat price on every Apify plan. Paste a store's URL (any Shopify website, not just your own) and this Shopify scraper reads its public Shopify products JSON feed (/products.json), paginated up to the 25,000 products Shopify's public feed serves per store: every product row carries 17 columns (20 in one-row-per-variant mode, which adds per-variant sku, price, compare_at_price, available and grams), plus an optional store-intelligence row with theme, currency, country, catalogue size and shipping reach. Turn on Only changed products and schedule it: this Shopify price monitor then delivers only new products and price or stock changes, and unchanged products are not delivered and not billed. A Shopify catalog scraper with no login, no API key, no browser automation, no code — export to CSV, Excel or JSON minutes later. Built for competitor price and stock tracking, dropshipping product research and store qualification, and it also finds popular Shopify stores by niche (nicheKeywords).
✨ What you get
- Scrape any store's full catalog — paste its URL and the Shopify product catalog comes out of the store's public
/products.json, 250 products per request, page after page, up to the 25,000 products that feed serves per store: one row per product with a price range (price_min/price_max,in_stock,variants_count), or one row per variant withsku,price,compare_at_price,availableandgrams— ideal for price and stock monitoring. - Price & stock monitor — turn on
onlyChangedProductsand schedule the run. The first run of a store is its baseline; later runs deliver only new products and price, compare-at price or stock changes, each tagged withchange_types. Unchanged products are not delivered and not billed. See "Price & stock monitor" below. - Store intelligence most Shopify scrapers don't give you — one extra
record_type: "store"row per catalog store with theme, currency, country, catalogue size, shipping reach and social handles, so you learn whether a store has 40 products or 25,000 before paying to scrape the catalogue. - Many stores in one run, failures skipped, flat rows — a store that fails (password-protected, feed disabled, not actually Shopify) is logged and skipped, a store that answers HTTP 429, 403 or 430 (Shopify's throttle and bot refusals) is retried on up to 5 proxy IPs before it is skipped, and both row shapes export to CSV, Excel or JSON with no post-processing.
- Find Shopify stores by niche — type a word like
coffeeand get the popular Shopify stores whose web address contains it, each confirmed live on its own/meta.json, with public email, country and catalogue size. Its section below says where the stores come from and what it cannot find.
Copy-paste input — this is the default run; storeUrls is all a catalog run needs:
{"storeUrls": ["https://www.kith.com"],"maxProducts": 50,"oneRowPerVariant": false,"includeStoreProfile": true,"includeCollections": false,"market": "US","proxyConfiguration": { "useApifyProxy": true }}
Add "onlyChangedProducts": true and schedule the run for the price & stock monitor. Leave nicheKeywords out or empty: every run without it is a catalog run, {} included.
Use it from AI agents (Claude, ChatGPT, Cursor) via Apify MCP
A Shopify API for agents: one call exports a store's Shopify products catalog with prices, SKUs and stock. nicheKeywords finds stores by niche.
- Connect: add
https://mcp.apify.comas a custom connector in Claude or ChatGPT (Developer mode), or install the Apify plugin in Cursor; sign in with OAuth or sendAuthorization: Bearer <APIFY_TOKEN>. - Call:
call-actorwithflash_scraper/shopify-store-scraper, or load this Shopify scraper as its own tool withhttps://mcp.apify.com?tools=flash_scraper/shopify-store-scraper. This input exports a store's catalog and bills at most 20 rows, $0.06 ($0.003 per row on every plan) plus at most $0.00005 for the start: 19 products plus onerecord_type: "store"row.callOptions.maxTotalChargeUsdcaps spend:
{"storeUrls": ["https://www.kith.com"], "maxProducts": 19}
- Monitor: add
"onlyChangedProducts": trueand repeat the call: after the first run, only new products and price or stock changes come back. - Wait:
call-actorwaits at most 45 s and returns the run status and storage IDs, not rows; pollget-actor-rununtil it finishes. ItsstatusMessagegives the delivered count, or why nothing was delivered. - Read:
get-dataset-itemswith the run'sdatasetIdreturns the rows (defaultlimit20 fits this call). Product rows carryprice_min,price_maxandin_stock; the store row haspublished_products_count.
What it does
- Finds Shopify stores by niche — searches the Chrome UX Report list of the 1 million most-visited websites for web addresses that contain your keyword, keeps those on Shopify's storefront network (a DNS check), confirms each store on its own
/meta.json(amyshopify_domainmust be present), reads its public email from the homepage and/pages/contact, and delivers onerecord_type: "store_lead"row per confirmed store. Unconfirmed candidates and keywords without stores cost nothing. - Filters the store list by country, catalogue size and email —
storeCountry,minProductsandrequireEmailare checked after a store is confirmed and before it is delivered, so a filtered store is neither in the dataset nor on the bill; filtered stores do not count towardmaxStores. - Picks the mode from
nicheKeywords— empty or absent means a catalog run onstoreUrls: the form's default, and every API call or saved task without it,{}included. Typed niche keywords start a store search instead, andstoreUrlsis then ignored with a note. A form saved before 2026-10-26 may still hold the old sample nichecoffee beans: empty it for a catalog run. - Reads each store's public
/products.jsonfeed and paginates the full catalog — the same product data Shopify serves to any visitor, 250 products per request, page after page, until the store runs out or Shopify's own feed limit is reached: the public feed serves at most 100 pages of 250, i.e. 25,000 products per store, so a bigger catalog delivers its first 25,000 products and the run marks it as capped.kith.com,www.kith.comor a full product URL all resolve to the correct store base. - Adds store intelligence to every catalog store — one extra
record_type: "store"row with theme, currency, country, catalogue size, shipping reach and social handles (details below). - Rides out throttling and bot refusals — a store that answers HTTP 429, 403 or 430 is retried on up to 5 proxy IPs, resuming at the page it stopped on; a store that still refuses is skipped and named in the run's status message, and the rest of the run continues.
Input
| Field | Type | Default | Description |
|---|---|---|---|
nicheKeywords | array | — | Find-stores mode: words to find popular Shopify stores by (coffee, candle), up to 20 keywords. A store is found only when its web address contains the word; a multi-word keyword searches its longest word, and a word of 4 letters or fewer must also be in the store's name or description. Leave it empty for a catalog run. |
maxStores | integer | 50 | Find-stores mode: stop after this many confirmed stores (1–500). Filtered-out stores do not count. |
includeContacts | boolean | true | Find-stores mode: return public emails from each store's homepage and /pages/contact. Off = no email columns (profile, theme and socials still returned). |
storeCountry | array | [] | Find-stores filter: keep only stores whose Shopify country (from its /meta.json) is one of these ISO-2 codes, e.g. ["US", "CA"] (one entry US, CA works too; USA and UK are read as US and GB; anything else, like United States, is ignored and the run says so). A store with no declared country is dropped when this is set. Empty = every country. |
minProducts | integer | 0 | Find-stores filter: keep only stores with at least this many published products (the store's own published_products_count; none reported = 0). 0 = no minimum. |
requireEmail | boolean | false | Find-stores filter: keep only stores where a public email was found. Needs includeContacts; with contacts off it is ignored and the run says so. A store whose homepage or contact page could not be read (throttled or slow) is skipped as a retry case, not billed. |
storeUrls | array | ["https://www.kith.com"] | Catalog mode: one or more Shopify store URLs. Bare domains work too. Keep nicheKeywords empty: typed niche keywords start a store search instead and storeUrls is ignored. |
maxProducts | integer | 50 | Catalog mode: products per store. 0 = the entire catalog, up to the 25,000 products Shopify's public feed serves per store — note that a large store takes about 100 requests, which can trigger HTTP 429 throttling; start with a limit, raise it once the store tolerates it. |
oneRowPerVariant | boolean | false | Catalog mode: ON = one row per variant (best for price/SKU monitoring). OFF = one row per product with a price range. |
onlyChangedProducts | boolean | false | Catalog mode: price & stock monitor. The first run of a store is the normal catalog (the baseline); later runs deliver and bill only new products and price, compare-at price or stock changes. See "Price & stock monitor" below. |
includeStoreProfile | boolean | true | Catalog mode: adds the record_type: "store" intelligence row per store. |
includeCollections | boolean | false | Catalog mode: adds the store's published collections (title, handle, product count, URL — up to 250) to the store row. |
market | string | "US" | Both modes: two-letter market to price in (US, GB, DE, …). See "Prices are pinned" below. |
proxyConfiguration | object | Apify Proxy (datacenter) | Both modes: keep this on: Shopify blocks the platform's bare run IP. The standard datacenter group is verified working — residential is not needed. |
Output columns
Every product/variant row carries: store, product_id, title, handle, url, vendor, product_type, tags, first image URL, images_count, and Shopify's created_at / published_at / updated_at timestamps.
| Column | Mode | Availability |
|---|---|---|
store, product_id, title, handle, url | both | every row |
vendor, product_type, tags | both | straight from the store's feed; empty when the merchant left them blank |
image, images_count | both | image is null for products with no images |
variants_count, price_min, price_max, in_stock | one row per product | price_min/price_max are null if no variant has a parseable price |
variant_id, variant_title, price, available, grams | one row per variant | every variant row |
sku | one row per variant | empty when the merchant never assigned one |
compare_at_price | one row per variant | null unless the item is marked down |
change_types, previous_price, previous_compare_at_price, previous_available, changes | onlyChangedProducts runs | why the row was delivered and the values on the previous run (see the monitor section) |
Both shapes are flat, so CSV export needs no post-processing.
Pricing — what does it cost per 1,000 products?
$0.003 per dataset row — $3.00 per 1,000 products (or variants) — plus a fraction-of-a-cent Actor start fee ($0.00005 per run start at the default 512 MB). The price is the same flat rate on every Apify plan. You pay only for rows actually delivered: a URL that is not a live Shopify store, and a run that returns nothing, cost nothing beyond that start fee; a Shopify store whose product feed is disabled or throttled still delivers (and bills) its one record_type: "store" row when the store profile is on.
Tip: variant mode produces more rows than product mode for the same store (one per SKU), so pick the shape that matches what you actually need.
Store intelligence — what other Shopify scrapers don't give you
Most Shopify scrapers return product rows and stop. With Include store profile on (the default), every store also yields one record_type: "store" row describing the merchant itself, read from the store's public /meta.json and storefront:
| Field | Example |
|---|---|
store_name, store_city, store_province, store_country | Misen, Brooklyn, New York, US |
store_currency, money_format | USD, ${{amount}} |
myshopify_domain | misenco.myshopify.com |
published_products_count | 342 — the store's TOTAL catalogue size, without scraping it |
published_collections_count | 218 |
ships_to_country_count, ships_worldwide | 134, true |
accepted_card_brands, offers_shop_pay_installments | ["visa","master",...], true |
theme_name, theme_id | 1.3.0 [New Relic/Speedsize], 198967558225 |
instagram, facebook, tiktok, twitter, youtube | misenkitchen |
The /meta.json fields are returned whenever the store serves that endpoint. Theme and social handles are read from the storefront HTML and are best-effort: if Shopify throttles the storefront page after all IP rotations, they come back empty and the run logs a warning — the /meta.json fields are still present.
How do I check what theme a Shopify store is using?
Shopify injects Shopify.theme = {...} into every storefront page, so theme_name and theme_id on the store row come back without any extension or manual source-viewing — for every store in your list at once. theme_name is the merchant's own label for the installed theme (like 1.3.0 [New Relic/Speedsize] in the table above), so it is often not the theme's public name such as Dawn or Prestige.
How many products does a Shopify store have?
published_products_count answers it from a single request: you learn whether a store has 40 products or 25,000 before paying to scrape the catalogue. Run with a tiny maxProducts cap to qualify a long list of stores cheaply, then scrape only the ones worth it.
Find Shopify stores by niche (store leads)
Find stores by niche (nicheKeywords) finds popular Shopify stores in a niche, instead of scraping stores you already know:
{ "nicheKeywords": ["coffee", "candle"], "maxStores": 50 }
- Where the stores come from — the Chrome UX Report (CrUX), Google's public list of the 1 million websites Chrome users visit most (the global list plus the newest US list). The finder keeps the web addresses that contain your keyword, keeps those that point at Shopify's storefront network (a DNS lookup, no visit), and then confirms each store on its own
/meta.json. - What to expect — measured 2026-10-26:
coffee1,240 popular web addresses → 546 on Shopify (24 of 24 sampled confirmed on/meta.json),candle277 → 134,yoga426 → 44 (most yoga addresses are studios, not shops). The status message says how many Shopify stores the list had for each keyword, so you know the pool. - Limits — it finds only stores whose web address contains the word:
coffeefindsbrandcoffee.com, never a roaster calledbluecopper.com. Popular sites only (the top 1 million). About 7% of Shopify stores sit behind their own CDN and are missed by the DNS check. A multi-word keyword searches its longest word (coffee beanssearchescoffee, addresses with both words first), and a plural is searched without its final s (candlessearchescandle,petssearchespet; addresses with the word as you typed it are checked first). Web addresses are searched in Latin letters and digits, so typecoffee, notкофе. A word of 4 letters or fewer also matches inside longer words (teainsteam,artinparty), so for those a store is delivered only when its name or description has the word. - Order — addresses that hold every word of the keyword first, then the most popular (
crux_rank). Several keywords take turns, somaxStoresspans all of them; a store found by several is delivered once. - Only live Shopify stores are delivered — every candidate is checked on its own
/meta.json: a closed store (HTTP 402), a 404 or a non-Shopify answer is skipped and not charged, and a store that answers only onwww.is asked there. - What each row holds — one
record_type: "store_lead"row per store:store,store_name,store_domain,myshopify_domain, city / province / country,store_currency,store_description, total catalogue size (published_products_count), collection count, countries shipped to, theme, Instagram / Facebook / TikTok / X (twitter) / YouTube handles, the keyword that found it (found_by_keyword), its popularity bucket (crux_rank: 1000 = among the 1,000 most-visited sites, up to 1000000) and, with Include contacts on, the publicemailsfound on its homepage and contact page (primary_emailis the one on the store's own domain when there is one).matched_productsandshop_app_marketstay as empty columns: the list names no products. Phone numbers are not returned. - Credit — store list: Chrome UX Report (CrUX), Google, published under CC BY 4.0 (developer.chrome.com/docs/crux/methodology), read from the zakird/crux-top-lists mirror. The list is only used to find candidates; it is never part of the output.
- Filters —
storeCountry(ISO-2 codes, e.g.["US", "CA"], compared with the country in the store's own/meta.json),minProducts(the store's ownpublished_products_count) andrequireEmail(needs Include contacts) drop stores after they are confirmed and before they are delivered. A dropped store is not billed and does not count towardmaxStores; the status message counts the dropped stores per reason, and if every confirmed store was dropped it says so and which filter to loosen. - Price — the same $0.003 per delivered row ($3 per 1,000 stores). Filtered-out stores, found-but-unconfirmed stores, failed searches and empty keywords cost nothing.
Then feed any store you like back into Store URLs to export its catalogue.
Price & stock monitor (schedule it)
Turn on Only changed products (onlyChangedProducts) and put the run in an Apify Schedule, for example daily.
- The first run of a store is its baseline. You get the normal catalog, billed as usual, each row tagged
change_types: ["baseline"]. - Later runs deliver only what changed: a new product or variant, a price up or down, a new compare-at price, back in stock or out of stock.
change_typessays which. An older product read for the first time (it entered yourmaxProductswindow, or an earlier run was cut off before it) is taggedfirst_seen, notnew_product. Variant rows also carryprevious_price,previous_compare_at_priceandprevious_available; product rows carry achangeslist. - Unchanged products are not delivered and not billed. A run with no changes delivers nothing and says so in its status; each run still pays the small per-run start fee. The store profile and collections rows are delivered once per store.
- One memory per store and market, in your own Apify account (a named key-value store,
shopify-store-scraper-monitor).kith.com,www.kith.comandhttp://kith.comshare one memory. Adding a store to the list does not reset the others. A change cut off by your charge limit is delivered on the next run. - Set
maxProductsto0to watch the whole catalog; with a limit, only the products read are compared. Removed products are not reported. - The memory holds up to 100,000 variants per store (fewer if the record would pass 8 MB). A bigger store keeps watching the variants it remembers and still reports new products; changes on the variants beyond the memory are not reported, and the status says how many.
Prices are pinned to one currency — read this if you compare stores
Shopify localises prices to whichever IP requests the page. Measured: the same variant returned 1827.00 from a Moroccan exit node and 190.00 (USD) with the market pinned. Because cloud scrapers rotate proxy IPs between countries, an unpinned scrape can return a different currency on different rows of the same run — which quietly ruins any price comparison built on it.
Set Market to GB, DE, CA etc. to price in that market instead.
How does it handle the products.json limit and pagination?
Shopify caps /products.json at 250 products per request, and the storefront endpoint ignores since_id — so this Actor paginates with 1-indexed page numbers, the only reliable cursor, until the store runs out. Shopify serves at most 25,000 products per store this way: past page 100 at 250 per page it answers HTTP 400 ("Page * Limit exceeds the 25000 limit"). A bigger catalog delivers those first 25,000 products, billed per row like any other, and the run log marks the store as capped (so does the status message, unless failed stores fill it); maxProducts sets your own tighter cap. Rows are saved page by page as they are read, so a large catalog never has to fit in the run's memory.
How do I export a Shopify store's products to CSV or Excel?
Run the Actor, open the run's Dataset tab and pick CSV, Excel, JSON or HTML — or pull the dataset programmatically via the Apify API. No Shopify admin access or export app needed: this works on any store, not just your own.
Use cases
- Competitor price tracking — schedule a daily run over competitors' stores and diff prices, new products, and stock status over time.
- Dropshipping product research — pull a winning store's catalog with vendors, tags and product types to spot trending products and suppliers.
- Catalog migration and backup — export a store's product list without private API keys or admin access.
- Market analysis — scrape every store in a niche and aggregate by
product_type,vendor, or price band. - Store qualification at scale — run with the store profile on and a tiny product cap to get each store's country, currency, catalogue size and shipping reach cheaply.
- Competitor benchmarking — compare catalogue size, collection count, shipping reach and tech (theme) across several merchants side by side.
Example output
A real sample from a live run (default product mode):
| title | vendor | product_type | price_min | price_max | in_stock |
|---|---|---|---|---|---|
| Men's Cruiser Terralux - Anthracite (Da… | Allbirds | Shoes | 135 | 135 | false |
| Women's Wool Runner NZ Mid Waterproof -… | Allbirds | Shoes | 160 | 160 | true |
| Free Returns Coverage | re:do | return,package_protection | 0.8 | 2.98 | true |
| Women's Wool Runner-up Mizzle - Hazy In… | Allbirds | Shoes | 60 | 60 | true |
Example row (default product mode):
{"store": "https://www.allbirds.com","product_id": 4547069443119,"title": "Men's Wool Runners","handle": "mens-wool-runners","url": "https://www.allbirds.com/products/mens-wool-runners","vendor": "Allbirds","product_type": "Shoes","tags": "mens, wool, runners","image": "https://cdn.shopify.com/s/files/1/1104/4168/products/wool-runner.jpg","images_count": 6,"created_at": "2020-03-18T09:12:44-07:00","published_at": "2020-03-20T08:00:01-07:00","updated_at": "2026-06-28T02:14:09-07:00","variants_count": 14,"price_min": 110.0,"price_max": 125.0,"in_stock": true}
What this Actor does NOT do
- No inventory quantities — Shopify's public feed carries no stock counts;
available/in_stockare true/false only. - No product descriptions — the HTML description body is not in the rows.
- No sales, revenue or best-seller rankings — Shopify does not publish sales numbers. Many stores expose a "best sellers" collection you can spot via
includeCollections, but this Actor does not order products by sales. - No reviews, and no Shopify App Store data — it scrapes merchant storefronts, not apps.apple/shopify listings.
- No password-protected storefronts — those are skipped with a warning, never logged into.
Tips / FAQ
Is this legal?
It reads each store's own public /products.json feed — data Shopify serves to any anonymous visitor. No login, no private data, no paywall bypass. As always, use scraped data responsibly and within applicable laws and the store's terms.
Do I need a proxy or an API key? No API key, no login, no headless browser. A proxy, yes — Shopify blocks Apify's bare run IP, so the Actor routes through Apify Proxy by default. The standard datacenter group is verified working and costs far less than residential; just leave the default on.
Does it work on every Shopify store?
Most standard stores, yes. Password-protected storefronts and stores that have disabled the public product feed return an error for /products.json; those are logged with a warning and skipped (their record_type: "store" row is still delivered when the store profile is on, since /meta.json answered), and the rest of the run continues. Non-Shopify URLs deliver nothing and are not billed. A few large stores (allbirds.com is a common example) throttle or refuse shared cloud IPs aggressively — the Actor retries each 429, 403 or 430 on up to 5 proxy IPs, resuming at the page it stopped on, before giving up on that store. A store that still refuses is named in the status message (as many names as fit); a catalog cut off part-way delivers (and bills) only the products read before it stopped and is named as incomplete. The run log has one outcome line per store, with its HTTP codes and the IPs tried.
Does it include product descriptions? No — rows include title, vendor, type, tags, timestamps, image URL and price/variant data, but not the HTML description body.
How do I track prices over time?
Turn oneRowPerVariant ON so every SKU gets its own row with price and compare_at_price, then schedule the actor (Apify Schedules) and compare datasets between runs — a competitor price tracker in two clicks.
How do I get only the price and stock changes?
Turn on onlyChangedProducts and schedule the run. The first run of each store delivers its catalog as a baseline; every later run delivers only new products and price, compare-at price or stock changes. You pay per delivered row, plus the small per-run start fee; a run with no changes bills no results. If a store's memory cannot be read, that store delivers nothing in that run - it is never re-delivered as a new baseline.
How fast is it, and are there limits?
It fetches 250 products per request, so even multi-thousand-product catalogs finish in minutes. Shopify's public feed stops at 25,000 products per store (100 pages of 250); a bigger catalog delivers its first 25,000 and is marked as capped in the run. maxProducts lets you set your own tighter cap.
Related actors
- Multi Job Board Scraper — LinkedIn, Indeed, Glassdoor and more boards, deduplicated, with only-new job alerts
- Remote Jobs Aggregator — keyless remote boards in one deduplicated feed
- Local Business Leads Scraper — any category, any city, verified emails, lead scores
- Creator Leads Scraper — TikTok, Instagram and YouTube creator emails in one run
- LinkedIn Jobs Scraper — listings by title and location, no login, CSV/JSON
Found a bug or need a feature? Open an Issue on this actor's Issues tab.