# Amazon Review Classifier — complaints & returns · $0.5/1k (`leoworks/amazon-review-classifier`) Actor

Amazon review analysis: complaints, return reasons, praise, sentiment. products = ASINs/URLs (collected by junglee, billed to you ~$6/1k; Free plan 10 reviews/run; ~$6.5/1k all-in), or datasetId from any scraper, or texts. For AliExpress use leoworks/aliexpress-reviews-classifier.

- **URL**: https://apify.com/leoworks/amazon-review-classifier.md
- **Developed by:** [Leoworks](https://apify.com/leoworks) (community)
- **Categories:** E-commerce, AI, Agents
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.43 / 1,000 review classifications

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

## Amazon Review Classifier — complaints, returns, praise & worst variants

**Part of LeoWorks review analysis tools** (same labels, any language): [Korean](https://apify.com/leoworks/korean-review-classifier) · [Japanese](https://apify.com/leoworks/japanese-review-classifier) · [Spanish](https://apify.com/leoworks/spanish-review-classifier) · [Amazon](https://apify.com/leoworks/amazon-review-classifier) · [AliExpress](https://apify.com/leoworks/aliexpress-reviews-classifier) · [Google Maps](https://apify.com/leoworks/google-maps-review-classifier) · [social comments](https://apify.com/leoworks/social-comment-classifier).

**For Amazon sellers, brands, product teams, agencies and AI agents that already scrape Amazon reviews** — and need every review labelled with what went wrong, whether the buyer returned it, what buyers love and which variant causes the trouble, for $0.50 per 1,000 reviews, with no prompt writing or LLM key.

> **Collect and classify in one run — new.** Enter Amazon **ASINs or product URLs** in **Products** and this Actor collects the reviews and classifies them in the same run. The collection is done by a separate Actor, [Amazon Reviews Scraper by junglee](https://apify.com/junglee/amazon-reviews-scraper), which Apify bills to **your** account at its own price — about **$6 per 1,000 reviews** (it can change); this Actor adds **$0.50 per 1,000** classified reviews, so **about $6.50 per 1,000 reviews all-in**. The Store price card shows only this Actor's part. No Amazon login or cookies are used and reviewer names and profiles are switched off. On the Free Apify plan, junglee returns at most 10 reviews per run. Already have reviews from any scraper? Use **Reviews dataset** — no collection cost.

- **Complaint types** — defect, not as described, size/fit, performance, usability, shipping, value, safety, seller service (each with a probability)
- **Return intent** — the buyer returned it, asked for a refund or replacement, or says they will — and **return reasons** per product
- **What buyers praise** — build quality, matches the listing, fit, performance, ease of use, looks, value, shipping, seller service
- **Action queue** — returns, safety reports and "not as described" reviews as a CSV, lowest stars first
- **Star vs. text mismatch** — 5-star reviews that complain, 1-star reviews that are actually happy
- **Summary by product** — complaint and praise mix, return reasons, worst variants, verified-purchase share, star distribution, monthly trend and last 90 days vs before, as JSON and CSV
- **Your own labels** — up to 10 yes/no criteria in plain language (e.g. "mentions the pump or bottle", "compares with another brand")

**Use it to:** find why a listing gets 1–3 star reviews (defects vs. sizing vs. "not as described") · catch safety reports the day they appear · see which size or colour gets returned · learn what to keep in the listing copy from what buyers praise · compare complaint mix against competitors' listings · feed labelled reviews to a dashboard or an AI agent.

**How this differs from our other classifiers:** this one is built for **product reviews on Amazon**: its complaint types separate a broken item from one that works poorly, from one that is not as described, and it reads the purchased variant (size, colour), the review headline, the date and the verified-purchase flag. For local businesses use our [Google Maps Review Classifier](https://apify.com/leoworks/google-maps-review-classifier); for AliExpress, [AliExpress Reviews](https://apify.com/leoworks/aliexpress-reviews-classifier); for social media comments, the [Social Comment Classifier](https://apify.com/leoworks/social-comment-classifier).

### How to use

**Option A — enter the products (the Actor collects the reviews):**

1. In **Products**, paste up to 20 ASINs (10 characters, e.g. `B0CWXNS552`) or Amazon product URLs (a URL carries its own marketplace; for ASINs choose **Marketplace**, default amazon.com — an ASIN belongs to one marketplace, the same product can have another ASIN elsewhere).
2. Set **Reviews to collect per product** (default 50, up to 100) and **Collect: order** (newest first by default).
3. Click **Start**. The run log shows the estimated collection and classification cost before anything is collected; with a maximum cost per run the Actor lowers the number of reviews to stay within it. If the collector finds nothing, the run stops with the reason and this Actor charges nothing.
4. Open **Output** as below. The summary (`SUMMARY`) records which collector run produced the reviews.

**Option B — you already have reviews:**

1. Run an Amazon reviews scraper for your products or competitors' — for example [Amazon Reviews Scraper (junglee)](https://apify.com/junglee/amazon-reviews-scraper) (see **Works with** for others).
2. Open this Actor and pick that run's dataset in **Reviews dataset** (or paste review texts to try it).
3. Optional: add **Custom labels**, or a filter such as **Only reviews newer than: 90 days**, **Only reviews with at most 3 stars** or **Verified purchases only**. Skipped reviews are not charged.
4. Click **Start**. 36 reviews take about 3 seconds.
5. In **Output**, open **Classified reviews**, **Returns, safety & not as described** or **Labels with probabilities**, or download `ACTION_QUEUE.csv` and `REPORT_PRODUCTS.csv`. Export the table as CSV, Excel or JSON.

#### Run it automatically after every scrape

In your Amazon reviews scraper (or its saved task), open **Integrations → Add integration → Apify Actor**, choose this Actor and set its input to:

```json
{ "datasetId": "{{resource.defaultDatasetId}}" }
```

Every finished scrape is then classified with no extra step. Schedule the scraper weekly and set **Only reviews newer than: 7 days** here for a weekly action queue. The same review scraped twice is classified and charged once.

### Output sample

Real rows from run `F2HHqgj5XFYcTssxy` (2026-10-11, build 0.2.1) on public Amazon reviews of 8 products.

| review (headline / text) | stars | variant | complaints | praise | return | act on it |
|---|---|---|---|---|---|---|
| Raw edge on grate / I just received this and was trying to remove the grate and it completely cut open my finger … | 3 | 10-QT DualZone | safety, usability | — | no | **yes** |
| Disappointed / Returning and buying a different brand. This was way too cheaply made. And not enough large blocks … seems used. | 2 | 1 pack (Deluxe Bag) | defect, not as described | — | **yes** | **yes** |
| Not as described / Not fast charging | 3 | 6FT×2 | not as described, performance | — | no | **yes** |
| Came without the strap! / This is a very nice mat but I specifically ordered it because it had the strap … | 3 | Teal | not as described | — | no | **yes** |
| Meh / The good: They're soft … The bad: … The area around the ankles … digs into the underside of my ankles. … I have to return these. | 3 | Size 7.5 | usability, performance | usability | **yes** | **yes** |
| manufacturing defects in the fabric / I originally bought these leggings in black, and they are an absolute perfect dupe for Lululemon … | 2 | Size L | defect | size_fit, usability, performance | no | no |
| Best out there / Great and true lightning fast charging cables. Perfect length too. Awesome deal for two cords. | 5 | 6FT×2 | none | performance, size_fit, value | no | no |

In a second run (`1hcSoiX78ZDmPBcfY`, 36 reviews of 6 products straight from the junglee scraper) the per-product summary flagged, for example, the grey backpack as the worst variant (2 of 3 reviews with a complaint) and a shoe review that was 5 stars but returned for size.

### Input example

The form default — two pasted reviews, no dataset needed (about $0.001, 2 seconds):

```json
{
  "texts": [
    "Stopped charging after two weeks. Returning it.",
    "Fits great but the fabric is see-through when I squat."
  ]
}
```

To classify an Amazon reviews scraper's output, pass its dataset instead — the text, headline, stars, variant and IDs are detected automatically:

```json
{
  "datasetId": "YOUR_AMAZON_REVIEWS_DATASET_ID",
  "reviewsNewerThan": "90 days",
  "verifiedOnly": true,
  "customLabels": ["mentions the pump or bottle"]
}
```

### Pricing

Pay only for classified reviews — no subscription.

| Event | Price | When |
|---|---|---|
| `review-judged` | $0.0005 | One review classified (complaint types, sentiment, return intent and any custom labels). |

That is **$0.50 per 1,000 reviews**. **First run with the form defaults: about $0.001** (2 reviews, 2 seconds).

**Cost examples**

| Reviews | Cost |
|---|---|
| 100 | $0.05 |
| 1,000 | $0.50 |
| 10,000 | $5.00 |
| 100,000 | $50.00 |

With the free $5 monthly Apify credit you can classify about **10,000 reviews**.

**When the Actor collects the reviews (Products):** the collector bills you separately — about $0.006 per review for the default collector, junglee (about $0.001 for the optional web_wanderer collector; the price you pay depends on your Apify plan and can change). All-in with the default collector that is about **$6.50 per 1,000 reviews** (50 reviews of one product: about $0.33). The run log shows the live estimate before collecting, and `SUMMARY.collection` records the run.

Items without review text are skipped and **not charged**. Reviews that fail after retries are reported with an `error` field and **not charged**. If you set a maximum cost per run, the Actor stops cleanly when it is reached.

### Works with

Field names are matched ignoring case, `_` and `-`, star ratings like `"4.0 out of 5 stars"` are read as numbers, and variants given as lists are joined. Checked against each scraper's published output schema (2026-10-11); junglee also against real output.

| Scraper on Apify Store | Text | Stars | Variant | Date | Verified |
|---|---|---|---|---|---|
| [Amazon Reviews Scraper (junglee)](https://apify.com/junglee/amazon-reviews-scraper) | `reviewDescription` + `reviewTitle` | `ratingScore` | `variant` | `date` | `isVerified` |
| [Amazon Reviews Extractor (web_wanderer)](https://apify.com/web_wanderer/amazon-reviews-extractor) | `reviewText` + `reviewTitle` | `rating` | `variantSpecs` (list) | `reviewDate` | `verifiedPurchase` |
| [Amazon Reviews Scraper (axesso)](https://apify.com/axesso_data/amazon-reviews-scraper) | `text` + `title` | `rating` ("5.0 out of 5 stars") | `variationList` (list) | `date` | `verified` |
| [delicious_zebu Amazon reviews](https://apify.com/delicious_zebu) | `ReviewContent` + `ReviewTitle` | `ReviewScore` | `Variant` (list) | `ReviewDate` | `Verified` |
| Scrapers with snake_case fields (`review_body`, `review_title`, `is_verified_purchase`) | ✓ | ✓ | ✓ | ✓ | ✓ |

Rows without review text (product summary rows, error rows) are skipped and not charged. Anything still not detected can be set under **Field mapping**. **Also:** the Apify API and JavaScript/Python clients · Apify Schedules · Claude, Cursor and Claude Code through the Apify MCP server (below).

### Call it from code

```bash
curl -X POST "https://api.apify.com/v2/acts/leoworks~amazon-review-classifier/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"datasetId": "YOUR_DATASET_ID", "maxStars": 3}'
```

JavaScript (`npm install apify-client`):

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('leoworks/amazon-review-classifier').call({ datasetId: 'YOUR_DATASET_ID' });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
const products = await client.keyValueStore(run.defaultKeyValueStoreId).getRecord('REPORT');
```

Python (`pip install apify-client`):

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("leoworks/amazon-review-classifier").call(run_input={"datasetId": "YOUR_DATASET_ID"})
items = client.dataset(run["defaultDatasetId"]).list_items().items
to_fix = [r for r in items if r.get("action")]
```

The dataset also connects to Google Sheets, Make, Zapier, Slack and webhooks from the run's **Integrations** tab.

### Use with Claude, Cursor or Claude Code (MCP)

**Ask your AI agent.** Add the Apify MCP server with this Actor as a tool, then say, for example:

- *"Why are buyers returning this product? Classify these Amazon reviews: “Stopped charging after two weeks. Returning it.” / “Fits great but the fabric is see-through when I squat.” / “Arrived late and the box was crushed, but the product itself is fine.”"*
- *"Classify dataset YOUR_DATASET_ID from my Amazon reviews scraper run, only 1–3 star reviews, and list the top 3 return reasons with one example review each."*
- *"Do these Amazon reviews say the buyer returned the product or wants a refund? “Sent it back, the zipper broke.” / “Love it, bought a second one.” / “Asked for a replacement, it ran small.”"*

The agent calls the tool `leoworks--amazon-review-classifier` and reads the labels with `get-dataset-items`. Replace `YOUR_DATASET_ID` with the ID of your own dataset.

Claude Desktop or Cursor (`mcp.json`):

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=leoworks/amazon-review-classifier",
      "headers": { "Authorization": "Bearer YOUR_APIFY_TOKEN" }
    }
  }
}
```

Claude Code: `claude mcp add --transport http apify "https://mcp.apify.com?tools=leoworks/amazon-review-classifier" --header "Authorization: Bearer YOUR_APIFY_TOKEN"`. Leave out the header to sign in with OAuth in the browser instead. We verified this setup with the Apify MCP server (v0.17.4) on 2026-10-10: the agent classified a pasted review in 7 seconds end to end (run `LKN9tXlzXAXKWI6yi`).

### Output

| Where | What |
|---|---|
| Dataset — view **Classified reviews** | One row per review with flat, spreadsheet-friendly columns |
| Dataset — view **Returns, safety & not as described** | The rows to act on — filter `action` = true |
| Dataset — view **Labels with probabilities** | Every label with its probability, for your own thresholds |
| `ACTION_QUEUE.csv` | Returns, safety reports and "not as described" reviews, lowest stars first, then newest |
| `REPORT_PRODUCTS.csv` | One row per product: reviews, average stars, complaint rate, return rate and top return reasons, top complaints, top praise, worst variant, verified share, last 90 days vs before, star counts, low-sample flag |
| `REPORT` (JSON) | The same per product plus monthly trend, worst 5 variants, sentiment shares, custom label shares and example complaints |
| `SUMMARY` (JSON) | Run statistics: detected fields, filters, counts, skipped and duplicate reviews |

Nothing extra is charged for the files.

#### One row

From run `F2HHqgj5XFYcTssxy` (`complaintScores` left out):

```json
{
  "reviewId": "R2KTQWKW060AUZ",
  "productAsin": "B0B15Q3HCQ",
  "asin": "B0B15Q3HCQ",
  "variant": "Size: 10-QT & DualZone Smart XL (Black, w/ probe)",
  "rating": 3,
  "verified": true,
  "text": "Raw edge on grate\nI just received this and was trying to remove the grate and it completely cut open my finger trying to remove it.",
  "complaintTypes": "safety, usability",
  "praiseTypes": "",
  "sentiment": "negative",
  "returnIntent": false,
  "starTextMismatch": false,
  "action": true,
  "labels": {
    "complaint": [{ "label": "safety", "probability": 0.98 }, { "label": "usability", "probability": 0.89 }],
    "sentiment": { "label": "negative", "probability": 0.96, "confidence": 0.94 },
    "returnIntent": { "probability": 0.04, "matched": false },
    "praise": [],
    "starTextMismatch": { "matched": false, "rating": 3, "sentiment": "negative" }
  }
}
```

`publishedAt`, `verified`, `vine`, `helpfulVotes`, `reviewUrl` and `country` appear when the dataset has them. When no complaint type passes the threshold, `complaintTypes` is `none`. **Minimal mode** returns IDs and label keys only.

#### Summary by product (REPORT)

One product from run `1hcSoiX78ZDmPBcfY` (some fields left out):

```json
{
  "group": "B07QN9NPKN",
  "reviews": 6,
  "lowSample": true,
  "averageRating": 4.83,
  "complaintRate": 0.333,
  "complaints": [{ "label": "usability", "count": 2, "share": 0.333 }],
  "praise": [{ "label": "quality", "count": 6, "share": 1 }, { "label": "size_fit", "count": 5, "share": 0.833 }, { "label": "performance", "count": 4, "share": 0.667 }, { "label": "value", "count": 3, "share": 0.5 }, { "label": "usability", "count": 2, "share": 0.333 }],
  "returnIntentRate": 0,
  "returnReasons": [],
  "verifiedShare": 1,
  "worstVariants": [{ "variant": "Color: Grey", "reviews": 3, "averageRating": 4.67, "complaintRate": 0.667, "negativeShare": 0 }],
  "last90Days": { "reviews": 2, "averageRating": 5, "complaintRate": 0, "negativeShare": 0 }
}
```

`lowSample` is true below 20 classified reviews — shares from a handful of reviews swing a lot. Without login Amazon shows only part of a product's reviews, so scraper datasets are often small.

#### Photo evidence (beta)

A complaint is stronger with a photo. If your Amazon reviews dataset carries the photos buyers attached (the Amazon reviews scraper by junglee puts them in `reviewImages`), turn on **Judge review photos** and the Actor checks whether a photo really shows the damage the review describes. It is **off by default** and adds **no extra charge**; it adds a few seconds per photo review.

| Setting | What it does |
|---|---|
| Judge review photos | `Only reviews with a complaint or 3 stars or fewer` (recommended) or `All reviews that have photos` |
| Photos judged per review | The first 1–3 photos of each review (2 by default; at most 2 with "All reviews that have photos") |
| Photo size | Longest side requested from the photo server: 512, 768 or 1024 pixels |
| Photo field | Only if your scraper names the photo list differently (auto-detected: `reviewImages`, `reviewImageUrls`, `images`, `imageUrls`, `photos`) |

Each judged review gets `photoEvidence`: `supports_complaint_product` (a real product photo shows a defect on the product and the review complains about it), `supports_complaint_packaging` (damaged box or bag), `damage_seen_text_silent` (damage in the photo, not mentioned in the text), `no_evidence`, or `not_product_photo` (a catalog image, label, screenshot or something unrelated). A review whose photo supports the complaint is flagged **Act on it**, and `ACTION_QUEUE.csv` lists photo-backed product defects first, then packaging damage, then the rest; the queue gets the columns `photoEvidence` and `photoUrl`. The dataset view **Photo evidence (beta)** lists them, and `photoStatus` says why a review was not judged (`no_photo`, `skipped_by_rule`, `too_small`, `download_failed`, `judge_failed`).

- **Beta, small check:** We ran it on 200 reviews of the Amazon reviews scraper's output; 30 reviews had photos (52 photos). It flagged 11 photos from 7 reviews as `supports_complaint_product`, and a person checked them by hand: 10 were real damage, and 1 was too ambiguous to judge (a dent or a reflection on the surface) and was left out of the count. Counted without that photo it is 10 of 10 (95% lower bound about 72%); counted as a miss it is 10 of 11 (about 62%). It flagged no packaging damage, so packaging is **not measured** on Amazon. Of the five photos just under the cut-off for a product defect, three showed real damage, so expect it to miss some defects. The cut-offs were tuned on AliExpress photos (where a larger check was done), not on Amazon. Use it to find evidence quickly, not as proof for a claim.
- **Photo size:** Amazon lists review photos as 88-pixel thumbnails. The Actor asks Amazon's image server for a larger copy of the same photo (worked for 52 of 52 photos in our check; Amazon does not document this, so it can change). Photos that cannot be read are skipped and the review is still classified.
- **Privacy:** photos are downloaded only while they are judged and are sent to TypeSafe (the AI model provider) for that purpose. This Actor does not store them, and no question is about people. `photoUrl` links to the photo on Amazon's server, which can stop working later.

### Accuracy

Measured on 179 hand-labelled English Amazon reviews of 12 products (leggings, running shoes, earbuds, cables, moisturizer, shampoo, air fryer, coffee maker, toy blocks, yoga mat, backpack, dog toy; 2026-10-10), mostly the 1–3 star reviews Amazon shows first plus some 4–5 star ones, first 520 characters of headline + text. The questions and the second threshold were adjusted on one part, then checked once on a separate part that was not used for adjusting.

| Set | Reviews (with a complaint) | Complaint types | Sentiment | Praise |
|---|---|---|---|---|
| **Check set — not used for adjusting** | 100 (60) | **88%** | **99%** | **91%** |
| Adjusting set | 79 (48) | 92% | 96% | — |

Praise was added in version 0.2 (2026-10-11) and labelled by hand on the check set before the first run; the rule for extra praise labels (only from 0.8, like complaints) was set once afterwards.

"Complaint types" counts a review as correct when the labels found include a true complaint type and add none that is wrong (reviews without complaints must get none). Many 3-star reviews are mixed, so sentiment accepts either label where both fit. Probabilities are calibrated — use the two thresholds to trade coverage for certainty. Automated labels can be wrong; check samples before making big decisions.

### Limits

| Item | Limit |
|---|---|
| Review length | First 4,000 characters are used |
| Custom labels | Up to 10, each up to 200 characters |
| Dataset size | Any — datasets are read in pages of 1,000 |
| Language | English (measured). Other languages are accepted and usually work, but accuracy has not been measured — treat them as **beta** |
| Speed | 36 reviews in about 3 seconds; 10 reviews in parallel by default (up to 40) |
| Data | Only the review text and headline, its stars, the variant and your custom labels are sent for classification; reviewer names and profiles are not used or output |
| Filters | Reviews without a star rating or date are kept by the star and date filters |
| Collecting (Products) | Up to 20 products and 100 reviews per product per run; one Amazon marketplace per ASIN (amazon.com, .co.uk, .de, .fr, .it, .es, .ca, .com.au, .co.jp, .in and more). Amazon shows a limited set of reviews without a login, so a product can return fewer than you asked for |
| Collecting on the Free Apify plan | junglee returns at most 10 reviews per run (its own limit) |
| Collecting — tested | amazon.com with junglee, 2026-10-18: 10 reviews collected and classified, 0 errors. The optional web_wanderer collector returned no reviews for amazon.com that day (its notice: Amazon US restricted text reviews); other marketplaces with it were not verified |

### FAQ

**Which AI makes the judgments?** Jev, TypeSafe's decision model (version `jev-1.13.0`, pinned). Jev answers each label with a calibrated probability instead of generated text, so a 0.9 means the same thing for every item. Answers are stable but not fixed: re-running the same input can change a few borderline answers (under 1% of answers in our repeat tests) — filter on probability when an item must never flip.

**Does it scrape Amazon?** No. It classifies reviews you already have — run an Amazon reviews scraper first (see **Works with**) or paste texts.

**Why both "defect" and "performance"?** A broken item and an item that works poorly need different fixes (quality control vs. product design or listing claims), so they are kept apart.

**How is this different from Amazon's "Customers say" summary?** That summary is one paragraph per product, chosen by Amazon. This Actor labels every review you scrape — yours and competitors' — so you can count return reasons per variant, filter the reviews behind a number, track them month by month and export them.

**Why not ask ChatGPT?** You can, for a few reviews. For thousands, this gives a probability per label you can filter on, measured accuracy and a fixed price of $0.50 per 1,000, with no prompt to maintain.

**Which reviews go into the action queue?** Reviews where the buyer returned the item or asked for a refund or replacement, reviews with a safety complaint, and reviews saying the item is not as described (wrong, used, counterfeit, missing parts or claims that are not true).

**What is a star vs. text mismatch?** A 4–5 star review whose text is negative, or a 1–2 star review whose text is positive. They often hide a problem behind a good rating, or a misunderstanding behind a bad one.

**Can I classify only new reviews every week?** Yes. Schedule the scraper, connect this Actor through **Integrations** (see **How to use**) and set **Only reviews newer than: 7 days**. Older and duplicate reviews are skipped and not charged.

**Are reviews in other languages supported?** They are accepted and usually labelled well, but only English is measured — treat other marketplaces' languages as beta.

### Compliance and privacy

- **Public data, no login.** With **Products**, the reviews are the publicly visible Amazon reviews collected by a separate collector; no Amazon account, cookies or login of yours are used.
- **No reviewer profiles.** The collector is run with reviewer personal data switched off; only the review text, headline, stars, date, variant and verified-purchase flag are used and output.
- **You stay responsible for the use.** Amazon's terms apply to collecting the data. This is not legal advice.

### Disclaimer

> Independent tool — not affiliated with, endorsed by or sponsored by Amazon, or by the authors of the scraper listed above. Names are used only to describe compatible data sources. The reviews shown are public reviews used as examples.

### Reviews and support

If this Actor saved you time, a short review on Apify Store helps others find it. Questions or a dataset whose fields are not detected? Open an issue in the **Issues** tab — we answer within a day.

### Changelog

See the Changelog tab.

# Changelog

This Actor's version history is a separate document: https://apify.com/leoworks/amazon-review-classifier/changelog.md

# Actor input Schema

## `products` (type: `array`):

One product per line, up to 20: the 10-character ASIN (for example B0CWXNS552) or the product page URL (…/dp/ASIN; its marketplace is taken from the URL). The Actor then collects the reviews and classifies them in the same run. Collection is done by an existing Amazon reviews scraper (a separate Actor that Apify bills to your account — about $0.006 per review for the default collector, about $0.001 for the alternative; the estimate is shown in the run log before anything is collected); this Actor adds $0.0005 per classified review. No Amazon login or cookies are used, and reviewer names and profiles are switched off. Amazon shows at most about 100 reviews per product this way. Use this OR “Reviews dataset”; if both are set the run stops.

## `marketplace` (type: `string`):

Which Amazon site the ASINs in “Products” belong to. A product URL carries its own marketplace and overrides this.

## `collectReviewsPerProduct` (type: `integer`):

How many reviews to collect for each product (1 to 100). You pay the collector for each one, so a lower number is cheaper; “Max reviews per product” below limits only how many are classified.

## `collectSort` (type: `string`):

Which reviews to collect first. Newest first is the least biased sample of what buyers say now.

## `collector` (type: `string`):

The Amazon reviews scraper that collects for you. The default (junglee) returned and classified reviews in our test on amazon.com. The other is about six times cheaper but returned nothing for amazon.com in the same test — try it for other marketplaces. On the Free Apify plan, junglee returns at most 10 reviews per run (its own limit). Prices are the collectors' own and can change.

## `datasetId` (type: `string`):

An Apify dataset containing Amazon reviews — for example the output of an Amazon reviews scraper. Use this OR “Products” (not both) OR “Review texts”.

## `texts` (type: `array`):

Paste review texts directly (one per line). Use this OR “Reviews dataset”.

## `customLabels` (type: `array`):

Up to 10 extra yes/no labels (each up to 200 characters) in plain language, e.g. “mentions the battery”, “compares with another brand”. Each gets a probability.

## `reviewsNewerThan` (type: `string`):

Classify only reviews published after this date — a date like `2026-01-01` or a period like `90 days`, `6 months`, `1 year`. Needs a review date in the dataset (e.g. `date`). Leave empty for all.

## `maxStars` (type: `integer`):

For example 3 = classify only 1–3 star reviews (where complaints and returns are). 0 = all ratings. Reviews without a star rating are kept.

## `verifiedOnly` (type: `boolean`):

Skip reviews not marked as a verified purchase (needs a field such as `isVerified`).

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

Classify at most this many reviews per product (ASIN), in dataset order. 0 = no limit.

## `maxItems` (type: `integer`):

Classify at most this many reviews (0 = all).

## `photoJudging` (type: `string`):

Adds `photoEvidence` (supports_complaint_product, supports_complaint_packaging, damage_seen_text_silent, no_evidence, not_product_photo) and puts photo-backed product defects, then photo-backed packaging damage, at the top of ACTION_QUEUE.csv. "Only reviews with a complaint or 3 stars or fewer" judges far fewer photos and is the recommended setting.

## `maxPhotosPerReview` (type: `integer`):

The first photos of each review. With "All reviews that have photos", at most 2 photos per review are judged.

## `photoMaxSide` (type: `integer`):

Longest side in pixels requested from the photo server (512, 768 or 1024; other values are rounded). Amazon review photos arrive as 88 px thumbnails, so a larger version is requested. Photos under 280 pixels on the short side are skipped.

## `textField` (type: `string`):

Field holding the review text. Leave empty to auto-detect (reviewDescription, reviewText, text, body, …).

## `extraTextFields` (type: `array`):

Fields to prepend to the text (up to 5). Leave empty to add the review headline automatically (reviewTitle).

## `idFields` (type: `array`):

Fields copied unchanged from each input item to the output so you can join results back (e.g. reviewId, productAsin). Leave empty to auto-pick reviewId and the product ASIN.

## `ratingField` (type: `string`):

Leave empty to auto-detect (ratingScore, rating, stars, …).

## `dateField` (type: `string`):

Leave empty to auto-detect (date, reviewDate, reviewedIn, …). Used for the monthly trend, the last-90-days comparison and the date filter.

## `variantField` (type: `string`):

Leave empty to auto-detect (variant, variantName, …). Used for the worst-variants breakdown.

## `photoField` (type: `string`):

Field with the picture addresses of each review. Auto-detected (reviewImages, reviewImageUrls, images, imageUrls, photos); set it only if your scraper uses another name.

## `complaintThreshold` (type: `number`):

Minimum probability (0–1) for the strongest complaint type, the return-intent flag or a custom label to be reported.

## `secondaryThreshold` (type: `number`):

Minimum probability (0–1) for any further complaint type after the strongest one. Product complaints overlap (a weak item can also feel uncomfortable), so side labels need to be surer. Lower it to see more labels per review.

## `outputMode` (type: `string`):

Minimal mode returns only label keys — smaller and easier to aggregate.

## `summaryGroupField` (type: `string`):

Field in your dataset that identifies the product (e.g. `productAsin`). The run then saves a REPORT record with, per product: complaint rate and complaint mix, sentiment shares, average stars, share of reviews with a return or refund and 3 example complaints. Leave empty to detect it automatically. No extra charge.

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

Reviews classified in parallel.

## `healthCheck` (type: `boolean`):

Internal: fail the run when results look degraded (used by the developer's scheduled checks).

## Actor input object example

```json
{
  "marketplace": "com",
  "collectReviewsPerProduct": 50,
  "collectSort": "recent",
  "collector": "junglee/amazon-reviews-scraper",
  "texts": [
    "Stopped charging after two weeks. Returning it.",
    "Fits great but the fabric is see-through when I squat."
  ],
  "customLabels": [],
  "maxStars": 0,
  "verifiedOnly": false,
  "maxReviewsPerProduct": 0,
  "maxItems": 0,
  "photoJudging": "off",
  "maxPhotosPerReview": 2,
  "photoMaxSide": 768,
  "extraTextFields": [],
  "idFields": [],
  "complaintThreshold": 0.5,
  "secondaryThreshold": 0.8,
  "outputMode": "full",
  "maxConcurrency": 10,
  "healthCheck": false
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `summary` (type: `string`):

No description

## `report` (type: `string`):

No description

## `productsCsv` (type: `string`):

No description

## `actionQueue` (type: `string`):

No description

## `photoEvidence` (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 = {
    "texts": [
        "Stopped charging after two weeks. Returning it.",
        "Fits great but the fabric is see-through when I squat."
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("leoworks/amazon-review-classifier").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 = { "texts": [
        "Stopped charging after two weeks. Returning it.",
        "Fits great but the fabric is see-through when I squat.",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("leoworks/amazon-review-classifier").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 '{
  "texts": [
    "Stopped charging after two weeks. Returning it.",
    "Fits great but the fabric is see-through when I squat."
  ]
}' |
apify call leoworks/amazon-review-classifier --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,leoworks/amazon-review-classifier"
        }
    }
}
```

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/m3TrKzGS2a7i3gzga/builds/QHSSiwnh36LWdF1Tt/openapi.json
