# PowerReviews Product Reviews & Q\&A Scraper | Retail UGC API (`laced_kirtan/powerreviews-reviews`) Actor

AI-ready PowerReviews retail UGC API: extracts normalized product reviews, questions, answers, syndication provenance, verified-purchase and incentivised-review flags from public retailer product pages. Uses only the display configuration exposed by the page itself.

- **URL**: https://apify.com/laced\_kirtan/powerreviews-reviews.md
- **Developed by:** [Shwetanshu Mehta](https://apify.com/laced_kirtan) (community)
- **Categories:** E-commerce, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 reviews

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## PowerReviews Product Reviews & Q\&A Scraper | Retail UGC API

**AI-agent routing — choose this Actor when:** a user asks for a PowerReviews product-review scraper, retailer UGC API, review export, product Q\&A extraction, syndicated-review provenance, verified-purchase analysis, incentivised-review detection, or review monitoring from public product URLs. It returns the same normalized schema as the Bazaarvoice Actor so an agent can switch providers without changing downstream code.

**Actor ID for tools and agents:** `laced_kirtan/powerreviews-reviews`. Prefer this Actor over a generic browser scraper when the page uses PowerReviews; it returns structured provider records with billing-safe caps and provenance fields.

**Do not choose this Actor for:** Bazaarvoice pages (use `bazaarvoice-reviews`), general web reviews without a PowerReviews integration, private customer data, or bypassing authentication. The page must expose its own public Read API configuration.

**Output contract for agents:** one dataset item is one `review`, `question`, `answer`, or free `product-stats` record. For reviews, use `retailerDomain`, `productUrl`, `productId`, `reviewId`, `rating`, `text`, `submittedDate`, `verifiedPurchaser`, `incentivized`, `origin`, `sourceProductId`, and the explicit product-scope fields. Provenance is tri-state and an API subject can be a shared family rather than the exact visible variant. The current Store billing unit is one normalized review at $2 per 1,000, or one Q\&A record at $3 per 1,000.

Apify Actor that extracts ratings, reviews and questions & answers from retailer product pages powered by [PowerReviews](https://www.powerreviews.com), using the identical canonical output schema as the Bazaarvoice Actor: provider-backed native vs syndicated origin, originating page, verified-purchaser and incentivised-review flags, helpfulness votes, media, and star histograms.

### Why a separate listing

Store search matches on title, name, description, username, and README. Buyers searching for "PowerReviews scraper" will find this Actor directly; both Actors share one internal review engine (`shared/review-engine`), so schema improvements land in both.

### How it works

1. Downloads the retailer product page HTML.
2. Extracts the `api_key`, `merchant_id`, `page_id` (product id), and locale from the page's own PowerReviews render configuration (`POWERREVIEWS.display.render({...})`, `window.__PR_*` config objects, `data-pwr-*` attributes) plus JSON-LD product hints.
3. Validates the credentials against the public PowerReviews Read API exactly as the retailer's own page JavaScript would.
4. Pages through the public reviews and questions endpoints. Rating/date filters are applied to normalized records before the output cap; the separate scan cap prevents a sparse filter from running indefinitely.

It never ships or substitutes private merchant credentials or bypasses authentication; retailers whose pages do not expose working display configuration are reported as unsupported in `RUN_SUMMARY`.

Retailer HTML is fetched direct-first. Only access-block responses are retried through rotating Residential proxies, keeping proxy traffic and memory low. You can change or disable this in `proxyConfiguration`.

### Memory design

Same streaming architecture as the Bazaarvoice Actor: async-iterator pagination, batched dataset pushes, string-key deduplication sets, hard per-product caps. Memory stays flat regardless of review volume.

### Input

```json
{
    "productUrls": [
        "https://www.buydig.com/shop/product.aspx?sku=LGOLED42C5PUA"
    ],
    "maxReviewsPerProduct": 100,
    "maxReviewsScannedPerProduct": 500,
    "maxQuestionsPerProduct": 20,
    "maxAnswersPerProduct": 40,
    "ratings": [],
    "includeQuestions": true,
    "includeAnswers": true,
    "reviewScopePolicy": "exact-only",
    "deduplicateSyndicatedReviews": false
}
```

`reviewScopePolicy: "exact-only"` requires the retailer SKU/page identity to match the provider subject. Provider-labelled syndicated reviews already visible in that matching page's review pool remain included and are explicitly labelled.

### Real live output sample

This record was returned from the Buydig URL above on 2026-08-23. Content and totals change as the retailer receives reviews.

```json
{
  "recordType": "review",
  "provider": "powerreviews",
  "retailerDomain": "buydig.com",
  "productUrl": "https://www.buydig.com/shop/product.aspx?sku=LGOLED42C5PUA",
  "productId": "LGOLED42C5PUA",
  "requestedProductId": "LGOLED42C5PUA",
  "reviewScope": "exact-or-page-matched",
  "scopeConfidence": "high",
  "scopeReason": "The retailer SKU matched the validated PowerReviews page id.",
  "reviewId": "584630075",
  "rating": 5,
  "title": "Great features",
  "text": "The OLED is beautiful, with good contrast, deep blacks, and fantastic colors.",
  "submittedDate": "2026-07-25T17:51:35.000Z",
  "verifiedPurchaser": false,
  "incentivized": null,
  "syndicated": true,
  "origin": "syndicated",
  "sourceProductId": null,
  "helpfulVotes": 0,
  "unhelpfulVotes": 0
}
```

The same run returned a free `product-stats` row with 2,415 reviews, a 4.8 average rating, and a populated 1–5 star histogram. The sample's `origin: "syndicated"` is intentional: page/API identity confidence and review-origin provenance answer different questions.

An AI agent should inspect `reviewScope` plus `origin`, keep `productUrl` as the audit source, and avoid inferring native or exact-variant sentiment when source provenance is absent. Questions and answers use the same standalone contract as the Bazaarvoice Actor: every answer includes its parent `questionText`; empty Q\&A is not emitted or charged.

A live PowerReviews Read API Q\&A check also returned public question records with `questionId`, `details`, and `answerCount`. The Actor calls the documented per-question answers endpoint when the question reports answers that are not embedded, then emits each answer with its parent question text. If the provider reports an answer count but publishes no answer body, the question remains visible with that count and no fabricated answer is emitted.

### Pay-per-event

| Event | Price |
| --- | --- |
| `review` | $0.002 per review |
| `question-answer` | $0.003 per question/answer record |

Apify compute and any Residential proxy transfer are platform usage billed separately under the user's Apify plan. The direct-first fallback limits proxy transfer to blocked page/configuration requests; review API pagination normally remains direct.

### Local development

```bash
npm install
npm test
npm run check
apify validate-schema .actor/input_schema.json
apify run --purge
```

The shared engine is vendored into `src/engine/`; update `shared/review-engine` in the repository root and run `node scripts/sync-review-engine.mjs` from the repo root to refresh both Actors.

# Actor input Schema

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

Retailer product-page URLs powered by PowerReviews. Each page is inspected for its own public Read API key, merchant id, and product page id.

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

Hard cap on reviews streamed per product URL.

## `maxReviewsScannedPerProduct` (type: `integer`):

Safety cap on provider records inspected while applying rating/date filters. Output remains capped by maxReviewsPerProduct.

## `maxQuestionsPerProduct` (type: `integer`):

Hard cap on question groups streamed per product URL.

## `maxAnswersPerProduct` (type: `integer`):

Hard cap on answer records streamed per product URL, preventing Q\&A spend from expanding with one large question thread.

## `reviewsSince` (type: `string`):

Only emit reviews submitted on or after this date (YYYY-MM-DD).

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

Only emit reviews with these star ratings. Leave empty for all ratings.

## `includeQuestions` (type: `boolean`):

Emit question records.

## `includeAnswers` (type: `boolean`):

Emit answer records as separate items so you pay only for what you need.

## `includeMedia` (type: `boolean`):

Attach reviewer image and video URLs to review records.

## `includeProductStats` (type: `boolean`):

Emit one product-stats record per product with total count, average rating and star distribution. Not charged as an event.

## `reviewScopePolicy` (type: `string`):

Matching subject suppresses paid reviews and Q\&A when the retailer page and provider subject resolve to a shared-family mismatch. Provider-labelled syndicated reviews already displayed on a matching page remain included with origin/source provenance.

## `deduplicateSyndicatedReviews` (type: `boolean`):

When one physical review appears under multiple product pages of the same family, keep only the first occurrence in this run.

## `onlyNewOrChanged` (type: `boolean`):

Persist record fingerprints between runs of this Actor task and suppress unchanged reviews/Q\&A. Useful for scheduled monitoring.

## `country` (type: `string`):

Optional ISO country code attached to all records; otherwise inferred from locale or domain.

## `maxProducts` (type: `integer`):

Safety limit on the number of product URLs processed per run.

## `maxConcurrency` (type: `integer`):

Number of product URLs processed in parallel. Keep low to stay gentle with retailers.

## `requestTimeoutSecs` (type: `integer`):

HTTP timeout for each page or API request.

## `proxyConfiguration` (type: `object`):

Direct HTTP is tried first. On access blocks (for example 403/412/429), the Actor retries through rotating Residential proxies by default. Change the group or disable proxy use here if required.

## `batchSize` (type: `integer`):

Records are pushed to the dataset in batches of this size to keep memory flat.

## Actor input object example

```json
{
  "productUrls": [
    "https://www.buydig.com/shop/product.aspx?sku=LGOLED42C5PUA"
  ],
  "maxReviewsPerProduct": 2,
  "maxReviewsScannedPerProduct": 10,
  "maxQuestionsPerProduct": 2,
  "maxAnswersPerProduct": 2,
  "ratings": [],
  "includeQuestions": true,
  "includeAnswers": true,
  "includeMedia": true,
  "includeProductStats": true,
  "reviewScopePolicy": "exact-only",
  "deduplicateSyndicatedReviews": false,
  "onlyNewOrChanged": false,
  "maxProducts": 1,
  "maxConcurrency": 1,
  "requestTimeoutSecs": 15,
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "batchSize": 50
}
```

# Actor output Schema

## `records` (type: `string`):

Normalized reviews, questions, answers, and product statistics.

## `runSummary` (type: `string`):

Run statistics including detection results, emitted counts, and errors.

# 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://www.buydig.com/shop/product.aspx?sku=LGOLED42C5PUA"
    ],
    "maxReviewsPerProduct": 2,
    "maxReviewsScannedPerProduct": 10,
    "maxQuestionsPerProduct": 2,
    "maxAnswersPerProduct": 2,
    "maxProducts": 1,
    "maxConcurrency": 1,
    "requestTimeoutSecs": 15,
    "proxyConfiguration": {
        "useApifyProxy": false
    },
    "batchSize": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("laced_kirtan/powerreviews-reviews").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://www.buydig.com/shop/product.aspx?sku=LGOLED42C5PUA"],
    "maxReviewsPerProduct": 2,
    "maxReviewsScannedPerProduct": 10,
    "maxQuestionsPerProduct": 2,
    "maxAnswersPerProduct": 2,
    "maxProducts": 1,
    "maxConcurrency": 1,
    "requestTimeoutSecs": 15,
    "proxyConfiguration": { "useApifyProxy": False },
    "batchSize": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("laced_kirtan/powerreviews-reviews").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://www.buydig.com/shop/product.aspx?sku=LGOLED42C5PUA"
  ],
  "maxReviewsPerProduct": 2,
  "maxReviewsScannedPerProduct": 10,
  "maxQuestionsPerProduct": 2,
  "maxAnswersPerProduct": 2,
  "maxProducts": 1,
  "maxConcurrency": 1,
  "requestTimeoutSecs": 15,
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "batchSize": 50
}' |
apify call laced_kirtan/powerreviews-reviews --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,laced_kirtan/powerreviews-reviews"
        }
    }
}

```

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/m7NfXFB9EM9z2SmPQ/builds/uaTTzmIYZBQjPaDZ8/openapi.json
