# Shopify Product Reviews Scraper | Multiple Sources (`cleanscrape/shopify-reviews-scraper`) Actor

Shopify reviews from Judge.me and Okendo: text, ratings, replies and public media links, with filters and coverage reports. Base rate: $0.95 per 1,000 reviews. Maintained by CleanScrape.

- **URL**: https://apify.com/cleanscrape/shopify-reviews-scraper.md
- **Developed by:** [CleanScrape](https://apify.com/cleanscrape) (community)
- **Categories:** E-commerce, Marketing
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.76 / 1,000 exported reviews

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

## Shopify Product Reviews Scraper

Export Shopify product reviews from **Judge.me and Okendo** into one consistent dataset. Paste product links from different stores, choose the ratings you need, and download the results as JSON, CSV or Excel. The price is **$0.95 per 1,000 exported reviews**, with no rating-filter add-on fee.

Use the results to compare customer feedback, investigate recurring product complaints, or feed an existing research workflow. Provider detection is automatic: you do not need to identify the review app or find its API keys.

### Supported review providers

| Provider | Collection and scope |
| --- | --- |
| **Judge.me** | Public product widgets, including supported JSON and HTML formats. Existing Judge.me inputs and output fields are preserved. |
| **Okendo** | Public product reviews, with product-group attribution when supplied. Separate aggregate-only ratings are not invented as individual reviews. |

Support depends on the storefront exposing a recognizable public integration. An installed app or a provider logo alone does not establish compatibility. The Actor does not use merchant/admin credentials, bypass access restrictions, or collect private customer fields. Loox, Yotpo, Stamped, Junip, Fera, Ali Reviews, Rivyo, Ryviu and other unlisted providers are not supported. This is not a Shopify App Store reviews scraper or a whole-store product-discovery tool.

### Make the first export easy to interpret

Paste a product-page URL; you do not need a shop ID, product ID, API token or country code. The Actor checks for a supported public source. If it cannot establish one, inspect the coverage report instead of treating the result as proof of zero reviews. If review widgets conflict and no safe source can be selected, it reports the ambiguity instead of silently combining their reviews. Existing Judge.me widgets retain their original extraction path.

Choose star ratings by their readable labels. **Reviews to check per product** is the scan budget before filtering. **Maximum reviews to export in total** is the run-wide result limit. For example, checking 100 reviews with only 1-star and 2-star selected might export 8 reviews, or none; it does not mean the tool searches the entire history until it finds 100 low-rated reviews.

**Review essentials and attribution** places the provider and review content beside the source's reviewed-product name and grouping flags. **Product reviews** and **Product attribution** retain the original views. A review in a product widget can be shared from another product or a bundle; it is not necessarily feedback on the exact requested variant. A null grouping flag means unknown, not false.

Open **Run summary and field guide** for plain-language stopping reasons, then **Coverage report** for full machine-readable details. Empty titles and ratings-only reviews can be legitimate source data. Missing dates, titles, verification badges and product attribution remain unknown rather than guessed. Raw output fields, existing limits, billing and API inputs are unchanged.

### Start with one product

Paste a product URL, choose how many reviews to scan, and run the Actor. Open **Exported reviews** to download JSON, CSV or Excel through Apify. Open **Coverage report** to see what was actually retrieved.

```json
{
  "productUrls": ["https://owalalife.com/products/freesip"],
  "maxReviewsPerProduct": 100,
  "maxTotalReviews": 100,
  "ratings": ["1", "2", "3", "4", "5"]
}
```

The example is a public third-party product page, not an affiliation or a guarantee that its layout will remain supported.

### Pricing

#### Store discounts

Apify applies your subscription tier automatically: **Bronze 10% off, Silver 15% off and Gold 20% off** the base event prices. Platinum and Diamond use the Gold rates. These discounts apply to every billable event listed below.

| Billable unit | Base / Free tier | Bronze (-10%) | Silver (-15%) | Gold (-20%) |
| --- | ---: | ---: | ---: | ---: |
| Exported review (1,000 events) | $0.95 | $0.855 | $0.8075 | $0.76 |

Base-price examples in this README are before discounts. Discounts do not change what is billable or any startup memory multiplier. See the Pricing tab for the rate applicable to your account.

All prices and examples below use the base rate before subscription discounts.

The price is **$0.95 per 1,000 exported reviews** ($0.00095 per review). There are no separate rating-filter or media-link events. Filtered-out records, duplicate records skipped within a run, and coverage reports do not incur a review event. Repeated runs export and charge for reviews again. This is not a changes-only monitor.

At that rate, 100 exported reviews cost $0.095; 1,000 cost $0.95. Set both an export limit and an Apify spending limit. Your own runs can still consume platform credit. Apify's displayed charges and account terms apply.

### What each row contains

| Field | Meaning |
| --- | --- |
| `reviewId`, `recordKey` | Provider ID and a stable shop/provider/review key for joining exports. |
| `productUrl`, `productId`, `productName` | Product page context. Missing names or IDs are null. |
| `rating`, `title`, `body` | The public rating and review text. Ratings-only reviews are retained. |
| `publishedAt`, `publishedAtRaw` | Source date normalized to UTC where parseable, plus the original value. |
| `observedAt` | When this run observed the review, not when it was published. |
| `reviewerName` | Public display name, not a verified identity. |
| `verifiedPurchase` | Source-provided true/false where available; true for an HTML buyer badge; otherwise null. |
| `merchantReply`, `mediaUrls` | Public reply text and exposed linked media, where available. No media files are downloaded. |
| `contentHash` | Comparison hash of rating, title, body, reply and media links. Not a change notification. |
| `reviewedProductUrl`, `reviewedProductName` | The reviewed product identified by the source, if supplied. It may differ from the requested page. |
| `isGroupedReview`, `isBundleReview` | Judge.me source flags; for Okendo, group attribution established from its product IDs and grouping response. Null means not established, not false. |
| `provider`, `shopDomain`, `schemaVersion`, `reviewScope` | Source and output format context. |

Some merchants share reviews across variants or grouped products. `reviewScope: "product_widget"` means the review belongs to that product's public widget feed; it does not prove a purchase of that exact variant. Some sources expose original-product attribution and others do not. Duplicate IDs within the same provider and shop are exported once per run, under the first product processed. Provider values are `judge.me` and `okendo`.

#### Why the product distinction matters

In a validation export, a clothing product's widget contained 675 reviews, of which 619 were flagged by the source as shared from its product group. Treating all 675 as feedback about that exact product would be misleading. Use `isGroupedReview`, `isBundleReview` and the reviewed-product fields to keep that distinction in your analysis. A null flag means the source did not establish it.

### Read the coverage report

A green Apify run status does not mean every historical review was available. `SUMMARY` records each product's scanned count, export count, source-reported total where available, and stopping reason.

- `source_count_matched`: observed unique IDs matched the source count, with no reported next page or invalid records. This is a bounded observation, not an atomic snapshot of a changing store.
- `scan_limit` or `page_limit`: the configured scan budget ended before full coverage could be established.
- `embedded_only`: this storefront exposed reviews in its HTML, but neither supported public pagination route could be established. Only those embedded reviews were read.
- `no_next_page` or `no_new_reviews`: pagination ended without confirmed complete coverage.
- `output_or_spending_limit`: no further paid output was allowed.
- `source_or_output_error`: a request, layout or output operation failed. Already stored results remain accessible.

The Actor does not translate, invent missing values, infer deleted reviews, or retry a failed provider by silently switching to another. Unsupported and blocked sources are reported explicitly rather than presented as confirmed zero-review products. Public media links do not guarantee every attachment is available.

Source-side limits still apply. In validation, one public widget route stopped at 990 unique reviews while reporting a much larger total. Increasing an input limit does not remove such a source ceiling; the export remains marked partial.

### Filters and limits

`ratings` filters the scanned reviews locally. For example, `["1", "2"]` exports low-rated reviews found within the scan window, not necessarily every low-rated review on the product. Provider ordering is preserved; newest-first ordering is not promised.

You can submit up to 20 product URLs, scan up to 2,000 unique reviews per product, and export up to 5,000 reviews per run. Requests are bounded to 100 review pages per product, plus product metadata and count checks. Homepages and private URLs are not accepted. Some storefronts need a browser or restrict access; this version does not bypass those restrictions or use paid proxies.

### Scheduling and integrations

Use Apify schedules or its API to repeat an export. Download the dataset in your preferred format or send it to your existing n8n workflow. Compare `recordKey` and `contentHash` downstream if you need to identify observed differences. Persistent history and change alerts are not included in this version.

### Interrupted runs

Reviews are stored as extraction progresses. Coverage checkpoints are saved during scanning, so a forced stop can leave a report that lags behind the final dataset. Treat the actual dataset and Apify run status as authoritative; a checkpoint still marked `running` is not proof that an aborted run finished.

Resurrecting or restarting a run whose dataset already contains results is deliberately blocked to avoid exporting and charging for the same reviews again into that dataset. Existing results and the previous coverage report are preserved. A fresh run creates a new export and may include reviews you have already paid for in earlier runs.

### Maintenance and ongoing use

CleanScrape maintains this Actor for both one-off exports and recurring workflows. We investigate reported errors, update supported integrations when source websites change, and test changes with existing inputs and output formats in mind.

If something stops working, open an issue or email <contact.cleanscrape@gmail.com> with the Actor name, run ID, public source URL and expected result. Never include API tokens or private customer data.

Source availability can change. Check the run report for errors and coverage limits before relying on an export as complete.

If the export was useful, an honest review helps other users decide whether it fits their workflow. Critical feedback is welcome too.

Use public review data responsibly and in accordance with applicable terms and privacy requirements.

### Disclaimer

This Actor is an independent tool developed by CleanScrape. It is not affiliated with, endorsed by, or sponsored by Shopify, Judge.me, Okendo, or the merchants referenced in its examples or output. All trademarks are the property of their respective owners. Brand names are used only to identify sources and illustrate usage.

# Actor input Schema

## `productUrls` (type: `array`):

1-20 HTTPS Shopify product URLs using Judge.me and Okendo. You can mix stores and providers. Use individual product pages, not homepages or Shopify App Store listings.

## `maxReviewsPerProduct` (type: `integer`):

How many reviews to inspect before applying the star-rating filter. Checking 100 reviews does not guarantee 100 matches. Maximum: 2000 per product.

## `maxTotalReviews` (type: `integer`):

Stop after this many exported reviews across all supplied products. Only exported reviews incur the review event. Also set an Apify spending limit.

## `ratings` (type: `array`):

Local filter with no separate event fee. The scan limit still applies; omitted reviews are not billed.

## Actor input object example

```json
{
  "productUrls": [
    "https://owalalife.com/products/freesip"
  ],
  "maxReviewsPerProduct": 100,
  "maxTotalReviews": 500,
  "ratings": [
    "1",
    "2",
    "3",
    "4",
    "5"
  ]
}
```

# Actor output Schema

## `reviews` (type: `string`):

No description

## `coverage` (type: `string`):

No description

## `userGuide` (type: `string`):

Plain-language explanation of result coverage, stopping reasons and missing fields. A saved checkpoint is not proof a run finished.

# 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 = {
    "productUrls": [
        "https://owalalife.com/products/freesip"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("cleanscrape/shopify-reviews-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 = { "productUrls": ["https://owalalife.com/products/freesip"] }

# Run the Actor and wait for it to finish
run = client.actor("cleanscrape/shopify-reviews-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 '{
  "productUrls": [
    "https://owalalife.com/products/freesip"
  ]
}' |
apify call cleanscrape/shopify-reviews-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,cleanscrape/shopify-reviews-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/O7dosXB05OlSD6HON/builds/fgj6eJINRuvvHr027/openapi.json
