Shopify Scraper
Pricing
from $3.00 / 1,000 product results
Shopify Scraper
Shopify store scraper, Shopify store finder: find Shopify stores by niche, search Shopify stores for a Shopify stores list with public emails, find Shopify store theme; export Shopify store data. Shopify catalog scraper, Shopify product data scraper (Shopify store catalog, Shopify products JSON).
Pricing
from $3.00 / 1,000 product results
Rating
5.0
(2)
Developer
Flash Scrape
Maintained by CommunityActor stats
0
Bookmarked
14
Total users
3
Monthly active users
2 days ago
Last modified
Categories
Share
Shopify Store Scraper finds Shopify stores by niche and exports any store's full catalog, in one Actor for $0.003 per result ($3 per 1,000 rows), the same flat price on every Apify plan. Type a niche like coffee beans and this Shopify scraper searches Shop by Shopify, confirms every candidate on its own /meta.json and returns one row per store with its public email, theme, catalogue size, country, currency and social handles — a Shopify stores list you can filter by country, catalogue size or email, and a filtered-out store is never billed. Then paste any store's URL (any Shopify website, not just your own) to export Shopify store data from 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. No login, no API key, no browser automation, no code — export to CSV, Excel or JSON minutes later. Built for Shopify lead lists, competitor price tracking, dropshipping product research and store qualification.
✨ What you get
- Find Shopify stores by niche — each keyword is one search on Shop by Shopify (shop.app) and reads one results page. Measured 2026-09-25:
coffee beansgave 17 confirmed stores from one page, yoga-mat phrasings 8–19 each,soy candles9, plaincandles1 (one large candle store filled the page). Several phrasings of the same niche find more stores; a store found by several keywords is delivered once. - One row per store, confirmed on its own
/meta.json—record_type: "store_lead"withprimary_emailandemails, theme,published_products_count(the store's TOTAL catalogue size), city / province / country,store_currency, Instagram / Facebook / TikTok / X / YouTube handles, the keyword that found it and up to three of its matching products. In the 2026-09-25 sample, 7 of 12 stores (58%) showed a public email. - Filter the lead list before you pay for it —
storeCountry(ISO-2 codes),minProducts(catalogue size, from the store's own count) andrequireEmaildrop the stores you do not want: a dropped store is not delivered and not billed, and the run's status message says how many were dropped and why. - Then 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. - 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. Prices are pinned to one market (defaultUS) andstore_currencyis returned, so a price is always interpretable. - 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.
Copy-paste input — this is the default run; nicheKeywords is all a store-finding run needs:
{ "nicheKeywords": ["coffee beans"], "maxStores": 50, "includeContacts": true }
Add "storeCountry": ["US", "CA"], "minProducts": 100 or "requireEmail": true to filter the list. To export a store's catalog instead, send storeUrls without nicheKeywords - every API call and saved task that leaves nicheKeywords out runs the catalog export exactly as before, {} included. In the console form, type your URLs under Store URLs; to export the sample https://www.kith.com itself from the form, empty the niche keywords.
{"storeUrls": ["https://www.kith.com"],"maxProducts": 50,"oneRowPerVariant": false,"includeStoreProfile": true,"includeCollections": false,"market": "US","proxyConfiguration": { "useApifyProxy": true }}
Use it from AI agents (Claude, ChatGPT, Cursor) via Apify MCP
A Shopify API for agents: one call finds Shopify stores by niche (a Shopify store finder) or exports a store's Shopify products catalog.
- 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 finds Shopify stores and bills at most 20 rows, $0.06 ($0.003 per row on every plan) plus at most $0.00005 for the start;callOptions.maxTotalChargeUsdcaps spend:
{"nicheKeywords": ["yoga mats"], "maxStores": 20}
- Catalog: for a store's products, leave
nicheKeywordsout and send{"storeUrls": ["https://www.kith.com"], "maxProducts": 20}: at most 21 rows, 20 products plus onerecord_type: "store"row. - 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; passlimit: 21for the catalog call). Store-finder rows (record_type: "store_lead") carryprimary_emailandpublished_products_count.
What it does
- Finds Shopify stores by niche (the default run) — searches Shop by Shopify once per keyword, confirms each candidate 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, failed searches and empty keywords cost nothing. - Filters the 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. - Switches to the catalog export when you type Store URLs — leave
nicheKeywordsuntouched (the sample niche) and typestoreUrls, and the run exports those stores' catalogs instead; an API call or saved task that does not sendnicheKeywordsalways keeps its catalog run (the field has a form prefill, no API default). A typednicheKeywordsmeans a store-finding run, andstoreUrlsis then ignored with a note; an emptynicheKeywordsmeans a catalog run. In the form,storeUrlscleared next to the untouched sample niche runs the store finder; empty the niche keywords to export the sample kith.com. - 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 | — (form prefill ["coffee beans"]) | Find-stores mode: products or niches to find Shopify stores for (coffee beans, yoga mats). Up to 20 keywords, one Shop by Shopify search each. The default run searches the sample niche. |
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. Mode rule: leave nicheKeywords untouched and type storeUrls → catalog run; change nicheKeywords and storeUrls is ignored. An API call or saved task without nicheKeywords always runs the catalog. |
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. |
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, …) and the Shop by Shopify market to search. 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 |
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. A free Apify plan is enough to try it on a full mid-size store.
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)
Don't have a Shopify stores list yet? This is the default run: Find stores by niche (nicheKeywords) searches Shopify stores by niche and the Actor finds Shopify stores that sell those products, instead of scraping stores you already know:
{ "nicheKeywords": ["yoga mats", "cork yoga mat", "travel yoga mat"], "maxStores": 50 }
- Where the stores come from — each keyword is one search on Shop by Shopify (shop.app), Shopify's own shopping marketplace. One search reads one results page: in our test runs that was 1 to 19 distinct stores per keyword (
travel yoga mat19,coffee beans17,candles1 because one large candle store filled the whole page). - More stores = more phrasings — five phrasings of "yoga mat" found 33 different stores. Stores found by several keywords are delivered once.
- Only real Shopify stores are delivered — every candidate is checked on its own
/meta.json; one that does not answer as a live Shopify store is skipped and not charged. - 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), up to three of its matching products (matched_products) 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). In two test runs 12 of 20 and 10 of 12 stores showed a public email; phone numbers are not returned. - Market — Shop by Shopify localises results to the visitor's country. With Apify Proxy on and no proxy country chosen, the run pins the exit to
market(defaultUS); each row'sshop_app_marketand the status message say which market was actually served. - 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.
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.
This Actor pins the market (default US) and returns store_currency on the store row, so a price is always interpretable. 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 (see the FAQ for the workaround).
- 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. If you need descriptions, pair it with an extraction actor on the product URLs (see Related actors below).
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 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
- Smart Scraper by Example — extract extra fields (like descriptions) from the product URLs this actor gives you.
- Multi Job Board Scraper — LinkedIn, Indeed, Glassdoor + 9 more boards, deduplicated, with only-new job alerts
- Remote Jobs Aggregator — 10 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 — typical response within 1 business day.