# Reddit Topic Watcher - Intent, Sentiment, B2B Triggers, MCP (`seibs.co/reddit-topic-watcher`) Actor

Reddit monitoring with intent classification (recommendation/comparison/alternative-seek/complaint), sentiment, B2B trigger scoring, author profile signals (karma, age, bot filter), competitor mention tracking, MCP-ready output. For SDR teams, brand monitoring, AI agents.

- **URL**: https://apify.com/seibs.co/reddit-topic-watcher.md
- **Developed by:** [Seibs.co](https://apify.com/seibs.co) (community)
- **Categories:** Social media, AI, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 post records

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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

## Reddit Topic Watcher

Reddit monitoring for B2B intent capture, brand tracking, and AI-agent ingestion - sentiment, 8-label intent, B2B trigger score, MCP markdown.

### What does Reddit Topic Watcher do?

It runs multi-keyword x multi-subreddit topic watch in a single run, classifies every post (and optionally each top comment) for sentiment, intent, and B2B-readiness, optionally enriches the author with karma / age / bot signals, and emits MCP-friendly Markdown summary blocks ready to feed an LLM agent or RAG store.

### AI / RAG / Agent

Reddit signal stream pre-shaped for AI sales agents and brand-monitoring bots. Set `output_mode=mcp` to get clean Markdown summary blocks an LLM can consume directly - no extra prompt-engineering. Intent labels (`recommendation`, `comparison`, `alternative_seek`, `complaint`, ...) and `b2b_trigger_score` let an agent filter for buying-intent posts before it even calls the model. Compatible with **MCP** runtimes (Claude Desktop, Cursor), **LangChain**, **LlamaIndex**, **Pinecone**, **Weaviate**, **Chroma**.

```python
from apify_client import ApifyClient
from langchain.schema import Document
from langchain_community.vectorstores import Pinecone
from langchain_openai import OpenAIEmbeddings

client = ApifyClient("APIFY_TOKEN")
run = client.actor("you/reddit-topic-watcher").call(run_input={
    "keywords": ["alternative to zendesk", "looking for crm"],
    "subreddits": ["SaaS", "smallbusiness", "Entrepreneur"],
    "output_mode": "mcp",
    "min_b2b_score": 0.6,
})

docs = [
    Document(
        page_content=item["mcp_block"],
        metadata={
            "subreddit": item["subreddit"],
            "intent": item["intent"],
            "sentiment": item["sentiment"],
            "b2b_score": item["b2b_trigger_score"],
            "permalink": item["permalink"],
        },
    )
    for item in client.dataset(run["defaultDatasetId"]).iterate_items()
]

Pinecone.from_documents(docs, OpenAIEmbeddings(), index_name="reddit-intent")
````

### Features

- Multi-keyword x multi-subreddit topic watch with cross-job dedupe and a hard cap on emitted records.
- Sentiment classification (positive / neutral / negative) with -1..+1 magnitude, lexicon + 2-token negation lookback.
- 8-label intent classifier (recommendation\_request, alternative\_seek, comparison\_request, complaint, frustration, question, praise, neutral\_discussion) with `intent_keywords_matched` for explainability.
- Composite B2B trigger score (0-1) blending intent, recency, subreddit relevance, author quality.
- Author profile enrichment - karma, account age, mod / verified flags, `probable_bot` indicator.
- Brand mention mode - counts competitor names across post + comments and emits per-topic aggregated `topic_summary` records with competitor leaderboards.
- MCP-friendly markdown output - drop into an agent's tool response, MCP resource, or vector store.
- Top-comments unwind view for one-row-per-comment analysis.

### Use cases

- SDR teams - surface recommendation\_request and alternative\_seek leads in real time across Reddit's vertical communities.
- RevOps / GTM analysts - track competitor mentions, sentiment trends, category demand signals.
- Brand managers - monitor brand mentions with sentiment split + reach (subscriber-weighted), alert on complaints.
- AI agent builders - feed MCP markdown summaries straight into an agent's context window or a RAG vector store.
- Market researchers - quantify category sentiment over a lookback window across any vertical community.

### FAQ

**Q: Is this legal?**
A: Yes - we use Reddit's public JSON endpoints (e.g. `reddit.com/r/<sub>/search.json`), which are publicly accessible without authentication. Use the data per Reddit's Terms of Service and applicable law. We do not scrape NSFW or quarantined subreddits (those require login).

**Q: Why might a run fail?**
A: (1) Reddit 429/503 - we self-throttle to ~30 req/min and respect `Retry-After`, but very high concurrency on a single keyword can still trip it. (2) Quarantined or login-walled subreddits return empty - skip them. (3) Misspelled subreddit names silently return zero results - double-check casing on edge cases like `r/Accounting`.

**Q: How fresh is the data?**
A: Live at crawl time. Posts and comments are pulled directly from Reddit's public JSON at run time - typically minutes-fresh on active subreddits.

**Q: Can I schedule this daily or weekly?**
A: Yes - daily for high-volume B2B intent watchlists (CRM, ERP, sales tools), hourly for crisis brand monitoring, weekly for category-trend research. Use Apify Schedules; combine with cross-job dedupe so re-runs do not re-emit the same posts.

**Q: How do I push results into a CRM or alerting tool?**
A: SDR-priority leads (records where `intent_classification` in {`recommendation_request`, `alternative_seek`} and `b2b_trigger_score >= 0.7`) forward to HubSpot, Salesforce, or Apollo via Zapier/Make/n8n. Brand-manager `complaint` alerts can webhook straight into a Slack channel. The MCP markdown output can also feed an LLM-based qualification step before CRM write.

**Q: What's MCP output?**
A: Model Context Protocol - the open spec for feeding structured tool results into LLM agents (Claude, GPT, LangChain, custom agents). Set `output_format: mcp` and each `topic_summary` record includes a `mcp_summary_md` markdown block ready to drop directly into an agent's tool response, an MCP resource, or a RAG vector store - no reformatting required. Lets you build "watch Reddit for X and tell my agent about it" in one step.

**Q: How is `b2b_trigger_score` computed?**
A: `0.50 x intent_weight + 0.20 x recency_score + 0.20 x subreddit_relevance + 0.10 x author_quality`. A score `>= 0.7` triggers a `high_intent_alert` PPE event - treat that threshold as the SDR-action floor.

**Q: How does PPE pricing actually work here?**
A: $0.003 per post, $0.001 per comment, $0.002 per unique author profile enrichment (cached per run), $0.008 per topic\_summary record, $0.005 surcharge per high-intent alert. A typical "3 keywords x 5 subreddits x 30 days" run with comments on is roughly $1-3.

### Related Actors

- [`b2b-sales-triggers`](../b2b-sales-triggers/) - score company-level intent (hiring, funding, exec changes) alongside the post-level Reddit intent signals from this actor.
- [`google-maps-reviews-pro`](../google-maps-reviews-pro/) - extend reputation monitoring from Reddit threads into Google Maps reviews on the same brand for full off-site coverage.
- [`youtube-intelligence`](../youtube-intelligence/) - layer YouTube comment / video sentiment on top of Reddit signals for cross-platform category research.

### Integrations

- Zapier - push to HubSpot/Salesforce/Pipedrive/Apollo/Klaviyo
- Make.com - workflow automation
- n8n - self-hosted automation
- Apify webhooks - POST to your endpoint
- API + dataset export (JSON/CSV/Excel/XML)
- MCP / AI agents - call from Claude/GPT/LangChain

### Modes

| Mode | Use case |
|---|---|
| `topic_watch` | Track N keywords across M subreddits (or all of Reddit). |
| `brand_mention` | Like topic\_watch plus counts competitor names and emits per-topic summaries. |
| `subreddit_dump` | Pull latest posts from each listed subreddit, no keyword filter. |
| `user_profile` | Bulk-enrich Reddit usernames with karma, account age, mod / verified, bot indicator. |

### Intent taxonomy

| Label | What it catches | Why SDRs / brand managers care |
|---|---|---|
| `recommendation_request` | "looking for", "anyone recommend", "what's the best" | Highest-signal SDR lead - active vendor evaluation. |
| `alternative_seek` | "alternatives to", "switching from", "tired of" | Conquest opportunity. |
| `comparison_request` | "X vs Y", "which is better", "pros and cons" | Mid-funnel evaluation. |
| `complaint` | "doesn't work", "broken", "ripoff" | Brand managers want these instantly. |
| `frustration` | "frustrating", "fed up" | Soft churn signal. |
| `question` | Generic interrogative | Lower priority, flagged for support. |
| `praise` | "highly recommend", "game-changer" | UGC for social proof. |
| `neutral_discussion` | Everything else | Default fallback. |

### Input

See `.actor/INPUT_SCHEMA.json`. Sample - track CRM intent across sales subreddits:

```json
{
    "mode": "topic_watch",
    "keywords": ["best CRM", "CRM alternative", "tired of HubSpot"],
    "subreddits": ["sales", "saas", "smallbusiness"],
    "lookback_days": 30,
    "min_b2b_trigger_score": 0.5,
    "include_comments": true,
    "max_comments_per_post": 10,
    "include_author_profiles": true,
    "output_format": "json",
    "concurrency": 4
}
```

### Output

**Sample output:** [`.actor/sample-output.json`](./.actor/sample-output.json) â€” copy-paste-ready preview of real-looking records.

First record inline:

```json
{
  "record_type": "post",
  "mode": "topic_watch",
  "scraped_at": "2026-05-13T17:11:48Z",
  "available": true,
  "reason": null,
  "query": "best CRM for small accounting firm",
  "post_id": "1d4kb78",
  "comment_id": null,
  "user_id": null,
  "permalink": "https://www.reddit.com/r/Accounting/comments/1d4kb78/best_crm_for_small_accounting_firm",
  "subreddit": "Accounting",
  "subreddit_subscribers": 514212,
  "title": "Best CRM for a 4-person CPA firm? Karbon vs TaxDome vs Canopy?",
  "body": "We're growing past spreadsheets and email. Currently 4 CPAs + 2 admin. Need: client task tracking, document portal, e-sign, and ideally something that talks to QBO. Karbon looks polished but pricey. TaxDome is half the price. Anyone moved from Karbon to TaxDome or vice versa?",
  "author": "ledgerlife_cpa",
  "author_karma": 8421,
  "author_account_age_days": 2188,
  "author_is_mod": false,
  "author_verified": false,
  "score": 142,
  "upvote_ratio": 0.94,
  "comment_count": 73,
  "created_utc": 1747165908,
  "is_self": true,
  "link_url": null,
  "is_video": false,
  "num_crossposts": 1,
  "sentiment": "neutral",
  "sentiment_score": 0.04,
  "intent_classification": "comparison_request",
  "intent_keywords_matched": [
    "best",
    "vs",
    "anyone moved from"
  ],
  "b2b_trigger_score": 0.88,
  "competitors_mentioned": [
    {
      "name": "karbon",
      "mention_count": 4
    },
    {
      "name": "taxdome",
      "mention_count": 3
    },
    {
      "name": "canopy",
      "mention_count": 1
    }
  ],
  "top_comments": [
    {
      "comment_id": "l9k2m4a",
      "author": "small_firm_partner",
      "body": "We moved from Karbon to TaxDome 6 months ago. TaxDome is messier UX but the e-sign and portal are way better for tax-heavy practices. Karbon is built for advisory, TaxDome is built for tax compliance.",
      "score": 84,
      "created_utc": 1747171200,
      "sentiment": "neutral",
      "sentiment_score": 0.12,
      "intent_classification": "recommendation_request",
      "intent_keywords_matched": [
        "moved from",
        "way better"
      ]
    },
    {
      "comment_id": "l9k4nq2",
      "author": "boutiquetax",
      "body": "Canopy got expensive after the rebuild and the 2024 outage scared us off. Stuck with Karbon for now.",
      "score": 41,
      "created_utc": 1747173600,
      "sentiment": "negative",
      "sentiment_score": -0.32,
      "intent_classification": "frustration",
      "intent_keywords_matched": [
        "expensive",
        "scared us off"
      ]
    }
  ],
  "author_profile": null,
  "mcp_summary_md": null
}
```

Sample post record:

```json
{
    "record_type": "post",
    "mode": "topic_watch",
    "subreddit": "sales",
    "title": "Tired of HubSpot pricing - what are people moving to?",
    "author": "salesguy42",
    "score": 187,
    "comment_count": 53,
    "sentiment": "negative",
    "sentiment_score": -0.42,
    "intent_classification": "alternative_seek",
    "intent_keywords_matched": ["tired of"],
    "b2b_trigger_score": 0.86,
    "permalink": "https://www.reddit.com/r/sales/comments/...",
    "available": true,
    "scraped_at": "2026-05-14T12:00:00Z"
}
```

### Pricing

Pay-per-event:

| Event | Price | When charged |
|---|---|---|
| `post_record` | $0.003 | Per emitted post |
| `comment_record` | $0.001 | Per top comment fetched |
| `author_profile_enrichment` | $0.002 | Per unique author (cached per run) |
| `topic_summary` | $0.008 | Per topic\_summary record |
| `high_intent_alert` | $0.005 | Surcharge when `b2b_trigger_score >= 0.7` |

### FAQ

**Q: Do I need a Reddit API key?**
A: No - we use Reddit's public JSON endpoints, which work without authentication. We self-throttle to ~30 req/min and respect `Retry-After` on 429/503.

**Q: Does this scrape NSFW or quarantined subreddits?**
A: No - quarantined subreddits require login. NSFW community results may be filtered by Reddit's anonymous endpoint based on the request session.

**Q: How is `b2b_trigger_score` computed?**
A: `0.50 * intent_weight + 0.20 * recency_score + 0.20 * subreddit_relevance + 0.10 * author_quality`. A score >= 0.7 triggers a `high_intent_alert` PPE event.

**Q: Can the MCP output be used directly with Claude / GPT-4?**
A: Yes - set `output_format=mcp` and the `topic_summary` records carry a `mcp_summary_md` markdown block ready for an LLM context window or RAG ingestion.

### Save your input as an Apify Task

Apify Tasks let you save a configured input once and re-run it with a single click - no need to re-type search terms, locations, filters, or tier settings every time. Tasks are the foundation for everything that comes next: schedules, monitor mode, and webhook routing all attach to a saved Task, not to the raw actor.

Steps to save your current input as a Task:

1. On this actor's Apify Store page, click `Run` with your input fully configured.
2. Click the `Save as task` button at the top of the run page.
3. Name the task something memorable (e.g. `Watch r/sysadmin for ConnectWise mentions - daily`).
4. Reload the task page and click `Start` anytime to re-run with the same inputs.

Tasks unlock the next two features below: scheduling and monitor mode.

### Run this weekly with Apify Schedules

Apify Schedules cron-run any saved Task automatically. Pair this with the saved Task above and you get hands-off recurring runs with no manual clicks, no missed weeks, and a steady stream of fresh data into your CRM or warehouse.

Steps to schedule a Task:

1. Save your input as a Task (see above).
2. Go to https://console.apify.com/schedules and click `Create new schedule`.
3. Pick your Task and set the cron expression. Common patterns:
   - Daily at 9am UTC: `0 9 * * *`
   - Weekly on Mondays at 9am: `0 9 * * 1`
   - Monthly on the 1st: `0 9 1 * *`
4. Save. Apify will run your Task on that schedule automatically, push the dataset to whatever integrations you have wired up, and fire run-completion webhooks for downstream automation.

Run daily to monitor for new mentions, complaints, and shifting sentiment across the subreddits you track.

### Monitor mode (v2, beta)

Monitor mode is the v2 evolution of this actor and is currently in BETA. It turns a recurring schedule into a true change-feed instead of a firehose of duplicate records.

How it works:

- When this actor runs under an Apify Schedule, monitor mode is enabled automatically.
- Instead of emitting ALL records every run, it emits ONLY records that are NEW or CHANGED since the last scheduled run.
- A digest record summarizes the delta (X new, Y changed, Z removed) at the top of every run.
- Optional: provide a Slack or email webhook URL in the `monitor_webhook_url` input field and the digest fires there too, so your team gets the delta in their inbox or channel without polling the dataset.
- Cost: a single `scheduled_delta_run` event ($0.05) per scheduled run, plus standard PPE on emitted delta records only. Predictable monthly cost, no surprise bills from re-charging for unchanged records.

Monitor mode is rolling out to the top 3 actors first (this one included if it's hotel-motel-lead-finder, google-maps-reviews-pro, or mcp-accounting-firm-leads). Full portfolio coverage by end of June.

### Support

Open an issue on the actor's GitHub or contact via Apify Store. Include the run ID and input config.

### Changelog

See [CHANGELOG.md](./CHANGELOG.md).

### Found this useful?

If this actor saved you time or money, please consider leaving a quick review on the Apify Store. Reviews help other buyers find work that solves their problem and let me prioritize the features paying customers actually use. Leave a review: https://apify.com/seibs.co/reddit-topic-watcher#reviews

# Actor input Schema

## `mode` (type: `string`):

topic\_watch: monitor N keywords across M subreddits. brand\_mention: track a primary brand + competitor list with mention counts, sentiment split, top mentioning subs. subreddit\_dump: pull latest posts from each subreddit (no keyword filter). user\_profile: enrich a list of usernames with karma + account age signals.

## `keywords` (type: `array`):

Search queries used in topic\_watch and brand\_mention modes. In brand\_mention, the FIRST entry is treated as the primary brand. Examples: \['best CRM alternative', 'HubSpot vs Salesforce'].

## `subreddits` (type: `array`):

Subreddit names without the r/ prefix. Leave empty in topic\_watch / brand\_mention to search across all of Reddit. Example: \['sales', 'saas', 'marketing'].

## `competitor_names` (type: `array`):

List of competing brand names to count alongside the primary brand. Mentions are case-insensitive whole-word matches. Example: \['Salesforce', 'HubSpot', 'Pipedrive'].

## `usernames` (type: `array`):

Reddit usernames to enrich (without u/ prefix). Returns karma, account age, mod/verified flags, plus a probable-bot indicator for very new low-karma accounts.

## `lookback_days` (type: `integer`):

Drop posts older than this many days. Reddit search returns up to ~1000 results regardless; this filters post-fetch.

## `min_score` (type: `integer`):

Drop posts/comments with Reddit score below this. Filters out junk and downvoted threads.

## `min_comments` (type: `integer`):

Drop posts with fewer comments than this. Use to focus on engaged threads.

## `min_author_karma` (type: `integer`):

Drop posts whose author has less combined karma than this. Requires include\_author\_profiles=true to take effect; otherwise ignored.

## `min_author_account_age_days` (type: `integer`):

Drop posts whose author's account is younger than this. Default 30 filters most bot accounts. Requires include\_author\_profiles=true; ignored otherwise.

## `intent_filter` (type: `array`):

If set, only emit posts whose intent\_classification matches one of these. Leave empty to emit all intents.

## `min_b2b_trigger_score` (type: `string`):

Drop posts whose composite b2b\_trigger\_score is below this. Leave empty to emit all. Score combines intent type weight, recency, subreddit relevance, author quality. 0.7+ = high-intent SDR lead.

## `include_comments` (type: `boolean`):

When true, fetches the top N comments for each emitted post and classifies sentiment + intent per comment. Adds latency but provides much richer signal.

## `max_comments_per_post` (type: `integer`):

Cap on comments fetched per post. Ignored when include\_comments is false.

## `include_author_profiles` (type: `boolean`):

Fetch each post author's /about.json: karma, account age, mod/verified flags. Slower but enables bot filtering, karma filtering, and author\_quality scoring. Cached per username across the run.

## `output_format` (type: `string`):

json: structured records (default; recommended for code). mcp: structured records PLUS topic\_summary records with markdown-formatted summary blocks ready for LLM RAG / agent ingestion. csv\_friendly: flattens nested fields and joins arrays with ' | ' for spreadsheet export.

## `use_apify_proxy` (type: `boolean`):

Route Reddit requests through Apify Proxy. Strongly recommended - Reddit blocks datacenter IPs aggressively.

## `apify_proxy_groups` (type: `array`):

Apify Proxy groups. RESIDENTIAL is most reliable for Reddit. Defaults to RESIDENTIAL.

## `concurrency` (type: `integer`):

Max parallel Reddit requests. Reddit allows ~60/min unauthenticated; default 4 stays well under that.

## `max_results` (type: `integer`):

Hard cap on total post records emitted. Comments and topic\_summary records do not count against this.

## Actor input object example

```json
{
  "mode": "topic_watch",
  "keywords": [
    "best CRM alternative"
  ],
  "subreddits": [
    "sales",
    "saas",
    "marketing"
  ],
  "competitor_names": [
    "Salesforce",
    "HubSpot",
    "Pipedrive"
  ],
  "usernames": [],
  "lookback_days": 30,
  "min_score": 5,
  "min_comments": 0,
  "min_author_karma": 0,
  "min_author_account_age_days": 30,
  "intent_filter": [],
  "min_b2b_trigger_score": "",
  "include_comments": true,
  "max_comments_per_post": 10,
  "include_author_profiles": false,
  "output_format": "json",
  "use_apify_proxy": true,
  "apify_proxy_groups": [
    "RESIDENTIAL"
  ],
  "concurrency": 4,
  "max_results": 200
}
```

# Actor output Schema

## `datasetItems` (type: `string`):

Narrow, token-efficient slice of every record. Consumer: LLM agents (Claude, GPT, LangChain tools), MCP hosts, dashboards. Reddit fields: subreddit, title, score, comment count, intent classification, B2B trigger score, permalink.

## `datasetItemsDetailed` (type: `string`):

All fields for every record. Consumer: humans browsing the dataset in the Apify UI, RAG ingest pipelines, and full backups. Larger payload — not recommended as a direct LLM tool response.

## `datasetItemsUnwind` (type: `string`):

Same records, but each element of the `comments` array is promoted to its own row. Consumer: Zapier / Make / n8n / Google Sheets users who want one row per item, and LLM agents that prefer flat rows over nested arrays.

## `datasetItemsMcp` (type: `string`):

First 50 overview records as a clean JSON array. Wrap on the agent side in an MCP tool-call response envelope, e.g. `{ "ok": true, "data": <this array>, "meta": { "actor": "reddit-topic-watcher", "count": <len>, "view": "overview" } }`. Consumer: MCP servers, Claude Desktop, Cursor, OpenAI Assistants tool calls.

## `datasetItemsCsv` (type: `string`):

Spreadsheet-friendly export of the overview view. Consumer: humans, sales-ops teams, Excel / Google Sheets users.

# 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 = {
    "mode": "topic_watch",
    "keywords": [
        "best CRM alternative"
    ],
    "subreddits": [
        "sales",
        "saas",
        "marketing"
    ],
    "competitor_names": [
        "Salesforce",
        "HubSpot",
        "Pipedrive"
    ],
    "usernames": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("seibs.co/reddit-topic-watcher").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 = {
    "mode": "topic_watch",
    "keywords": ["best CRM alternative"],
    "subreddits": [
        "sales",
        "saas",
        "marketing",
    ],
    "competitor_names": [
        "Salesforce",
        "HubSpot",
        "Pipedrive",
    ],
    "usernames": [],
}

# Run the Actor and wait for it to finish
run = client.actor("seibs.co/reddit-topic-watcher").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "mode": "topic_watch",
  "keywords": [
    "best CRM alternative"
  ],
  "subreddits": [
    "sales",
    "saas",
    "marketing"
  ],
  "competitor_names": [
    "Salesforce",
    "HubSpot",
    "Pipedrive"
  ],
  "usernames": []
}' |
apify call seibs.co/reddit-topic-watcher --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=seibs.co/reddit-topic-watcher",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Reddit Topic Watcher - Intent, Sentiment, B2B Triggers, MCP",
        "description": "Reddit monitoring with intent classification (recommendation/comparison/alternative-seek/complaint), sentiment, B2B trigger scoring, author profile signals (karma, age, bot filter), competitor mention tracking, MCP-ready output. For SDR teams, brand monitoring, AI agents.",
        "version": "0.1",
        "x-build-id": "f1mrrkez03a7uTjpJ"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/seibs.co~reddit-topic-watcher/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-seibs.co-reddit-topic-watcher",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/seibs.co~reddit-topic-watcher/runs": {
            "post": {
                "operationId": "runs-sync-seibs.co-reddit-topic-watcher",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/seibs.co~reddit-topic-watcher/run-sync": {
            "post": {
                "operationId": "run-sync-seibs.co-reddit-topic-watcher",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "mode"
                ],
                "properties": {
                    "mode": {
                        "title": "Mode",
                        "enum": [
                            "topic_watch",
                            "brand_mention",
                            "subreddit_dump",
                            "user_profile"
                        ],
                        "type": "string",
                        "description": "topic_watch: monitor N keywords across M subreddits. brand_mention: track a primary brand + competitor list with mention counts, sentiment split, top mentioning subs. subreddit_dump: pull latest posts from each subreddit (no keyword filter). user_profile: enrich a list of usernames with karma + account age signals.",
                        "default": "topic_watch"
                    },
                    "keywords": {
                        "title": "Keywords / search queries",
                        "type": "array",
                        "description": "Search queries used in topic_watch and brand_mention modes. In brand_mention, the FIRST entry is treated as the primary brand. Examples: ['best CRM alternative', 'HubSpot vs Salesforce'].",
                        "items": {
                            "type": "string"
                        }
                    },
                    "subreddits": {
                        "title": "Subreddits",
                        "type": "array",
                        "description": "Subreddit names without the r/ prefix. Leave empty in topic_watch / brand_mention to search across all of Reddit. Example: ['sales', 'saas', 'marketing'].",
                        "items": {
                            "type": "string"
                        }
                    },
                    "competitor_names": {
                        "title": "Competitor names (brand_mention mode)",
                        "type": "array",
                        "description": "List of competing brand names to count alongside the primary brand. Mentions are case-insensitive whole-word matches. Example: ['Salesforce', 'HubSpot', 'Pipedrive'].",
                        "items": {
                            "type": "string"
                        }
                    },
                    "usernames": {
                        "title": "Usernames (user_profile mode)",
                        "type": "array",
                        "description": "Reddit usernames to enrich (without u/ prefix). Returns karma, account age, mod/verified flags, plus a probable-bot indicator for very new low-karma accounts.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "lookback_days": {
                        "title": "Lookback window (days)",
                        "minimum": 1,
                        "maximum": 365,
                        "type": "integer",
                        "description": "Drop posts older than this many days. Reddit search returns up to ~1000 results regardless; this filters post-fetch.",
                        "default": 30
                    },
                    "min_score": {
                        "title": "Minimum post score",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Drop posts/comments with Reddit score below this. Filters out junk and downvoted threads.",
                        "default": 5
                    },
                    "min_comments": {
                        "title": "Minimum comment count",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Drop posts with fewer comments than this. Use to focus on engaged threads.",
                        "default": 0
                    },
                    "min_author_karma": {
                        "title": "Minimum author karma",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Drop posts whose author has less combined karma than this. Requires include_author_profiles=true to take effect; otherwise ignored.",
                        "default": 0
                    },
                    "min_author_account_age_days": {
                        "title": "Minimum author account age (days)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Drop posts whose author's account is younger than this. Default 30 filters most bot accounts. Requires include_author_profiles=true; ignored otherwise.",
                        "default": 30
                    },
                    "intent_filter": {
                        "title": "Intent filter (emit only matching)",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "If set, only emit posts whose intent_classification matches one of these. Leave empty to emit all intents.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "question",
                                "complaint",
                                "recommendation_request",
                                "comparison_request",
                                "alternative_seek",
                                "praise",
                                "frustration",
                                "neutral_discussion"
                            ]
                        },
                        "default": []
                    },
                    "min_b2b_trigger_score": {
                        "title": "Minimum B2B trigger score (0-1)",
                        "type": "string",
                        "description": "Drop posts whose composite b2b_trigger_score is below this. Leave empty to emit all. Score combines intent type weight, recency, subreddit relevance, author quality. 0.7+ = high-intent SDR lead.",
                        "default": ""
                    },
                    "include_comments": {
                        "title": "Fetch top comments per post",
                        "type": "boolean",
                        "description": "When true, fetches the top N comments for each emitted post and classifies sentiment + intent per comment. Adds latency but provides much richer signal.",
                        "default": true
                    },
                    "max_comments_per_post": {
                        "title": "Max comments per post",
                        "minimum": 0,
                        "maximum": 50,
                        "type": "integer",
                        "description": "Cap on comments fetched per post. Ignored when include_comments is false.",
                        "default": 10
                    },
                    "include_author_profiles": {
                        "title": "Fetch author profiles",
                        "type": "boolean",
                        "description": "Fetch each post author's /about.json: karma, account age, mod/verified flags. Slower but enables bot filtering, karma filtering, and author_quality scoring. Cached per username across the run.",
                        "default": false
                    },
                    "output_format": {
                        "title": "Output format",
                        "enum": [
                            "json",
                            "mcp",
                            "csv_friendly"
                        ],
                        "type": "string",
                        "description": "json: structured records (default; recommended for code). mcp: structured records PLUS topic_summary records with markdown-formatted summary blocks ready for LLM RAG / agent ingestion. csv_friendly: flattens nested fields and joins arrays with ' | ' for spreadsheet export.",
                        "default": "json"
                    },
                    "use_apify_proxy": {
                        "title": "Use Apify Proxy",
                        "type": "boolean",
                        "description": "Route Reddit requests through Apify Proxy. Strongly recommended - Reddit blocks datacenter IPs aggressively.",
                        "default": true
                    },
                    "apify_proxy_groups": {
                        "title": "Proxy groups",
                        "type": "array",
                        "description": "Apify Proxy groups. RESIDENTIAL is most reliable for Reddit. Defaults to RESIDENTIAL.",
                        "default": [
                            "RESIDENTIAL"
                        ],
                        "items": {
                            "type": "string"
                        }
                    },
                    "concurrency": {
                        "title": "Concurrency",
                        "minimum": 1,
                        "maximum": 6,
                        "type": "integer",
                        "description": "Max parallel Reddit requests. Reddit allows ~60/min unauthenticated; default 4 stays well under that.",
                        "default": 4
                    },
                    "max_results": {
                        "title": "Max results per run",
                        "minimum": 1,
                        "maximum": 2000,
                        "type": "integer",
                        "description": "Hard cap on total post records emitted. Comments and topic_summary records do not count against this.",
                        "default": 200
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
