# Reddit Post Scraper — score velocity (`entrogix_works/reddit-subreddit-momentum`) Actor

Scrape subreddit posts with what a raw score cannot tell you: upvotes per hour, rank within the batch, comments per 100 upvotes, and estimated up/down votes. Plus a summary (median score, p90, posts per day) so you know what 'doing well' means there. Unofficial; not affiliated with Reddit.

- **URL**: https://apify.com/entrogix\_works/reddit-subreddit-momentum.md
- **Developed by:** [Entrogix Works](https://apify.com/entrogix_works) (community)
- **Categories:** Social media
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$5.00 / 1,000 post scrapeds

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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 Post Scraper — score velocity

Scrape subreddit posts and get the thing a raw score can't tell you: **how fast each post
is climbing**, where it ranks against the rest of the batch, and how much of its
engagement is discussion rather than passive upvoting.

> Unofficial. Not affiliated with, endorsed by, or connected to Reddit.

### Why this one

A score of `177` means nothing on its own. It's a different post if it earned that in
2 hours than in 2 days — and a different post again if it came with 4 comments instead
of 400. Most Reddit scrapers hand you the number and leave the arithmetic to you.

| Field | What it answers |
|---|---|
| `scorePerHour` | Is this climbing, or has it just been sitting there? |
| `velocityPercentileInBatch` | Is that fast **for this subreddit**? |
| `commentsPer100Score` | Are people arguing, or just upvoting and moving on? |
| `estimatedUpvotes` / `estimatedDownvotes` | How contested is it, behind the net score? |
| `ageHours` + `isEarly` | Is the post old enough for velocity to mean anything? |

#### The numbers are honest about their own limits

- **`scorePerHour` floors the denominator at 1 hour.** Without that, a post 3 minutes old
  with 5 points reads as 100/hour and takes over the ranking — sorting by *newness*
  while claiming to sort by *momentum*. Anything under 2 hours is flagged `isEarly`
  so you can decide whether to trust it.
- **Percentiles say `InBatch` in the name** because that's what they are: rank among the
  posts this run fetched, not among all of Reddit. A percentile against an unstated
  population is worse than no percentile.
- **Estimated votes return `null` near a 0.5 upvote ratio.** The estimate is
  `total = score / (2 × ratio − 1)`, which diverges as the ratio approaches 0.5. Rather
  than print a large confident-looking number for the most contested posts, it returns nothing.
- **Reddit fuzzes displayed vote counts by design.** Everything derived from `score`
  inherits that. This is Reddit's behaviour, not a defect in the Actor.
- **One clock per run.** Age is measured from a single timestamp taken at start, not
  per row. Reading the clock per post would make later pages look older, and the bias
  would always run the same direction.

### What you get

**Per post:** title, URL, author handle, subreddit, posted time, score, upvote ratio,
comment count, post type, linked domain and URL, language, awards, flair — plus every
derived field above.

**A `MOMENTUM_SUMMARY` record** per run: `medianScore`, `medianComments`,
`medianUpvoteRatio`, `medianScorePerHour`, `p90Score`, `postsPerDay`, oldest/newest
post time, top linked domains, and the post-type mix. That's the baseline you need
before "500 points" can mean anything.

### What this Actor does not do

- **No user profiles, and no way to search by username.** You cannot point this at a
  person and assemble their history. Only subreddits are accepted as input.
- **No avatars, no profile URLs, no karma.** The author handle is the only identifier returned.
- **No post bodies or comment threads.** If you need full text, other Actors cover it —
  this one is for measurement.
- **No CAPTCHA solving or bot-detection bypass.**
- **No logged-in scraping.** Public subreddit pages only.

### Reliability

Success rate was measured **before** this Actor was written: **12/12 fetches** through
the same browser path used in production, across two subreddits. It is monitored twice
daily against a live page.

Reddit renders posts client-side as web components, so this Actor drives a real browser
and waits for the posts to appear rather than for a fixed delay. Use `useProxy: true`
with `RESIDENTIAL`.

### Input

```json
{
  "subreddits": ["programming", "r/technology"],
  "sort": "hot",
  "maxItemsPerSubreddit": 50,
  "useProxy": true,
  "proxyType": "RESIDENTIAL"
}
```

`sort` accepts `hot`, `new`, and `rising`. Use `new` to watch fresh posts climb and
`rising` for what is accelerating right now. Names, `r/name`, and full subreddit URLs
are all accepted.

> **`top` is deliberately not offered.** Reddit serves a generic landing page instead of
> the subreddit for `/top/` often enough that it isn't shippable — measured **8/25 (32%)**
> across both URL forms, against `new` 5/5, `rising` 5/5, `hot` 23/25. Shipping it would
> mean selling a mode that fails two runs out of three. It will come back if Reddit's
> behaviour changes and a re-measurement clears the 95% bar.

Paging uses Reddit's own cursor, so adding pages doesn't re-deliver posts you already paid for.

### Billing

Pay per event: one `post-scraped` event per post actually delivered to your dataset.
Duplicates are removed before charging, and a run that returns nothing costs nothing.

# Actor input Schema

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

Subreddit names, r/name, or full subreddit URLs. User pages are not supported.

## `sort` (type: `string`):

Use 'new' to watch fresh posts climb, 'rising' for what is accelerating right now, 'hot' for the current front page.

## `maxItemsPerSubreddit` (type: `integer`):

Capped at 500. One page returns about 25.

## `minIntervalMs` (type: `integer`):

Requests are serialized with at least this gap.

## `useProxy` (type: `boolean`):

Keep this on. Reddit blocks unproxied requests and datacenter IPs — RESIDENTIAL was the only config measured at 5/5.

## `proxyType` (type: `string`):

RESIDENTIAL is measured to work reliably here. DATACENTER is cheaper but gets blocked.

## Actor input object example

```json
{
  "subreddits": [
    "programming",
    "r/technology"
  ],
  "sort": "hot",
  "maxItemsPerSubreddit": 50,
  "minIntervalMs": 3000,
  "useProxy": true,
  "proxyType": "RESIDENTIAL"
}
```

# Actor output Schema

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

Every row this run produced, as JSON.

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

Totals and medians for this run, so you can judge the rows without reading them all.

# 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 = {
    "subreddits": [
        "programming",
        "r/technology"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("entrogix_works/reddit-subreddit-momentum").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 = { "subreddits": [
        "programming",
        "r/technology",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("entrogix_works/reddit-subreddit-momentum").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 '{
  "subreddits": [
    "programming",
    "r/technology"
  ]
}' |
apify call entrogix_works/reddit-subreddit-momentum --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,entrogix_works/reddit-subreddit-momentum"
        }
    }
}

```

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/OZd8uqTEERjc7kZGr/builds/nixfnbA40DazMqyJA/openapi.json
