# E-commerce Product Scraper - Any Store (Structured Data) (`plotpointtech/ecommerce-product-scraper-any-store`) Actor

- **URL**: https://apify.com/plotpointtech/ecommerce-product-scraper-any-store.md
- **Developed by:** [Plot Point Technologies](https://apify.com/plotpointtech) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.62 / 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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## E-commerce Product Scraper - Any Store (Structured Data)

Get clean, consistent product data from online stores you choose: name, brand, SKU, GTIN/barcode, MPN, price, sale price, currency, availability, condition, variants, rating and review count, images, category and breadcrumbs, description and seller. Paste product pages, category pages, a store's home page or a sitemap URL. The scraper finds the products and returns one row per product in the same format for every store.

### How it works

Most online stores publish machine-readable product data in their pages so search engines and shopping services can show prices and stock. This tool reads that standard data instead of guessing from page layouts. That makes it work across platforms without per-site setup:

- **schema.org Product data** in JSON-LD, microdata or RDFa, including offers, aggregate offers, product groups and variants
- **Open Graph product tags** (`product:price:amount`, `product:availability` and similar) as a fallback and to fill gaps
- **Shopify fast path**: the public `products.json` feed and product `.js` endpoints give every variant with its SKU, barcode, price, compare-at price and stock
- **WooCommerce fast path**: the public WooCommerce Store API gives prices, sale prices, stock, categories and ratings

The platform is detected automatically: Shopify, WooCommerce, BigCommerce, Magento (Adobe Commerce), Salesforce Commerce Cloud, PrestaShop, Shopware, Wix, Squarespace and others. Stores on custom platforms also work when they publish schema.org product data, and most large retailers do.

### What you can paste

| Input | What happens |
|---|---|
| Product page URL | One product from that page |
| Category / collection page URL | Product links on the page are found and each product is scraped. Next-page links are followed up to "Max pages per category" |
| Store home page | Shopify and WooCommerce stores: the product feed. Other stores: the product sitemap, then links on the home page |
| Sitemap URL (.xml, .xml.gz, sitemap index) | Product URLs from the sitemap; product sitemaps are preferred |

### Input

| Field | Default | Description |
|---|---|---|
| Store URLs | 2 sample product pages | Any mix of product, category, home page and sitemap URLs from any stores |
| Max products per category / store URL | 20 | Limit for each category, home page or sitemap URL |
| Max products in total | 0 (no limit) | Limit for the whole run |
| Max pages per category | 5 | Pagination depth for category pages |
| Include variants | on | Variant list (options, SKU, GTIN, price, stock) inside each product row |
| Use Shopify / WooCommerce fast paths | on | Read the platforms' public product feeds |
| Browser rendering | fallback | `fallback` renders a page in a headless browser only when plain HTTP finds no product data or product links; `always` renders every page; `never` uses plain HTTP only. Browser pages have an extra charge (see Pricing). 2 GB memory or more is recommended for heavy browser use |
| Track price changes | off | Compare with the previous run and flag changes |
| Price history store name | product-price-history | Named key-value store that keeps the previous prices |
| Output only new or changed products | off | With tracking on, skip unchanged products (they are not charged) |
| Description length | 2000 | Characters kept from each description (0 = no limit) |
| Parallel requests | 5 | Overall concurrency (maximum 10) |
| Minimum delay per store | 0.4 s | Gap between requests to the same store |

### Output

One row per product:

`url`, `storeDomain`, `storeName`, `platform`, `name`, `brand`, `sku`, `gtin`, `mpn`, `productId`, `price` (the current price you would pay), `salePrice` and `regularPrice` (filled when the product is discounted), `onSale`, `discountPercent`, `currency`, `priceMin` / `priceMax` (range across variants or offers), `availability` (schema.org value such as InStock, OutOfStock, PreOrder, BackOrder), `inStock`, `condition`, `variantCount`, `variants` (name, options, sku, gtin, price, regularPrice, availability, url, image), `rating`, `reviewCount`, `imageUrl`, `images`, `category`, `breadcrumbs`, `description`, `seller`, `tags`, `dataSources` (where the values came from), `renderedWithBrowser`, `scrapedAt`.

With price tracking on, each row also has `isNew`, `previousPrice`, `priceChanged`, `priceChange`, `priceChangePercent`, `previousAvailability`, `availabilityChanged` and `previousScrapedAt`.

Example (shortened):

```json
{
  "url": "https://www.revzilla.com/motorcycle/arai-regent-x-helmet",
  "storeDomain": "revzilla.com",
  "platform": null,
  "name": "Arai Regent-X Helmet",
  "brand": "Arai Helmets",
  "price": 659.95,
  "currency": "USD",
  "availability": "InStock",
  "variantCount": 42,
  "rating": 4.6,
  "reviewCount": 232,
  "category": "Vehicles & Parts > Vehicle Parts & Accessories > ... > Motorcycle Helmets",
  "breadcrumbs": ["Home", "Helmets", "Full Face"],
  "dataSources": ["json-ld"]
}
```

### Typical uses

- **Competitor price monitoring**: schedule a daily run on competitors' category pages with price tracking on and "Output only new or changed products", then send changes to Google Sheets, Slack or a webhook.
- **Catalog and feed building**: collect GTINs, SKUs, brands and images from supplier or brand sites to match products across retailers.
- **MAP and reseller checks**: brands can watch how their products are priced and stocked on retailer sites.
- **Market research**: compare assortments, price ranges and ratings across stores in a niche.

### Pricing

You pay per product saved, with lower prices on higher Apify plans. Pages that have to be opened in a headless browser have a separate **Browser-rendered page** charge, added to the product price. A browser costs far more to run than a plain request. The browser charge applies only when:

- Browser rendering is `fallback` (the default) **and** plain HTTP found no product data or product links on a page, or
- Browser rendering is `always` (every page is rendered and charged).

Most stores publish their product data in the plain HTML, so with the default setting most runs have no browser charges. Set Browser rendering to `never` to rule them out completely. Pages that fail, are blocked or are skipped by robots.txt are not charged as products. A browser-rendered page is charged even when it turns out to have no product. The log lists how many pages were rendered in a browser.

### Price tracking

When "Track price changes" is on, the last seen price and availability of every product are stored in a named key-value store in your Apify account. A later run with the same store name compares against it. Run the same input on a schedule to build a change feed. Use different store names for separate watch lists.

### Notes and limits

- The scraper follows each store's robots.txt, including crawl delays, identifies itself with a bot user agent and paces requests per store. It does not use proxies to get around blocking, does not log in and does not solve CAPTCHAs. Stores that block automated requests (HTTP 403 or bot challenges) are skipped and listed in the log.
- Shopify limits storefront requests per IP. The scraper keeps a gentle shared pace for all Shopify stores, waits as instructed when rate-limited and falls back to product pages.
- Data quality depends on what each store publishes. Some fields (GTIN, MPN, ratings, condition) are only filled when the store includes them. Prices are what the page shows to a visitor without a login, in the store's default currency and region.
- Pages with too little product data (no price, SKU or availability) are skipped and not charged. A failing page never stops the run.
- Marketplaces whose terms forbid scraping (for example Amazon or eBay) are not a target for this tool. Use it on stores you are allowed to collect public data from.

Plot Point Technologies is not affiliated with Shopify, WooCommerce, BigCommerce, Adobe (Magento) or any store you scrape.

# Actor input Schema

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

Any mix of: product page URLs, category / collection page URLs, store home pages (the whole catalog is found through the store's product feed or sitemap), or sitemap URLs (.xml).

## `maxProductsPerStartUrl` (type: `integer`):

For category pages, store home pages and sitemaps: stop after this many products. A product page URL always gives one product.

## `maxResults` (type: `integer`):

Stop the whole run after this many products. You can also cap spending with the run's maximum cost.

## `maxListingPages` (type: `integer`):

How many pages of a category to follow (next-page links) when collecting product links.

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

Add the list of variants (size, color...) with their own SKU, GTIN, price and stock, when the store exposes them. Variants stay inside the product row (no extra charge).

## `usePlatformApis` (type: `boolean`):

On Shopify and WooCommerce stores, read the public product feeds these platforms publish (products.json, product .js, WooCommerce Store API). Faster and more complete (all variants, compare-at prices, stock).

## `renderJavaScript` (type: `string`):

Some stores add product data with JavaScript. 'Fallback' opens a page in a headless browser only when plain HTTP finds no product data and no product links. Each page rendered in a browser is charged as a separate 'Browser-rendered page' event on top of the product price. Choose 'Never' to avoid browser charges.

## `trackPriceChanges` (type: `boolean`):

Remember each product's price in a named key-value store and add previousPrice, priceChanged, priceChange, priceChangePercent and availabilityChanged on the next run. Schedule the same input to monitor prices.

## `priceHistoryStoreName` (type: `string`):

Named key-value store that keeps the previous prices. Use a different name for each separate watch list.

## `outputOnlyChanges` (type: `boolean`):

With price tracking on: only save products that are new, or whose price or availability changed since the last run. Unchanged products are not saved and not charged.

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

Cut product descriptions to this many characters (0 = no limit).

## `maxConcurrency` (type: `integer`):

Pages fetched at the same time across all stores. Each store is still paced individually and its robots.txt crawl delay is honored.

## `minDelayPerSiteSecs` (type: `number`):

Minimum gap between two requests to the same store.

## Actor input object example

```json
{
  "startUrls": [
    "https://cutterbuck.com/baltimore-orioles-stretch-oxford-shirt/",
    "https://www.zumiez.com/dravus-monarch-black-t-shirt.html"
  ],
  "maxProductsPerStartUrl": 20,
  "maxResults": 0,
  "maxListingPages": 5,
  "includeVariants": true,
  "usePlatformApis": true,
  "renderJavaScript": "fallback",
  "trackPriceChanges": false,
  "priceHistoryStoreName": "product-price-history",
  "outputOnlyChanges": false,
  "descriptionMaxLength": 2000,
  "maxConcurrency": 5,
  "minDelayPerSiteSecs": 0.4
}
```

# Actor output Schema

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

No description

# 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": [
        "https://cutterbuck.com/baltimore-orioles-stretch-oxford-shirt/",
        "https://www.zumiez.com/dravus-monarch-black-t-shirt.html"
    ],
    "maxProductsPerStartUrl": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("plotpointtech/ecommerce-product-scraper-any-store").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": [
        "https://cutterbuck.com/baltimore-orioles-stretch-oxford-shirt/",
        "https://www.zumiez.com/dravus-monarch-black-t-shirt.html",
    ],
    "maxProductsPerStartUrl": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("plotpointtech/ecommerce-product-scraper-any-store").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": [
    "https://cutterbuck.com/baltimore-orioles-stretch-oxford-shirt/",
    "https://www.zumiez.com/dravus-monarch-black-t-shirt.html"
  ],
  "maxProductsPerStartUrl": 20
}' |
apify call plotpointtech/ecommerce-product-scraper-any-store --silent --output-dataset

```

## MCP server setup

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

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/aoFItB6sZjfmNqezq/builds/ari0KVCdGb8U55Vlt/openapi.json
