WooCommerce Product Catalog Data Scraper
Pricing
from $0.70 / 1,000 products
WooCommerce Product Catalog Data Scraper
Export public WooCommerce Store API products with prices, currency units, stock, categories and variation metadata from permitted stores, without API keys.
Pricing
from $0.70 / 1,000 products
Rating
0.0
(0)
Developer
Tim Zinin
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Export public WooCommerce products into JSON with prices, currency units, stock, categories and embedded variation metadata. Supply the permitted store origins, choose a product cap, and receive complete parent products plus separate explanations for incomplete catalog scope.
Evidence status (2026-09-06). The actor was built on the Apify platform (build CXiwdnltwsFej57Y1), its pay-per-event tariff was read back from the platform, and three private acceptance runs on Apify infrastructure against the reviewed Porter & York Store API produced the rows shown in R6: two complete products with a free scope notice, one product under maxProductsPerStore=1, and a duplicate store origin processed once. The empty and rate-limited examples remain clearly labelled synthetic response fixtures.
R1. What you get
- Public parent products with stable store and product identity, names, SKUs and permalinks.
- Raw price strings with the currency code and minor-unit scale actually returned by the store.
- A stock boolean, public category metadata and embedded variation identities and attributes.
- Optional description fields from the JSON API, with no page crawling or browser rendering.
- Pagination through the Store API's reported page count, bounded by your per-store product cap.
- Complete product rows that remain usable when a later page fails, with separate free partial notices.
The collection comes from the public keyless Store API. The Actor neither requires nor accepts a WooCommerce consumer key. It does not use the authenticated administration API. Product permalinks are evidence fields, not instructions to fetch those pages. Links, images and plugin-generated endpoints embedded in a response do not expand the scope of a run.
R2. Who uses it
Store owners can export a small public catalog sample to check an integration, inspect how currency units appear in the Store API, or prepare a permitted product feed for a partner. Agencies can run the same bounded contract against several client stores that have authorized the work. A PIM or warehouse team can retain the public product snapshot alongside its own internal catalog identifiers.
The buyer chooses an allowlist of store origins and remains responsible for permission to process their catalogs. Entering a URL does not create a license to reuse descriptions or other copyrighted content. The default store has a documented access review; another store may have different conditions, robots rules, API availability or custom behavior. The runtime enforces the selected origin and robots boundary, while the operator must establish applicable content rights.
This product is appropriate when the public storefront representation is the evidence you need. It cannot substitute for private inventory, order management, customer records, administrator product metadata or authenticated wholesale prices. Those systems require separate authorized access and a different contract. A public inStock value is not the number of items available for a particular order.
R3. How to run
- Use the prefill for a two-product smoke test, or enter up to three permitted store origins such as https://your-store.example.
- Keep maxProductsPerStore small for the first run. Increase it only after checking the output mapping and the store's permissions.
- Leave includeDescriptions false unless you need the additional API HTML strings and have appropriate reuse rights.
- Start the Actor and inspect the product rows, any free catalog notice and OUTPUT.partial together.
- Import complete product rows by the pair storeUrl and productId. Route source errors and partial scope to an operational branch.
Provide an origin, not a shop page, product page or full API endpoint. A trailing slash is normalized, but a path, query or fragment is rejected. The Actor constructs the fixed products endpoint itself. Stores installed under a subdirectory are outside this input contract; the Actor does not discover a WordPress installation path by scraping HTML.
A redirect to another origin is refused even when both origins appear in input. Use the actual final permitted origin as a separate source after verifying its access basis. Do not rely on HTTP-to-HTTPS or www-to-apex redirects to silently widen a run. This preserves a clear association between the store you requested and the store whose product identity you are importing.
R4. Pricing
The tariff is $0.003 per start + $0.001 per complete parent product, read back from the platform on 2026-09-06 (apify-actor-start $0.003, result-found $0.001, model PAY_PER_EVENT). The prefill's two products produce $0.005 at this rate, including one start event at the default 256 MB setting. Ten, 100 and 300 complete parent products in one run would produce $0.013, $0.103 and $0.303. These are tariff calculations, not observed platform charges or compute-cost measurements.
Platform evidence for the tariff above (charged event counts of the accepted runs): two products xND9QpajxcVnBoo2l result-found: 2; maxProductsPerStore=1 bQAH03VPyCVVXqUVe 1; duplicate store origin aUkSVGAXWdtRbXSrd 2; the free limit notices were not charged. The start event is charged once per GB of run memory: the acceptance runs were started with 4096 MB and therefore show apify-actor-start: 4, while a run at the default memory pays one start unit per GB.
One product row can contain several categories and embedded variations without adding a charge per child item. This version does not fetch or sell separate variation-price rows. A zero-price product can still be a complete billable catalog result: the merchandise's price and the Actor's extraction price are different quantities.
A clean empty catalog, exhausted 429, HTML shell, malformed JSON, source error or output limit emits no result-found event for its explanatory row. A nonzero start event can still apply to a run that returns no products. Products fully delivered before a later page failure or catalog cap remain billable; the free notice describes the missing scope and does not reverse those completed units.
Automatic dataset-item pricing must be absent or zero. The Actor checks pricing before writing and fails closed when the supposedly free channel could be charged. Budget is checked under the same lock as the linked result write. The last paid product is counted before stopping at a budget boundary. Separate runs have no shared replay ledger and can bill the same product again.
R5. Input contract
| Field | Default | Contract |
|---|---|---|
| storeUrls | ["https://porterandyork.com"] | 1–3 public WooCommerce origins you are entitled to process. This list is the run allowlist. No path, query, login, cart or checkout access. |
| maxProductsPerStore | 2 | 1–100 unique parent products per store. Complete products remain billable; further scope is a free partial notice. |
| includeDescriptions | false | Include API description and short_description as untrusted HTML strings; no HTML page fallback or rendering. |
{"storeUrls": ["https://porterandyork.com"],"maxProductsPerStore": 2,"includeDescriptions": false}
The runtime rejects unknown properties, invalid booleans, numeric strings in place of integers and explicit null values. It validates the input array length before normalizing duplicates. storeUrls has one through three entries, and maxProductsPerStore has one through 100. The maximum requested product count is therefore 300, but time, response-size and budget limits can stop work earlier.
Origins use HTTP or HTTPS without credentials or a nonstandard port. DNS checks reject private and local addresses before the connection. Every source request remains within the current input origin, and only robots.txt plus the fixed products collection route are allowed. The Actor never requests cart, checkout, customers, orders, reviews or arbitrary REST routes.
The page size is the smaller of 20 and maxProductsPerStore. The page number starts at one and advances according to X-WP-TotalPages. The Actor does not follow a source-provided Link header; it constructs each page URL under the same source origin. X-WP-Total is retained when provided, while missing or malformed required page counts produce an error instead of pretending the first page was the full catalog.
Products are deduplicated by ID within each store during a run. Two stores can legitimately have the same numeric product ID, so global deduplication by ID alone would lose data. Repeating the exact same origin with and without a trailing slash does not create another source task. A different scheme or hostname is a different origin and must be reviewed as such.
R6. Accepted platform run examples and fixture examples (2026-09-06)
Input of the accepted platform run xND9QpajxcVnBoo2l (identical to the build-time probe):
{"storeUrls": ["https://porterandyork.com"],"maxProductsPerStore": 2,"includeDescriptions": false}
Accepted platform rows (run xND9QpajxcVnBoo2l, maxProductsPerStore=2): two paid products and the free scope notice, unedited:
[{"input": "https://porterandyork.com","sourceUrl": "https://porterandyork.com/wp-json/wc/store/v1/products?per_page=2&page=1","found": true,"status": "ok","resultCount": 1,"partial": false,"error": "","warnings": [],"checkedAt": "2026-09-05T21:12:08.156Z","schemaVersion": "1.0","storeUrl": "https://porterandyork.com","productId": 63635,"type": "simple","name": "Organic Diestel Whole Turkey 12 – 14lb","sku": "PY6020","permalink": "https://porterandyork.com/product/whole-turkey-12-14lb/","prices": {"price": "115","currencyCode": "USD","currencyMinorUnit": 0},"inStock": false,"categories": [{"id": 591,"name": "Poultry","slug": "poultry"},{"id": 17,"name": "Chicken","slug": "buy-chicken-online"}],"variations": [],"variationPricesAvailable": false,"page": 1,"totalProducts": 69,"totalPages": 35},{"input": "https://porterandyork.com","sourceUrl": "https://porterandyork.com/wp-json/wc/store/v1/products?per_page=2&page=1","found": true,"status": "ok","resultCount": 1,"partial": false,"error": "","warnings": [],"checkedAt": "2026-09-05T21:12:08.156Z","schemaVersion": "1.0","storeUrl": "https://porterandyork.com","productId": 63346,"type": "simple","name": "31/40 Shrimp – 2LB","sku": "PY5460","permalink": "https://porterandyork.com/product/31-40-shrimp-2lb/","prices": {"price": "24","currencyCode": "USD","currencyMinorUnit": 0},"inStock": true,"categories": [{"id": 16,"name": "Seafood","slug": "buy-seafood-online"}],"variations": [],"variationPricesAvailable": false,"page": 1,"totalProducts": 69,"totalPages": 35},{"input": "https://porterandyork.com","sourceUrl": "https://porterandyork.com/wp-json/wc/store/v1/products?per_page=2&page=1","found": false,"status": "limit_exceeded","resultCount": 0,"partial": true,"error": "maxProductsPerStore=2 reached; complete delivered parent products remain billable","warnings": [],"checkedAt": "2026-09-05T21:12:08.335Z","schemaVersion": "1.0","storeUrl": "https://porterandyork.com","productCount": 2,"totalProducts": 69}]
Synthetic empty fixture input and observed processInput output:
{"input": {"storeUrls": ["https://porterandyork.com"],"maxProductsPerStore": 2,"includeDescriptions": false},"rows": [{"input": "https://porterandyork.com","sourceUrl": "https://porterandyork.com/wp-json/wc/store/v1/products?per_page=2&page=1","found": false,"status": "not_found","resultCount": 0,"partial": false,"error": "","warnings": [],"checkedAt": "2026-09-05T19:41:38.005Z","schemaVersion": "1.0","storeUrl": "https://porterandyork.com","productCount": 0,"totalProducts": 0}]}
Synthetic rate-limited fixture input and observed processInput output:
{"input": {"storeUrls": ["https://porterandyork.com"],"maxProductsPerStore": 2,"includeDescriptions": false},"rows": [{"input": "https://porterandyork.com","sourceUrl": "https://porterandyork.com/wp-json/wc/store/v1/products?per_page=2&page=1","found": false,"status": "rate_limited","resultCount": 0,"partial": false,"error": "http 429 after bounded retries","warnings": [],"checkedAt": "2026-09-05T19:41:38.013Z","schemaVersion": "1.0","storeUrl": "https://porterandyork.com","productCount": 0}]}
The accepted platform run xND9QpajxcVnBoo2l reported 69 products in the store (the build-time local probe saw 35 pages at per_page=2). It returned two complete simple products, then the Actor emitted a free limit notice because more catalog scope remained. The product rows have partial=false; OUTPUT.partial=true describes the incomplete catalog. This distinction lets an importer use the delivered products without representing them as the entire store.
The observed USD currencyMinorUnit was zero. The raw values "115" and "24" therefore mean 115 and 24 units at that source's reported scale. Do not force every USD value to two decimals when decoding a Store API response. Store settings or plugins can affect the representation, and the result preserves the source's explicit unit instead of assuming a currency convention.
The empty, rate-limited and byte-limit examples below the platform rows use saved injected responses. They exercise status routing without claiming that the reviewed production store is empty or rate-limited. A corresponding real empty-store platform golden remains a release acceptance item; an arbitrary mock endpoint is not accepted by the production Actor merely to manufacture that evidence.
R7. Field dictionary
| Field | Meaning and use |
|---|---|
| storeUrl | Normalized input origin and the first half of the product identity. |
| productId | Positive integer parent-product ID, unique only within a store. |
| type | Store API product type such as simple or variable, preserved from the response. |
| name | Public product name string; source HTML entities can remain encoded. |
| sku | Source SKU string, including an empty SKU or leading zeros. |
| permalink | Public product URL supplied by the API; retained as evidence and not fetched. |
| prices.price | Nonnegative integer string in the source's reported minor units. Zero stays "0". |
| prices.currencyCode | Source currency code, retained with the raw amount. |
| prices.currencyMinorUnit | Decimal scale from the source; use it when formatting the raw price. |
| inStock | Public stock boolean, not a stock count, reservation or checkout guarantee. |
| categories | Embedded category id, name and slug values; one category does not create another paid product. |
| variations | Embedded variation IDs and name/value attributes; no separate variation endpoint is queried. |
| variationPricesAvailable | False: this output does not provide separate variant prices. |
| description | Optional API description HTML string when includeDescriptions is true. |
| shortDescription | Optional API short_description HTML string under the same option. |
| page | One-based API page that supplied the product. |
| totalProducts | X-WP-Total if supplied, otherwise null on a complete product. |
| totalPages | X-WP-TotalPages reported on the page supplying the product. |
| sourceUrl | Actual validated products URL used for the response. |
| found and resultCount | A complete product row carries found=true with resultCount 1; free explanation rows carry found=false with resultCount 0. |
| partial | Whether this row is incomplete; catalog-wide incompleteness is also recorded in OUTPUT. |
| checkedAt | UTC observation time of the parsed product, not its publication or modification date. |
| warnings | Explicit limitations, including missing per-variation prices for variable products. |
| status / error | Outcome and explanation; clean absence uses not_found with an empty error string. |
| schemaVersion | This output contract's version, currently 1.0. |
Treat monetary values as integer strings plus an explicit scale. For exact arithmetic, use an integer or decimal library rather than converting a large string to a JavaScript Number. A display formatter can split the string according to currencyMinorUnit, pad leading fractional zeros and add a presentation symbol. Store the unformatted string and code so the displayed form can be changed without losing evidence.
The Actor does not calculate taxes, shipping, discounts for a logged-in customer or exchange rates. A storefront price is an observation, and actual checkout behavior can depend on context. Do not present the exported price as a binding offer or an all-in order quote. If a destination needs those values, obtain them through a separate permitted workflow designed for that purpose.
Variation metadata is deliberately narrow. An embedded ID and attribute combination can help link a parent product to a local variation table, but it does not establish a complete priced SKU matrix. An empty variations array does not prove that no optional configuration exists elsewhere in the store. Use the warning and variationPricesAvailable fields to prevent a downstream UI from inventing prices from a parent value.
Descriptions remain source strings. They can contain markup, links or text that looks like an instruction. The Actor does not render that markup, download linked assets or execute scripts. If you display descriptions in a web application, sanitize according to your own rendering policy. If you send them to an LLM, keep them in a data boundary rather than treating them as commands.
The name and description fields are not normalized into plain text. The live example contains an encoded dash entity in a product name. A destination may decode entities for display, but retain the original value when auditability matters. A display transformation should not be confused with a source change when comparing snapshots.
R8. Evidence and boundaries
The reviewed default uses the documented public Store API, a robots file whose wildcard group does not prohibit /wp-json, and terms reviewed by Claude on 5 September 2026 with no automated-access ban found. The actual wildcard exclusions are /wp-login.php, /cart/, /checkout/, /add-to-cart=, /my-account/, /size/* and /rl_gallery/. These facts apply to this reviewed origin at the review time; they are not a blanket permission for every WooCommerce site.
The runtime checks robots for each selected origin. A disallowed products route stops retrieval. A missing robots file is handled separately from a network failure or HTML shell in place of robots. A positive Crawl-delay is respected along with the minimum one-second request spacing. A store's API or access rules can change after this manual was written, in which case the correct outcome may be a free error.
Each response is limited to 2 MB and each projected product to 1 MB. Total downloads, request reservations, pages and the working deadline are bounded. A too-large description can therefore make a product page yield a free limit even if includeDescriptions is requested intentionally. Reduce scope or leave descriptions off when the destination does not require them.
A JSON response with missing required product identity, invalid price units, inconsistent page counts or the wrong collection shape is an error. A 200 HTML landing page is an error. A 404 for a disabled Store API is an error. Only a valid empty array with consistent collection counts represents a clean empty catalog. These distinctions prevent a storefront outage from erasing your destination catalog.
Complete products remain useful if a later page is unavailable. The error row includes the number already delivered and partial=true. If every store fails before delivering any product, the run's fatal value is All stores failed. A documented limit-only result stays nonfatal. A mixed limit and real source failure also stays nonfatal at run level, with the failure still explicit on its individual row.
R9. Decision routing
| Outcome | Next step |
|---|---|
| Complete product | Upsert by storeUrl plus productId after validating your mapping. |
| Product with variation warning | Import parent metadata; avoid generating a priced variation feed from absent variant prices. |
| Clean not_found | Confirm that an empty public catalog is expected before any destructive synchronization. |
| Free catalog cap | Keep delivered products and record that the store scope is incomplete. |
| Rate limit or source failure | Retain the previous destination snapshot and retry later under a bounded schedule. |
| HTML shell or invalid JSON | Ask the store operator to verify the public Store API and any security/plugin layer. |
| Robots refusal | Stop access and have the authorized store operator resolve the access policy. |
| Budget exhaustion | Continue only the remaining planned scope in a new appropriately capped run. |
A product missing from a two-product sample is simply outside that sample. It is not evidence of deletion, unavailability or a discontinued SKU. Require a complete catalog run, stable identity mapping and full dataset ingestion before using absence as a change signal. Even then, confirm that upstream pagination did not move records while you were collecting pages.
R10. Commercial playbooks
Check a client catalog integration
Start with two products from a permitted client store. Verify the identity key, raw price, scale, stock boolean and source URL in the destination. Include a product with a zero price and a variable product in a controlled fixture test before trusting a generic mapping. A live sample containing two simple products does not test every WooCommerce product type.
Keep the first run's JSON and the destination representation together as a mapping baseline. If a plugin update changes currencyMinorUnit or a field's shape, stop automatic merging until the mapping is reviewed. A schema failure is more useful than silently converting malformed source values into zeros or empty strings.
Export a partner's public product feed
Agree on the permitted store scope and the fields the partner actually needs. Leave descriptions off unless they are required and licensed for reuse. Use a stable store-plus-product key when generating the feed so an update changes an existing record instead of creating duplicates. Carry checkedAt and sourceUrl into the partner metadata to identify the observation behind each value.
Do not include arbitrary source plugin extensions merely because the API returns them. This Actor projects a narrow public catalog contract. A requested private or custom field should be evaluated separately for access, semantics and data rights before a future version includes it.
Reconcile a PIM with storefront evidence
Join complete public products against a PIM mapping table using storeUrl and productId or an explicitly maintained SKU mapping. Flag mismatches in displayed name, price representation or stock state for review. Do not automatically overwrite private inventory values with a public storefront boolean. The two systems can describe different scopes and update on different schedules.
When a run is partial, constrain reconciliation to the products actually observed. Keep an evidence record for each proposed change and let the PIM's own policy decide whether it should be applied. The Actor reports observations; it neither edits the store nor sends changes to a partner system.
Monitor a small permitted catalog over time
Schedule a bounded run at a frequency that matches useful source changes. Store the run ID and observation time with each complete product. Compare by identity and retain both old and new values for a review queue. Repeated runs may bill the same products again, so use the smallest permitted scope that answers your operational question.
A paginated live catalog is not a transactional snapshot. Products added or reordered during a run can cause duplicates or movement between pages. The Actor removes repeated parent IDs within a store, but that cannot prove that no item moved past a page boundary. Avoid strong deletion claims from a single observation, especially when the summary is partial.
R11. Integration recipes
Run once from the Apify Console
Start with the supplied prefill and inspect the resulting dataset before connecting a production destination. The Input tab is a form for the documented input object. Unknown properties are rejected by the runtime even if a client permits sending them. Keep the first run small enough that a human can inspect every result. Export JSON when the result includes arrays or objects: a spreadsheet export is useful for an overview, but a nested value in one CSV cell is not a normalized relational table.
After the run, inspect the run state, the dataset and the OUTPUT summary together. A dataset can contain useful rows even when the run later fails. A successful run can contain a documented free limit notice. A nonempty dataset alone therefore cannot drive a success notification. For a full import, require a clean source status, the expected identity fields, the expected schemaVersion, and a summary that accounts for every requested input. For an incremental import, keep complete rows and separately route incomplete work for review.
Call the asynchronous API
Use the Actor API documentation shown in the Console to copy the current endpoint for this Actor. Send a JSON input body to the run endpoint, authenticate through the Authorization header, and retain the returned run ID before waiting for completion. A run may take longer than a short HTTP client timeout. Poll the run endpoint with bounded backoff, or use a completion webhook, then obtain the dataset ID from that run. Do not substitute the Actor's most recent run: another scheduled or interactive invocation could have started in the meantime.
Keep the platform token in your automation's secret storage. It authenticates your Apify account and is separate from any source service configuration. Do not put it in source URLs, dataset fields, spreadsheet columns, screenshots or support tickets. If a client prints complete request URLs, use Authorization headers so ordinary request logging does not reveal the platform token. Examples in this manual intentionally contain no usable credentials.
A transport timeout while starting a run is ambiguous: the platform might have created the run before the client lost the response. Check recent runs and your own job record before starting another one. This Actor has no persistent request-id ledger. Repeating a start request can create another billable run, and repeating a completed input can produce another result event for the same source identity. Store your own job ID to run ID mapping if an upstream system automatically retries submissions.
Retrieve and page through results
Read the dataset associated with the completed run. Use a page size supported by the platform and continue until all items are retrieved. Free explanations occupy dataset rows, so the number of dataset items is not the number of billed results. The source cap and the dataset retrieval page size are different controls: changing a download page size cannot recover source data that the Actor deliberately did not fetch. Preserve the original dataset index alongside your transformed record when you need an audit trail.
For a destination that only accepts flat records, flatten after checking the outer row status. Repeat the outer source identity and checkedAt on each child row. Assign an explicit child index or domain key; do not rely on destination row order as an identity. Keep arrays of warnings and provenance in a companion JSON record if the destination cannot represent them. Test that empty strings, zero, false and null retain their different meanings after the transformation.
The dataset is the detailed result channel; OUTPUT is the aggregate accounting channel. Archive both with the input JSON and the run ID. A dashboard that stores only the success rows loses the reason an input was missing. A dashboard that stores only OUTPUT loses the actual evidence behind a result. Retaining both lets support distinguish a source change, a permission change, a configured limit and a delivery failure without rerunning the source.
Use n8n
Create a small workflow with a manual trigger, a node that starts this Actor, a wait or polling step, a dataset read step and an IF or Switch node. Route complete results to the importer, clean absence to a review branch, and errors or limits to a separate operational queue. Avoid a workflow that maps every returned row directly into a production table. A free explanatory row intentionally does not have every field of a complete result.
In the import branch, retain sourceUrl, checkedAt, schemaVersion and the domain identity. Use an upsert key appropriate to your destination instead of blind insertion. Put a unique constraint on your own job ID plus result identity if your webhook handler can run more than once. If the destination rejects a row, retry the destination write from the saved dataset; there is usually no reason to start another source run and pay to retrieve evidence you already have.
Set the workflow timeout above the Actor's expected run duration and use a bounded polling schedule. A stopped or failed run must leave the workflow's waiting state. Record the run ID in failure notifications, but avoid embedding entire source records when they contain information your notification channel should not receive. Test the negative and partial branches with the examples in this manual before enabling a schedule.
Use Make or Zapier
Build the scenario around a completed run, then retrieve its dataset. An iterator over dataset items should be followed by a filter on the documented status and completeness fields. Name branches by their operational meaning: import, no current result, retry source later, and investigate configuration. Include a final count comparison so a scenario that silently drops a row cannot report a complete import.
If a run yields nested arrays, decide whether the destination expects one object per result or one object per child record. Expanding nested arrays can multiply automation tasks even though it does not create extra Actor result events. Estimate those destination operations separately from this Actor's tariff. The Actor's result price is not a quote for third-party workflow subscriptions, destination API usage or your own data storage.
Schedules belong to the automation or to Apify. Avoid enabling both for the same job unless you intentionally want two independent polling streams. Include the exact input configuration in your job description, because a copied scenario can keep an older cap or strategy without anyone noticing. After an input change, perform one manual run and inspect both a complete result and the new summary before resuming recurring execution.
Use a completion webhook
A webhook signals that a run reached a terminal state; it is not itself the complete dataset. Read the run ID from the event, resolve that run's dataset, and process it using an idempotent destination operation. Webhook systems can deliver the same event more than once. Keep a processed-event record and reject duplicate destination work without assuming that a second notification means the Actor ran twice.
Keep webhook verification and destination credentials in your receiving service. The Actor does not accept arbitrary callback URLs in its input and does not send your extracted data to a buyer-supplied endpoint. Configure platform webhooks through the platform's supported controls. This keeps source retrieval separate from your choice of destination and makes it possible to replay destination processing from a saved dataset.
Treat terminal FAILED and successful partial runs as different cases. A failed run requires inspection of its summary and log; a successful limit run requires a decision about the missing scope. Neither should trigger an automatic delete in your destination. If you notify a team, include a short status, the run ID and a link to the retained evidence rather than a claim that the source has no data.
Load a warehouse or database
Use a staging table before merging into a production table. Store the raw JSON with a run ID, dataset index and ingestion timestamp, then project domain fields into typed columns. This preserves the ability to correct a transformation without fetching the source again. The original checkedAt describes the Actor observation; your ingestion timestamp describes arrival at the destination. Keeping both exposes queue delays.
Choose a uniqueness policy before importing historical runs. A current-state table often uses the source identity as its key and updates on later observations. A history table uses the identity plus observation or run ID. These are different products: overwriting a current-state table cannot later answer historical questions, while appending every retry into a history table can create misleading duplicate observations.
Do not infer a deletion from the absence of a source identity in a partial run. First establish that the requested scope was complete, the source returned the expected form, and all dataset pages were ingested. For a destructive synchronization, require a separate complete-run marker and an explicit downstream policy. This Actor provides evidence and accounting; it does not issue deletion commands to your catalog, CRM or warehouse.
Pass results to an LLM or retrieval pipeline
Filter and normalize the structured output before constructing a prompt. Source text is untrusted content, including product copy, spreadsheet cells and diagnostic titles. Keep it in a clearly separated data field and do not interpret embedded instructions as workflow commands. A source string that asks an assistant to reveal secrets or call a URL remains a source string. The Actor does not execute it.
Retain provenance when chunking results for retrieval. Each chunk should point back to the source identity, checkedAt and run ID. If a response is incomplete, carry that state into the retrieval index metadata so an answer does not present a partial snapshot as a complete source. Generated summaries should link to the structured evidence and should not replace the original fields used for calculations.
Limit the fields sent to the model to the actual task. Numeric values should be calculated in your application when exact arithmetic matters. Treat an LLM's interpretation as a separate derived artifact with its own model and prompt version. The Actor's schemaVersion describes this extraction contract; it does not describe the accuracy of a downstream model or the provenance of a generated narrative.
R12. Operating guide
Start with a baseline
Record a first small run with its input, date, runtime, result counts and actual platform charge. Compare the result to the source manually. Keep this baseline when you later change a cap, URL set or downstream mapping. If output changes after a source update, a baseline helps distinguish an extraction defect from a legitimate change in the source. Do not treat the included synthetic controls as representative customer volume or as proof of commercial demand.
Use the Console's currently displayed price as the commercial authority. The price in this manual was read back from the deployed tariff on 2026-09-06; check the Store page before a large run, because a tariff change is an operator action. Startup, complete result events and free status rows are separate concepts. A free result status means no result-found event for that row; it does not imply that all platform or account costs vanish, and an Actor with a nonzero start event can still have a startup charge on an empty run.
Set a spending cap
Set the platform's maximum total charge for the run according to the number of complete units you intend to buy, allowing for any start charge shown in the Console. The Actor checks remaining money immediately before each paid dataset write. If the next complete unit does not fit, it stops paid delivery. A cap is a financial limit, not a promise that the Actor will retrieve exactly a certain number of source units.
A smaller cap can stop a run before all requested inputs are processed. Inspect budgetExhausted and unprocessed in OUTPUT, and retain whatever complete results were delivered. Raising the cap later requires another run; it does not resume the previous run through an internal replay ledger. If you only need to finish a subset, construct a smaller input from the remaining work instead of repeating every successful source.
A failure to read pricing or budget is different from normal exhaustion. The Actor stops with a fatal explanation rather than treating unknown money as unlimited. If automatic dataset items have a nonzero price, the Actor refuses dataset writes, including explanations that would otherwise be free. In that condition the log is the explanation channel. Contact support with the run ID; repeatedly rerunning the same broken pricing configuration is not a remedy.
Understand delivery uncertainty
A paid result is sent using a linked dataset write and result event. If a remote write or charge operation fails, it can be impossible for the client to know whether the row landed. The Actor stops and records deliveryUncertain rather than retrying the same row automatically. This prevents a silent duplicate, but it also means that a failed run can require reconciliation against the platform's actual dataset and charged-event counts.
For a destination integration, a dataset row is evidence of a delivered record, while OUTPUT.paid records the SDK-confirmed count. Investigate any uncertainty instead of equating those quantities mechanically. If support needs a reproduction, provide the smallest input that demonstrates the issue and the original run ID. Avoid deleting the evidence or restarting multiple times before the original state has been inspected.
Plan schedules around source behavior
Choose a polling interval that reflects how often the source can usefully change and how soon your decision needs fresh evidence. A schedule does not make an upstream cache fresh. Repeated identical runs can be billed again and may not add useful information. Begin with manual or infrequent execution and increase frequency only after observing actual changes and operational value.
The implementation runs source work sequentially. This keeps request pressure and memory usage bounded and makes small runs easy to inspect. Increasing the number of URLs does not create parallel workers. The platform timeout is 300 seconds with a 240-second working deadline. The remaining time is reserved for delivery and summary work, but the platform can still interrupt a process for reasons outside the source request path.
There are at most two retries after an initial transient request failure. Only network failures, HTTP 429 and server errors qualify; a malformed successful body or ordinary client error is not repeatedly fetched. Retry-After is honored within the remaining working deadline. If the requested wait no longer fits, the Actor returns the appropriate free explanation and stops that source attempt. This is a bounded retry policy, not a guarantee that a busy upstream service becomes available.
Read the summary as a ledger
requested is the number of normalized source work units requested by the run. processed records units whose domain processing reached an output decision; its exact unit is explained in the product-specific contract. unprocessed records the remainder. delivered counts complete result rows confirmed by the delivery path. paid counts confirmed result events when running with monetized pricing; local development can deliver results with paid equal to zero.
free counts explanatory or clean absence rows written without result-found. failed counts free rows that describe actual errors, excluding documented limit_exceeded results. A free row may still contain a partial snapshot for inspection. partial indicates incomplete source scope, output, budget coverage or a fatal interruption. fatal is an empty string for a normal complete run and for documented nonfatal limits; a nonempty string explains a run-level failure.
replaySafe is false because the Actor does not maintain a persistent ledger across runs. checkedAt in OUTPUT is the summary time and can be later than each row's checkedAt. Keep row timestamps for source comparisons. A summary is deliberately small and does not duplicate all the data. If writing the summary itself fails, the log and terminal run state become necessary evidence for troubleshooting.
Monitor useful signals
Track runs that produce complete results, clean absence, source errors, limits and budget exhaustion as separate categories. A rising number of free rows can indicate either correctly enforced limits or a failing source; the status tells you which. Alert on repeated source failures or missing configuration, and review recurring limits against your intended input size. Do not use dataset row count alone as a health metric.
Track source request duration and run duration separately if your observability stack supports them. Startup, retries, throttling and destination processing can all contribute to end-to-end delay. A fast source request does not prove that a whole automation completed quickly. Conversely, a slow upstream result does not imply a broken dataset importer. Preserve the run ID through each system so latency can be traced.
Change one control at a time
When investigating a failure, keep the source and other controls fixed while changing one relevant limit or option. Compare the status, extracted values and summary to the baseline. If a permission problem is suspected, have the source owner verify access through the documented public route. Do not add credentials to a URL or try a different unapproved route to make a free error disappear.
When a schema or source changes, run a small comparison before switching a scheduled destination. Verify identifiers, numeric units, missing-value behavior, nested arrays and the clean absence branch. A transformation that works for a happy result can still fail on a documented status row. Version your own mapping independently from the Actor input so you can roll back a destination change without reverting the source configuration.
Prepare a useful support report
Include the Actor name, run ID, input with sensitive values removed, expected behavior, observed status and the relevant row or summary fragment. State whether the problem reproduced once or repeatedly and whether the source changed recently. Include a source URL only if you can share it safely. Do not send API keys, platform tokens, cookies or private source documents to a public issue.
For numeric discrepancies, include the original structured value and its unit rather than only a screenshot of a formatted cell. For missing records, include the configured caps and completeness state. For a suspected billing discrepancy, retain the platform's actual event counts and the run memory setting. These details let support isolate the responsible layer without guessing from an incomplete screenshot.
R13. FAQ
Does this require WooCommerce API credentials? No. It uses the public keyless Store API. It does not accept a consumer key, secret, login cookie or administrator endpoint.
Why did two products produce three dataset rows? The extra row is a free catalog-scope notice because the store had more products than the cap. It is not a third product or an extra result event.
Why is a product with price zero billable? A valid zero price is useful catalog data. The merchandise's price does not determine the extraction event price. Missing or invalid price data is an error instead.
Can I assume USD uses two decimal places? Use currencyMinorUnit from the response. The live default-store probe returned zero. Keeping the scale beside the raw string avoids incorrect price conversion.
Are variation prices included? No. Embedded variation IDs and attributes are preserved, but separate prices are not fetched. The parent price must not be assigned automatically to every variant.
Can I scrape HTML when the Store API is disabled? No. HTML shells and disabled API routes produce free errors. The Actor does not switch to product-page parsing or a browser.
Can I use a WordPress installation in a subdirectory? This version accepts origins and uses the root /wp-json route. A subdirectory installation needs a separately specified and reviewed contract.
Does inStock mean I can order a specific quantity? No. It is a public source boolean. The Actor does not reserve inventory, create a cart, calculate shipping or verify a transaction.
Can I filter by category or search term? This narrow input exposes origins, a cap and descriptions. It does not accept arbitrary API query parameters. Apply a downstream filter to the observed products or request a scoped future feature.
Why did the run fail with a nonempty dataset? Earlier complete products can remain delivered when a later failure occurs. Read OUTPUT and the row statuses before deciding which records to import.
Can a limit-only run succeed? Yes. A documented limit is a free result. It does not count toward the all-stores-failed condition, and it must still be handled as incomplete scope by the importer.
Does the Actor save previous catalog state? No. Deduplication is within one run. Your destination owns historical storage, change detection and webhook idempotency.
R14. Sources, rights and support
The official Store API documentation describes the public unauthenticated API and pagination. The products reference describes the catalog resource. The reviewed default origin's terms and robots file are source-specific access evidence, not a universal content license.
Process catalogs you own or are entitled to use, and retain attribution or other notices required by the applicable content terms. Public product metadata can still contain copyrighted descriptions and branding. The Actor's origin allowlist enforces technical scope; it does not decide whether your intended republication is permitted.
For support, use the issue channel on the Actor's Apify page with the run ID, observed status and a small permitted input. Include raw price and currencyMinorUnit when reporting a monetary-display discrepancy. Do not share store credentials or customer records. The crosslinks and the platform examples above are final; the two Store diagrams are added after publication.
Related tools
Related tools for adjacent workflows in e-commerce.
| Actor | What it does |
|---|---|
| Shopify Catalog & Merchandising Intelligence | Pair it in the e-commerce workflow: Qualify Shopify merchant leads with evidence-backed public catalog coverage, observed price positioning,... |
| Chotot Vietnam Listings Scraper | Pair it in the e-commerce workflow: Pull live classified ad listings (real estate, vehicles, electronics, jobs and more) straight from... |
| Shopify Store Price & Catalog Change Monitor | Pair it in the e-commerce workflow: Monitor store-level price range, catalog size, currency, Shopify detection, and heuristic revenue-band... |
| Zid Product Export Intelligence | Pair it in the e-commerce workflow: Turn merchant-owned, merchant-authorized, or otherwise licensed Zid product exports into stable evidence,... |
| Competitor Change Monitor — Tech, Hiring & Filings | Pair it in the e-commerce workflow: Monitor one competitor domain for technology, hiring, and SEC-name changes with explicit baselines,... |