# Reddit Keyword Search — Posts by Topic & Subreddit (`northglasslabs/reddit-post-search`) Actor

Search public Reddit posts by keyword across Reddit or one subreddit. Export normalized titles, authors, links, timestamps, text, and available engagement metadata through live and archival sources.

- **URL**: https://apify.com/northglasslabs/reddit-post-search.md
- **Developed by:** [North Glass Labs](https://apify.com/northglasslabs) (community)
- **Categories:** Social media
- **Stats:** 1 total users, 0 monthly users, 85.7% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.34 / 1,000 result storeds

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/platform/actors/running/actors-in-store#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 Search — Turn Public Reddit Posts into Research Data

Search public Reddit posts by keyword across all of Reddit or within one subreddit. Use the normalized dataset for **keyword research**, **subreddit monitoring**, or **AI and RAG datasets**—without a Reddit API key or login.

The Actor makes one fast request to Reddit's public Atom search feed. If that source is unavailable or has no verified posts, it tries the public Arctic Shift archive and then the independent PullPush archive through the configured proxy. The run fails visibly if every source is blocked, malformed, or empty.

### What you can do

- **Keyword research:** collect the language people use around a problem, product category, competitor, or topic. Compare titles, post text, subreddits, and available engagement metadata.
- **Subreddit monitoring:** schedule searches for a brand, product, issue, or topic within one community. Use `sortBy: "new"` and deduplicate downstream by `id`; archival fallback data can lag Reddit, so this is not a guaranteed real-time alerting feed.
- **AI and RAG datasets:** send normalized JSON records to a document pipeline, vector store, classifier, or summarizer. Filter sensitive or unsuitable content and confirm that your use complies with source terms and applicable law.

### Input

| Field | Type | Required | Default | Description |
|---|---:|---:|---:|---|
| `searchQuery` | string | Yes | — | Keywords to search for |
| `maxResults` | integer | No | `25` | Maximum records to return, from 1 to 100 |
| `sortBy` | string | No | `relevance` | Requested Atom order: `relevance`, `new`, `top`, or `hot`; archival fallbacks return newest matching posts |
| `timeFilter` | string | No | `all` | `hour`, `day`, `week`, `month`, `year`, or `all` |
| `subreddit` | string | No | empty | Subreddit name, with or without `r/` |
| `proxyConfiguration` | object | No | Apify Proxy prefill | Proxy settings used only for the final PullPush fallback |

#### Example input

```json
{
  "searchQuery": "python packaging",
  "maxResults": 10,
  "sortBy": "new",
  "subreddit": "r/python",
  "timeFilter": "month"
}
```

### Output

Each default-dataset record has the same normalized fields:

- `id` — Reddit post identifier, normalized with the `t3_` prefix
- `title` — post title
- `subreddit` — subreddit name
- `author` — Reddit author name when available
- `score` — score from an archive, or `0` for Atom
- `numComments` — comment count from an archive, or `0` for Atom
- `permalink` — absolute Reddit post URL
- `url` — external destination for link posts, otherwise an empty string
- `createdUtc` — Unix creation timestamp
- `isSelf` — whether the record is a self post
- `isVideo` — video flag when available
- `selftext` — text supplied by the selected source
- `linkFlairText` — flair text when available
- `upvoteRatio` — ratio from an archive, or `0` for Atom
- `nsfw` — NSFW flag when available

Reddit Atom exposes titles, authors, links, timestamps, and feed HTML content, but not scores or comment counts. Atom results use `0` for `score`, `numComments`, and `upvoteRatio`, with empty or false compatibility values for other unavailable fields. Arctic Shift and PullPush may populate engagement, flair, video, and NSFW fields from archived Reddit submissions.

### API recipes

Set an Apify API token with permission to run the Actor, then replace `YOUR_ACTOR_ID` with the Actor ID or `username~actor-name`. These synchronous recipes wait for the run and return default-dataset items as a JSON array.

### cURL

```bash
export APIFY_TOKEN='YOUR_APIFY_TOKEN'

curl --fail-with-body \
  --request POST \
  'https://api.apify.com/v2/acts/YOUR_ACTOR_ID/run-sync-get-dataset-items?clean=true&format=json' \
  --header "Authorization: Bearer $APIFY_TOKEN" \
  --header 'Content-Type: application/json' \
  --data '{
    "searchQuery": "python packaging",
    "maxResults": 10,
    "sortBy": "new",
    "subreddit": "python",
    "timeFilter": "month"
  }'
```

### Python

Requires Python 3 and `requests` (`python -m pip install requests`).

```python
import os
import requests

actor_id = os.environ.get("APIFY_ACTOR_ID", "YOUR_ACTOR_ID")
url = f"https://api.apify.com/v2/acts/{actor_id}/run-sync-get-dataset-items"
response = requests.post(
    url,
    params={"clean": "true", "format": "json"},
    headers={
        "Authorization": f"Bearer {os.environ['APIFY_TOKEN']}",
        "Content-Type": "application/json",
    },
    json={
        "searchQuery": "python packaging",
        "maxResults": 10,
        "sortBy": "new",
        "subreddit": "python",
        "timeFilter": "month",
    },
    timeout=300,
)
response.raise_for_status()
posts = response.json()
print(f"Received {len(posts)} posts")
```

### JavaScript

Works in Node.js 18+ using the built-in `fetch` API.

```javascript
const actorId = process.env.APIFY_ACTOR_ID || 'YOUR_ACTOR_ID';
const endpoint = new URL(
  `https://api.apify.com/v2/acts/${actorId}/run-sync-get-dataset-items`,
);
endpoint.searchParams.set('clean', 'true');
endpoint.searchParams.set('format', 'json');

const response = await fetch(endpoint, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.APIFY_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    searchQuery: 'python packaging',
    maxResults: 10,
    sortBy: 'new',
    subreddit: 'python',
    timeFilter: 'month',
  }),
});

if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);
const posts = await response.json();
console.log(`Received ${posts.length} posts`);
```

### n8n / HTTP Request

Create an **HTTP Request** node with these settings:

1. **Method:** `POST`
2. **URL:** `https://api.apify.com/v2/acts/YOUR_ACTOR_ID/run-sync-get-dataset-items`
3. **Query parameters:** `clean` = `true`, `format` = `json`
4. **Send Headers:** on
   - `Authorization` = `Bearer YOUR_APIFY_TOKEN`
   - `Content-Type` = `application/json`
5. **Send Body:** on; **Body Content Type:** JSON
6. **JSON body:**

```json
{
  "searchQuery": "python packaging",
  "maxResults": 10,
  "sortBy": "new",
  "subreddit": "python",
  "timeFilter": "month"
}
```

The node output is the returned array of post records. For monitoring, run the workflow on a Schedule Trigger and deduplicate records by `id` before sending alerts or storing data.

### Live feed and archive limitations

- **Reddit Atom is the live source.** The Actor makes at most one fast Atom attempt. Reddit can block automated addresses or return no matching feed entries.
- **Arctic Shift and PullPush are archival fallbacks.** They can lag live Reddit, have incomplete coverage, or include posts that Reddit later removed or deleted.
- **Sort semantics differ by source.** `sortBy` controls the requested Atom order. Arctic Shift and PullPush fallbacks return newest matching posts; they do not reproduce Reddit's `relevance`, `hot`, or `top` ranking exactly.
- **Metrics differ by source.** Atom does not provide score, comment count, or upvote ratio, so those compatibility fields are `0`. Archive records may contain those values.
- **Availability is not guaranteed.** Upstream services can block, throttle, change, or go offline. Instead of silently returning a successful empty dataset, the Actor raises an error when all three sources produce no verified records.

### Pricing

Current pay-per-event pricing is **$0.02 per run** plus **$0.00275 per dataset result**.

For example, a run that returns the full default `maxResults` of 25 has a maximum charge of:

`$0.02 + (25 × $0.00275) = $0.08875`

In other words, **25 returned posts cost $0.08875** at the current event prices. If fewer than 25 posts are returned, fewer result events are charged. Apify plan discounts or platform usage charges, if applicable to your account, are separate; check the Store listing for the current rates before running at scale.

### Responsible use

Search only public posts. Apply appropriate retention and filtering, avoid sensitive-data misuse, and comply with Reddit's terms, archive-provider terms, and applicable law.

# Actor input Schema

## `searchQuery` (type: `string`):

Keywords to search for in Reddit posts (e.g. 'best mechanical keyboard', 'python tips')

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

Maximum number of posts to return

## `sortBy` (type: `string`):

Requested sort for the live Reddit Atom source. Arctic Shift and PullPush archival fallbacks return newest matching posts.

## `timeFilter` (type: `string`):

Filter results by time period

## `subreddit` (type: `string`):

If provided, searches within this subreddit only (without the r/ prefix, e.g. 'programming'). Leave empty to search all of Reddit.

## `proxyConfiguration` (type: `object`):

Used for the final PullPush fallback. The Actor first requests Atom and Arctic Shift directly, then uses a fresh session from this configured Apify Proxy if PullPush is needed.

## Actor input object example

```json
{
  "searchQuery": "python",
  "maxResults": 25,
  "sortBy": "relevance",
  "timeFilter": "all",
  "subreddit": "",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

Results stored in the default dataset

# 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 = {
    "searchQuery": "python",
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("northglasslabs/reddit-post-search").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 = {
    "searchQuery": "python",
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("northglasslabs/reddit-post-search").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 '{
  "searchQuery": "python",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call northglasslabs/reddit-post-search --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/9w7N46mXdvKr4SdqS/builds/ann7SVqOD81SKidCT/openapi.json
