Shopify & WooCommerce Scraper and Price Tracker avatar

Shopify & WooCommerce Scraper and Price Tracker

Pricing

from $1.50 / 1,000 product returneds

Go to Apify Store
Shopify & WooCommerce Scraper and Price Tracker

Shopify & WooCommerce Scraper and Price Tracker

Shopify scraper and WooCommerce scraper in one: export every product (prices, sale prices, variants, SKUs, barcodes, stock, weights, images) to JSON, CSV or Excel, and track price drops, restocks, new and removed products between runs.

Pricing

from $1.50 / 1,000 product returneds

Rating

0.0

(0)

Developer

AgentToolWorks

AgentToolWorks

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

8 minutes ago

Last modified

Categories

Share

What is this Shopify and WooCommerce scraper?

This Actor is a Shopify scraper and WooCommerce scraper in one, with a built-in price tracker. Paste the URLs of any Shopify or WooCommerce stores, mixed in one list, and get every product back in the same clean format: titles, prices, sale prices, variants, SKUs, barcodes (GTIN/UPC/EAN), stock, weights, options, images with their sizes and alt text, tags, categories and dates.

Turn on change tracking and schedule it, and it becomes a competitor price monitor: each run outputs only what changed since the previous one (price drops, price increases, back in stock, out of stock, new products, removed products).

Shopify and WooCommerce scraper: store URLs in, one normalized product dataset out

What data can you extract from Shopify and WooCommerce stores?

One row per product, with its variants nested (or one row per variant, see Output). Every row has the same fields whichever platform the store runs on.

Product dataVariant dataStore data
Title, handle, URLVariant title and options (Size, Color)Platform detected (Shopify or WooCommerce)
Vendor or brand, product typeSKU and barcode (GTIN, UPC, EAN)Store domain and URL
Categories and tagsPrice and compare-at (sale) priceCurrency
Lowest and highest price, compare-at price, on saleIn stock, stock quantity where publicCollection or category read
Options with all their valuesBackorder policyRun summary per store
Images: URL, width, height, alt text, linked variantsWeight in grams
Description as plain text and as HTMLRequires shipping, taxable
Rating and review count (WooCommerce)Variant image and position
Created, updated and published datesCreated and updated dates (Shopify)

Everything comes from the store's own public storefront: Shopify's products.json and Ajax product endpoints, and the public WooCommerce Store API. No login, no account, no customer data.

What can you use Shopify and WooCommerce product data for?

  • Competitor price monitoring: track price changes and discounts across many stores, daily or hourly.
  • Restock alerts: know when a sold-out product or size is back in stock.
  • Product research and dropshipping: see what a brand sells, at what price, and what it launches.
  • Price comparison and product feeds: match products across stores by barcode (GTIN) and build a feed.
  • Catalog audits: missing SKUs or barcodes, out-of-stock share, sale depth, image alt text coverage.
  • Data for AI agents and pipelines: one predictable JSON schema for any Shopify or WooCommerce store.

How to scrape a Shopify or WooCommerce store

  1. Click Try for free (or Start) on this page and sign in to Apify.
  2. Paste one or more store URLs in Store URLs: a home page (https://www.allbirds.com), a Shopify collection (https://www.allbirds.com/collections/mens) or a WooCommerce category page.
  3. Set Max products per store. You pay per product returned, so start small to look at the data.
  4. Turn on Include stock levels, barcodes and image alt text if you need them (Shopify; slower).
  5. Click Start. When the run finishes, open the Output tab, pick the Products or Variants view, and export as JSON, CSV, Excel or XML, or read it through the API.

The Actor's input form in Apify Console: store URLs, max products per store, change tracking and options

Input

FieldWhat it does
storeUrlsShopify or WooCommerce store URLs, mixed. A home page, a Shopify collection page or a WooCommerce category page. Up to 100 stores per run.
maxProductsPerStoreStop after this many products per store (default 1,000, up to 100,000). You pay per product returned.
trackChangesSave a snapshot per store and output what changed since the last run.
outputProductsTurn off to output only the changes (for scheduled monitoring).
collectionA Shopify collection handle or WooCommerce category slug, for every store whose URL does not already name one.
includeInventoryShopify: read each product's public Ajax endpoint for stock counts, barcodes, backorder policy and image alt text. Slower: at most 500 products per store per run.
includeDescriptionAdd description (plain text) and descriptionHtml (the store's HTML), plus shortDescription on WooCommerce.
proxynone (default) or datacenter (Apify Proxy) if a store rate-limits your runs.

Example: one Shopify collection and one WooCommerce store, with barcodes and stock.

{
"storeUrls": ["https://www.allbirds.com/collections/mens", "https://woocommerce.com"],
"maxProductsPerStore": 500,
"includeInventory": true
}

Example: a daily price and stock monitor that outputs only changes.

{
"storeUrls": ["https://competitor-one.com", "https://competitor-two.com"],
"maxProductsPerStore": 20000,
"trackChanges": true,
"outputProducts": false
}

Output

The dataset has three ready-made views in Apify Console and in the API:

  • Products: one row per product.
  • Variants (one row each): one row per variant, with SKU, barcode, price, stock and weight. The same as adding unwind=variants to the dataset API.
  • Changes: the change rows, when change tracking is on.

Products view of a real run: Allbirds and Kith products with image, price, stock, vendor, type and counts

Variants view of a real run: one row per size with SKU, barcode, price, stock and weight in grams

A Shopify product row from a real run (variants and images shortened):

{
"rowType": "product",
"platform": "shopify",
"storeDomain": "www.allbirds.com",
"storeUrl": "https://www.allbirds.com",
"productId": "7340901859408",
"handle": "womens-allbirds-flip-flop-dusty-pink",
"title": "Women's Allbirds Flip Flop - Dusty Pink",
"url": "https://www.allbirds.com/products/womens-allbirds-flip-flop-dusty-pink",
"vendor": "Allbirds",
"productType": "Shoes",
"categories": [],
"tags": ["allbirds::complete => true", "allbirds::edition => limited"],
"price": 25,
"priceMax": 25,
"compareAtPrice": 50,
"onSale": true,
"currency": "USD",
"available": true,
"requiresShipping": true,
"sku": null,
"inventoryQuantity": 13,
"variantCount": 7,
"options": [{ "name": "Size", "position": 1, "values": ["5", "6", "7", "8", "9", "10", "11"] }],
"variants": [
{
"variantId": "42146889039952",
"variantTitle": "5",
"variantSku": "A12513W050",
"variantOptions": { "Size": "5" },
"variantPrice": 25,
"variantCompareAtPrice": 50,
"variantAvailable": false,
"variantInventory": 0,
"variantAllowsBackorder": false,
"variantBarcode": "196942293089",
"variantWeightGrams": 455,
"variantRequiresShipping": true,
"variantTaxable": true,
"variantImage": null,
"variantPosition": 1,
"variantCreatedAt": "2026-03-27T14:03:50-07:00",
"variantUpdatedAt": "2026-09-30T17:03:07-07:00"
}
],
"image": "https://cdn.shopify.com/s/files/1/1104/4168/files/A12513_26Q2_Allbirds-Flip-Flop-Dusty-Pink_PDP_LEFT.png?v=1774646345",
"images": ["https://cdn.shopify.com/s/files/1/1104/4168/files/A12513_26Q2_Allbirds-Flip-Flop-Dusty-Pink_PDP_LEFT.png?v=1774646345"],
"imageDetails": [
{
"src": "https://cdn.shopify.com/s/files/1/1104/4168/files/A12513_26Q2_Allbirds-Flip-Flop-Dusty-Pink_PDP_LEFT.png?v=1774646345",
"alt": null,
"width": 4000,
"height": 4000,
"position": 1,
"variantIds": []
}
],
"imageCount": 5,
"rating": null,
"reviewCount": null,
"createdAt": "2026-03-27T14:03:50-07:00",
"updatedAt": "2026-09-30T17:03:07-07:00",
"publishedAt": "2026-09-25T16:58:13-07:00",
"collection": null,
"scrapedAt": "2026-10-01T00:03:06.433Z"
}

A WooCommerce product row has exactly the same fields. Where the WooCommerce Store API publishes nothing, the field is null rather than guessed: no creation or update dates, no barcodes, no shipping or tax flags. In exchange, WooCommerce rows carry rating and reviewCount.

{
"rowType": "product",
"platform": "woocommerce",
"storeDomain": "woocommerce.com",
"productId": "18734006912442",
"title": "PH PostNord Shipping with Print Label",
"url": "https://woocommerce.com/products/ph-postnord-shipping-with-print-label/",
"categories": ["WooCommerce extensions", "Shipping, delivery and fulfillment", "Label printing"],
"price": 99,
"currency": "USD",
"available": true,
"variantCount": 1,
"imageCount": 5,
"rating": null,
"reviewCount": 0
}

Prices are numbers in the row's currency (25 means 25.00), so they sort and chart directly. Weights are always grams, whatever unit the store uses.

Change rows

With trackChanges on, each run also outputs one row per change since the previous run. A real one: two sizes of a sneaker came back in stock at Kith between two runs 46 minutes apart.

{
"rowType": "change",
"changeType": "back_in_stock",
"platform": "shopify",
"storeDomain": "kith.com",
"storeUrl": "https://kith.com",
"productId": "8286820892800",
"variantId": "45144949096576",
"title": "adidas x Entire Studios Adizero Adios 9 - Core Black / Feather Grey / Mist Stone",
"variantTitle": "7",
"handle": "aakj2303",
"url": "https://kith.com/products/aakj2303",
"price": 180,
"oldPrice": null,
"newPrice": null,
"available": true,
"currency": "USD",
"detectedAt": "2026-10-01T01:05:34.945Z",
"previousCheckAt": "2026-10-01T00:19:56.772Z"
}

changeType is one of new_product, removed_product, price_up, price_down, back_in_stock, out_of_stock. Price changes fill oldPrice and newPrice (compared to the cent); stock changes leave them null and give the current price. A change on a single variant carries its variantId and variantTitle; a new or removed product has them null.

Run summary

The run's key-value store holds a SUMMARY record with the status of each store: ok, partial (stopped part way, with the reason; the products read are kept), blocked (the store refused the request: a bot challenge or an HTTP 403), unsupported (not Shopify, or WooCommerce with its Store API closed), refused (not a public https address) or failed. It also says whether a store had more products than your limit, so a cut catalog is never silent.

How to monitor competitor prices with a schedule

  1. Run the Actor once with Track changes since the last run on. This first run saves a baseline for each store and reports no changes.
  2. On the input page, click Save as a new task. Turn off Output product rows in the task if you only want the changes.
  3. Open Schedules, create a schedule (daily, or every few hours) and add the task to it.
  4. Every scheduled run outputs only what changed since the previous run. Add an integration (email, Slack, Google Sheets, a webhook, Make, Zapier or n8n) to be notified when a run has rows.

Snapshots are kept in your account's named key-value store storecatalog-state, one record per store and per collection or category. Delete a record to start that store over from a new baseline.

Two things worth knowing:

  • Cover the whole catalog (maxProductsPerStore above the store's size) to detect new and removed products. When a run stops at your limit, a product it did not reach may still exist, so the run reports only price and stock changes for that store and says so in the summary.
  • If a run stops at your spending limit before every change is delivered, that store's snapshot is not updated, so the next run reports those changes again instead of losing them.

How much does it cost to scrape a Shopify store?

Pay per event, no subscription, platform usage included:

EventPrice
Product returned$1.50 per 1,000 products ($0.0015 each)
Change detected$0.005 per change
Run start$0.00005

Examples:

  • A 1,000 product store: $1.50.
  • Apify's free plan includes $5 of monthly usage (apify.com/pricing), enough for about 3,300 products a month.
  • A daily monitor of a 2,000 product store with Output product rows off pays only for changes: a day with 12 price or stock changes costs $0.06.

A run that finds nothing to output costs only the start fee. Set a maximum cost per run in the run options and the Actor stops cleanly when it is reached.

Use the Actor through the Apify API

Run it and get the products in one HTTP call (replace YOUR_APIFY_TOKEN, from Settings > API & Integrations in Apify Console):

curl -X POST "https://api.apify.com/v2/acts/agenttoolworks~shopify-woocommerce-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"storeUrls": ["https://www.allbirds.com"], "maxProductsPerStore": 100}'

Node.js, with the official apify-client:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('agenttoolworks/shopify-woocommerce-scraper').call({
storeUrls: ['https://www.allbirds.com', 'https://woocommerce.com'],
maxProductsPerStore: 100,
includeInventory: true,
});
// One item per variant instead of per product: add { unwind: 'variants' }.
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.map((p) => [p.title, p.price, p.currency]));

Python, with the official apify-client:

from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("agenttoolworks/shopify-woocommerce-scraper").call(
run_input={"storeUrls": ["https://www.allbirds.com"], "maxProductsPerStore": 100}
)
for product in client.dataset(run["defaultDatasetId"]).iterate_items():
print(product["title"], product["price"], product["currency"])

The API tab on this page has ready-made snippets for every language and endpoint.

FAQ

Does it work on every Shopify store?

On nearly every one: products.json is part of every Shopify storefront. A store behind an extra bot challenge is reported as blocked in the run summary.

Does it work on every WooCommerce store?

On WooCommerce stores whose Store API is open, which is the default in recent WooCommerce versions. Stores that close it are reported as unsupported, and stores behind a firewall as blocked.

How fast is it?

Measured on Apify: Allbirds (692 products, 3 catalog requests) in 3 seconds, the first 5,000 Kith products in 29 seconds. With Include stock levels, barcodes and image alt text, each product needs one more request, so plan about 1.5 minutes per 300 products (measured: 300 Allbirds products in 90 seconds). WooCommerce speed depends mostly on the store's server.

Can I get stock quantities and barcodes?

Shopify: turn on Include stock levels, barcodes and image alt text. Barcodes come back for every product that has one; stock counts only for stores that track inventory publicly. WooCommerce publishes a stock count only when stock is low, and never barcodes.

Can I get one row per variant, for a spreadsheet?

Yes: choose the Variants (one row each) view before exporting, or add unwind=variants to the dataset items API.

Can I scrape only one collection or category?

Yes: paste the collection URL (/collections/sale) or the WooCommerce category URL, or set Collection or category to apply the same one to every store.

Can I use it with Make, Zapier, n8n or Google Sheets?

Yes, through Apify's integrations: the Actor's dataset works with every Apify integration, and a webhook can fire when a run finishes.

Can AI agents use it through MCP?

Yes. Apify's hosted MCP server exposes Store Actors to MCP clients such as Claude or Cursor: https://mcp.apify.com?tools=agenttoolworks/shopify-woocommerce-scraper.

The Actor reads only the product information a store publishes to every visitor, through the storefront's public endpoints, without logging in, and it collects no personal data. As with any data, how you use it is your responsibility.

Something is missing or broken?

Open an issue in the Issues tab: we read every one, and fields asked for by users get added.

Other Actors by AgentToolWorks

Learn more

Built by AgentToolWorks. Not affiliated with Shopify or with WooCommerce.