Sentiment Analysis - Reviews, Reddit & Comments to Insights avatar

Sentiment Analysis - Reviews, Reddit & Comments to Insights

Pricing

from $10.40 / 1,000 ai insight extracteds

Go to Apify Store
Sentiment Analysis - Reviews, Reddit & Comments to Insights

Sentiment Analysis - Reviews, Reddit & Comments to Insights

Sentiment analysis of reviews, Reddit posts and comments you already have: per text sentiment, product issue, product names and exact sentences, plus AI issue analysis and issue clusters (on by default). 1,000 texts: about $17.60 on BRONZE, $1.60 rules only. Reads Actor datasets and CSV.

Pricing

from $10.40 / 1,000 ai insight extracteds

Rating

0.0

(0)

Developer

daehwan kim

daehwan kim

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Share

Turn the reviews, Reddit posts, comments and support tickets you already have into product insights. Each text comes back as one row: its sentiment (positive, negative, mixed or neutral), the product issue it raises (complaint, request, question, praise or usage context), the product or feature it names and the exact sentence that shows it — in English and Korean. On paid plans an AI analysis reads every text for its product issues, each with a quote from the text, and issue clusters count how many texts raise the same problem of the same product (battery life, overheating and charging trouble are separate clusters).

Feed it the results of another Apify Actor directly (Reddit, app reviews, Google Maps reviews, Threads, Telegram, Naver blog, YouTube comments…), a CSV or JSON export, or texts you paste.

What a default run costs: 1,000 texts with the AI analysis (on by default) ≈ $17.60 on the BRONZE plan ($0.004 run start + 1,000 × $0.0016 rules + 1,000 × $0.016 AI). With the rules only (aiInsights: false): $1.60. Issue clusters add $0.04 a cluster row (default up to 50: at most $19.60 in all). The run-start fee includes reading the first 1,000 rows of your sources; each further 1,000 rows read is $0.0016 (rows-read). Your run's maximum charge is always respected.

Free plan and paid plans

Free plan (preview)Paid Apify plan (Starter and up)
Texts per runthe first 1up to maxTexts (default 1,000, 20,000 a run)
Sentiment and one sentence that shows iton that oneon every text
The rest of the rule verdict (categories, your product names, every evidence sentence with its category, score and signal words)locked — the row says how many a paid run gives for that text (categories.count, targets.count, evidenceLocked.count), never the valueson every text
AI analysis (beta): product issues, product or feature, one-line summary, exact quotelocked — a free run asks no modelon by default, for up to aiMaxTexts texts (5,000 a run)
Issue clusters (3+ texts about the same problem of the same product: count, share, sentiment, 1–3 quotes, links)the upper bound a paid run of your settings could make (maxClusters; the free plan does not analyse your other texts, so it gives no count)one row per cluster, up to maxClusters (200 a run)
What a paid run of the same input getsin the free-plan-preview row: how many texts your input holds (a free run reads up to 5,000 rows), how many are locked, the estimate of this run with your settings and of the whole input (how many runs, the startAt of each, the total; BRONZE prices). No analysis of the other texts — no rows, no sentiment or category counts—
Pricerun-started and text-scoredall five events, with plan discounts

Rules and AI on the same text (fixed example)

The rules part below is what this Actor's rules return for these two made-up texts. The AI part is the model's real answer for them (claude-haiku-5-5, 2026-10-16, after our checks). A free run shows only the sentiment and one sentence of your first text; this is the whole output.

English — Love the Pixel 8 camera, but the battery dies by 3pm and it gets hot while charging. Please add a battery saver mode.

  • rules: mixed; complaint, request, praise — the battery and the heat share one complaint sentence (and "gets hot" is not on the word list), and that same sentence is also the praise.
  • AI: mixed; praise · Pixel 8 · "Love the Pixel 8 camera" — complaint · battery · "the battery dies by 3pm" — complaint · battery · "it gets hot while charging" (three issues at most: the request was the fourth).

Korean — 갤럭시 S24 화면은 정말 선명한데 배터리가 반나절도 못 가요. 업데이트 후로 카메라 앱이 자꾸 튕겨요. 절전 모드 좀 개선해 주세요.

  • rules: mixed; complaint, request, praise — "배터리가 반나절도 못 가요" has no word on the list, so the battery complaint is missed and its sentence counts as praise ("선명").
  • AI: mixed; praise · 화면 · "화면은 정말 선명한데" — complaint · 배터리 · "배터리가 반나절도 못 가요" — complaint · 카메라 앱 · "업데이트 후로 카메라 앱이 자꾸 튕겨요".

The free preview row carries the same example in its example field.

Paid-plan discounts (applied by Apify to every event of this Actor):

Apify planDiscount
FREElist price
BRONZE (Starter)20% off
SILVER (Scale)35% off
GOLD and up (Business, Enterprise)48% off

What it is for

  • Product teams: what users complain about and ask for, by feature, with the sentences to paste into a planning doc.
  • Customer support: sort a ticket export into complaints, questions and requests; find the product that causes most of them.
  • Marketing and research: sentiment of Reddit threads, app reviews or comments about your product or a competitor's, with source links.
  • Korean feedback: Naver blog posts, Coupang or app reviews in Korean are read with a Korean word list, and by the AI.

How to use it

  1. Run a scraper you already use (for example a Reddit, Google Play or Google Maps reviews scraper) and copy its dataset ID, or upload a CSV export somewhere public, or paste texts.
  2. Put the dataset ID in datasetIds, the file address in csvUrls or the texts in texts. Add your product and feature names to productHints.
  3. Run it. Open the Texts view for one row per text, Issue clusters for the grouped issues, and the last rows for the notices and the run report (limits). On the free plan, open Free plan preview and paid estimate for what a paid run of the same input would analyse and cost.

Input

FieldTypeDescription
datasetIdsarrayIDs of datasets in your Apify account, read with this run's token (the run-start fee pays for the first 1,000 rows of all sources; each further 1,000 rows read is a rows-read event). Text fields are found by themselves: text, body, content, reviewText, reviewBody, review, feedback, comment, commentText, selftext, caption, postText, fullText, message, snippet, description (letter case, spaces and _ aside). A post with a title and a body (a Reddit post) is analysed as "title, blank line, body". Notice and summary rows of other Actors are left out
csvUrlsarrayPublic http(s) addresses of CSV (header row; comma, semicolon, tab or pipe; a file with one column is read by the same rules: a quoted cell may run over several lines, and reading stops at its first row that is not valid CSV), JSON or JSONL files, up to 20 MB each (their rows count as rows read; a CSV row with more cells than the header row is left out, not charged; at a row that is not valid CSV — a quote never closed, or text right after a closing quote — reading of that file stops: the rows before it are read, from its line on nothing is read or charged; both come with a source-parse-error notice; empty cells at the end of a row are ignored and a shorter row gets empty cells)
textsarrayTexts pasted here, one per entry (or objects { "text", "url", "id", "date" }); they count as rows read too
textFieldstringThe text field's name, when it has another one (tried first)
productHintsarrayYour product and feature names, up to 30
languagestringauto (default), en or ko — which word lists the rules use
aiInsightsbooleanAI analysis on paid plans of the whole text a row holds, up to 5,000 characters (default true; 1,000 texts ≈ $17.60 on BRONZE with it, $1.60 without)
aiMaxTextsintegerTexts analysed by AI in a run, 1–5,000 (default 1,000)
clustersbooleanIssue cluster rows on paid plans (default true; $0.04 a row on BRONZE)
maxClustersintegerCluster rows in a run, 1–200 (default 50)
maxTextsintegerTexts in a run, 1–20,000 (default 1,000; free plan: 1 — the free preview uses this value for its estimates)
maxItemsPerSourceintegerRows read from one dataset or file, 1–100,000 (default 20,000)
startAtintegerTo go on from an earlier run of the same input: texts before this place (in input order, each once) are passed over, not analysed or charged as texts. The earlier run's input-limit row, status and limits.resume.nextStartAt give the exact value. Passed-over rows are still read (rows read). Default 0

A row is one review: rows with different IDs are different texts even when their words are the same (each is a row and a text-scored event; the AI analyses those words once and charges once — see ai.sameTextAs). The same ID with the same words given twice, or the same words without an ID (letter case and spacing aside), is one text. Two texts that differ only past their 5,000th character are two texts. Rows without a text field and texts shorter than 3 characters are skipped and no text row is charged for them; they count as rows read, and a notice row says how many.

Large inputs. A run takes up to maxTexts texts. When your sources hold more, the run's input-limit row and status give nextStartAt: run the same input again with startAt set to it, and the next run takes the next texts without analysing or charging the earlier ones again. Each run reads the sources from the start (rows before startAt count as rows read).

Output

A text row (recordType: "text"):

FieldWhat it holds
text, title, truncatedThe text as analysed — by the rules and by the AI (up to 5,000 characters; truncated: true when the source text was longer), the title it came with
sourceType, sourceRef, sourceId, sourceUrl, publishedAt, ratingWhere it came from: dataset, file or input, which one, the row's id, address, date and star rating (1–5) when the source has them
languageen, ko or other
sentiment, sentimentSourcepositive, negative, mixed or neutral; ai when the AI analysis was delivered, else rules
categories, primaryCategoryRule categories: complaint, request, question, praise, usage-context
targetsYour productHints the text names
evidence[]For each category, the sentence that shows it: quote (cut out of text, letter for letter), start, end, category
rulesThe rule verdict: sentiment, score (−1 to 1 from the counts of signal words — not a probability), signals (the words that counted, not … when a negation turned one around)
aistatus: analysed with sentiment, noProductIssue (about the analyzedChars characters it read — the whole text), issues[] (category, target, issue, quote, start, end), analyzedChars, model, modelRequests, and sameTextAs (the textKey of the row whose analysis this is, when an earlier row had the same words: not charged again); or locked (free plan, with paidGets), off, or not-analysed with a reason
textKey, bodyKeyFixed keys (16 characters of a SHA-256): textKey of the row (its ID and words), also used in issue-cluster.textKeys; bodyKey of its words alone
Free plancategories, primaryCategory, targets, evidenceLocked, rules are { "locked": true, "count", "paidGets" }: what a paid run gives for this text, as a count; evidence[] holds one sentence without its category
plan, locked[], billedEvents[], analyzedAt, disclaimer, rowIdThe plan, what is withheld, the events this row is charged for, when, the notice below, and the row's fixed id within the run

An issue cluster row (recordType: "issue-cluster", paid plans) is one problem: the same category, the same product name (target; null with productNamed: false for texts that name none of your products — a cluster of their own) and the same topic (battery-life, overheating, charging, crashes, connectivity, performance, display, sound, camera, build, price, shipping, support, software or other, from the words of each issue's quote). Fields: label (for example complaint: Pixel 8 — battery life), topicLabel, texts (how many reviews — rows with the same words count each), distinctTexts (how many different wordings), share (of the run's texts), sentimentMix, languages, quotes[] (1 to 3 representative texts' quotes, each with sourceUrl and textKey), sourceUrls[] (up to 20), textKeys[], firstSeen, lastSeen, basis (ai, rules or mixed).

Example text row (paid plan, AI analysis on; the rules part is what the rules give, the AI part is the model's answer measured on 2026-10-16):

{
"recordType": "text",
"text": "Love the Pixel 8 camera, but the battery dies by 3pm and it gets hot while charging. Please add a battery saver mode.",
"sentiment": "mixed",
"sentimentSource": "ai",
"categories": ["complaint", "request", "praise"],
"primaryCategory": "complaint",
"targets": ["Pixel 8"],
"evidence": [
{ "quote": "Love the Pixel 8 camera, but the battery dies by 3pm and it gets hot while charging.", "start": 0, "end": 84, "category": "complaint" },
{ "quote": "Please add a battery saver mode.", "start": 85, "end": 117, "category": "request" },
{ "quote": "Love the Pixel 8 camera, but the battery dies by 3pm and it gets hot while charging.", "start": 0, "end": 84, "category": "praise" }
],
"rules": { "sentiment": "mixed", "score": 0, "signals": { "positive": ["love"], "negative": ["dies"] } },
"ai": {
"status": "analysed",
"sentiment": "mixed",
"noProductIssue": false,
"issues": [
{ "category": "praise", "target": "Pixel 8", "issue": "The writer likes the camera of the Pixel 8.", "quote": "Love the Pixel 8 camera", "start": 0, "end": 23 },
{ "category": "complaint", "target": "battery", "issue": "The battery runs out by mid-afternoon.", "quote": "the battery dies by 3pm", "start": 29, "end": 52 },
{ "category": "complaint", "target": "battery", "issue": "The device gets hot while charging.", "quote": "it gets hot while charging", "start": 57, "end": 83 }
],
"analyzedChars": 117,
"model": "claude-haiku-5-5",
"modelRequests": 1
},
"plan": "paid",
"billedEvents": ["text-scored", "insight-extracted"]
}

The same text on the free plan: "sentiment": "mixed", "evidence": [{ "quote": "Love the Pixel 8 camera, but the battery dies by 3pm and it gets hot while charging.", "start": 0, "end": 84 }], and "categories": { "locked": true, "count": 3, … }, "targets": { "locked": true, "count": 1, … }, "evidenceLocked": { "locked": true, "count": 2, … }, "rules": { "locked": true, … }, "ai": { "status": "locked", … }.

Notice rows (noticeCode, message) are never charged: free-plan-preview, source-unreadable, source-no-text, source-parse-error (rows of a CSV file with more cells than the header row were left out: skippedRows, firstSkippedLine; restNotRead: true and notReadFromLine when a row that is not valid CSV starts on that line: from there the file was not read — not tried, not found invalid, and not charged; the rows before it were read; that source's readCut is "csv-errors"), rows-skipped, duplicate-input, invalid-input, input-limit (with nextStartAt: the startAt of the next run), reading-stopped (the maximum charge did not pay for reading the next 1,000 rows: the texts read before are analysed as usual), ai-off, ai-stopped-charge-limit (the run's maximum charge stopped paying for AI analyses: the remaining texts go on with the rule verdict and no AI charge), charge-limit-reached, billing-unavailable (after a restart the platform's charge counts did not show earlier charges yet: nothing charged again, resurrect the run later) and others. The last row of a run, recordType: "limits", is its report: what each source gave, how many rows were read and what the reading was charged (reading), where the next run goes on (resume.nextStartAt; resume.inputFinished is true when nothing is left, false when texts are left and null when it is not known: the run had maxTexts texts and whether more follow is not known, or a CSV file stopped at a row that is not valid CSV — its rest was not read, and startAt does not reach it: fix the row and run again; the status message says which file and line), what was analysed, what was charged.

AI analysis (optional, beta, paid plans)

  • When it is on, the texts are sent to the Anthropic API (United States) with e-mail addresses and phone numbers replaced by [email] and [phone]. The model is claude-haiku-5-5. Turn it off with aiInsights: false.
  • The texts and your product names are sent as data, not instructions: a text that tells the model what to answer is not obeyed.
  • Every answer is checked before it is delivered or charged: each quote must be in your text letter for letter, each product or feature must be named in the text, and the summary may not write a number the text does not hold or any web or e-mail address. An answer that fails one check is thrown away whole and not charged; the row keeps its rule verdict and says why (ai.reason).
  • An answer that the text raises no product issue (noProductIssue: true) is an analysis too and is charged.
  • It reads the product, never the person: no scores of anyone's personality, politics, health or mood are made.
  • What it reads: the whole text the row holds (up to 5,000 characters; ai.analyzedChars). "No product issue" is about all of it.
  • Measured before release (2026-10-16, 30 real public texts: 15 Korean App Store reviews and 15 English Reddit comments): 30 of 30 answers passed our checks, none was refused; our model cost was about $0.0004 per analysis (about $0.0013 for a Korean text of 5,000 characters). Texts with the same words in one run are analysed once.

Pricing

Pay per event. Your run's maximum charge is always respected: rows are counted against it before they are written, and a run that reaches it ends normally (SUCCEEDED) with a notice.

EventFREEBRONZESILVERGOLD and upWhen
insight-extracted$0.02$0.016$0.013$0.0104An AI analysis that passed our checks is delivered on a text row (paid plans)
text-scored$0.002$0.0016$0.0013$0.00104A text is delivered as a row with its rule verdict — also when it is neutral
issue-cluster$0.05$0.04$0.0325$0.026A cluster row of 3 or more texts (paid plans)
run-started$0.005$0.004$0.00325$0.0026Once per run that has something to read, before the sources are read — also when they turn out to hold no usable text. Includes reading the first 1,000 rows
rows-read$0.002$0.0016$0.0013$0.00104Paid plans: each further 1,000 rows (or part) actually read from your sources, all together — rows without a text, duplicates and rows passed over with startAt too. Asked of your maximum charge before the rows are read

insight-extracted is the AI analysis that is on by default. Not charged: notices, rows without a text, duplicates, AI answers we threw away, and an input with nothing to read (no source and no text of 3 characters or more: no run-started either). Reading: the first 1,000 rows of a run are in run-started; each further 1,000 rows read is a rows-read event (a source that cannot be opened is not read and not charged). A restarted run reads again, without a new event, the rows it has already paid for. A free run reads at most 5,000 rows, without rows-read. Platform usage is included.

Example: 1,000 app reviews on the BRONZE plan with AI analysis (the default) and 20 clusters ≈ $0.004 + 1,000 × $0.0016 + 1,000 × $0.016 + 20 × $0.04 = $18.40; the same with the rules only (aiInsights: false, clusters: false) = $1.60. 2,000 reviews with the default maxTexts (1,000) take two runs (startAt 0 and 1,000): about $35.21 with AI and without clusters — the second run reads 2,000 rows, one rows-read event.

Limits and good to know

  • The rule verdict uses word lists and patterns. It is fast and free of model calls, and it misses sarcasm and context — that is what the AI analysis is for. Its score is not a probability.
  • Two runs started at the same time on the same input each deliver and charge their own rows.
  • A run that is restarted by the platform goes on where it stopped: rows already in the dataset are not written or charged again.
  • The platform's charge counts can show a charge a few minutes late. When a restarted run's counts still do not show what it charged before the restart, it does not charge those events again and stops (billing-unavailable): resurrect the run a few minutes later and it goes on from its own dataset. A new run, even with the same input, starts over and charges the texts again.
  • A run reads at most what its maximum charge pays for: when the limit does not pay for the next 1,000 rows it stops reading and delivers what it read, with the startAt to go on from.

Responsibility

This is an unofficial, independent tool. It is not affiliated with, endorsed by or sponsored by Reddit, Google, Apple, Meta, Telegram, Naver or any site your texts come from. It analyses only the texts you supply and sends no messages. You are responsible for having the right to process these texts, including any personal data in them (for example under GDPR, CCPA or PIPA), and for complying with the terms of the sites they come from. You are the data controller for the output. Scores and categories are automated estimates, not facts about any person.