Woocommerce Scraper
Pricing
$19.99/month + usage
Woocommerce Scraper
WooCommerce Scraper extracts product data from WooCommerce stores with accuracy. Collect product names, prices, SKUs, categories, images, and availability for research, monitoring, and catalog building. Ideal for eCommerce analysis and automation.
Pricing
$19.99/month + usage
Rating
5.0
(1)
Developer
Scraper Engine
Maintained by CommunityActor stats
0
Bookmarked
13
Total users
1
Monthly active users
15 hours
Issues response
15 hours ago
Last modified
Categories
Share
WooCommerce Scraper — Products, Prices, Stock and Reviews
WooCommerce Scraper reads any WooCommerce store's public Store API and returns its products as structured JSON — name, SKU, price in real currency units, stock status, average rating, review count, images, categories, tags and attributes. Switch the Resource input and the same run pulls categories, brands, tags, attributes, reviews, pages or posts instead. No login, API key or WooCommerce REST API credentials are required. Start a run below with a single store URL.
What is WooCommerce Scraper?
WooCommerce Scraper is an Apify Actor that reads a WooCommerce store's public WooCommerce Store API (/wp-json/wc/store/*) and WordPress REST API (/wp-json/wp/v2/*) and returns the results as structured JSON — one row per product, category, review, page or whichever resource you select. No WooCommerce account, REST API consumer key/secret or store login is required: it reads the same public endpoints the store's own shop page calls in a browser. It's built for competitor-pricing teams, dropshippers, catalogue researchers and AI engineers who need a store's data as clean, typed JSON rather than parsed HTML.
What WooCommerce product data is publicly available to scrape?
Any WooCommerce store running version 4.0 or newer publishes its product catalogue, taxonomy and reviews through the Store API without requiring a login. Order, customer and checkout data are never public — they sit behind the store's own wp-admin session or a WooCommerce REST API key the store owner has to issue.
| Data category | Publicly available | Restricted |
|---|---|---|
| Product listing (name, price, stock, images) | ✅ wc/store/products | — |
| Product taxonomy (categories, tags, attributes) | ✅ | Brands taxonomy only if the WooCommerce Brands plugin is installed — otherwise brands answers 200 with an empty list |
Product reviews via the Store API reviews resource | ✅ | — |
Product reviews via WordPress wp/v2/comments | ⚠️ Hidden from logged-out clients | WooCommerce filters review-type comments out of that endpoint — use resource: "reviews" instead |
Pages and posts (wp/v2/pages, wp/v2/posts) | ✅ | — |
Registered users (wp/v2/users) | ✅ on some stores | ❌ Disabled (404) on many hardened stores |
| Draft, private or trashed products | ❌ | Never exposed — the Store API only publishes what a shopper can see |
| Orders, customers, coupons, checkout | ❌ | wp-admin login or a WooCommerce REST API consumer key/secret |
WooCommerce Scraper only returns publicly visible data — what any shopper's browser already loads. Nothing behind a login wall, an admin session or a REST API key.
What data can I extract with WooCommerce Scraper?
Each product row carries identity, taxonomy and content fields alongside computed pricing, stock and rating metrics. Every value comes straight from the store's own API response — a field the store didn't send comes back null, never a guess.
🏷️ Identity, taxonomy and content fields
| Field | Description |
|---|---|
url | Product permalink |
id | WooCommerce product ID |
name | Product name (HTML entities decoded) |
slug | URL slug |
parent | Parent product ID (0 for a standalone product; the parent's ID on a variation row) |
type | simple, variable, grouped, external or variation |
variation | Variation attribute values, present on variation rows |
sku | Store-assigned SKU |
short_description / description | Rendered as Markdown, plain text or raw HTML, per the Output Format input |
categories / tags / brands / attributes | Arrays of taxonomy term objects exactly as the store publishes them |
images | Array of image objects (src, thumbnail, srcset, alt, …) |
variations | Array of variation ID/attribute pairs (expand into full rows with Include Variations) |
grouped_products | Child product IDs on a grouped product |
store / resource_type | The store URL this row came from, and the resource it was fetched under |
📊 Pricing, stock and rating fields
| Field | Description |
|---|---|
prices | Raw store object: price, regular_price, sale_price, price_range, currency_code, currency_symbol, currency_minor_unit, currency_decimal_separator, currency_thousand_separator, currency_prefix, currency_suffix |
price_value / regular_price_value / sale_price_value | The prices above divided by the store's own minor unit, as real numbers (60.0, not "60") |
currency_code | ISO currency code, flattened alongside price_value for convenience |
on_sale | true/false |
average_rating | String exactly as the store publishes it, e.g. "4.50" |
review_count | Integer, kept even when it's 0 |
is_in_stock / is_on_backorder | Stock flags |
low_stock_remaining | Units left, or null if the store doesn't publish low-stock counts |
sold_individually | true if only one unit can be bought per order |
stock_availability | { text, class } stock-status label the store shows on the page |
has_options / is_purchasable | Variable-product and purchasability flags |
add_to_cart | { minimum, maximum, multiple_of, single_text, url } order-quantity rules |
extensions | Whatever WooCommerce or third-party plugin extension blocks the store attaches (e.g. name-your-price data), or {} |
Switching Resource away from products returns categories, brands, tags, attributes, reviews, pages, posts, comments, post-categories, post-tags or users exactly as the store's own API publishes each record, with store and resource_type added to every row.
🤖 Add-on: Need data from other storefronts too?
If you're benchmarking a WooCommerce store against Shopify competitors in the same category, pair this with Shopify Products Scraper for the equivalent catalogue read on Shopify storefronts.
How does WooCommerce Scraper differ from the official WooCommerce REST API?
WooCommerce's own REST API (wp-json/wc/v3) requires the store owner to generate a consumer key and secret in WooCommerce → Settings → Advanced → REST API before a single request works, and every call must authenticate with that key pair (woocommerce.github.io, checked 2026-08-16). That makes it unusable for reading a store you don't own or administer — exactly the case for competitor research, price monitoring and market surveys.
| Feature | WooCommerce REST API (wc/v3) | WooCommerce Scraper |
|---|---|---|
| Read a store you don't own | ❌ needs a consumer key/secret the store owner issues you | ✅ reads the same public Store API a shopper's browser calls |
| Setup | Store owner generates keys; you configure Basic Auth or OAuth1.0a | Paste a store URL and run |
| Multiple unrelated stores in one run | ❌ separate key pair per store | ✅ one run, any number of URLs in startUrls |
| Published rate limit | Not published in WooCommerce's own docs | Self-paced, with automatic proxy escalation only when a store pushes back |
| Data returned | Whatever the key's scope allows, including orders and customers | Products, taxonomy, reviews and WordPress content — public storefront data only, never orders or customers |
| Output shape | Raw wc/v3 REST objects you normalize yourself | Prices pre-converted to real currency units alongside the raw store values |
Use the WooCommerce REST API when you own the store and need write access, orders or customer data. Use WooCommerce Scraper for read-only catalogue collection across stores you don't control, without asking the merchant for a key.
How to use WooCommerce Scraper
- Open WooCommerce Scraper on the Apify Store and click Try for free (or Start, if you already have it saved) to open the input form in Apify Console.
- Fill in
startUrlswith at least one store address — a bare domain (https://example.com) or a sub-directory install (https://example.com/shop) both work. - Optionally set
resource,sort,stock,category,min_price/max_priceor the other product filters to narrow what comes back. - Click Start.
- Open the run's dataset and export it as JSON, CSV, Excel, XML or HTML, or pull it through the Apify API.
How to scale to bulk product extraction
startUrls is an array — add as many store addresses as you need in one run, and each gets its own store value on every row. For a store list too long to paste in, point dev_fileupload at a hosted text or JSON file listing one URL per line (or a JSON array); its URLs are merged into the run automatically.
What can you do with WooCommerce product data?
- 💰 Competitor price monitoring — a pricing analyst schedules a daily run across rival stores and diffs
price_valueandon_saleperskuto catch markdowns as they happen. - 📦 Inventory and backorder tracking — an ops analyst watches
is_in_stock,is_on_backorderandlow_stock_remainingto see what a competitor is about to sell out of. - 🗂️ Catalogue and PIM enrichment — a catalogue manager pulls
name,description,images,categoriesandattributesto seed or refresh an internal product database. - ⭐ Review mining — a CX researcher sets
resource: "reviews"to collect rating, reviewer and review text for sentiment analysis without touching the storefront HTML. - 🤖 AI shopping-assistant / RAG pipelines — an AI engineer indexes
name,descriptionandattributesinto a vector store so an agent can answer product questions or compare SKUs across stores without re-scraping. The typed JSON output is a ready tool response for any agent framework that can call the Apify API.
How does WooCommerce Scraper handle rate limits and blocking?
Requests start with no proxy. If a store refuses a direct request, the run escalates automatically — Apify datacenter proxy first, then Apify residential proxy, retrying up to 3 times on the residential tier with a 2-second pause between attempts. Once a tier answers 200 it is kept for the rest of the run. A 4xx response that isn't a block signal (anything other than 401, 403, 407 or 429) is treated as the request's own fault and returned immediately rather than escalated, since a bigger proxy budget can't fix a bad filter value. If an endpoint answers 200 with a body that isn't valid JSON, that's reported as the store likely serving an HTML challenge page rather than silently returning an empty result. Between stores in a multi-store run, the actor pauses one second. No CAPTCHA solving is performed.
⬇️ Input
Required per schema: none — but a run needs at least one store URL in startUrls or url to produce data.
| Parameter | Required | Type | Description | Example value |
|---|---|---|---|---|
startUrls | No | array | Store home pages. A bare domain works, and a sub-directory install is kept. Fill this or url. | ["https://porterandyork.com"] |
url | No | array | Alternative to startUrls. | [] |
limit | No | integer | Max records per store (1–1000, default 10). Variations from Include Variations are returned on top of it. | 50 |
resource | No | string | products (default), categories, brands, tags, attributes, reviews, pages, posts, comments, post-categories, post-tags, users. | "products" |
include_variations | No | boolean | Also fetch every variation of the variable products found (default false). | true |
format | No | string | md (default), text or html — for description, short_description and review bodies. | "md" |
sort | No | string | date (default), modified, id, include, title, slug, price, popularity, rating, menu_order, comment_count, or "" for the store's own order. Unsupported values for the chosen resource are logged and skipped. | "price" |
order | No | string | "" (default, auto), asc or desc. Applied only when sort is supported by the resource. | "asc" |
search | No | string | Text search, run by the store. Not supported for attributes or reviews. | "steak" |
sku | No | string | Exact SKU. Products only. | "PY1261" |
rating | No | string | "" (default, any), 1–5. Products only; the Store API honours one value. | "5" |
min_price | No | integer | Minimum price, in the store's minor currency unit (1999 = 19.99 on a 2-decimal store). Products only. | 1000 |
max_price | No | integer | Maximum price, same minor-unit rule. Products only. | 5000 |
category | No | string | Comma-separated category term IDs. Run once with resource: "categories" to get them. Products only. | "21,34" |
tag | No | string | Comma-separated tag term IDs. Products only. | "12" |
product_type | No | string | "" (default, any), simple, grouped, external, variable, wbs_bundle, variation. Products only. | "variable" |
stock | No | string | "" (default, any), instock, outofstock, onbackorder. Products only. | "instock" |
featured | No | boolean | Featured products only (default false). Products only. | false |
sale | No | boolean | On-sale products only (default false). Products only. | true |
proxyConfiguration | No | object | Apify proxy settings. By default no proxy is used; the actor escalates on its own if a store refuses the direct request. | {"useApifyProxy": false} |
dev_proxy_config | No | string | Your own http(s)://user:pass@host:port proxy, used instead of the Apify proxy. SOCKS is not supported. | "" |
dev_custom_headers | No | string | Extra HTTP headers: a JSON array of {name, value}, a JSON object, or Name: value lines. | "" |
dev_custom_cookies | No | string | Extra HTTP cookies, same three accepted shapes. | "" |
dev_transform_fields | No | string | Comma-separated field paths to keep in the output, e.g. id,name,prices.price. | "" |
dev_dataset_name | No | string | Write to a named dataset instead of the default one. Masks: {ACTOR}, {DATE}, {TIME}. | "" |
dev_dataset_clear | No | boolean | Empty the named dataset above first (default false). No effect without dev_dataset_name. | false |
dev_no_strip | No | boolean | Keep null/empty-string/empty-array/empty-object fields in the output (default false). Booleans and zeros are always kept. | false |
dev_fileupload | No | string | URL of a text or JSON file holding one store URL per line, or a JSON array of URLs. | "" |
⚠️ min_price/max_price match a variable product if any of its variations falls in the range — so a 50–70 filter can return a product whose own price_value is 15. Set include_variations: true to get one row per variation with its own price if you need an exact match.
Example input
{"startUrls": ["https://porterandyork.com", "https://mercantile.wordpress.org"],"limit": 100,"resource": "products","sale": true,"stock": "instock","max_price": 5000,"sort": "price","order": "asc","include_variations": true,"format": "md","proxyConfiguration": { "useApifyProxy": false }}
⬆️ Output
Results land in the Actor's dataset as typed JSON, exportable as JSON, CSV, Excel, XML or HTML from Apify Console or via the API. Each record written to the dataset is billed once under the row_result pricing event; a store that doesn't answer, or a resource that returns no records, is never charged.
Example output
{"url": "https://porterandyork.com/product/buy-porterhouse-steak-online/","id": 15,"name": "Porterhouse Steak","slug": "buy-porterhouse-steak-online","parent": 0,"type": "variable","sku": "PY1261","short_description": "A cross between the tenderloin and the strip.","description": "Hand-cut and dry-aged porterhouse steak, USDA Prime.","on_sale": false,"prices": {"price": "6000","regular_price": "6000","sale_price": "6000","price_range": { "min_amount": "6000", "max_amount": "9500" },"currency_code": "USD","currency_symbol": "$","currency_minor_unit": 2,"currency_decimal_separator": ".","currency_thousand_separator": ",","currency_prefix": "$","currency_suffix": ""},"price_value": 60.0,"regular_price_value": 60.0,"sale_price_value": 60.0,"currency_code": "USD","average_rating": "4.50","review_count": 12,"images": [{ "id": 1234, "src": "https://porterandyork.com/wp-content/uploads/porterhouse.jpg", "alt": "" }],"categories": [{ "id": 21, "name": "Beef", "slug": "beef", "link": "https://porterandyork.com/product-category/beef/" }],"tags": [],"brands": [],"attributes": [{ "id": 1, "name": "Size", "taxonomy": "pa_size", "has_variations": true, "terms": [] }],"variations": [{ "id": 1230, "attributes": [{ "name": "Size", "value": "24-oz-usda-prime" }] }],"grouped_products": [],"has_options": true,"is_purchasable": true,"is_in_stock": true,"is_on_backorder": false,"low_stock_remaining": null,"sold_individually": false,"stock_availability": { "text": "", "class": "in-stock" },"add_to_cart": {"minimum": 1,"maximum": 9999,"multiple_of": 1,"single_text": "Add to cart","url": "https://porterandyork.com/product/buy-porterhouse-steak-online/"},"extensions": {},"store": "https://porterandyork.com","resource_type": "products"}
Other resources (categories, brands, tags, attributes, reviews, pages, posts, comments, post-categories, post-tags, users) are written to the same dataset shape-for-shape as the store's own API publishes them, with store and resource_type added to every row.
How does it work?
WooCommerce Scraper calls the same public JSON endpoints a browser loads when it visits a WooCommerce storefront — the Store API (/wp-json/wc/store/*) for products and product taxonomy, and the WordPress REST API (/wp-json/wp/v2/*) for pages, posts, comments and users. No browser is launched and no JavaScript is rendered; these are direct HTTP calls. Each store URL is normalised so both a bare domain and a sub-directory install resolve, and the chosen resource is paged with per_page/offset until your limit is reached. Requests start on a direct connection and only route through an Apify datacenter or residential proxy if the store pushes back. Only publicly visible data is ever returned — nothing behind a login. Because every WooCommerce store publishes this API in the same shape, the output schema stays the same regardless of which theme or page builder the store is running.
Integrations
WooCommerce Scraper works with the tools you already use for automation and analysis — no plugin required, since it's just an Apify Actor reachable over the standard Apify API.
Calling WooCommerce Scraper programmatically
from apify_client import ApifyClientclient = ApifyClient("<YOUR_API_TOKEN>")run = client.actor("scraper-engine/woocommerce-scraper").call(run_input={"startUrls": ["https://porterandyork.com"],"limit": 100,"resource": "products",})for item in client.dataset(run["defaultDatasetId"]).iterate_items():print(item["name"], item.get("price_value"))
Works in Go, Ruby, Node.js, cURL — any language that can make an HTTP request against the Apify API.
No-code tools (n8n, Make, LangChain)
In n8n, use the HTTP Request node pointed at the Actor's run-sync-get-dataset-items endpoint with your API token, or the dedicated Apify node if you have it installed. In Make, the Apify app's "Run an Actor" module accepts the same startUrls/resource input and returns the dataset items to the next module. In LangChain, the ApifyWrapper/Apify Actor tool can call this Actor and load its dataset directly as Document objects for a retrieval pipeline.
Is it legal to scrape WooCommerce products?
Scraping publicly available product data is generally lawful — this Actor returns only what any shopper's browser can already load from a storefront, without bypassing a login, password or paywall. Product catalogues, prices and SKUs are business/product data, not personal data, so GDPR and CCPA do not attach to this Actor's core output; the relevant framework instead is the store's terms of service and whatever database-rights protections apply to a compiled catalogue in your jurisdiction. If you set resource: "reviews", review text is content the reviewer chose to publish on the store; treat any reviewer name in it accordingly. Consult legal counsel if your use case involves bulk storage or redistribution of a store's data.
Frequently asked questions
What WooCommerce product fields does WooCommerce Scraper return?
The top fields are name, sku, price_value (with regular_price_value/sale_price_value), is_in_stock and average_rating. See What data can I extract above for the full field tables.
Does WooCommerce Scraper require a WooCommerce account or login?
No. It reads the store's public Store API and WordPress REST API exactly as a shopper's browser would — no account, consumer key/secret or store login is needed.
How many products can I extract in one run?
Up to limit per store (1–1000, default 10). Setting include_variations: true adds every variation of the variable products found on top of that number.
What happens if a product is out of stock or removed from the store?
An out-of-stock product still comes back, with is_in_stock: false, is_on_backorder set accordingly and low_stock_remaining populated if the store publishes it. A product that has been unpublished, put back into draft or trashed never appears at all — the Store API only exposes what a shopper can currently see, so there's no separate "removed" status to check for.
Can I scrape multiple WooCommerce stores at once?
Yes. Put every store URL in startUrls, or point dev_fileupload at a hosted file listing them. Each row carries its store URL so you can tell rows from different stores apart in one dataset.
Does WooCommerce Scraper work with Claude, ChatGPT and other AI agent tools?
Yes, as an HTTP endpoint any agent framework can call through the Apify API — the JSON output is typed and consistent, so it drops straight into a tool call or RAG pipeline without extra parsing.
How does WooCommerce Scraper compare to other WooCommerce scrapers?
Most WooCommerce scrapers only read the product listing. WooCommerce Scraper's resource switch also reads categories, brands, tags, attributes, reviews and the store's WordPress pages, posts and comments from the same run, and it tracks which sort and filter values each endpoint actually accepts — a request that would otherwise get an HTTP 400 from the store is detected and skipped, with a log line, instead of silently returning zero rows.
Does WooCommerce Scraper return data in a format LLMs can use directly?
Yes. Typed, normalized JSON with consistent field names across runs — no HTML parsing, no selectors. Pass it directly to an LLM, index it into a vector store, or feed it to an agent tool.
What happens when a WooCommerce store changes its theme or anti-bot setup?
The Store API and WordPress REST API this Actor reads are WooCommerce's own stable data endpoints, not the rendered storefront page, so a theme change doesn't change the output schema. No specific update turnaround is published for anti-bot changes on a store's side.
Can I use WooCommerce Scraper without managing proxies or browser infrastructure?
Yes. There's no browser to configure — requests are direct HTTP calls — and escalation through an Apify datacenter or residential proxy happens automatically if a store pushes back, with no proxy setup required unless you want to supply your own.
Which fields work best for AI training data and RAG indexing?
For RAG, index name, description and short_description as descriptive text alongside attributes and categories for structured lookups. For training data, price_value, average_rating, review_count and is_in_stock are the most consistently structured fields across every product row. All fields return as typed primitives — strings, numbers, booleans or arrays — never mixed types.
Related scrapers
| Scraper | What it extracts |
|---|---|
| Shopify Products Scraper | A Shopify store's full product catalogue: variants, SKUs, price and stock |
| Shopify Store Scraper | Store-level profile: theme, installed apps, catalogue size |
| Shopify Merchant Scraper | Store contact details, socials and tech stack |
| Alibaba Listings Scraper | Alibaba product listings: prices, MOQ, supplier details |
| Amazon Product Details Scraper | Product details from Amazon listing pages |
| eBay Product Listing Scraper | Product data from eBay search and listing pages |
Your feedback
Found a bug, or missing a field you need from a WooCommerce store? Open an issue on this Actor's Issues tab in Apify Console — that's the fastest way to reach the maintainer directly.