Shopify Products Scraper & AI Shopping Readiness Audit avatar

Shopify Products Scraper & AI Shopping Readiness Audit

Pricing

from $0.64 / 1,000 product returneds

Go to Apify Store
Shopify Products Scraper & AI Shopping Readiness Audit

Shopify Products Scraper & AI Shopping Readiness Audit

Shopify products scraper and catalog export with a 0-100 AI shopping readiness audit. Every store gets a row explaining its result; can read past Shopify's 25,000-product feed limit and says if the catalogue is complete.

Pricing

from $0.64 / 1,000 product returneds

Rating

0.0

(0)

Developer

Your Evenings

Your Evenings

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

an hour ago

Last modified

Share

Shopify Products Scraper & AI Shopping Readiness Audit turns a list of Shopify store domains into two things:

  1. A Shopify catalog export: one clean row per product with title, vendor (brand), product type, tags, variant count, price range, availability, SKUs, barcodes, image count, product URL and dates.
  2. An AI shopping readiness audit for each store: how much of the catalogue is missing the product data that AI shopping assistants and product feeds rely on (GTIN/barcode, brand, product type, a real description, image alt text, SKUs, unique titles), rolled up into a 0–100 readiness score with the top issues and example product handles to fix first.

Why this one

  • Find variants with missing, invalid or duplicate barcodes across the whole catalogue. Turn on readAllProductDetails and every variant's barcode is checked: missing, invalid (wrong length or check digit for GTIN-8, 12, 13 or 14), or the same barcode on more than one variant. You get a status on each variant, totals in the audit row and a BARCODE-ISSUES CSV listing only the problem variants. It's read-only: nothing in the store is changed.
  • No run ends with unexplained zero results. Every store gets a row: its audit, or a status with a plain-English note (not Shopify, password-protected or headless, no products, blocked, or disallowed by robots.txt).
  • Whole catalogues, with completeness you can check. Paging continues past short pages until the feed is really empty, and above Shopify's 25,000-product feed limit the rest comes from the store's public sitemap, collection feeds and product pages. Each audit row says whether the whole catalogue was read (catalogueComplete, true only when verified) and the store's known product total; if anything was missed, the note says what and why.
  • Free "is this a Shopify store?" check. Paste any domain; sites that aren't Shopify return one free not_shopify row.
  • Your limits hold, and status rows are free. maxProductsPerStore is a hard cap on products returned and charged per store. You pay for product rows and store audits plus the small per-run start fee; status rows are never charged.
  • Every image and every variant, not just a summary. Each product row lists all image URLs in position order and every variant with SKU, price, compare-at price, options and availability, and there's a one-row-per-variant view. Turn on readAllProductDetails to add barcodes, image alt text, weights and stock counts where the store publishes them. Nothing is estimated.
  • Polite by default. robots.txt (including Crawl-delay) is respected, requests are limited to one per second per store, and the Actor backs off when a store answers HTTP 429.

Quick start

Paste this into the JSON view of the Input tab and press Start. It reads up to 20 products from one public Shopify store and returns a row per product plus the store's AI shopping readiness audit.

{
"stores": [
"partakefoods.com"
],
"maxProductsPerStore": 20
}

For more ready-made inputs, see the example tasks.

Works with: Shopify stores

Runs on Apify Apify. Use it from Make, Zapier, n8n n8n or the Apify API.

It reads only the public storefront product JSON that Shopify stores serve (/products.json, /collections.json, each product's own .json and the store's public /meta.json), plus the store's public product sitemap for catalogues above 25,000 products. No login, no browser, no proxies, and no customer data.

What you can use it for

  • Shopify products scraper / catalog export. Pull a competitor's or supplier's full public catalogue into a spreadsheet, a database or a price-monitoring pipeline.
  • AI shopping readiness checks. See which catalogue data gaps commonly keep products from showing up well in AI shopping answers and product feeds, and which products to fix first.
  • Agency and freelancer audits. Run it over a prospect list and lead with a concrete, measured data-quality finding per store.
  • Product feed QA. Check GTIN, brand and product-type coverage before sending a catalogue to Google Merchant Center or other feeds.

Example tasks (ready-made inputs)

What the audit checks

All rules are deterministic (no AI model is involved), so the same catalogue always gets the same score.

CheckWhat counts as a problemMeasured onWeight
GTIN / barcodeVariant has no barcode, or the barcode is not a valid GTIN-8, UPC-A (12), EAN-13 or GTIN-14 check digitDetail sample of variants20
DescriptionProduct has no description or fewer than 30 words after removing HTMLAll scanned products20
Product typeProduct type is blankAll scanned products10
Vendor (brand)Vendor is blankAll scanned products10
Image alt textImage has empty alt textDetail sample of images10
SKUVariant SKU is blankAll scanned variants10
ImagesProduct has no imageAll scanned products10
Duplicate titlesTitle is identical to another product's (case and spacing ignored)All scanned products10

Readiness score formula (version 1.0):

score = round( 100 × (1 − Σ(weight × problem% / 100) / Σ weight) )

The sums run over the checks that were measured. If a check can't be measured (for example, the detail sample is turned off), it drops out and the remaining weights are rescaled. Grades: good 90–100, fair 70–89, needs work 50–69, poor under 50. Every audit row includes a scoreBreakdown with each check's weight, problem percentage and penalty points, and topIssues ranked by how many score points each issue costs.

Why a detail sample? Shopify's catalogue-wide /products.json doesn't include variant barcodes or image alt text. Those are only in each product's own JSON, so the Actor reads that for a sample of products spread evenly across the catalogue (20 by default, up to 250). The GTIN and alt-text percentages are measured on that sample, and the sample size is in every audit row. Products in the sample have barcodeChecked: true and detailRead: true, with their barcode and alt-text fields filled. With readAllProductDetails on, every product's own JSON is read and the checks cover the whole set of products read.

What the score is not. It measures catalogue data quality only. It is not a ranking factor of any AI assistant or search engine and doesn't guarantee that products will appear in ChatGPT, Google or any other shopping surface. Those platforms also weigh eligibility, merchant settings, reviews, pricing and much else.

Barcode check: missing, invalid and duplicate barcodes

The Actor checks the barcode of every variant it reads from each product's own public JSON. With readAllProductDetails on, that's every variant of every product read. With it off, it's the detail sample only (detailSampleSize, 20 products by default). Each checked variant gets a barcodeStatus:

  • valid: a GTIN-8, UPC-A (12 digits), EAN-13 or GTIN-14 with a correct check digit.
  • missing: the variant has no barcode.
  • invalid: the barcode isn't a GTIN of those lengths, or its check digit is wrong.
  • duplicate: an earlier variant in the same store has the same barcode (a 12-digit UPC and the same code as a 13-digit EAN count as the same). barcodeDuplicateOf names that earlier variant, and barcodeValidGtin still says whether the code itself is a valid GTIN.

Where to find the results:

  • BARCODE-ISSUES CSV in the run's key-value store (linked from the Output tab and the run's status message): one line per problem variant, with store, product title, handle, product URL, variant ID and title, options, SKU, barcode and status. For each duplicated barcode, the first variant that has it is listed too (with variantsWithThisBarcode), so every variant sharing a barcode is in the file. If nothing is wrong, the CSV has only its header line.
  • Audit row barcodeCheck: variants checked and how many are valid, missing, invalid or duplicate, plus the number of duplicated barcodes and up to 10 examples. The valid count includes the first variant of each duplicated barcode.
  • Variants view: every variant with its barcodeStatus.

To check barcodes only, run with includeCatalogueRows: false and readAllProductDetails: true. You pay only the store audit (no product rows), and the product JSON requests are free. The check reads only what the store publishes and changes nothing in Shopify.

Input

FieldWhat it doesDefault
storesShopify store domains or URLs, one per line3 example stores
includeCatalogueRowsOne row per producton
includeAuditOne readiness-audit row per storeon
maxProductsPerStoreStop after this many products per store (0 = whole catalogue, up to 100,000)250
readAllProductDetailsRead every product's own JSON, so every row gets barcodes, image alt text, weights and inventory fields where the store publishes them. One extra request per product (about 1 s each); raise the run timeout for big catalogues. No extra chargeoff
detailSampleSizeProducts checked for barcodes and image alt text (0 = skip these two checks)20
requestTimeoutSecsPer-request timeout; failed requests are retried 3 times with backoff15

Example input:

{
"stores": ["beardbrand.com", "https://www.allbirds.com/collections/mens", "partakefoods.com"],
"includeCatalogueRows": true,
"includeAudit": true,
"maxProductsPerStore": 250,
"detailSampleSize": 20
}

Paths in URLs are ignored: the whole store is read. Audit-only runs (includeCatalogueRows: false) are the cheapest way to score many stores.

Output

The dataset has three kinds of rows, told apart by recordType. The Output tab has Products, Variants (one row per variant), Readiness audits and Store status views.

A product row (recordType: "product"):

{
"recordType": "product",
"status": "ok",
"store": "partakefoods.com",
"storeUrl": "https://partakefoods.com",
"productId": "7776301088866",
"handle": "girl-scouts-sparkables",
"title": "Girl Scout Sparkables™",
"vendor": "Partake Foods",
"productType": "Cookies",
"tags": ["no_purchase"],
"variantsCount": 1,
"availableVariantsCount": 1,
"anyAvailable": true,
"priceMin": 0,
"priceMax": 0,
"compareAtPriceMax": null,
"currency": "USD",
"options": [],
"skus": [],
"variantsMissingSku": 1,
"barcodeChecked": true,
"barcodes": [],
"variantsWithBarcode": 0,
"variantsWithValidGtin": 0,
"imageCount": 4,
"imagesMissingAlt": 4,
"featuredImageUrl": "https://cdn.shopify.com/s/files/1/0012/2296/7353/files/Girl_Scout_Sparkables_Partake_Cookie.png?v=1787935354",
"images": [
{ "imageId": "35504456368226", "position": 1, "url": "https://cdn.shopify.com/s/files/1/0012/2296/7353/files/Girl_Scout_Sparkables_Partake_Cookie.png?v=1787935354", "width": 3000, "height": 3000, "alt": null, "variantIds": [] },
"… 3 more images"
],
"variants": [
{ "variantId": "43229654909026", "title": "Default Title", "position": 1, "sku": null, "barcode": null, "barcodeStatus": "missing", "barcodeValidGtin": null, "barcodeDuplicateOf": null, "price": 0, "compareAtPrice": null, "options": {}, "available": true, "grams": null, "weight": null, "weightUnit": null, "inventoryQuantity": null, "inventoryTracked": null, "sellsWhenOutOfStock": null, "requiresShipping": false, "imageId": null }
],
"detailRead": true,
"descriptionWordCount": 120,
"url": "https://partakefoods.com/products/girl-scouts-sparkables",
"createdAt": "2026-08-21T13:00:05.000Z",
"updatedAt": "2026-10-21T17:40:01.000Z",
"publishedAt": "2026-09-12T17:03:23.000Z"
}

An audit row (recordType: "store-audit", shortened):

{
"recordType": "store-audit",
"status": "ok",
"store": "partakefoods.com",
"storeName": "Partake Foods",
"currency": "USD",
"publishedProductsCount": 15,
"catalogueComplete": true,
"totalProductsKnown": 15,
"totalProductsKnownSource": "products.json (read to the end)",
"productsRead": 15,
"productSources": { "products.json": 15 },
"productsScanned": 15,
"variantsScanned": 28,
"detailSampleProducts": 15,
"pctVariantsMissingBarcode": 71.4,
"pctVariantsWithoutValidGtin": 71.4,
"pctProductsMissingVendor": 0,
"pctProductsMissingProductType": 26.7,
"pctProductsMissingOrThinDescription": 0,
"duplicateTitleGroups": 0,
"pctImagesMissingAlt": 100,
"pctProductsWithoutImages": 0,
"pctVariantsMissingSku": 17.9,
"readinessScore": 71,
"readinessGrade": "fair",
"topIssues": [
{
"issue": "missingGtin",
"description": "Variants without a valid GTIN/barcode (UPC, EAN or ISBN)",
"affectedPercent": 71.4,
"affectedCount": 20,
"outOf": 28,
"unit": "variants (detail sample)",
"impactPoints": 14.3,
"exampleHandles": ["girl-scouts-sparkables", "mini-chocolate-chip-grahams", "crunchy-ginger-snap"]
}
],
"collectionsCount": 35,
"thinDescriptionThresholdWords": 30,
"scoreFormulaVersion": "1.0"
}

Images and variants. images lists every product image in position order (url, width, height, variantIds). variants lists every variant with sku, price, compareAtPrice, options (for example {"Size": "M", "Colour": "Red"}), available and grams, all from the store's product feed. Some fields are only in each product's own JSON, so they are filled only when that was read (detailRead: true, which is every product with readAllProductDetails on, or the audit sample otherwise): image alt, variant barcode, weight with weightUnit, and the inventory fields.

Stock. Shopify's public feed shows only whether each variant is available. Some stores also publish a stock count in each product's own JSON. Where one is published, inventoryQuantity copies it, along with inventoryTracked and sellsWhenOutOfStock (Shopify's "continue selling when out of stock" setting). Many stores hide these, and the store controls the number, so it may be rounded, capped or out of date. When it isn't published, the field is null. Stock counts are never estimated.

One row per variant. The Variants view in the Output tab shows one row per variant. To export that shape, add unwind=variants to the dataset items API URL (for example https://api.apify.com/v2/datasets/{datasetId}/items?format=csv&unwind=variants). You're charged per product row either way.

A status row (recordType: "store") is returned, free of charge, for inputs that can't be read:

  • not_shopify: no Shopify product feed and no Shopify markers on the homepage.
  • shopify_products_unavailable: the site is a Shopify store, but its public product feed is closed (password-protected, headless or blocked).
  • blocked_by_robots: the store's robots.txt disallows /products.json or /products/ for this crawler (or for all crawlers), so it was skipped without reading the catalogue.
  • blocked: the site refused the requests (for example HTTP 429), so it couldn't be checked. Try again later.
  • no_products, duplicate (same store as an earlier line), invalid_input or error (with a note).
  • catalogue_incomplete: only when includeAudit is off. The catalogue couldn't be read in full, and the row carries the same completeness fields and note as the audit row would.

A run summary (status, product count, score and timing per store) is saved as SUMMARY in the run's key-value store.

Pricing

This Actor uses pay-per-event pricing. You pay for results, not for compute:

EventWhen it is chargedPrice
Actor startOnce per run (per GB of memory; the default 256 MB run counts as one start)$0.00005
ProductEach product row returned$0.0008
Store auditEach store readiness-audit row returned$0.02

Status rows (not_shopify, shopify_products_unavailable, errors and so on) are never charged. Higher Apify plans get tier discounts (Silver −10%, Gold −20%). Prices on the Actor's Pricing tab are authoritative.

Examples at the base price:

  • Audit only, 100 stores: 100 × $0.02 + $0.00005 = about $2.00.
  • Catalogue and audit for 10 stores of 250 products each: 2,500 × $0.0008 + 10 × $0.02 = about $2.20.
  • The default input (3 stores, 128 products when tested): 128 × $0.0008 + 3 × $0.02 = about $0.16.

The Actor respects the maximum cost per run you set. When the limit is close it stops adding product rows, still delivers the audit for the store it's working on if that fits, and says so in the status message.

Large catalogues and completeness

Shopify's public product feed lists 250 products per page and stops at page 100 (25,000 products); page 101 returns an error. Some stores also return short pages in the middle of the catalogue, so the Actor keeps paging until a page is empty rather than stopping at the first short page. It also stops if a page only repeats products it has already read.

Above 25,000 products the Actor:

  1. Reads the store's public product sitemap (/sitemap.xml → sitemap_products_N.xml) to get the full list of product handles.
  2. Reads public collection feeds (/collections/{handle}/products.json), largest first, to pick up products the main feed didn't reach. A collection that only repeats products already read is skipped after three pages, and collections stop altogether once they find fewer new products than requests.
  3. Reads each product that is still missing from its own public JSON (/products/{handle}.json).

Every audit row reports completeness honestly:

FieldMeaning
catalogueCompletetrue only when verified: the main feed was read to an empty page (or to the exact count in /meta.json), or every product in the store's sitemap was found. false when maxProductsPerStore, the run budget, the run timeout, robots.txt or an error stopped it.
totalProductsKnownThe store's product total when it's known: the count read when the catalogue is complete, otherwise /meta.json (exact only below 25,000; Shopify reports 25001 for anything larger) or the sitemap. null when unknown.
totalProductsKnownSourceWhere that total came from: products.json (read to the end), meta.json or sitemap.
productsRead, productSourcesProducts read, and how many came from each route.

When the catalogue is truncated, the audit's note says so, for example "Shopify's public feed stops at 25,000 products; catalogue truncated…", with how many products the sitemap lists and how many weren't read.

Run time. Requests are rate-limited (one per second per store, or longer if robots.txt asks), so about 25,000 products take at least 100 seconds through the main feed, and anything above that takes one request per collection page or per product. The Actor's default run timeout is 300 seconds. For catalogues above about 20,000 products, raise the run timeout in the run options (in our test, 35,140 products took about 30 minutes). If time runs out, the Actor stops fetching about 45 seconds before the timeout, still delivers the audit, and marks the catalogue incomplete.

Speed and politeness

Each store's robots.txt is read first and respected: stores that disallow the product feed are skipped, disallowed paths (including collection feeds, sitemaps and product pages) are never fetched, and a Crawl-delay for this crawler or for all crawlers is honoured. Requests to each store are limited to one per second, with at most three stores in parallel, a 15-second timeout, and retries with backoff on HTTP 429 and 5xx (using Retry-After when the store sends it). In local tests (21–22 Oct 2026, 256 MB memory), a 250-product store with the default 20-product detail sample took about 22–27 seconds, a full 9,357-product catalogue took about 50 seconds, and a full 35,140-product catalogue (above the 25,000 feed limit) took about 30 minutes.

Use it from code, spreadsheets or an AI agent

  • Schedule it: Console > Schedules, for example weekly, to re-export catalogues or re-check readiness scores.

  • Google Sheets, Make, Zapier, n8n, Slack: use the Actor's Integrations tab to send each run's dataset where you need it.

  • API (Python):

    from apify_client import ApifyClient
    client = ApifyClient("<YOUR_APIFY_TOKEN>")
    run = client.actor("yourevenings/shopify-catalogue-audit").call(run_input={"stores": ["allbirds.com"]})
    for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["recordType"], item.get("store"), item.get("title"), item.get("readinessScore"))
  • AI agents: the Actor can be run through the Apify MCP server, so Claude, ChatGPT or Cursor agents can call it with their own input.

AI agents can pay for runs themselves

AI agents can run this Actor and pay with stablecoins such as USDC through the x402 or MPP protocols, with no Apify account needed. The agent buys a prepaid, spend-capped Apify API token from Apify's Agent General Interface (AGI) and then runs the Actor with it as normal. Prepaid tokens only run Actors that use limited permissions, and this Actor does. Agentic payments are an experimental Apify feature, and the terms (minimum amount, expiry, usage limits) are set by Apify. See Apify's docs: Let your AI agent pay for Actor runs, x402 and MPP.

FAQ

Is this an official Shopify, OpenAI or Google product? No. It's an independent tool and isn't affiliated with or endorsed by Shopify, OpenAI, Google or any store it reads. The names are used only to describe what it works with.

Where does the data come from? From the public storefront JSON that Shopify stores serve to anyone: /products.json, /collections.json, /collections/{handle}/products.json, /products/{handle}.json and /meta.json, plus the public product sitemap for catalogues above 25,000 products. It doesn't log in, use the Admin API or read checkout, cart or customer data. From /meta.json it uses only the store name, currency and published product count; it never outputs the store's address, city or contact details.

Does it collect personal data or emails? No. It reads published product information (merchants' business data) only. It never collects customer data, reviews or email addresses.

Why is a store returned as shopify_products_unavailable? Some Shopify stores close their public product feed (password pages, headless storefronts, or bot protection). There's nothing to read, so the row is free.

Will fixing the issues get my products into ChatGPT or Google AI shopping? Nobody can promise that. Complete GTINs, brands, product types, descriptions and alt text are the kind of structured product data AI shopping and product feeds commonly depend on, so the audit tells you where those gaps are. Inclusion and ranking are decided by each platform.

Why do barcode and alt-text percentages use a sample? Shopify only publishes them in each product's own JSON, which means one request per product. The sample keeps runs fast and polite. Set detailSampleSize up to 250 for a fuller check.

Did I get the whole catalogue? Check catalogueComplete on the audit row. It's true only when the Actor verified it read every product; totalProductsKnown and the note tell you what's missing when it isn't. With the default maxProductsPerStore of 250, larger stores are deliberately capped; set it to 0 for the whole catalogue (and raise the run timeout for very large stores).

How do I check if a store is on Shopify? Paste the domain: stores that aren't Shopify return one free not_shopify row. Shopify stores that close their public product feed return a free shopify_products_unavailable row instead.

Is it legal to use this data? The Actor reads only product information that merchants publish on their public storefronts, with polite rate limits. You're responsible for using the data in line with the laws that apply to you and the terms of the sites you use it with.

Feedback

Found a store that should work, a wrong figure or a check you'd like added? Open an issue on the Issues tab with the store and run ID, and it'll be looked at quickly.