Shopify Store Lookup — Product Catalog & Detection API avatar

Shopify Store Lookup — Product Catalog & Detection API

Pricing

from $3.00 / 1,000 successful lookups

Go to Apify Store
Shopify Store Lookup — Product Catalog & Detection API

Shopify Store Lookup — Product Catalog & Detection API

Detect Shopify stores and fetch product catalogs directly from /products.json — titles, prices, vendors, availability. No API key or scraping needed. Charged once per store, never for misses.

Pricing

from $3.00 / 1,000 successful lookups

Rating

0.0

(0)

Developer

Adrian Voss

Adrian Voss

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

Shopify Store Lookup

Check whether a domain runs on Shopify, and if it does, pull its live product catalog — titles, vendors, prices, availability, tags — straight from Shopify's own public /products.json endpoint. Every Shopify storefront exposes this feed by default, so there's no Admin API key to request and no HTML to scrape: you get the same JSON the store's own theme reads, for up to 50 products per domain.

Who it's for

The accountable_eel catalogue sells company intelligence columns for outbound. Each actor takes a list of domains or company identifiers and returns one flat, stably-named row per input — firmographics, registry IDs, tech stack, email route, hiring activity — the shape a Clay table, an n8n workflow, or an AI agent can consume without post-processing. Pricing is pay-per-event and per-domain: a few tenths of a cent for a row that was actually found, and nothing for a miss, so a list that doesn't enrich costs you next to nothing. Where an official source exists — VIES, GLEIF, SEC EDGAR, Brønnøysund, PRH, RDAP — it is queried directly instead of scraped. No seat licence, no monthly minimum, no credit system to decode. This one answers a narrower question than most of the catalogue: does this specific domain run on Shopify, and if so, what's actually on the shelf right now.

Why this one

  • Reads Shopify's own data, not a scrape of rendered HTML. /products.json is the same JSON feed the storefront's theme pulls from — no headless browser, no CSS selectors that break when a theme changes.
  • One call answers two questions. isShopify gives you a clean yes/no signal, and when it's yes you already have the catalog — no second lookup needed.
  • You don't pay to find out "no." A domain that isn't on Shopify, has the endpoint disabled, or rate-limits the request comes back found: false and is never billed.
  • No Admin API key, no app install. The endpoint is public and unauthenticated by Shopify's own design, so there's no merchant permission to request.
  • Accepts whatever format your list is already in. Bare domains or full URLs with a path both resolve to the same lookup — you don't need to clean the list first.

What you get

One row per input domain. Every field below is stably named — it won't be renamed between runs, which matters if you're wiring this into an agent or a Clay column that reads the schema once and keeps using it.

FieldType / formatDescription
querytextThe domain exactly as submitted, before normalization.
foundbooleanWhether /products.json returned valid JSON with at least one product. Gates billing — false rows are never charged.
statustextShort result status (e.g. OK).
domaintextThe normalized store domain (scheme and path stripped) that the catalog was fetched from.
isShopifybooleanWhether the domain is confirmed to run Shopify — true only when found is true.
productCountnumberNumber of products in this single page of results (capped at 50). Not the store's total catalog size.
productsarrayThe full list of product objects returned, each with the fields below.
idnumberShopify's internal product ID.
titletextProduct title.
vendortextThe product's vendor/brand field, as set by the merchant.
productTypetextShopify's product_type field — merchant-defined, not a fixed taxonomy.
tagsarrayTags attached to the product.
createdAtdate (ISO 8601)When the product was created in the store's Shopify admin.
pricetextThe first variant's price, as a string with no currency symbol.
availablebooleanTrue if any variant of the product is in stock.
imageUrllinkURL of the product's first image.
handletextThe URL slug — append it to the store's domain for the product page.
scrapedAtdate (ISO 8601)When this actor made the request.

Price

$5 per 1,000 domains, plus a $0.005 start fee. Misses (found:false) are never charged.

You're billed per domain confirmed to run Shopify with at least one product returned — a domain that isn't Shopify, blocks the request, or rate-limits the endpoint costs nothing. Run 1,000 domains through this actor and, at the live FREE-tier per-row price, that's roughly $5.29 if every one of them is found — less as some domains turn out not to be Shopify stores, and less again on paid Apify plans, where the per-row price drops. The same 1,000 rows through a credit-based enrichment platform typically runs $80–$400. There's no seat, no monthly minimum, and no credits to track — you pay for confirmed stores.

How to use

  1. In the Apify Console. Open the actor page and click Start — the domains field is already pre-filled with a working example. Results land in the run's dataset as soon as each item is found.
  2. Via the API. Call it directly with a POST request — no Console needed once you have an API token:
    curl "https://api.apify.com/v2/acts/accountable_eel~shopify-store-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
    -X POST \
    -H "Content-Type: application/json" \
    -d '{"domains":["allbirds.com"]}'
  3. On a schedule. Save this actor as an Apify Task with the input you want, then add a Schedule (hourly, daily, weekly) so it runs on its own — no server of your own required.
  1. Paste a list of domains into domains — bare hosts or full URLs, one per input, mixed formats are fine.
  2. Run the actor. It fetches /products.json?limit=50 for each domain, in parallel up to maxConcurrency.
  3. Read the dataset. Each row tells you isShopify and, when true, hands you up to 50 products with pricing and availability already parsed out of Shopify's variant data.
  4. Filter to found: true if you only want confirmed stores in your export — non-Shopify domains are still written to the dataset (unless you drop them downstream) but were never charged.

Common ways teams use this:

  • Qualify e-commerce leads by confirming a prospect actually runs Shopify before pitching a Shopify-specific tool, app, or service.
  • Pull a competitor's live product list — names, prices, availability, tags — for assortment or pricing research.
  • Build a dataset of Shopify merchants in a niche by running a list of candidate domains and keeping only the isShopify: true rows.
  • Monitor a watchlist of stores for new launches or price changes by re-running the lookup on a schedule and diffing products between runs.
  • Feed catalog fields into a market-mapping pipelinevendor, productType, and tags are enough to bucket stores by what they sell without opening a browser.

Input

{
"domains": [
"allbirds.com"
]
}

One domain per line — bare domain or full URL, with or without https:// and any path (both are stripped down to the bare host). Accepted formats: allbirds.com, kyliecosmetics.com.

{
"items": ["allbirds.com", "kyliecosmetics.com"],
"maxConcurrency": 5,
"proxyConfiguration": { "useApifyProxy": true }
}

items is a list of domains (with or without https:// and any path — both are stripped down to the bare host). One dataset row is returned per item; rows with "found": false are never charged. maxConcurrency (default 5) caps parallel requests — kept conservative since some stores rate-limit this endpoint. proxyConfiguration routes requests through Apify Proxy; residential is recommended for stores that are more aggressive about blocking.

Sample output

queryfoundstatusdomainisShopifyproductCountproductsidtitlevendorproductTypetagscreatedAtpriceavailableimageUrlhandlescrapedAt
allbirds.comtrueOKallbirds.comtrue50<all products (full list)>7205198004304Women's Dasher NZ - Blizzard/Deep Navy (Blizzard Sole)AllbirdsShoes["allbirds::carbon-score => undefined","allbirds::cfId => color-c09d6e63b4a11feebc68f762220735d5","allbirds::complete => true","allbirds::edition => classic","allbirds::gender => womens","allbirds::hue => blue","allbirds::hue => white","allbirds::master => womens-dasher-nz","allbirds::material => tree","allbirds::price-tier => msrp","allbirds::silhouette => dasher","FLEX3818571 (PL 553696876312)","loop::returnable => true","OOS DNS","WAVE 2 ECDC","WAVE 2 WCDC","YCRF_womens-perform-shoes","YGroup_ygroup_womens-dasher-nz"]2025-08-06T20:08:21-07:00140.00truehttps://cdn.shopify.com/s/files/1/1104/4168/files/A12464_26Q1_Dasher-NZ-Blizzard-Deep-Navy-Blizzard_PDP_LEFT_e38509e9-51da-49a3-a794-53de6797a109.png?v=1768948779womens-dasher-nz-blizzard-deep-navy2026-08-26T06:01:38.607Z
{
"query": "allbirds.com",
"found": true,
"data": {
"domain": "allbirds.com",
"isShopify": true,
"productCount": 50,
"products": [
{
"id": 4392847259691,
"title": "Men's Tree Runners",
"vendor": "Allbirds",
"productType": "Shoes",
"tags": ["Men", "Runners", "Everyday"],
"createdAt": "2019-03-12T10:15:00-04:00",
"price": "98.00",
"available": true,
"imageUrl": "https://cdn.shopify.com/s/files/1/example/tree-runners.jpg",
"handle": "mens-tree-runners"
}
]
},
"scrapedAt": "2026-08-20T14:03:11.000Z"
}

A row is only marked found: true — and only then billed — once /products.json returns valid JSON with at least one product. A domain that isn't running Shopify, has disabled the endpoint, or rate-limits/blocks the request (a real, observed outcome on some stores) comes back as found: false and is never charged. productCount reflects the number of products in this single page of results, capped at 50 — it is not the store's total catalog size.

Use it from Clay, n8n, Make, or an AI agent

This actor runs synchronously over plain HTTP — call it directly from a script, a workflow tool, or an AI agent, no Apify Console needed once you have an API token.

curl "https://api.apify.com/v2/acts/accountable_eel~shopify-store-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
-X POST \
-H "Content-Type: application/json" \
-d '{"domains":["allbirds.com"]}'

n8n. Add an HTTP Request node: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~shopify-store-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body Content Type JSON, JSON Body {"domains":["allbirds.com"]} (swap in an expression from an earlier node for a real value).

Clay. Add an "HTTP API" column: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~shopify-store-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body {"domains":["{{domain}}"]}, mapping the row's domain into the domains array.

MCP. In Claude, Cursor, or any MCP client with the Apify MCP server, ask for "Shopify Store Lookup | Apify" — the agent will find and run this actor.

Tips

  • Filter to found: true before you export. Non-Shopify domains still take a dataset row so you can see what was checked, but you almost never want them in a lead list.
  • Use productType and tags for niche mapping, not a fixed taxonomy. Both fields are whatever the merchant typed in Shopify admin — expect inconsistent casing and synonyms across stores.
  • productCount caps at 50 — don't read it as total catalog size. A store with 3,000 SKUs and a store with 12 both cap out differently; only a count below 50 tells you the true total.
  • Turn on residential proxies for stores you know block scrapers. The default Apify Proxy setting works for most domains; residential helps on the more defensive ones.
  • Re-run on a schedule and diff products to catch new launches or price changes on a watchlist of competitor or partner stores.

vs. alternatives

What it costsWhat you getTrade-off
This actor (shopify-store-lookup)$0.00529 per found row (less on paid tiers), $0.00005 actor start, nothing for a domain that isn't Shopify or blocks the requestA yes/no Shopify signal plus up to 50 live products per store — title, vendor, price, availability, tags — read straight from the store's own /products.json feedCapped at 50 products per store (Shopify's own page limit, no pagination), no historical data, and some stores rate-limit or disable the endpoint entirely
BuiltWithFrom $295/monthHistoric tech data going back years, plus lead lists filtered by technologyIf you need "every site that added Shopify last quarter", that's a database question and BuiltWith answers it. This answers "what is this one domain running, right now".
Clay$0.08–$0.40 per enriched row in credits, on top of a seatA whole enrichment workspace — waterfalls across dozens of providers, plus the table and the sequencing around itIf you want one place that does everything and you're not counting rows, that's Clay. This is one column, priced per column, callable from Clay via its HTTP step.
Doing it yourselfYour time + handling 429s from stores that rate-limit the endpoint, normalizing domain formats, and re-parsing Shopify's variant structure for price/availabilityThe same dataThis actor already absorbs the retry logic, concurrency limits, and the domain-format cleanup — you paste a list and read a flat table.

Prices for third-party tools are their published list prices as of August 2026 and are not tracked here — check the vendor before relying on the comparison.

FAQ

What happens when a domain isn't running Shopify? The row comes back found: false and you are not charged for it. The request either 404s, returns non-JSON HTML, or returns JSON with no products array — any of those outcomes counts as not found, and none of them appear as a line item on your bill. You still get the row in the dataset, with status telling you why, so you can see which domains were checked even though nothing was billed.

Are there rate limits? Shopify itself, not Apify, is the limiting factor — some stores throttle or disable public access to /products.json. maxConcurrency (default 5) keeps this actor's own request rate conservative so it doesn't trip a store's own defenses; a store that returns 429 anyway is recorded as found: false rather than retried indefinitely, since a store that's actively rate-limiting isn't going to resolve on a second try within the same run.

How fresh is the data? Every request hits the store live at run time — there's no cache or stored snapshot between runs, and nothing is retained after the run finishes. scrapedAt on each row is the exact timestamp of that request, so you always know how current a price or availability figure is when you read it downstream.

Do I need to configure a proxy? No — proxyConfiguration defaults to Apify Proxy and works for most stores out of the box. Switch to residential proxies for domains you already know are aggressive about blocking non-browser traffic; it costs more per request but recovers stores that would otherwise come back found: false on the default setting.

Is any personal data collected? No. The output is a store's public product catalog — titles, prices, tags, images — the same data any visitor's browser loads when it hits the storefront. No customer records, order data, or personal data of any kind is read, derived, or stored.

Can I run this on a schedule? Yes — Apify's built-in Scheduler can trigger a run on any interval you set, from hourly to monthly. Combined with diffing products between runs downstream, that's how the watchlist use case (catching new product launches or price changes on competitor stores) works in practice — no separate cron infrastructure needed.

Can an AI agent call this directly? Yes — through the Apify MCP server, an agent can find and run this actor by name ("Shopify Store Lookup | Apify") without any custom integration code.

Does it need a Shopify Admin API key? No — this only calls the public, unauthenticated storefront JSON endpoint that requires no authentication or app installation.

Can I pass a full product URL instead of a bare domain? Yes — any https:// prefix and path are stripped automatically, so https://allbirds.com/collections/mens and allbirds.com resolve to the same lookup.