# Shopify & WooCommerce Products Scraper – Any Store, Schema.org (`openharvest/ecommerce-product-scraper`) Actor

Scrape Shopify products, WooCommerce products and any online store with schema.org markup (JSON-LD, microdata, OpenGraph). Get prices, compare-at prices, currency, stock, variants, SKU, GTIN, brand, images, categories, tags and ratings. Paste store, collection or product URLs. No browser.

- **URL**: https://apify.com/openharvest/ecommerce-product-scraper.md
- **Developed by:** [Enes Bulanık](https://apify.com/openharvest) (community)
- **Categories:** E-commerce, Automation, Developer tools
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.50 / 1,000 products

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Shopify & WooCommerce Products Scraper – Any Store, Schema.org

Scrape Shopify products, WooCommerce products and any online store with schema.org markup (JSON-LD, microdata, OpenGraph). Get prices, compare-at prices, currency, stock, variants, SKU, GTIN, brand, images, categories, tags and ratings. Paste store, collection or product URLs. No browser.

**Price: $1.50 per 1,000 products** – no proxy surcharge, no browser, and URLs that fail are never charged.

### What data do you get?

One flat row per product, with the same fields for every platform:

- 🏷 **Identity** – `title`, `brand`, `productId`, `handle`, `sku`, `gtin` (EAN/UPC/ISBN, validated), `mpn`
- 💲 **Pricing** – `price` (lowest available variant), `compareAtPrice` (original price when on sale), `currency` (ISO code)
- 📦 **Stock** – `inStock` (true/false) and schema.org `availability` (`InStock`, `OutOfStock`, `BackOrder`, `PreOrder`…)
- 🎨 **Variants** – `variantCount` and `variants[]` with `id`, `title`, `sku`, `gtin`, `price`, `compareAtPrice`, `available` and `options` (e.g. `{"Size": "10", "Color": "Black"}`)
- 🖼 **Media & text** – `image`, `images[]`, plain-text `description` (HTML stripped, trimmed to your length)
- 🗂 **Taxonomy** – `category` (or breadcrumb path), `productType`, `tags[]`
- ⭐ **Ratings** – `rating` and `reviewCount` (when the store publishes them)
- 🔎 **Meta** – `store`, `platform` (shopify, woocommerce, magento, bigcommerce, shopware, prestashop, wix, squarespace, …), `source`, `createdAt`, `updatedAt`, `url`

### How it works

| Store type | How products are read | Typical speed |
|---|---|---|
| **Shopify** | Public `/products.json` (250 products per request), `/collections/{handle}/products.json`, `/products/{handle}.json` + `.js` | ~1,000 products in a few seconds |
| **WooCommerce** | Public Store API `/wp-json/wc/store/v1/products` (100 per request) + variations in bulk | ~1,000 products in under a minute |
| **Any other store** (Magento, BigCommerce, Shopware, PrestaShop, Salesforce Commerce Cloud, custom…) | Sitemap discovery (robots.txt → product sitemaps) or link crawling, then JSON-LD / microdata / OpenGraph from each product page | ~1–3 pages per second |

`mode: "auto"` detects the platform for you. If a Shopify/WooCommerce API is disabled, the Actor automatically falls back to structured data.

### Use cases

- **Competitor price monitoring** – track prices, discounts (`compareAtPrice`) and stock of competitor stores on a schedule.
- **Product catalog import / dropshipping research** – export a whole Shopify or WooCommerce catalog with variants and images.
- **MAP & reseller compliance** – find resellers selling your GTINs/SKUs below the minimum advertised price.
- **Market & assortment research** – compare categories, brands, price ranges and new products across many stores.
- **Feeds & AI** – build product feeds, enrich PIM data or feed product info into RAG and LLM agents.

### Input example

```json
{
    "startUrls": [
        { "url": "https://www.allbirds.com" },
        { "url": "https://nalgene.com/product-category/bottles/" },
        { "url": "https://www.ikea.com/us/en/p/strala-led-floor-lamp-matchstick-shaped-wood-50645611/" }
    ],
    "mode": "auto",
    "maxProducts": 500,
    "includeVariants": true
}
```

| Field | Type | Description |
|---|---|---|
| `startUrls` | array | Store homepages (whole catalog), collection/category URLs (only that category) or product URLs (only that product). |
| `mode` | string | `auto` (default), `shopify`, `woocommerce` or `structuredData`. |
| `maxProducts` | integer | Max products per start URL. `0` = no limit. Default `100`. |
| `includeVariants` | boolean | Include the `variants` list. Default `true`. |
| `maxPagesPerStore` | integer | Structured-data crawling only: max HTML pages per start URL. Default `200`. |
| `descriptionMaxLength` | integer | Trim descriptions to N characters (`0` = full text). Default `1000`. |
| `proxyConfiguration` | object | Optional. Use Apify Proxy (residential) for stores that block bots. |

### Output example

Real output (shortened):

```json
{
    "type": "product",
    "url": "https://www.allbirds.com/products/womens-allbirds-flip-flop-dusty-pink",
    "store": "allbirds.com",
    "platform": "shopify",
    "source": "shopify-json",
    "productId": "7340901859408",
    "handle": "womens-allbirds-flip-flop-dusty-pink",
    "sku": "A12513W100",
    "gtin": null,
    "title": "Women's Allbirds Flip Flop - Dusty Pink",
    "brand": "Allbirds",
    "description": "Sun on your feet. Comfort underneath. Light, easy, and made for warm weather, these flip flops bring everyday comfort to sunny days, beach walks, and everything in between. Just slip them on and go.",
    "price": 25,
    "compareAtPrice": 50,
    "currency": "USD",
    "inStock": true,
    "availability": "InStock",
    "variantCount": 7,
    "variants": [
        { "id": "42146889039952", "title": "5", "sku": "A12513W050", "gtin": null, "price": 25, "compareAtPrice": 50, "available": false, "options": { "Size": "5" } },
        { "id": "42146889203792", "title": "10", "sku": "A12513W100", "gtin": null, "price": 25, "compareAtPrice": 50, "available": true, "options": { "Size": "10" } }
    ],
    "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"],
    "category": null,
    "productType": "Shoes",
    "tags": ["allbirds::gender => womens", "allbirds::material => sugar"],
    "rating": null,
    "reviewCount": null,
    "createdAt": "2026-03-27T14:03:50-07:00",
    "updatedAt": "2026-10-07T13:59:51-07:00",
    "scrapedAt": "2026-10-07T21:21:47.377Z"
}
```

A product from a non-platform store (schema.org JSON-LD, IKEA):

```json
{
    "type": "product",
    "url": "https://www.ikea.com/us/en/p/strala-led-floor-lamp-matchstick-shaped-wood-50645611/",
    "store": "ikea.com",
    "platform": "other",
    "source": "json-ld",
    "productId": "506.456.11",
    "sku": "506.456.11",
    "title": "STRÅLA LED floor lamp - matchstick-shaped wood",
    "brand": "IKEA",
    "price": 44.99,
    "currency": "USD",
    "inStock": true,
    "availability": "InStock",
    "category": "Floor lamps",
    "rating": 4.7,
    "reviewCount": 17
}
```

URLs that cannot be scraped produce a **free** row like `{"type": "error", "url": "...", "errorCode": "BLOCKED", "error": "HTTP 429 ... try a residential proxy."}`. Error codes: `INVALID_INPUT`, `NOT_FOUND`, `BLOCKED`, `CONNECTION_FAILED`, `NO_PRODUCTS_FOUND`, `SCRAPE_FAILED`.

The dataset has ready-made views: **Overview**, **Details**, **Variants** and **Errors**.

### Pricing

Pay-per-event – you only pay for products saved to the dataset. Platform usage is included.

| Event | Price | When it is charged |
|---|---|---|
| `product` | **$0.0015** per product ($1.50 / 1,000) | Each product row saved to the dataset |
| Errors | **Free** | Invalid URLs, blocked stores, pages without product data |

| Job | Cost |
|---|---|
| 100 products from one Shopify store | **$0.15** |
| 1,000 products from 5 stores | **$1.50** |
| 50,000-product catalog | **$75** |

The same product is never charged twice in one run (e.g. when you add both a store and one of its product URLs). Set **Max cost per run** in the run options – the Actor stops cleanly when your budget is reached.

### Use with AI agents (MCP)

This Actor works as a tool for AI agents through the [Apify MCP server](https://mcp.apify.com) (Claude, ChatGPT, Cursor, n8n and other MCP clients). Ask, for example, *"Get the 200 newest products of allbirds.com with prices and tell me which ones are discounted."* The agent calls the Actor with:

```json
{
    "startUrls": [{ "url": "https://www.allbirds.com" }],
    "maxProducts": 200,
    "includeVariants": false,
    "descriptionMaxLength": 300
}
```

The flat, platform-independent fields (`price`, `compareAtPrice`, `currency`, `inStock`) make results from different stores directly comparable. Turn off `includeVariants` and shorten descriptions to keep LLM context small.

### FAQ

**Which stores are supported?**
Any public store. Shopify and WooCommerce get the fastest and richest extraction through their public JSON. Other stores work when their product pages contain schema.org Product markup (JSON-LD, microdata or OpenGraph price tags) – which almost every store does for Google Shopping and rich results.

**Why is `gtin` empty for some Shopify products?**
Shopify's catalog listing (`products.json`) does not include barcodes. GTINs are filled when you scrape a **product URL** (we read `/products/{handle}.json`) or when the store publishes them in JSON-LD. Values that are not valid 8–14 digit codes are dropped.

**Why is `rating` empty?**
Shopify and many stores do not publish ratings in their product JSON. Ratings are filled from WooCommerce, from schema.org `aggregateRating` and, for Shopify product URLs, from the page's JSON-LD (review apps such as Judge.me or Yotpo inject it).

**Which currency do I get?**
The store's default currency for the country the request comes from (Shopify Markets and some stores localise prices by visitor country). Use Apify Proxy with a country (e.g. `apifyProxyCountry: "GB"`) to see that country's prices. Shopify locale paths such as `https://store.com/en-gb/collections/mens` are kept in all requests.

**A store returns `BLOCKED`. What can I do?**
Some large stores use bot protection (Cloudflare, Akamai). Enable **Apify Proxy** with the **Residential** group in the input. You are never charged for blocked URLs.

**How are products found on non-Shopify / non-WooCommerce stores?**
For a homepage the Actor reads `robots.txt`, follows the sitemaps (product sitemaps first) and opens product pages. If there is no usable sitemap, or you give a category URL, it crawls links from the page. `maxPagesPerStore` caps the number of pages fetched.

**Can I monitor prices daily?**
Yes – save your input as a Task and add a Schedule. Combine with webhooks, Google Sheets, Make, Zapier or n8n integrations.

### Is it legal to scrape online stores?

This Actor only reads **publicly available product information** – the same public JSON endpoints and schema.org markup that stores publish for search engines and shopping feeds. It does not log in, does not access customer accounts, and collects **no personal data**. Product descriptions and images may be protected by copyright, and some stores' terms of service restrict automated access – check them and use the data responsibly (e.g. price comparison and analysis rather than republishing content). Keep request volumes reasonable. If you are unsure, consult a lawyer. Read more: [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/)

### Related actors

- Sitemap URL Extractor – all URLs of any website from its sitemaps
- Shopify App Store Scraper – apps, pricing plans, ratings & reviews
- Google Shopping Scraper *(coming soon)*
- Amazon Product Scraper *(coming soon)*

### Support

Found a store that doesn't work or a missing field? Open an issue in the **Issues** tab with the store URL – we usually respond within a day.

# Actor input Schema

## `startUrls` (type: `array`):

One or more URLs. A store homepage (e.g. <code>https://www.allbirds.com</code>) scrapes the whole catalog, a collection/category URL (<code>/collections/mens</code>, <code>/product-category/bottles/</code>) only that category, a product URL only that product. Works with Shopify, WooCommerce and any store with schema.org Product markup.

## `mode` (type: `string`):

<b>Auto</b> (recommended) checks for the Shopify and WooCommerce product APIs and falls back to structured data. Force a mode only if auto-detection picks the wrong source.

## `maxProducts` (type: `integer`):

Maximum number of products to save for each start URL. Set to 0 for no limit (whole catalog). You pay per product, so this also caps your cost.

## `includeVariants` (type: `boolean`):

Add the list of variants (size, color... with their own ID, SKU, price and availability) to each product. Turn off for smaller rows - <code>variantCount</code> is always included.

## `maxPagesPerStore` (type: `integer`):

Only used for stores without a Shopify/WooCommerce API: the maximum number of HTML pages fetched per start URL while discovering and reading product pages. Pages without product data are free.

## `descriptionMaxLength` (type: `integer`):

Product descriptions are converted to plain text and trimmed to this many characters. Set to 0 to keep the full description.

## `proxyConfiguration` (type: `object`):

Usually not needed - Shopify and WooCommerce APIs work without a proxy. Enable Apify Proxy (residential works best) for stores that block automated requests (HTTP 403/429 or 'Just a moment...' pages).

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.allbirds.com"
    },
    {
      "url": "https://nalgene.com/product-category/bottles/"
    },
    {
      "url": "https://www.ikea.com/us/en/p/strala-led-floor-lamp-matchstick-shaped-wood-50645611/"
    }
  ],
  "mode": "auto",
  "maxProducts": 500,
  "includeVariants": true,
  "maxPagesPerStore": 200,
  "descriptionMaxLength": 1000,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `results` (type: `string`):

All scraped items in the default dataset (JSON, CSV, Excel and more via the dataset export).

## `files` (type: `string`):

Records saved in the default key-value store, e.g. the run summary.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "startUrls": [
        {
            "url": "https://www.allbirds.com"
        },
        {
            "url": "https://nalgene.com/product-category/bottles/"
        }
    ],
    "maxProducts": 20,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("openharvest/ecommerce-product-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "startUrls": [
        { "url": "https://www.allbirds.com" },
        { "url": "https://nalgene.com/product-category/bottles/" },
    ],
    "maxProducts": 20,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("openharvest/ecommerce-product-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "startUrls": [
    {
      "url": "https://www.allbirds.com"
    },
    {
      "url": "https://nalgene.com/product-category/bottles/"
    }
  ],
  "maxProducts": 20,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call openharvest/ecommerce-product-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,openharvest/ecommerce-product-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/MXznE2pGRrFe3ZJ1q/builds/BGKJf9lwFgZAidX8g/openapi.json
