# Discourse Community Topic Monitor (`maydit/discourse-community-topic-monitor`) Actor

Track recent public Discourse topics by community and keyword. Compare topic activity and saved changes with source links. Bounded latest-topic coverage; no private forums.

- **URL**: https://apify.com/maydit/discourse-community-topic-monitor.md
- **Developed by:** [Brandt May](https://apify.com/maydit) (community)
- **Stats:** 2 total users, 1 monthly users, 66.7% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.60 / 1,000 saved topic observations

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Discourse Community Topic Monitor

Paste a public Discourse community URL and collect a small review queue of topic observations. Track titles, tags, source dates and counts; optionally match literal keywords and compare with previously saved observations.

The default returns up to **three topics from Python Discussions**. No API key, login, proxy, browser or outside service is required for the tested public communities. Access remains subject to each forum’s settings and limits.

### Start with one community

```json
{"communityUrls":["https://discuss.python.org"],"maxResults":3}
```

1. Paste the forum’s HTTPS base URL into **Community URLs**.
2. Run, then open the dataset and saved **RUN_REPORT**.
3. Check **SOURCE_COVERAGE** before treating the result as a complete check of your selected window.

An omitted input or empty community list uses the Python example. It reads exactly one `/latest.json` response. The first source window is not a full archive, whole-forum search or chronological list of newly created topics. Pinned discussions and older active topics can appear; source order and `pinned` are retained.

### What each row contains

- Forum URL, stable forum/topic identity, title and direct topic link.
- Tags and numeric category ID when supplied. Category names are not fetched.
- Source creation and last-post dates; observation time is separate.
- Post count, views and likes when present; missing optional values stay null.
- Pinned, closed and archived states when supplied.
- Literal keyword evidence from the title or tag text, if filtering is enabled.
- Comparison status, changed fields, prior saved observation and numeric deltas when comparison is enabled.

`sourceReplyCount` preserves the API’s `reply_count` field. **It does not establish that a topic is unanswered.** Real source topics can have several posts and a zero `reply_count`. There is no inferred answer quality, sentiment, purchase intent or resolution state. The Actor does not request post bodies, profile pages, private content, thread details or accepted answers. User records embedded in the public topic-list response are ignored and are not included in dataset rows.

The dataset contains real topic observations only. Invalid source responses and access failures appear in the summary and coverage, never as paid diagnostic rows. `RUN_REPORT` presents saved topics and source coverage without adding dataset items.

### Keyword matching

Add optional keywords or phrases in **Advanced options**. Matching ignores case and uses literal text, not an AI classification. Whole-word matching uses Unicode letter/number boundaries; disable it for deliberate substring matching.

Keywords match the title and individual tags. They do not search post text or fetch additional pages. A zero-match result means no match within the selected source window, not no matching discussion anywhere on the forum. Evidence includes the term, matched field and a bounded excerpt. Each keyword has at most one title excerpt and one tag excerpt, capped at 40 evidence entries per row.

### Saved comparisons

Enable `comparePrevious` to establish a baseline. Later runs compare topic identity within the same forum. `onlyChanges` also enables comparison and saves only new or changed observations; an unchanged run can save zero rows successfully.

History scope includes the forum list, keywords, whole-word setting, inspected window size and comparison name. Use one sequential writer per scope. Only **confirmed saved rows** advance history. A topic excluded by an earlier result cap can be “new” on a later run because it was never saved before.

`metricDeltas` subtract the previous saved count from the current count only when both are numeric. Negative differences are retained and listed in `countersDecreased`; they are not deletion evidence. No rates, reach estimates or inferred activity are calculated. Missing topics, smaller response windows, failures and partial runs never establish removal.

### Three ready-to-run examples

#### Python Discussions

```json
{"communityUrls":["https://discuss.python.org"],"maxResults":3}
```

#### Hugging Face community

```json
{"communityUrls":["https://discuss.huggingface.co"],"maxResults":3}
```

#### Rust users forum

```json
{"communityUrls":["https://users.rust-lang.org"],"maxResults":3}
```

### Coverage, limits and cost

- One fixed `/latest.json` GET per community; no pagination, topic-detail calls or cross-host redirects.
- Up to 10 community URLs and 100 inspected topics per community, limited to what that one response contains. The default inspects at most 30 topics and saves at most three globally.
- A fulfilled result cap is a successful bounded selection with `selectionTruncated: true`. Unreached later communities, processing failures, time limits or spending stops remain explicit and can make the run partial.
- Each source response is limited to 2 MiB and each request to 15 seconds within the remaining run deadline. Total source response bodies are limited to 8 MiB; the last received chunk can cross the bound before closing. Five seconds of the run budget are reserved for output. Cloud SDK storage calls and shutdown have five-second bounds; storage retries are disabled.
- Only public HTTPS base URLs are accepted. Credentials, private/reserved DNS addresses, local hosts, custom ports, queries, fragments and subpath installations are unsupported. DNS results are validated and pinned for the connection. TLS verification stays enabled.
- Redirects and source retries are disabled. Login-only, restricted, error-shaped or incompatible forum responses fail honestly. The Actor does not automatically change connections or attempt an access workaround.

Base pricing is **$0.001 per saved topic observation** plus **$0.00005 per run start**. The Store pricing panel and your run charge limit govern actual charges. This package adds no paid source provider or subscription. Source-byte and row caps are not an infrastructure billing ceiling. A successful small sample is not an uptime guarantee.

### Source contract

The [official Discourse API client](https://github.com/discourse/discourse_api/blob/main/lib/discourse_api/api/topics.rb) uses `/latest.json` for current topic lists. Its [maintainer changelog](https://github.com/discourse/discourse_api/blob/main/CHANGELOG.md) includes support for unauthenticated public requests. Each community controls its own permissions and public surface; the [official API documentation](https://docs.discourse.org/) also covers authenticated operations that this Actor does not use.

The examples were checked with small direct public probes and selected Apify runs. On 18 October 2026 UTC, bounded cloud samples returned usable topic metadata from Python Discussions, the Hugging Face community and the Rust users forum. Discourse Meta returned HTTP 429 on its first cloud request; that failed observation was retained, with no retry or access workaround.

These observations cover the selected communities and run windows. They do not establish access to every Discourse installation or continuing availability. Each run reports its actual source outcome. Forum content rights and terms still apply; output keeps attribution links and does not redistribute full threads.

# Actor input Schema

## `communityUrls` (type: `array`):

Up to 10 public HTTPS community base URLs, such as https://discuss.python.org. Leave empty for that default. Paths, query strings, fragments, credentials, private networks and custom ports are rejected. No login-only forums.

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

Optional: up to 20 literal terms (80 characters each). Matches title and tag text, ignoring case. Empty means all selected topics. This filters the returned latest-topic window; it is not whole-forum or post-text search.

## `wholeWords` (type: `boolean`):

Use Unicode letter/number boundaries. Disable for intentional substring matches. No sentiment or intent classification.

## `maxTopicsPerCommunity` (type: `integer`):

Inspect at most this many topics from the single latest.json response, in source order. The forum may return fewer, with pinned or older active topics. There is no pagination.

## `comparePrevious` (type: `boolean`):

First run establishes a baseline. Later runs compare matching forum/topic IDs and produce changedFields and numeric deltas. Only confirmed saved rows advance history. Missing topics never establish deletion.

## `onlyChanges` (type: `boolean`):

Also enables comparison. An unchanged run may save zero rows. Topics not saved in an earlier capped run can appear as new later.

## `snapshotName` (type: `string`):

1-80 letters, digits, underscores or hyphens. Use one sequential writer per comparison scope. Changing forums, keywords or topic-window size selects a separate baseline.

## `maxResults` (type: `integer`):

Global output cap across communities. The default is three. Fulfilling this cap is a bounded successful selection; later unreached communities are reported as partial coverage.

## `maxRunSeconds` (type: `integer`):

30-900 seconds, also bounded by platform timeout minus 25 seconds. Source requests reserve five seconds for output and have a 15-second ceiling within the remaining budget.

## Actor input object example

```json
{
  "communityUrls": [
    "https://discuss.python.org"
  ],
  "keywords": [],
  "wholeWords": true,
  "maxTopicsPerCommunity": 30,
  "comparePrevious": false,
  "onlyChanges": false,
  "snapshotName": "default",
  "maxResults": 3,
  "maxRunSeconds": 60
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

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

No description

## `coverage` (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 = {
    "communityUrls": [
        "https://discuss.python.org"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("maydit/discourse-community-topic-monitor").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 = { "communityUrls": ["https://discuss.python.org"] }

# Run the Actor and wait for it to finish
run = client.actor("maydit/discourse-community-topic-monitor").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 '{
  "communityUrls": [
    "https://discuss.python.org"
  ]
}' |
apify call maydit/discourse-community-topic-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,maydit/discourse-community-topic-monitor"
        }
    }
}
```

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/RugehOff9Hn0c9XB8/builds/kQKyibxnp1BIbnA0c/openapi.json
