# Reddit Trend & Buyer Intent Radar (`privatex/reddit-trend-buyer-intent-radar`) Actor

Explainable buyer-intent, pain-point and trend analysis of Reddit discussion exports you are authorized to use (CSV, JSON, JSONL or an Apify dataset). Does not fetch Reddit.

- **URL**: https://apify.com/privatex/reddit-trend-buyer-intent-radar.md
- **Developed by:** [PRIVATEX](https://apify.com/privatex) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 analyzed rows

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?

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

## Reddit Trend & Buyer Intent Radar

Turn Reddit discussion data **you are already authorized to use** into a ranked, evidence-linked list of buyer intent, complaints, product comparisons, feature requests and rising terms. Every label shows the rule that produced it.

> **This Actor does not fetch, scrape or crawl Reddit.** It analyses rows you provide: an Apify dataset in your account, or a CSV, TSV, JSON or JSONL file at an HTTPS URL. Reddit's Data API Terms require a separate agreement with Reddit for commercial use of its data. Make sure your agreement or licence covers this analysis before you run it on Reddit content.

### Who needs it

- **Product and research teams** who hold Reddit data under their own Reddit Data API agreement or from a licensed data provider, and need to know what people complain about, ask for and compare.
- **Agencies** that receive discussion exports from clients and must hand back a short, defensible insight report with sources.
- **Community and support teams** analysing exports from communities they run. The input format is generic, so other forums' exports work too.

### What it does

1. **Reads your rows.** It auto-detects common export field names (`id`, `title`, `body`/`selftext`/`text`, `created_utc`/`createdAt`, `subreddit`/`communityName`, `score`/`upVotes`, `permalink`/`url`, `dataType`/`kind`). It also reads Reddit API `Listing` JSON.
2. **Cleans them.** Duplicates (same id or link), `[deleted]`/`[removed]` content and empty rows are dropped. Every rejected row is counted with its reason.
3. **Labels each row with one intent**, using documented phrase rules:

   - `REQUEST_FOR_RECOMMENDATION`
   - `COMPARISON`
   - `COMPLAINT`
   - `FEATURE_REQUEST`
   - `PURCHASE_CONSIDERATION`
   - `GENERAL_DISCUSSION`
   - `UNCERTAIN`

   Each row lists the rules that fired (`matched_rules`) and a heuristic confidence.
4. **Matches your keyword groups**, for example `Battery: battery life, charging`. Matching is whole-word and ignores case and accents.
5. **Builds a report:**
   - top pain points
   - recommendation requests
   - "X vs Y" and "alternative to X" comparisons
   - feature requests and purchase-consideration themes
   - an intent mix
   - short "actionable opportunities", each backed by example links
6. **Tracks change over time.** Give the same **monitor name** on every run to see which rows are new and which terms are rising or new since the previous run.

### What it does NOT do

- No live Reddit access, no scraping, no logins, no proxies. The connector for live Reddit data is **disabled** until the Actor owner holds a Reddit commercial agreement. The run summary reports this as `BLOCKED_PENDING_REDDIT_COMMERCIAL_AUTHORIZATION`.
- No posting, voting, commenting or messaging.
- No author profiling. Usernames are never output. An optional per-monitor pseudonymous hash only lets you count repeated posters.
- No AI model and no AI training on your data. The labels are deterministic rules. They can be wrong on sarcasm, irony and complex negation. The rules are English, so most non-English text is labelled `UNCERTAIN`; no accuracy is claimed for other languages.
- No sentiment score and no inference of sensitive traits.

### Start in 60 seconds

1. Click **Start** with the prefilled input. With no source given, the Actor runs a **synthetic demo** (no row or report charges): 22 hand-written, fictional discussions about invented products. Every row is labelled `SYNTHETIC_DEMO`. It is not real Reddit content and not market evidence.
2. Open the **Intent overview** table and the **Intent report (Markdown)** output.
3. For your own data, pick your dataset (or paste an HTTPS file URL), tick **"I have the right to analyse this data"**, and optionally add keyword groups and a monitor name.

#### Example input

```json
{
    "datasetId": "<your dataset>",
    "dataRightsConfirmed": true,
    "dataSourceNote": "Reddit Data API under our agreement, export of 2026-10-28",
    "keywordGroups": ["Battery: battery, battery life, charging", "Support: support, refund, customer service"],
    "dateFrom": "2026-10-01",
    "monitorName": "robot-vacuum-weekly"
}
```

#### Example output row (from the synthetic demo)

```json
{
    "topic": "(ungrouped)",
    "detected_intent": "COMPLAINT",
    "confidence": 0.95,
    "matched_rules": ["cpl.negative_word", "cpl.stopped_working", "cpl.waste"],
    "intent_signals": ["COMPLAINT"],
    "content_type": "comment",
    "community": "demo_robotvacuums",
    "language": "en",
    "source_timestamp": "2026-10-02T09:00:00.000Z",
    "engagement_number": 18,
    "evidence_excerpt": "My AcmeVac Pro keeps disconnecting from wifi. Support was useless, total waste of money.",
    "allowed_permalink": "https://example.invalid/demo/demo_robotvacuums/c1",
    "source_reference": "row-id:demo_c1",
    "is_new_since_last_run": null,
    "provenance": { "data_origin": "SYNTHETIC_DEMO", "source_type": "demo", "rights_confirmed_by_user": false }
}
```

Example report lines (synthetic demo):

```
- Most repeated complaint theme: "battery life" in 2 complaint rows.
- Most discussed comparison: zentro x2 vs acmevac pro (1 row).
```

### Output

| Where | What |
|---|---|
| Dataset (default) | One row per analysed discussion item. Main columns: `detected_intent`, `confidence`, `matched_rules`, `topic`, `matched_terms`, `community`, `source_timestamp`, `engagement_number`, `evidence_excerpt`, `allowed_permalink`, `is_new_since_last_run`, `provenance`. |
| `REPORT` / `REPORT_MD` | Aggregated report as JSON and Markdown. |
| `ROWS_CSV` | Dataset rows as CSV with a UTF-8 BOM for Excel. Cells that start with `=`, `+`, `-` or `@` are neutralised against spreadsheet formula injection. |
| `OUTPUT` | Run summary: status, counts, rejected rows by reason, billing and connector status. |

**Run statuses** (in `OUTPUT.status`):

| Status | Meaning |
|---|---|
| `SUCCEEDED` | The analysis completed. |
| `PARTIAL_RESULT` | The run stopped at your spending limit or at `maxRows`. The report covers exactly the delivered rows. |
| `EMPTY_INPUT` | The source had no rows. No charge. |
| `NO_MATCHING_ROWS` | Every row was filtered out. No charge. |
| `FAILED` | The run failed with an error code: `INPUT_INVALID`, `RIGHTS_NOT_CONFIRMED`, `ACCESS_DENIED`, `NOT_FOUND`, `RATE_LIMITED`, `UPSTREAM_UNAVAILABLE`, `INPUT_TOO_LARGE`, `PARSE_ERROR` or `UNSUPPORTED_FORMAT`. No charge. |

All times are ISO-8601 UTC. Ambiguous dates such as `03/04/2026` are left empty, not guessed. Scores are copied only when present in your data.

### Pricing

Pay per event:

| Event | Price | When it is charged |
|---|---|---|
| `analyzed-row` | **$0.0005** | Once per row that passes your filters and is delivered to the dataset. |
| `analysis-report` | **$0.02** | Once per run, only when at least one row was delivered. |

Examples: 1,000 analysed rows cost $0.52; 10,000 rows cost $5.02. A tiny Apify start fee ($0.00005) also applies. Platform usage is included in these prices.

You are **not charged** for:

- rejected, duplicate or filtered-out rows;
- failed runs;
- demo runs (only Apify's automatic $0.00005 start event applies to every run);
- the same row twice, even if the run restarts.

The Actor respects your **maximum cost per run**. It reserves room for the report, analyses only as many rows as your limit allows, and finishes with `PARTIAL_RESULT`.

### Limits

| Setting | Default | Range |
|---|---|---|
| Rows read (`maxRows`) | 5,000 | up to 100,000 |
| File size (`maxFileSizeMb`) | 25 MB | up to 100 MB |
| Excerpt length (`excerptChars`) | 200 characters | 50–500 |

Typical runs need 256–512 MB of memory.

### Privacy and security

- Usernames are dropped by default and never output.
- E-mail addresses and phone numbers inside excerpts are masked.
- Excerpts can be turned off (`includeExcerpts: false`).
- Monitor state stores only counts and hashed row keys, never text. It lives in a key-value store named `discussion-intent-radar-state` in **your** Apify account. Delete it there to reset all monitors.
- File URLs must be HTTPS. Private, internal, loopback and cloud-metadata addresses are refused, on the first request and after every redirect.
- Oversized and compressed-bomb downloads are cut off.
- Query strings (pre-signed tokens) are never written to logs.
- The Actor runs with **limited permissions**. It can read only the dataset you pick in the input.

### API and scheduling

Run it through the Apify API, client libraries or integrations like any Actor. For weekly monitoring, schedule it with the same `monitorName` and a fresh export each week. The `OUTPUT` record tells your automation whether the run `SUCCEEDED`, `PARTIAL_RESULT`, `EMPTY_INPUT` and so on.

### FAQ

**Can it fetch Reddit for me?**
No. See "What it does NOT do".

**Why is my non-English text `UNCERTAIN`?**
The intent rules are English. Other languages pass through without a guessed label.

**Is `confidence` a probability?**
No. It is a heuristic score from the number and strength of the matched rules.

### Support

Open an issue on this Actor's **Issues** tab in Apify Store.

# Actor input Schema

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

A dataset in your Apify account that holds Reddit discussion rows you are authorized to analyse. Common field names are detected automatically (id, title, body/selftext/text, created_utc/createdAt, subreddit/communityName, score/upVotes, permalink/url, dataType).

## `fileUrl` (type: `string`):

Direct https:// link to an export file. Private, internal and non-HTTPS addresses are refused. Pre-signed links are fine; their query string is never logged.

## `dataRightsConfirmed` (type: `boolean`):

Required for your own data. Confirm that you obtained these rows lawfully and that your licence or agreement (for example a Reddit Data API agreement or a licensed data provider) allows this analysis. Not needed for the demo.

## `dataSourceNote` (type: `string`):

Short provenance note copied into every row, e.g. "Reddit Data API under our agreement, exported 2026-10-28".

## `demoMode` (type: `boolean`):

Runs on hand-written fictional discussions so you can see the output in under a minute. Demo rows are labelled SYNTHETIC_DEMO; no row or report events are charged. Also runs automatically when no dataset or file is given. Ignored when you give a dataset or file.

## `keywordGroups` (type: `array`):

One group per line: "Group name: term, term, term". Matching is whole-word and ignores case and accents. Example: "Battery: battery life, charging".

## `onlyMatchingRows` (type: `boolean`):

Only applies when keyword groups are given. Rows that are dropped are not charged.

## `intents` (type: `array`):

Leave empty to keep every intent.

## `dateFrom` (type: `string`):

Keep rows created on or after this date, e.g. 2026-10-01. Rows without a timestamp are dropped when a date filter is set.

## `dateTo` (type: `string`):

Keep rows created on or before this date/time.

## `languages` (type: `array`):

Language codes to keep, e.g. en. Uses the source's language field or a simple guess (en, tr, de, es, und). Intent rules are English; other languages are mostly labelled UNCERTAIN.

## `minEngagement` (type: `integer`):

0 = no filter. Above 0, rows without a score in the source are dropped (scores are never estimated).

## `maxRows` (type: `integer`):

Safety cap on rows read from the source.

## `maxFileSizeMb` (type: `integer`):

Downloads larger than this are refused.

## `monitorName` (type: `string`):

Give the same name on every run to compare with the previous run: new rows, rising and new terms. Stored as counts and hashed row keys (no text) in a key-value store in your own account.

## `includeExcerpts` (type: `boolean`):

Short evidence excerpt per row. E-mail addresses and phone numbers are masked. Turn off if your licence does not allow quoting.

## `excerptChars` (type: `integer`):

Maximum excerpt length. Longer text is cut with an ellipsis.

## `includePermalinks` (type: `boolean`):

Copy the permalink/url from your data (only http/https links).

## `authorHandling` (type: `string`):

Author names are never output. "Hash" adds a per-monitor pseudonymous reference so repeated posters can be counted without being identified.

## Actor input object example

```json
{
  "dataRightsConfirmed": false,
  "demoMode": false,
  "onlyMatchingRows": true,
  "minEngagement": 0,
  "maxRows": 5000,
  "maxFileSizeMb": 25,
  "includeExcerpts": true,
  "excerptChars": 200,
  "includePermalinks": true,
  "authorHandling": "drop"
}
```

# Actor output Schema

## `rows` (type: `string`):

No description

## `reportMarkdown` (type: `string`):

No description

## `reportJson` (type: `string`):

No description

## `csv` (type: `string`):

No description

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

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("privatex/reddit-trend-buyer-intent-radar").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("privatex/reddit-trend-buyer-intent-radar").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 '{}' |
apify call privatex/reddit-trend-buyer-intent-radar --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,privatex/reddit-trend-buyer-intent-radar"
        }
    }
}
```

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/zUGnhVgOwDFjDlT3x/builds/AOk6XdzcyPwcU2lTy/openapi.json
