# RevZilla Product Scraper — Prices & Stock (`muhammadafzal/revzilla-product-scraper`) Actor

Extract RevZilla product prices, stock, SKU variants, ratings, and part numbers from product or category URLs for catalog and price monitoring.

- **URL**: https://apify.com/muhammadafzal/revzilla-product-scraper.md
- **Developed by:** [Muhammad Afzal](https://apify.com/muhammadafzal) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $9.60 / 1,000 revzilla 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

## RevZilla Product Scraper

Extract current public RevZilla catalog products into structured JSON for motorcycle gear price monitoring, SKU research, stock checks, and catalog comparisons. Supply product pages or public category pages. The Actor saves one record per unique product, with its published variants grouped inside that record.

### RevZilla product data

| Field | Meaning |
| --- | --- |
| `productId`, `url`, `name` | Stable product identity and canonical product URL |
| `brand`, `category` | Published brand and catalog category path |
| `description` | Published short description |
| `priceMin`, `priceMax`, `currency` | Range across published variant offers |
| `availability` | Distinct published availability states |
| `rating`, `reviewCount` | Published aggregate rating and review count |
| `imageUrls` | Image references; no downloaded images |
| `variantCount`, `variants` | Deduplicated public SKU variants |
| `scrapedAt` | UTC extraction timestamp |

Each variant contains `sku`, `color`, `style`, `storeSku`, `manufacturerPartNumber`, `price`, `currency`, `availability`, and `availabilityText`. Fields the source does not publish remain `null`. Variants may include out-of-stock offers. Product pricing is the range of source-published offers, rather than a selected checkout price. Ratings may be shared across models by RevZilla.

### Product URLs and category URLs

Product pages provide detailed catalog records. Category pages discover product links and then fetch those product pages. Category cards are not billed or emitted as incomplete product records. Product IDs deduplicate across category and direct URL inputs. URLs selecting different SKUs normalize to a single product, whose variants are returned together.

Default input fetches the Shoei RF-1400 Helmet page and allows up to five results. It usually returns one product because it starts from one product page. Missing input uses this same example. Explicitly empty `startUrls` is rejected with a correction in the run summary.

```json
{
  "startUrls": [{"url": "https://www.revzilla.com/motorcycle/shoei-rf-1400-helmet"}],
  "maxResults": 1,
  "includeVariants": true
}
```

For category discovery:

```json
{
  "startUrls": [{"url": "https://www.revzilla.com/motorcycle-helmets"}],
  "maxResults": 5,
  "maxPages": 1,
  "maxRequests": 15,
  "maxRunSeconds": 180
}
```

A category URL with `?page=2` starts at its second page. `maxPages` limits pages per starting category. The result cap, request budget, and runtime can end pagination earlier. Multiple categories share the global result cap.

### Limits and predictable execution

`startUrls` accepts 1–20 public RevZilla HTTPS URLs. `maxResults` accepts 1–50 products; default 5. Verified Apify free-plan runs are capped at five products even if a higher limit is requested. Paid runs retain the requested ceiling. An unknown local plan does not trigger the free cap. The effective ceiling appears in `OUTPUT` and the terminal status.

`maxPages` accepts 1–5 category pages per starting URL, default 1. `maxRequests` counts HTTP attempts, including retries, and accepts 1–80, default 25. `maxRunSeconds` accepts 10–240 seconds, default 180. The cloud timeout can impose a shorter duration. The scraper also stops at 100 MB of response bodies or after two consecutive systemic failures. It uses sequential requests, a minimum delay of approximately one second, and a 20-second request timeout. These limits bound work independently of the PPE spending cap.

Set `includeVariants` to false to omit the nested variant payload. The `variants` field becomes an empty array while `variantCount`, price range, and aggregate availability remain present. This does not change the billing unit.

### Output and exports

The default dataset contains products only and supports JSON, CSV, Excel, and other Apify dataset exports. Nested variant arrays are most useful in JSON. The products table highlights name, brand, prices, currency, availability, ratings, variant count, and source URL. The output panel links to the dataset and the `OUTPUT` key-value record.

`OUTPUT` records `outcome`, `deliveredRecords`, `resultEvents`, `startEvents`, `stopReason`, `effectiveLimit`, `freePlanCap`, `requests`, `responseBytes`, `routes`, `warnings`, and elapsed seconds. Possible outcomes are `DATA`, `PARTIAL`, `EMPTY`, `BLOCKED`, `REJECTED`, and `FAILED`. A real missing page can be empty; a denied page is blocked. Unrecognized markup is an extraction failure, never a fabricated fallback product. Valid partial products remain available after later failures.

### Pay-per-event pricing

One saved product is one automatic `apify-default-dataset-item` event. All returned SKU variants are included. There is also an automatic `apify-actor-start` fee. No manual synthetic charges or separate variant events are used. Failed, missing, and rejected products do not create product events; the start fee still applies. Platform-usage pass-through is disabled.

| Event | FREE | BRONZE (2.5% off) | SILVER (5% off) | GOLD (20% off) |
| --- | ---: | ---: | ---: | ---: |
| Actor start | $0.005 | $0.005 | $0.005 | $0.005 |
| Saved product | $0.012 | $0.0117 | $0.0114 | $0.0096 |

The start fee has a $0.005 floor in every tier. At list pricing, one product totals $0.017 and five products total $0.065. At GOLD pricing those totals are $0.0146 and $0.053. Free-plan billing follows Apify's platform rules. These tables describe configured event prices, not a guarantee of creator revenue.

The Actor checks the SDK's remaining event allowance before requests and before every write. Set the run's `maxTotalChargeUsd` option in Apify Console or API to constrain events. A charge cap does not constrain platform compute or an external proxy invoice, so request and runtime bounds remain necessary. Initial pricing uses conservative HTML-transfer allowances and is verified against cloud costs before handoff.

### API and AI-agent use

Call `muhammadafzal/revzilla-product-scraper` with the same JSON inputs from Apify Console, the Apify API client, or an Apify Actor integration. Configure a spending cap and timeout in run options. Poll the run, inspect `OUTPUT`, then read its default dataset. Do not interpret a successful container alone as evidence that products were delivered. Consume nullable fields as unavailable information.

### Access and scope

Extraction uses public HTML, embedded JSON-LD, and the public SKU table. US network routing is managed privately by the operator, with coherent request headers and cookies. Inputs never accept proxy credentials or user sessions. Search URLs are excluded because RevZilla's robots policy disallows search. Account, cart, checkout, API, editorial, and OEM pages are outside the contract. Reviews are aggregate counts and ratings only; individual review text, private inventory, purchases, and guaranteed vehicle fitment are unsupported.

The Actor follows only allowlisted public RevZilla destinations, including redirects. It does not solve CAPTCHAs, log into accounts, or bypass paywalls. Use it only where you have the right to collect and use the information, and respect RevZilla's terms and applicable requirements. This independent scraper is not affiliated with RevZilla. Source prices, stock, and catalog structure can change between runs.

### Operator development

Run `npm ci`, `npm run check`, and `npm test` from this Actor directory. Use bounded `apify run --purge` cases for local validation. Configure the current user's provider credentials as private Actor environment secrets. Local storage and `.env` files are excluded from deployment. Cloud build, billing, output, metadata, privacy, and final matrix evidence are documented separately in `VALIDATION.md` after verification. Publication remains an owner action.

For private route canaries, operators can write `OPERATOR_ROUTING` with a predefined `route` in a canary run's default key-value store before resuming it. It accepts only `residential-us`, `mobile-us`, `apify-residential-us`, or `direct`; credentials and proxy endpoints remain server-side. Ordinary runs use automatic routing without this record. Apify snapshots version environment variables when building, so changing those variables requires a new build.

# Actor input Schema

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

Use public product URLs or catalog category URLs, e.g. https://www.revzilla.com/motorcycle/shoei-rf-1400-helmet or https://www.revzilla.com/motorcycle-helmets. Accepts 1–20 entries. Search, account, editorial and OEM pages are unsupported. Tracking and SKU parameters are removed; variants are grouped.

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

Maximum unique products saved and billed, 1–50. Defaults to 5. Verified free-plan users can receive at most five. One record includes all public variants when enabled.

## `maxPages` (type: `integer`):

Maximum category pages followed per starting category, 1–5. Default 1. The product limit and request budget may stop pagination earlier. A starting URL with ?page=2 begins at page two.

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

Include public SKU, color, product style, store SKU, manufacturer part number, price and availability in each product record. Default true. False returns an empty variants array while retaining variantCount and product price range.

## `maxRequests` (type: `integer`):

Total HTTP attempts, including retry attempts, 1–80. Default 25. A category page consumes an attempt before its product pages. A low budget can yield partial data; OUTPUT explains the stop reason.

## `maxRunSeconds` (type: `integer`):

Maximum scraping duration, 10–240 seconds. Default 180. The platform timeout can shorten this budget. Requests use a 20-second timeout and a one-second minimum delay.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.revzilla.com/motorcycle/shoei-rf-1400-helmet"
    }
  ],
  "maxResults": 5,
  "maxPages": 1,
  "includeVariants": true,
  "maxRequests": 25,
  "maxRunSeconds": 180
}
```

# Actor output Schema

## `products` (type: `string`):

No description

## `summary` (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": [
        {
            "url": "https://www.revzilla.com/motorcycle/shoei-rf-1400-helmet"
        }
    ]
};

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

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

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

```

## Python example

```python
from apify_client import ApifyClient

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

# Prepare the Actor input
run_input = { "startUrls": [{ "url": "https://www.revzilla.com/motorcycle/shoei-rf-1400-helmet" }] }

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

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

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

```

## CLI example

```bash
echo '{
  "startUrls": [
    {
      "url": "https://www.revzilla.com/motorcycle/shoei-rf-1400-helmet"
    }
  ]
}' |
apify call muhammadafzal/revzilla-product-scraper --silent --output-dataset

```

## MCP server setup

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

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

## OpenAPI specification

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