WooCommerce Scraper: Store API Products & Categories avatar

WooCommerce Scraper: Store API Products & Categories

Pricing

from $0.56 / 1,000 product scrapeds

Go to Apify Store
WooCommerce Scraper: Store API Products & Categories

WooCommerce Scraper: Store API Products & Categories

Scrape WooCommerce stores through the public Store API: products, prices, stock status, categories, attributes, variations and reviews. Works on any Woo store with the API enabled.

Pricing

from $0.56 / 1,000 product scrapeds

Rating

0.0

(0)

Developer

Arman Hossain

Arman Hossain

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

7 days ago

Last modified

Share

WooCommerce Store Scraper: Products, prices, stock status, categories, attributes, variations and clean descriptions from any WooCommerce store

WooCommerce Store Scraper pulls the full public catalogue from any WooCommerce store, product names, prices, stock status, categories, tags, attributes, variations, ratings, images and clean plain-text descriptions.

Every WooCommerce install ships a Store API that the storefront itself uses to render products. This Actor reads it directly: no browser, no proxies, no login. A 2,000-product catalogue returns in seconds.

This is the Store API (wc/store/v1), not the authenticated admin API (wc/v3). They are different things, the Store API is the one your storefront already exposes to the public.

Agent skill: SKILL.md

https://api.apify.com/v2/key-value-stores/t7YoTxpZEJOWvw4Ug/records/woocommerce-store-scraper.md

What you get

Output fieldMeaning
storeStore origin the record came from
productId, name, slug, permalinkIdentity and the public product URL
priceCurrent, priceRegular, priceSale, currencyPrices as real decimal numbers in the store's currency
priceMin, priceMax, isPriceRangeThe variation price span a variable product publishes, null/false when the store publishes none
onSaleWhether the store is currently discounting the product
stockStatusinstock, outofstock or onbackorder
stockQuantityUnits remaining, see the caveat below
categories, tagsSlug lists
attributesAttribute name, taxonomy and available terms
variationsVariation IDs with their attribute name/value pairs
averageRating, reviewCountReview aggregates
imagesFull-size image URLs
descriptionPlainDescription as clean plain text: HTML and page-builder shortcodes stripped, entities decoded
scrapedAtRun timestamp

A RUN_SUMMARY record in the key-value store holds per-run counts, a per-store breakdown, the filters used, and any store that failed.

Common use cases

  • Price monitoring. Track competitor pricing across dozens of independent retailers on a schedule.
  • Product comparison engines. Build a catalogue index from many small stores at once.
  • Sourcing and dropshipping. Watch stockStatus to find what is actually available.
  • Market research. Measure catalogue size, price bands and category mix across a niche.

Quick start

Two stores, everything they have:

{
"stores": ["barefootbuttons.com", "woocommerce.com"]
}

One category, in stock only, capped:

{
"stores": ["barefootbuttons.com"],
"categories": ["accessories"],
"inStockOnly": true,
"maxProductsPerStore": 200
}

Search a niche across many stores:

{
"stores": ["store-a.com", "store-b.com", "store-c.com"],
"searchQuery": "hoodie",
"maxProductsPerStore": 50
}

Input

FieldTypeDefaultNotes
storesarray-Required. Domains or URLs. Paths are stripped, paste a product page if that is what you have. shop.com, www.SHOP.com, http://shop.com and a deep URL on it are one store, scraped and charged once.
categoriesarray[]Category slugs (or numeric term IDs). Multiple values are OR-ed.
searchQuerystring""Full-text search, executed by the store.
maxProductsPerStoreinteger0Cap per store. 0 = whole catalogue.
inStockOnlybooleanfalseAsk the store for in-stock products only.

categories, searchQuery and inStockOnly all run server-side and combine with AND, so narrowing them makes the run faster as well as smaller. maxProductsPerStore is applied last, after the store has filtered.

Output example

A real record, description trimmed:

{
"store": "https://barefootbuttons.com",
"productId": 1475,
"name": "Replacement Set Screw and Allen Wrench Kit",
"slug": "replacement-set-screw-and-allen-wrench-kit",
"permalink": "https://barefootbuttons.com/product/replacement-set-screw-and-allen-wrench-kit/",
"priceCurrent": 1.95,
"priceRegular": 1.95,
"priceSale": null,
"priceMin": null,
"priceMax": null,
"isPriceRange": false,
"currency": "USD",
"onSale": false,
"stockStatus": "instock",
"stockQuantity": null,
"categories": ["accessories"],
"tags": [],
"attributes": [
{
"name": "Set Screw Size",
"taxonomy": null,
"terms": [
"For V1/V2 Mini and V1/V2 Tallboy Mini",
"For V1/V2 Standard, V1/V2 Standard Skirtless & V1/V2 Tallboy",
"For Big Bore Standard, Big Bore Standard Skirtless, Big Bore Tallboy & Max Bore"
]
}
],
"variations": [
{ "id": 1485, "attributes": [{ "name": "Set Screw Size", "value": null }] }
],
"averageRating": 0,
"reviewCount": 0,
"images": ["https://barefootbuttons.com/wp-content/uploads/2026/06/set-screws-allen-wrench-prodcut.png"],
"descriptionPlain": "Every Barefoot Button includes the hardware needed for installation, but sometimes extra parts come in handy.…",
"scrapedAt": "2026-08-11T12:37:30.056Z"
}

This store publishes no value for the variation's attribute, so value is null rather than a guess — see the note on honest nulls below.

A variable product carries its span instead:

{
"productId": 55151,
"name": "Chasing Tone Unisex T-Shirt",
"priceCurrent": 19,
"priceRegular": 19,
"priceMin": 19,
"priceMax": 21,
"isPriceRange": true,
"currency": "USD"
}

API example

curl -X POST "https://api.apify.com/v2/acts/arman-bd~woocommerce-store-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"stores": ["barefootbuttons.com"],
"inStockOnly": true,
"maxProductsPerStore": 100
}'

JavaScript example

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('arman-bd/woocommerce-store-scraper').call({
stores: ['barefootbuttons.com', 'woocommerce.com'],
inStockOnly: true,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const p of items) console.log(`${p.name}, ${p.priceCurrent} ${p.currency} (${p.stockStatus})`);

Limits and behaviour

  • Prices are converted, not copied. The Store API returns money as an integer string in the currency's minor unit ("5900" with currency_minor_unit: 2). This Actor divides it out, so priceCurrent is 59 and not 5900.
  • stockQuantity is usually null, and that is correct. The Store API never publishes an exact inventory figure. The only quantity it exposes is low_stock_remaining, which the store fills in only once its low-stock threshold is crossed. A number here is real; null means the store did not publish one. Nothing is estimated.
  • Bad stores don't kill the run. A site without the Store API, a DNS failure or a WAF block is recorded in RUN_SUMMARY.failures; the Actor only errors out if every store fails.
  • HTML 404 pages are rejected. Many WordPress hosts answer /wp-json/wc/. with a themed 404 page. The response content type is checked, so a 200-status HTML page is treated as "no Store API", not as data.
  • Transient errors are retried. 429, 5xx and network faults get three attempts with exponential backoff and a 30-second timeout.
  • Pagination is read, not guessed. Page count comes from the x-wp-totalpages response header.
  • One store is one store. shop.com, www.shop.com, HTTP://SHOP.COM and a pasted deep URL all collapse to the same origin, so a list that names the same shop several ways is fetched once and billed once.
  • Descriptions are prose, not layout. Page builders such as Divi store their whole layout as [shortcode] blocks inside the description, and <style>/<script> blocks hide CSS and JS there too. All of that is removed and only the text it wraps is kept.
  • Public data only. No authentication, no personal data, no access-control bypass.

FAQ

Do I need WooCommerce API keys? No. You supply no credentials.

Why did a store return nothing? Either the Store API is disabled or firewalled, or your filters matched no products. RUN_SUMMARY.stores carries one { store, matched, saved } entry per store — the store's own match count next to the saved count — which separates the two. A store that failed outright is also listed in RUN_SUMMARY.failures with the reason.

How do I find a category slug? Open a category page on the store, /product-category/accessories/ means the slug is accessories. Numeric term IDs work too.

Does it include variation prices? Not one price per variation, no. variations carries each variation's ID and attribute values, and the store publishes the span those variations cover as a range on the parent — that arrives as priceMin, priceMax and isPriceRange. When isPriceRange is true, priceCurrent is the cheapest variation, not the whole story.

Can I schedule it? Yes, it is designed for scheduled runs. Diff on productId plus priceCurrent to build a price-history feed, and include priceMax so a variable product's top price is not invisible.

Can I integrate it with something else? Yes, Apify API, client libraries, webhooks, scheduled runs, dataset exports (JSON/CSV/Excel) or MCP. Output is structured JSON.