# Reddit Historical Archive Scraper | Enterprise Grade (`fatihtahta/reddit-scraper-fast`) Actor

All-in-one Reddit Scraper. Scrape posts and full comment threads from any search, subreddit, user, or direct post URL. This enterprise-grade scraper is the fastest in the market and delivers clean and detailed JSON.

- **URL**: https://apify.com/fatihtahta/reddit-scraper-fast.md
- **Developed by:** [Fatih Tahta](https://apify.com/fatihtahta) (community)
- **Categories:** Social media, Lead generation, Automation
- **Stats:** 49 total users, 2 monthly users, 80.0% runs succeeded, 5 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

$11.99/month + usage

To use this Actor, you pay a monthly rental fee to the developer. The rent is subtracted from your prepaid usage every month after the free trial period.You also pay for the Apify platform usage, which gets cheaper the higher Apify subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#rental-actors

## 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

## Historical Reddit Archive Search

**Actor name:** `reddit-historical-archive-search`

### Overview

Historical Reddit Archive Search finds Reddit submissions in a stored, indexed archive instead of crawling Reddit live. Give it one or more search phrases, optionally focus on a subreddit or UTC date range, and receive structured post records ready for research, analytics, monitoring, enrichment, or ETL workflows.

The Actor is designed for repeatable historical research. Keyword searches use proprietary month-partitioned full-text indexes, while keyword-free subreddit listings use proprietary subreddit hash buckets derived from the same canonical archive. Matching records stream to the default dataset, duplicate Reddit IDs are removed across overlapping queries and archive pages, optional relevance and engagement filters are applied, and a machine-readable run summary is saved for review and automation.

This Actor searches archived **posts only**. It does not visit live Reddit pages, scrape direct Reddit URLs, collect comment threads, or guarantee that every historical Reddit submission exists in the underlying archive.

### Table of Contents

- [Archive at a Glance](#archive-at-a-glance)
- [Why Use This Actor](#why-use-this-actor)
- [Feature Highlights](#feature-highlights)
- [Common Research Workflows](#common-research-workflows)
- [Choosing a Search Strategy](#choosing-a-search-strategy)
- [How Archive Search Works](#how-archive-search-works)
- [Input Parameters](#input-parameters)
- [Example Inputs](#example-inputs)
- [Understanding Input Interactions](#understanding-input-interactions)
- [Output](#output)
- [Field Reference](#field-reference)
- [Data Guarantees and Limitations](#data-guarantees-and-limitations)
- [Performance](#performance)
- [How to Run on Apify](#how-to-run-on-apify)
- [Scheduling and Automation](#scheduling-and-automation)
- [Export and Integration Options](#export-and-integration-options)
- [Recommended Production Patterns](#recommended-production-patterns)
- [Responsible Use](#responsible-use)
- [Troubleshooting](#troubleshooting)
- [Frequently Asked Questions](#frequently-asked-questions)
- [Support](#support)

### Archive at a Glance

This is not a thin wrapper around Reddit's current search results. It is backed by a privately operated, month-partitioned archive built for historical discovery at scale.

- **29.2+ billion verified archive rows:** The audited storage layers contain approximately **2.60 billion submission rows** and **26.62 billion comment rows**.
- **More than 20 years of stored history:** Verified archive material spans **June 2005 through May 2026**, with additional months and indexes added as they become available.
- **Indexed instead of live-scrolled:** Keyword runs use monthly full-text indexes, and complete subreddit listings fetch one compact owned hash bucket per month rather than downloading an entire month or stopping at the practical depth of a live feed.
- **Search by topic or community:** Find archived posts with one or more keyword phrases, optionally restricted to a subreddit and an exact UTC date range.
- **Fast archive retrieval:** A measured full-month index lookup over **47,453,180 submissions** returned broad-query candidates in approximately **0.12 seconds** after the index was available locally. End-to-end Actor time also includes startup, network transfer, filtering, enrichment, and dataset writes.
- **Progressive results:** Matching posts are written to the dataset as monthly windows finish, so large historical searches do not need to complete before results become visible.
- **Analysis-ready output:** Optional deterministic sentiment analysis adds polarity, confidence, and normalized scores. Optional content analysis adds conservative taxonomy labels and paths when the record contains enough evidence.
- **Research controls built in:** Apply strict token matching, subreddit targeting, score and comment-count thresholds, NSFW controls, deduplication, and global output limits without assembling a separate pipeline.

The underlying archive also stores comments, but the current public Actor searches and returns **submissions only**. Comment counts on post records are archived metadata, not collected comment threads. Storage totals describe verified rows across the base and repair/backfill layers; they are not a claim that every Reddit record is unique, complete, or currently exposed through this Actor.

### Why Use This Actor

- **Market and consumer research:** Study historical opinions, category discussions, purchase considerations, and recurring user pain points.
- **Brand and competitor monitoring:** Find older mentions, launch reactions, reputation signals, and shifts in community discussion.
- **Product research:** Discover feature requests, complaints, workflows, and language customers used at different points in time.
- **Trend analysis:** Compare topics across communities and fixed reporting periods without depending on Reddit's current search window.
- **Data engineering:** Export stable, structured JSON records into warehouses, dashboards, search indexes, or enrichment pipelines.
- **AI and NLP workflows:** Add deterministic sentiment and content-category fields before routing records into downstream models or agents.

### Feature Highlights

- **Historical keyword discovery:** Search stored Reddit submissions beyond the practical window exposed by live Reddit search.
- **Multiple search phrases:** Run several related phrases in one job and receive one overlap-safe dataset.
- **Subreddit targeting:** Restrict research to a specific community without relying on live subreddit pages.
- **Exact UTC date ranges:** Reproduce fixed reporting periods with inclusive `dateFrom` and `dateTo` boundaries.
- **Rolling time windows:** Use current-day, seven-day, 30-day, 365-day, or all-time archive windows.
- **Progressive monthly collection:** Search newest archive months first and save rows while the Actor continues through the selected range.
- **Strict query verification:** Require every query token to occur in a post's title, body, or canonical URL.
- **Engagement thresholds:** Keep only records meeting minimum score or discussion-size requirements.
- **NSFW controls:** Exclude archived 18+ records by default or include them explicitly.
- **Deterministic sentiment:** Add polarity, normalized score, confidence, and human-readable sentiment labels.
- **Conservative content classification:** Attach taxonomy labels only when the post contains enough evidence.
- **Rich normalized records:** Receive stable IDs, canonical URLs, temporal dimensions, engagement metrics, media details, and analysis-friendly derived fields.
- **Run-level deduplication:** Save each Reddit `kind:id` identity once even when several queries, pages, or months overlap.
- **Bounded filtered pagination:** Continue through archive pages to fill a requested limit without launching an unrestricted backend scan.
- **Machine-readable summaries:** Inspect found, filtered, duplicate, saved, monthly, page, stop-reason, and broker metadata.
- **ETL-friendly output:** Export consistent rows to JSON, JSONL, CSV, Excel, XML, RSS, or supported Apify integrations.

### Common Research Workflows

#### Brand history and reputation research

Search a brand name, product name, former brand name, and common misspellings across a fixed historical period. Add a subreddit filter when community context matters, or leave it empty to compare where conversations occurred organically.

Useful settings:

```json
{
  "queries": [
    "ExampleBrand",
    "Example Product",
    "ExampleBrand alternative"
  ],
  "dateFrom": "2018-01-01",
  "dateTo": "2025-12-31",
  "sentiment_analysis": true,
  "content_analysis": true,
  "maxPosts": 2000
}
```

#### Product feedback discovery

Combine product and problem-oriented phrases such as `battery issue`, `pricing problem`, `feature request`, and `switched from`. Use `minimumComments` to focus on posts that produced a meaningful discussion.

#### Competitive intelligence

Run separate scheduled inputs for each competitor so datasets and summaries remain easy to compare. Use identical date windows and engagement thresholds across jobs for cleaner longitudinal analysis.

#### Historical trend analysis

Use fixed monthly, quarterly, or yearly windows and retain `created_year`, `created_month`, `created_day_of_week`, and subreddit fields in your downstream model. Fixed exact dates make reruns reproducible.

#### Community research

Set `subredditName` by itself to collect every indexed post from that community in the selected time window. Add `subredditKeywords` only when you want to narrow the subreddit listing to a topic. The Actor searches archived submissions; it does not crawl the current subreddit feed.

#### Dataset construction for NLP

Disable content classification when you plan to supply your own taxonomy. Keep sentiment enabled for a lightweight baseline, or disable both enrichment options when you only need source and normalized metadata.

#### Academic and policy research

Use exact date windows, preserve the input and `RUN-SUMMARY`, and document archive-coverage limitations alongside any conclusions. The dataset provides useful temporal and community features, but archive presence is not a complete census of Reddit.

### Choosing a Search Strategy

#### Start broad, then narrow

A practical workflow is:

1. run one phrase over one representative month with `maxPosts` between 25 and 100;
2. inspect titles, bodies, subreddits, `recordsFound`, and `recordsFiltered`;
3. add a subreddit or strict matching only when irrelevant candidates are visible;
4. add engagement thresholds only when low-activity posts are not useful;
5. expand the date window after the query behavior is understood.

#### Use several focused phrases instead of one long sentence

Archive full-text search generally works best with short topic phrases, names, product terms, or recognizable wording. A long natural-language question may be unnecessarily restrictive.

For example, prefer:

```json
{
  "queries": [
    "electric bike battery",
    "ebike range",
    "electric bike commute"
  ]
}
```

over one long question containing every concept.

#### Understand query overlap

The same Reddit post can match several input phrases. The Actor preserves the first normalized match it saves and removes later rows with the same `kind:id` identity. `recordsDuplicate` reports how many repeated identities were removed.

#### Choose precision or recall deliberately

- Leave `strictTokenFilter=false` for broader archive recall.
- Enable `strictTokenFilter=true` for datasets where every query word must be visibly supported by the record.
- Use `minimumScore` and `minimumComments` for engagement quality, not semantic relevance.
- Add `subredditName` when community scope is part of the research question.

Combining all filters can produce a very precise but small or empty dataset. The run summary helps distinguish “the archive found nothing” from “the Actor found candidates but filtered them out.”

### How Archive Search Works

The Actor sends each query and date window through the indexed historical archive path. Search is split into UTC month windows, newest first, and results are saved progressively. Keyword searches use the private monthly full-text indexes. A `subredditName` without keywords resolves to one of 256 proprietary monthly subreddit buckets, avoiding multi-gigabyte month-wide index downloads and third-party search APIs.

The runtime:

1. validates the input and resolves the effective UTC date range;
2. searches the relevant monthly keyword index or direct subreddit index;
3. normalizes source records into a consistent Reddit post schema;
4. applies NSFW, strict-query, score, and comment-count filters;
5. removes duplicate Reddit IDs across pages, months, and overlapping queries;
6. optionally adds sentiment and content-category fields;
7. saves dataset rows and updates `RUN-SUMMARY`.

Archive coverage and source-field availability vary by month. A successful empty run means no matching records were found in the searched archive range; it does not prove that the topic never appeared on Reddit.

### Input Parameters

Provide at least one phrase in `queries` or `subredditKeywords`, or provide `subredditName` by itself for a complete subreddit listing.

| Parameter | Type | Description | Default |
| --- | --- | --- | --- |
| `queries` | `string[]` | One or more phrases to search for in archived Reddit submissions. When both query fields are populated, this field takes priority. | – |
| `sort` | `string` | Order candidates inside each monthly keyword-search batch by relevance, recency, hot engagement, score, or comments. | `relevance` |
| `subredditName` | `string` | Subreddit without the `r/` prefix. With no keywords, collects every indexed post from that subreddit in the selected date window. | – |
| `subredditKeywords` | `string[]` | Optional query list for narrowing a subreddit search. Leave empty for the complete subreddit listing. | – |
| `subredditSort` | `string` | Candidate ordering for subreddit-focused runs. Overrides `sort` when `subredditName` is present. | `relevance` |
| `timeframe` | `string` | Inclusive UTC calendar window used when exact dates are absent: `all`, `year` (365 days), `month` (30 days), `week` (7 days), or `day` (current UTC day). | `all` |
| `dateFrom` | `string` | Earliest UTC archive date to include, formatted as `YYYY-MM-DD`. Takes priority over `timeframe`. | – |
| `dateTo` | `string` | Latest UTC archive date to include, formatted as `YYYY-MM-DD`. | Current UTC date |
| `strictSearch` | `boolean` | Compatibility control that enables full-query token verification on the indexed archive path. | `false` |
| `strictTokenFilter` | `boolean` | Require every word from the originating query to appear in the saved post title, body, or canonical URL. | `false` |
| `minimumScore` | `integer` | Only save posts with at least this archived Reddit score. | – |
| `minimumComments` | `integer` | Only save posts with at least this reported comment count. | – |
| `includeNsfw` | `boolean` | Include posts marked NSFW or 18+. | `false` |
| `sentiment_analysis` | `boolean` | Add deterministic sentiment scores, confidence, and labels. | `true` |
| `content_analysis` | `boolean` | Add deterministic content-category labels and taxonomy paths when evidence is strong enough. | `true` |
| `maxPosts` | `integer` | Maximum number of unique records saved across all queries and month windows. Omit it to continue until the selected archive range is exhausted. | – |
| `mcpConnectors` | `string[]` | Optional Apify MCP connector selections. Connector IDs remain shell-owned and are not sent to the archive broker. | `[]` |

Exact dates are inclusive. If `dateFrom` is later than `dateTo`, the Actor completes without searching and records `empty_date_window` in the run summary.

#### Strict query matching

Enable `strictTokenFilter` when precision matters more than recall. The archive first returns indexed candidates; the Actor then verifies that every query token occurs in the normalized title, body, or URL. `strictSearch=true` enables the same verification as a compatibility alias, so enabling either option is sufficient.

For example, the phrase `electric bike` requires both `electric` and `bike` to be present somewhere in those searchable fields. Records matching only one word are filtered out.

#### Candidate ordering

Use `sort` for general keyword searches. When `subredditName` is set, `subredditSort` takes priority.

- `relevance`: more query-token coverage first, then newer posts;
- `new`: newest posts first;
- `hot`: highest combined archived score and comment count first;
- `top`: highest archived Reddit score first;
- `comments`: highest archived `num_comments` first.

Sorting is deterministic within each bounded monthly archive batch. The Actor still traverses archive months newest first and saves progressively, so these controls are not a claim of one global ranking across every selected month.

#### Engagement filters

Use `minimumScore` and `minimumComments` to focus on posts that reached a chosen engagement threshold. The values reflect archived Reddit metadata and may be unavailable or incomplete for some historical records. Missing numeric values are treated as zero for filtering.

Filtered limited runs use bounded archive overscan so the Actor can continue searching for enough qualifying records without turning a small request into an unrestricted backend scan.

#### Sentiment labels

When `sentiment_analysis` is enabled, the Actor adds:

- `sentiment_score`: raw lexicon-and-rules score;
- `sentiment_score_normalized`: bounded score adjusted for text length;
- `sentiment_confidence`: heuristic confidence from `0` to `1`;
- `sentiment_label`: `positive`, `negative`, `neutral`, `mixed`, or `uncertain`.

The analyzer is deterministic and lightweight. It is useful for sorting, triage, and aggregate analysis, but it is not a substitute for domain-specific human review.

#### Content categories

When `content_analysis` is enabled, the Actor evaluates the post title and body with supporting signals such as subreddit, flair, and outbound domain.

Confident matches can add:

- `content_category_label`
- `content_category_path`
- `content_category_confidence`
- `content_category_match_type`

Classification is intentionally conservative. Category fields remain absent when the record does not contain enough evidence.

### Example Inputs

#### Historical keyword research

```json
{
  "queries": [
    "electric bike"
  ],
  "dateFrom": "2020-01-01",
  "dateTo": "2024-12-31",
  "maxPosts": 500
}
```

#### Subreddit-focused research

```json
{
  "subredditName": "technology",
  "subredditKeywords": [
    "artificial intelligence",
    "AI regulation"
  ],
  "timeframe": "year",
  "maxPosts": 250
}
```

#### High-precision engagement search

```json
{
  "queries": [
    "electric bike"
  ],
  "dateFrom": "2023-01-01",
  "dateTo": "2025-12-31",
  "strictTokenFilter": true,
  "minimumScore": 25,
  "minimumComments": 10,
  "includeNsfw": false,
  "sentiment_analysis": true,
  "content_analysis": true,
  "maxPosts": 100
}
```

#### Lightweight ETL output

```json
{
  "queries": [
    "venture capital"
  ],
  "dateFrom": "2015-01-01",
  "dateTo": "2020-12-31",
  "sentiment_analysis": false,
  "content_analysis": false,
  "maxPosts": 1000
}
```

#### Rolling weekly monitoring

```json
{
  "queries": [
    "ExampleBrand",
    "ExampleBrand outage"
  ],
  "timeframe": "week",
  "includeNsfw": false,
  "sentiment_analysis": true,
  "content_analysis": false,
  "maxPosts": 250
}
```

The effective window is the latest seven inclusive UTC calendar dates ending at `dateTo`, or the current UTC date when `dateTo` is omitted.

#### High-engagement discussions

```json
{
  "queries": [
    "remote work"
  ],
  "dateFrom": "2019-01-01",
  "dateTo": "2024-12-31",
  "minimumScore": 100,
  "minimumComments": 50,
  "maxPosts": 500
}
```

#### Archive-wide community search

```json
{
  "subredditName": "personalfinance",
  "subredditKeywords": [
    "emergency fund",
    "credit card debt",
    "first home"
  ],
  "timeframe": "all",
  "includeNsfw": false,
  "maxPosts": 1000
}
```

Omitting exact dates with `timeframe=all` searches from the Actor's earliest configured archive date through the current UTC date. This can span many monthly indexes.

#### Precision-first compliance research

```json
{
  "queries": [
    "AI regulation",
    "artificial intelligence regulation"
  ],
  "subredditName": "technology",
  "dateFrom": "2023-01-01",
  "dateTo": "2025-12-31",
  "strictTokenFilter": true,
  "minimumScore": 5,
  "includeNsfw": false,
  "sentiment_analysis": true,
  "content_analysis": true,
  "maxPosts": 300
}
```

#### Quick archive availability test

```json
{
  "queries": [
    "google"
  ],
  "dateFrom": "2005-06-01",
  "dateTo": "2005-06-30",
  "maxPosts": 3
}
```

Small, fixed-window inputs are useful for validating an integration before starting a broad historical job.

### Understanding Input Interactions

#### `queries` and `subredditKeywords`

- At least one of these lists must contain a non-empty phrase.
- If `queries` contains values, it becomes the effective query list.
- If `queries` is empty, `subredditKeywords` becomes the effective query list.
- If both keyword lists are empty, `subredditName` becomes a complete indexed subreddit listing.
- With keywords present, `subredditName` acts as an archive filter.

#### `timeframe`, `dateFrom`, and `dateTo`

- `dateFrom` takes priority over the relative `timeframe`.
- `dateTo` defaults to the current UTC date.
- `day` selects the current or specified `dateTo` UTC calendar date.
- `week` selects seven inclusive UTC dates.
- `month` selects 30 inclusive UTC dates.
- `year` selects 365 inclusive UTC dates.
- `all` begins at the Actor's configured archive start date.

Date inputs accept `YYYY-MM-DD`. Values such as `2025-02-31` are rejected as invalid rather than silently rolled into another month.

#### Filters and `maxPosts`

`maxPosts` counts successfully saved unique records. Candidates rejected by local filters or deduplication do not consume the saved-record limit.

For limited filtered runs, the Actor asks the archive for bounded pages larger than the remaining save limit. It can then remove unsuitable candidates and follow the archive cursor until one of these conditions is met:

- enough unique records have been saved;
- the archive month is exhausted;
- every requested month is exhausted;
- a fatal broker response stops the run.

The inactivity watchdog is scoped to the current monthly shard and renewed after every returned result page. Total shard duration is not the timeout condition. If a shard produces no result page within the inactivity window, the Actor records that month as incomplete and continues with the remaining months instead of discarding the rest of the requested window.

#### Enrichment controls

`sentiment_analysis` and `content_analysis` affect output enrichment only. They do not change which archive records match the query. Disable them when smaller processing overhead or a source-focused schema matters more than built-in analysis.

#### NSFW behavior

`includeNsfw=false` excludes records where archived source metadata explicitly marks `over_18=true`. Historical records without a reliable NSFW flag cannot be inferred as adult content solely from this option.

#### Optional MCP connectors

`mcpConnectors` lets you select user-authorized MCP resources through Apify's resource picker. The Actor treats connector IDs as shell-owned configuration and never forwards them to the archive broker or includes them in dataset records. The archive dataset and `RUN-SUMMARY` remain the authoritative run outputs; the full Reddit dataset is not transmitted through MCP.

### Output

#### Dataset

The default dataset contains one JSON object per unique archived Reddit post. Results can be downloaded from Apify in JSON, JSONL, CSV, Excel, XML, RSS, and other supported formats.

A representative record:

```json
{
  "kind": "post",
  "query": "electric bike",
  "id": "example123",
  "reddit_fullname": "t3_example123",
  "title": "My experience commuting with an electric bike",
  "body": "After six months of daily use...",
  "author": "example_user",
  "author_url": "https://www.reddit.com/user/example_user/",
  "score": 184,
  "num_comments": 37,
  "subreddit": "ebikes",
  "subreddit_url": "https://www.reddit.com/r/ebikes/",
  "created_utc": "2024-04-18T09:30:00.000Z",
  "created_timestamp": 1713432600,
  "created_date": "2024-04-18",
  "created_year": 2024,
  "created_month": 4,
  "url": "https://www.reddit.com/r/ebikes/comments/example123/example/",
  "canonical_url": "https://www.reddit.com/r/ebikes/comments/example123/example/",
  "old_reddit_url": "https://old.reddit.com/r/ebikes/comments/example123/example/",
  "over_18": false,
  "engagement_total": 221,
  "word_count": 42,
  "retrieved_at": "2026-07-23T09:00:00.000Z"
}
```

Fields are included when the archive source or Actor can derive them reliably. Optional fields are omitted rather than filled with misleading placeholders.

#### Stable identity and deduplication

Use the following idempotency key for upserts:

```text
kind + ":" + id
```

For example:

```text
post:example123
```

The Actor applies this identity internally and does not save the same Reddit post twice when it appears across overlapping queries, archive pages, or month windows.

#### Run summary artifacts

The default key-value store contains:

- `RUN-SUMMARY`: the standard machine-readable run artifact;
- `ARCHIVE_SEARCH_SUMMARY`: a backward-compatible alias with the same content.

Important summary fields include:

| Field | Meaning |
| --- | --- |
| `queries` | Effective archive search phrases. |
| `subredditName` | Applied subreddit filter, or `null`. |
| `dateFrom` / `dateTo` | Effective inclusive UTC archive window. |
| `maxPosts` | Requested save limit, or `null` when omitted. |
| `recordsFound` | Records returned by the archive before local filters and deduplication. |
| `recordsFiltered` | Records removed by NSFW, strict-token, score, or comment-count filters. |
| `recordsDuplicate` | Repeated Reddit identities removed across archive pages or months. |
| `recordsSaved` | Unique dataset rows successfully saved. |
| `monthsRequested` | Number of UTC month windows planned. |
| `monthsChecked` | Number of month windows completed or recorded. |
| `monthsIncomplete` | Number of requested month windows that timed out or had no available index. |
| `monthSummaries` | Per-month and per-page search details. |
| `stopReason` | Why collection ended. |
| `brokerMetadata` | Operational source metadata useful for support. |
| `traceId` | Broker trace identifier when available. |

Common `stopReason` values:

- `completed`: the selected archive range was exhausted;
- `limit_reached`: the Actor saved the requested maximum;
- `empty_date_window`: `dateFrom` was later than `dateTo`;
- `missing_target`: neither a usable keyword nor a subreddit was provided;
- `partial`: one or more months timed out or had no available index, while the remaining months continued;
- `failed`: invalid input, an invalid broker response, or another fatal error stopped the run.

A representative summary:

```json
{
  "source": "b2_sqlite_fts",
  "mode": "fast",
  "queries": [
    "electric bike"
  ],
  "subredditName": "ebikes",
  "dateFrom": "2024-01-01",
  "dateTo": "2024-12-31",
  "maxPosts": 100,
  "recordsFound": 146,
  "recordsSaved": 100,
  "recordsFiltered": 31,
  "recordsDuplicate": 15,
  "stopReason": "limit_reached",
  "monthsRequested": 12,
  "monthsChecked": 7,
  "monthSummaries": [
    {
      "label": "2024-12",
      "dateFrom": "2024-12-01",
      "dateTo": "2024-12-31",
      "status": "completed",
      "recordsFound": 28,
      "recordsSaved": 19,
      "recordsFiltered": 6,
      "recordsDuplicate": 3,
      "pages": [
        {
          "page": 1,
          "status": "completed",
          "recordsFound": 28,
          "recordsSaved": 19,
          "recordsFiltered": 6,
          "recordsDuplicate": 3
        }
      ]
    }
  ],
  "brokerMetadata": {
    "sourceId": "reddit_historical_archive",
    "platform": "apify"
  },
  "traceId": null
}
```

Counts in this example are illustrative. Use the summary saved by your run as the authoritative record.

#### Reading summary counts

The principal count relationship is:

```text
recordsFound
  -> recordsFiltered removed by configured filters
  -> recordsDuplicate removed by stable identity
  -> recordsSaved written to the dataset
```

The values do not always form a simple subtraction when `maxPosts` stops a page early, because the archive can return more candidates than the remaining save limit. The dataset count and `recordsSaved` remain authoritative for delivered rows.

#### Empty and failed runs

The Actor preserves a summary even when normal rows are not expected:

- missing target: zero rows and `stopReason=missing_target`;
- inverted date window: zero rows and `stopReason=empty_date_window`;
- valid search with no candidates: zero rows and `stopReason=completed`;
- invalid date or broker response: zero or partial rows and `stopReason=failed`;
- broker deadline or unavailable monthly index: zero or partial rows and `stopReason=partial`; later months are still attempted.

This makes scheduled jobs easier to monitor because a zero-row dataset can be interpreted using the accompanying artifact instead of process exit alone.

### Field Reference

#### Identity and provenance

- `kind` *(string)*: Record category. Public archive search currently returns `post`.
- `id` *(string)*: Stable Reddit post identifier without a kind prefix.
- `reddit_fullname` *(string)*: Kind-prefixed Reddit identifier such as `t3_example123`.
- `query` *(string)*: Originating archive phrase associated with this match.
- `archive_source` *(string, optional)*: Archive source label supplied by the backend.
- `archive_mode` *(string, optional)*: Archive retrieval mode supplied by the backend.
- `archive_shard_id` *(string, optional)*: Archive shard or partition identifier.
- `sourceFile` *(string, optional)*: Historical source-file identifier.

#### Content and authorship

- `title` *(string)*: Archived post title.
- `body` *(string)*: Normalized self-text or archived body text.
- `body_html` *(string, optional)*: HTML-formatted body when available.
- `author` *(string)*: Archived Reddit username or a deletion placeholder.
- `author_url` *(string, optional)*: Deterministic Reddit profile URL for a usable username.
- `author_fullname` *(string, optional)*: Internal kind-prefixed author identifier.
- `author_flair_text` *(string, optional)*: Author flair visible on the archived post.
- `author_premium` *(boolean, optional)*: Archived premium-status indicator.
- `flair` *(string, optional)*: Post link-flair text.

#### Community and engagement

- `subreddit` *(string)*: Subreddit name without `r/`.
- `subreddit_url` *(string, optional)*: Deterministic canonical subreddit URL.
- `subreddit_id` *(string, optional)*: Internal kind-prefixed subreddit identifier.
- `subreddit_name_prefixed` *(string, optional)*: Display form such as `r/technology`.
- `subreddit_subscribers` *(number, optional)*: Subscriber count present in the archived payload.
- `score` *(number)*: Archived Reddit score.
- `upvote_ratio` *(number, optional)*: Archived upvote ratio.
- `num_comments` *(number)*: Reported post comment count.
- `engagement_total` *(number)*: `score + num_comments`.
- `comment_to_score_ratio` *(number, optional)*: Comment count divided by score when score is positive.
- `is_high_engagement` *(boolean)*: Convenience flag based on the Actor's high-engagement threshold.
- `score_per_hour` *(number)*: Score divided by post age with a small minimum age floor.
- `comments_per_hour` *(number)*: Comment count divided by post age with a small minimum age floor.
- `total_awards_received` *(number, optional)*: Total awards in the archived payload.
- `all_awardings` *(array, optional)*: Raw archived award objects.
- `gilded` *(number, optional)*: Archived gilding count.

#### Dates and analytics

- `created_utc` *(string)*: Normalized ISO creation timestamp.
- `created_timestamp` *(integer)*: Unix creation timestamp in seconds.
- `created_date` *(string)*: UTC date in `YYYY-MM-DD` format.
- `created_year` *(integer)*: UTC creation year.
- `created_month` *(integer)*: UTC creation month from `1` to `12`.
- `created_day` *(integer)*: UTC day of month.
- `created_hour_utc` *(integer)*: UTC hour from `0` to `23`.
- `created_day_of_week` *(string)*: English UTC weekday name.
- `retrieved_at` *(string)*: ISO time when the Actor normalized the row.
- `age_hours` *(number)*: Approximate record age at retrieval time.
- `title_length` *(integer)*: Character count of the normalized title.
- `body_length` *(integer)*: Character count of the normalized body.
- `word_count` *(integer)*: Lightweight word count across title and body.

#### URLs and media

- `url` *(string)*: Canonical Reddit post URL.
- `permalink` *(string)*: Relative Reddit permalink.
- `canonical_url` *(string)*: Canonical full Reddit URL.
- `old_reddit_url` *(string)*: Equivalent legacy Reddit URL.
- `short_url` *(string)*: `redd.it` short URL derived from the post ID.
- `url_overridden_by_dest` *(string, optional)*: Outbound destination for link posts.
- `outbound_url_host` *(string, optional)*: Parsed hostname from the outbound destination.
- `domain` *(string, optional)*: Reddit domain field or inferred self-post domain.
- `post_hint` *(string, optional)*: Archived Reddit post-type hint.
- `thumbnail` *(string, optional)*: Thumbnail URL or archived Reddit thumbnail marker.
- `media` *(object, optional)*: Raw media object.
- `secure_media` *(object, optional)*: Raw secure-media object.
- `secure_media_embed` *(object, optional)*: Secure embed metadata.
- `preview` *(object, optional)*: Reddit preview metadata.
- `media_metadata` *(object, optional)*: Raw media metadata keyed by media ID.
- `gallery_data` *(object, optional)*: Raw Reddit gallery structure.
- `gallery_images` *(array)*: Normalized gallery image list.
- `media_assets` *(array)*: Normalized media-asset list.
- `media_type` *(string)*: Normalized class such as `text`, `link`, `image`, `gallery`, `video`, or `gif`.
- `has_media` *(boolean)*: Convenience flag for image, gallery, GIF, or video records.
- `gallery_count` *(integer)*: Number of normalized gallery images.

##### Normalized gallery image fields

Each `gallery_images` item can include:

- `media_id`
- `caption`
- `width`
- `height`
- `url`
- `previews`

Each `media_assets` item can include:

- `type`
- `media_id`
- `mime_type`
- `original_url`
- `preview_urls`

#### Status and moderation

- `over_18` *(boolean, optional)*: Archived NSFW indicator.
- `spoiler` *(boolean, optional)*: Whether the post is marked as a spoiler.
- `locked` *(boolean, optional)*: Whether replies were locked.
- `archived` *(boolean, optional)*: Archived-state indicator from Reddit.
- `pinned` *(boolean, optional)*: Whether the post was pinned.
- `stickied` *(boolean, optional)*: Whether the post was stickied.
- `is_self` *(boolean, optional)*: Whether the record is a self/text post.
- `is_video` *(boolean, optional)*: Reddit video indicator.
- `is_gallery` *(boolean, optional)*: Reddit gallery indicator.
- `is_original_content` *(boolean, optional)*: Original-content indicator.
- `edited` *(boolean | number, optional)*: `false` when untouched or an edit timestamp.
- `hidden` *(boolean, optional)*: Archived hidden-state value when present.
- `distinguished` *(string, optional)*: Moderator, administrator, or other distinction.
- `score_hidden` *(boolean, optional)*: Whether the archived score was hidden.
- `is_deleted_or_removed` *(boolean)*: Conservative flag derived from deletion placeholders and removal metadata.
- `content_flags` *(array)*: Normalized flags such as NSFW, spoiler, or locked.
- `num_duplicates` *(number, optional)*: Reddit-reported duplicate count.
- `num_crossposts` *(number, optional)*: Reddit-reported crosspost count.
- `crosspost_parent_list` *(array, optional)*: Raw crosspost-parent records.

#### Optional enrichment

- `sentiment_score` *(number)*: Raw deterministic sentiment score.
- `sentiment_score_normalized` *(number)*: Length-adjusted bounded score.
- `sentiment_confidence` *(number)*: Heuristic confidence between `0` and `1`.
- `sentiment_label` *(string)*: `positive`, `negative`, `neutral`, `mixed`, or `uncertain`.
- `content_category_label` *(string)*: Most specific confident category label.
- `content_category_path` *(array)*: Category hierarchy from broad to specific.
- `content_category_confidence` *(number)*: Confidence assigned to the category match.
- `content_category_match_type` *(string)*: Evidence type used for the classification.

### Data Guarantees and Limitations

- **Archived data:** Results come from stored historical sources, not live Reddit pages.
- **Best-effort coverage:** Archive completeness varies by month, subreddit, and source.
- **Posts only:** The public archive path currently searches submissions and does not collect comments.
- **Optional fields:** Historical records can lack fields available on newer Reddit payloads.
- **UTC dates:** Date filtering operates on inclusive UTC calendar dates.
- **Deterministic limits:** `maxPosts` applies across the entire run, not separately to each query.
- **Progressive saves:** Records are pushed as archive pages complete.
- **Deduplicated output:** Repeated `kind:id` identities are saved once per run.
- **Conservative enrichment:** Sentiment and category fields are omitted when disabled; category fields can also be absent when evidence is weak.
- **Empty results:** A zero-row run can mean no archive match, incomplete archive coverage, or filters that excluded all candidates.

### Performance

Performance depends primarily on:

- the number of UTC months searched;
- query selectivity;
- whether a subreddit filter is applied;
- how many candidates local filters reject;
- whether enrichment is enabled;
- archive index and broker readiness.

In the local release matrix, both 1,000-row lanes completed in roughly two seconds including Actor startup. A live production-broker smoke saved three requested records from a single indexed month in about eleven seconds. In the complete May 2026 subreddit-bucket pilot, **47,453,180 owned archive posts were partitioned into exactly 256 objects in about 10.1 minutes**. The resulting Logitech bucket occupied 31.1 MB, materialized its persistent local cursor index in 1.32 seconds, and returned a 100-record page in under one millisecond. Broad multi-year or unlimited searches can still take longer because more archive windows must be checked.

For quick validation, start with one query, one month, and a small `maxPosts`. Expand the date range after confirming the query returns the expected kind of records.

#### Performance planning by workload

##### Small validation run

Typical shape:

- one query;
- one subreddit or no subreddit;
- one month;
- `maxPosts` between 3 and 100.

Use this shape to validate wording, field availability, and integration behavior.

##### Focused research run

Typical shape:

- one to five related queries;
- one to 12 months;
- optional strict or engagement filtering;
- `maxPosts` between 100 and 2,000.

This is a practical range for most interactive research tasks and scheduled reports.

##### Broad historical run

Typical shape:

- multiple phrases;
- several years or `timeframe=all`;
- no save limit or a high limit;
- enrichment enabled.

These runs can traverse many monthly indexes and should be treated as batch jobs. Schedule them with enough platform timeout and inspect monthly progress in `RUN-SUMMARY`.

#### Why a zero-result query can still take time

Output count is not the same as search work. A selective query that finds three records early can stop quickly when `maxPosts=3`. A phrase with no archive matches may need to check every selected month before the Actor can confidently finish with zero rows.

#### Enrichment overhead

Sentiment and content classification run locally after archive candidates are normalized. In the release matrix, the enriched and non-enriched 1,000-row lanes both finished near two seconds including local Actor startup. Real cloud duration is usually dominated by archive access, monthly index work, and storage rather than these deterministic enrichments.

#### Dataset size considerations

Rich Reddit records can contain media metadata, preview objects, gallery structures, awards, or crosspost data. CSV exports flatten complex values less naturally than JSON or JSONL. For large analytical pipelines:

- prefer JSONL or direct dataset API reads;
- disable enrichment when it is not needed;
- select only required columns downstream;
- use `kind:id` as the warehouse upsert key;
- partition downstream storage by `created_year` and `created_month`.

#### Cost and run-size control

Use `maxPosts` to bound delivered records and start with a narrow date window before scaling. When filters are enabled, the Actor may inspect more candidates than it saves, because rejected and duplicate records do not count toward the save limit.

### How to Run on Apify

1. Open the Actor in Apify Console.
2. Add at least one archive search phrase.
3. Optionally choose a subreddit and UTC date window.
4. Configure relevance, engagement, NSFW, and enrichment controls.
5. Set `maxPosts` for bounded runs.
6. Click **Start**.
7. Review dataset rows and `RUN-SUMMARY` before exporting or automating downstream actions.

### Scheduling and Automation

Use Apify schedules for recurring research windows and webhooks for downstream processing.

Typical workflows include:

- monthly brand or competitor history reports;
- periodic product-feedback research;
- fixed-window academic or market analysis;
- automatic export into a warehouse or spreadsheet;
- notifications when a run completes or fails.

For recurring jobs, prefer fixed `dateFrom` and `dateTo` values when reproducibility matters. Relative windows are useful for rolling reports but naturally change between runs.

### Export and Integration Options

#### Apify dataset API

Use the default dataset API for programmatic reads after a run. The Actor output schema exposes a direct results link, and Apify supports common options for format, field selection, cleaning, pagination, and downloads.

Recommended pipeline pattern:

1. wait for the Actor run to reach a terminal state;
2. read `RUN-SUMMARY`;
3. confirm `stopReason` and `recordsSaved`;
4. fetch dataset items;
5. upsert by `kind:id`;
6. persist the run ID and summary alongside the imported batch.

#### Webhooks

Configure Apify webhooks to notify a downstream service when runs succeed, fail, time out, or are aborted. The receiving workflow should inspect both the platform run status and `RUN-SUMMARY`.

#### Schedules

Schedules are useful for:

- weekly rolling mention research;
- monthly fixed-window exports;
- quarterly category analysis;
- repeatable competitor comparisons;
- periodic archive backfills.

Avoid overlapping scheduled windows unless your downstream system performs identity-based upserts. The Actor deduplicates within one run, while downstream storage must deduplicate across separate runs.

#### Google Sheets and spreadsheets

Spreadsheet exports work well for smaller review datasets. Prefer a focused field set such as:

- `query`
- `id`
- `title`
- `body`
- `author`
- `score`
- `num_comments`
- `subreddit`
- `created_utc`
- `canonical_url`
- `sentiment_label`
- `content_category_label`

Large media objects and nested arrays are better handled in JSON-oriented tools.

#### Warehouses and databases

Suggested modeling:

- primary key: `kind:id`;
- event time: `created_utc`;
- ingestion time: `retrieved_at`;
- partitions: `created_year`, `created_month`;
- community dimension: `subreddit`;
- query attribution: `query`;
- engagement measures: `score`, `num_comments`, `engagement_total`;
- optional NLP dimensions: `sentiment_label`, `content_category_label`.

#### Search and vector systems

For full-text or semantic search, a useful document string is:

```text
title + "\n\n" + body
```

Keep `id`, `canonical_url`, `subreddit`, `created_utc`, score fields, and archive provenance as metadata. Do not treat Actor sentiment or taxonomy output as the only interpretation of the text.

#### Dashboards and BI tools

Useful aggregate views include:

- records by month;
- records by subreddit;
- average score and comments;
- sentiment distribution;
- category distribution;
- high-engagement share;
- top outbound domains;
- query-to-subreddit distribution.

Use `recordsFiltered` and `recordsDuplicate` from run summaries to monitor whether an input is becoming too restrictive or repetitive over time.

### Recommended Production Patterns

#### Reproducible historical batch

- Use exact `dateFrom` and `dateTo`.
- Store the input JSON with the exported dataset.
- Store `RUN-SUMMARY`.
- Use a bounded `maxPosts` or document that the range was intentionally exhausted.
- Record archive limitations with the analysis.

#### Rolling monitoring job

- Use `timeframe=week` or `timeframe=month`.
- Schedule at a predictable UTC time.
- Upsert by `kind:id`.
- Expect overlap between adjacent rolling windows.
- Track `recordsSaved` and stop reasons for operational alerts.

#### High-precision review queue

- Enable `strictTokenFilter`.
- Add moderate score or comment thresholds.
- Keep enrichment enabled.
- Use a smaller limit.
- Review the first dataset rows before expanding the range.

#### Broad discovery corpus

- Leave strict matching disabled.
- Avoid engagement thresholds initially.
- Use several focused phrases.
- Export JSONL.
- Deduplicate across separate runs in downstream storage.
- Apply custom NLP after collection when domain-specific interpretation is important.

### Responsible Use

This Actor processes publicly sourced historical Reddit content. Users are responsible for ensuring their collection and use comply with applicable laws, regulations, organizational policies, Reddit's terms, and relevant data-protection requirements.

Recommended practices:

- collect only the data needed for a legitimate purpose;
- avoid using archived content for harassment, spam, or invasive profiling;
- protect usernames and other personal information appropriately;
- honor deletion, retention, and access requirements that apply to your use case;
- validate important conclusions against source context and archive limitations.

### Troubleshooting

#### The run saved no records

- Confirm that at least one phrase exists in `queries` or `subredditKeywords`, or enter `subredditName` for a complete subreddit listing.
- Try a broader phrase or remove `strictTokenFilter`.
- Lower `minimumScore` or `minimumComments`.
- Expand the date range.
- Remove the subreddit filter to search across available communities.
- Inspect `recordsFound`, `recordsFiltered`, and `stopReason` in `RUN-SUMMARY`.

#### The summary reports `partial`

Check `monthsIncomplete` and `monthSummaries` to see exactly which monthly indexes timed out or were unavailable. The Actor continues through the rest of the requested window, so the dataset remains usable without being presented as complete.

#### Fewer records were saved than requested

The selected archive range may have been exhausted, filters may have removed candidates, or repeated Reddit IDs may have been deduplicated. Compare `recordsFound`, `recordsFiltered`, `recordsDuplicate`, and `recordsSaved`.

#### Some fields are missing

Historical Reddit payloads vary. Optional values are omitted when the source does not provide them or when enrichment is disabled or inconclusive.

#### A saved input contains live-scraper fields

Fields for direct URLs, live ranking, comment scraping, or maximum-coverage crawling are ignored by archive search. The Actor emits a warning listing any recognized legacy fields that do not affect the archive path.

### Frequently Asked Questions

#### Does this Actor scrape Reddit live?

No. It searches stored historical archive indexes. Use a live Reddit scraper when you need current pages, direct URLs, current comments, or Reddit's present ranking behavior.

#### Does it collect comments?

No. The public archive path currently requests Reddit submissions only. `num_comments` is the archived comment count reported on a post, not a collection of comment records.

#### Do I need exact dates?

No. A query can run with `timeframe=all`, and `dateTo` defaults to the current UTC date. Exact dates are recommended for reproducible research and smaller, more predictable jobs.

#### How far back does the archive go?

The Actor's configured search start is June 2005, but actual coverage varies by month and source. The presence or absence of a record should not be interpreted as proof of complete Reddit coverage.

#### Is `maxPosts` applied per query?

No. It is the maximum number of unique records saved across the entire run, including all queries and monthly windows.

#### Why can `recordsFound` exceed `maxPosts`?

The archive can return a page of candidates larger than the remaining save limit. Local filters and deduplication run before final rows are capped and saved.

#### Why is `recordsSaved` smaller than `recordsFound`?

Candidates may be removed because they are NSFW, do not satisfy strict token matching, fall below engagement thresholds, repeat an existing Reddit identity, or arrive after the save limit has been reached.

#### What does strict token matching do?

It tokenizes the originating query and requires every token to appear in the normalized title, body, or canonical URL. It is a local precision filter applied after archive retrieval.

#### Does strict matching support an exact phrase?

No. It requires all tokens, but they can appear in different searchable fields or positions. Exact-phrase matching is not currently a public input mode.

#### Does `minimumComments` download comments?

No. It filters posts using the archived `num_comments` value.

#### Are scores and comment counts current?

No. They reflect the metadata captured in the historical source record and may differ from values visible on Reddit today.

#### Are sentiment fields generated by an external AI API?

No. The Actor uses a deterministic lexicon-and-rules analyzer. This keeps output repeatable and avoids sending post text to a separate AI provider for sentiment.

#### Why is the category missing when content analysis is enabled?

The classifier is conservative. It leaves fields absent when title, body, subreddit, flair, and domain signals do not provide enough evidence for a reliable category.

#### Can the same post appear under multiple queries?

The same post can match multiple queries, but it is saved once per run using the `kind:id` identity. `recordsDuplicate` counts repeated identities that were removed.

#### Can I include NSFW content?

Yes. Set `includeNsfw=true`. Keep it disabled when adult content is unnecessary or unsuitable for the intended downstream system.

#### What happens if I omit `maxPosts`?

The Actor continues until the selected archive range is exhausted or the run stops because of an error, timeout, or platform limit. No arbitrary hidden result cap is added by the Actor.

#### What happens if the date range is reversed?

The Actor saves no normal rows, writes a summary with `stopReason=empty_date_window`, and completes without sending an archive request.

#### What happens if the date itself is invalid?

An impossible date such as `2025-02-31` fails validation during runtime, writes a failure summary, and causes the Actor execution to fail.

#### How should I monitor scheduled runs?

Check the platform run state and read `RUN-SUMMARY`. Alert on unexpected `failed` or `partial` reasons, non-zero `monthsIncomplete`, unusual drops in `recordsSaved`, or large increases in filtered and duplicate counts.

#### Which export format should I use?

- Use JSON or JSONL for complete nested records.
- Use CSV or Excel for smaller human-review datasets with a selected column set.
- Use the dataset API for automated pipelines.

#### Can I use the data for AI training?

That depends on your legal basis, policies, Reddit's applicable terms, data-protection obligations, and the nature of the training use. The Actor provides collection tooling, not permission or legal advice.

#### Why might a known Reddit post be absent?

Possible reasons include incomplete archive coverage, a missing month or shard, query mismatch, subreddit filtering, local filters, deleted or altered historical source data, or the post being outside the selected date range.

#### Is an empty successful run an error?

Not necessarily. A successful run with `recordsSaved=0` means the Actor completed its planned search without delivering a qualifying row. Inspect `recordsFound` and `recordsFiltered` to understand whether the archive returned candidates.

### Support

For help, use the Issues tab or the Actor page on Apify. Include:

- the Apify run ID;
- the exact input with sensitive values removed;
- the expected result and actual result;
- the `RUN-SUMMARY` record;
- a small dataset sample when available.

# Actor input Schema

## `queries` (type: `array`):

Optionally add phrases to search for in archived Reddit submissions. Leave this empty when you want every indexed post from the subreddit selected below.

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

Choose how matching candidates are ordered inside each monthly archive batch. Archive months are still searched newest first so results can be saved progressively.

## `subredditName` (type: `string`):

Enter a subreddit without the `r/` prefix, for example `technology`. With no keywords, the Actor collects every indexed post from that subreddit in the selected date window. With keywords, it returns matching posts from that subreddit.

## `subredditKeywords` (type: `array`):

Optionally add phrases to search within the selected subreddit. Leave this empty to collect every indexed post from that subreddit. If the main keyword field is filled, it takes priority.

## `subredditSort` (type: `string`):

Choose how candidates are ordered when a subreddit is selected. This overrides the keyword sort for subreddit-focused runs and applies inside each monthly archive batch.

## `timeframe` (type: `string`):

Restrict archive results to an inclusive UTC calendar-date window. Use All time to search the available archive range. Exact dates below take priority when provided.

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

Choose the earliest post date to include. Leave this empty to let the actor use the relative time window above or the full available archive range.

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

Choose the latest post date to include. Leave this empty to search through the current day. Date-only values are interpreted as UTC archive days.

## `minimumScore` (type: `integer`):

Only save archived posts with at least this Reddit score. Use 0 to include neutral or positively scored posts, or leave it empty to avoid score filtering.

## `minimumComments` (type: `integer`):

Only save archived posts with at least this many reported comments. Leave it empty to include posts regardless of discussion size.

## `includeNsfw` (type: `boolean`):

Enable this to include archive records marked as NSFW or 18+. Keep it disabled for a safer default dataset.

## `strictSearch` (type: `boolean`):

Enable strict archive search to keep results closely tied to the keywords you entered. On this indexed archive path, this acts as a compatibility alias for full-query token verification.

## `strictTokenFilter` (type: `boolean`):

Require every word from the originating query to occur in the saved post title, body, or canonical URL. Enabling either this option or Strict Archive Search applies the same full-query verification.

## `sentiment_analysis` (type: `boolean`):

Analyze each saved post title and body with the built-in sentiment model. Disable this when you only need source fields and want lighter record processing.

## `content_analysis` (type: `boolean`):

Classify saved posts into deterministic content categories using their title, body, subreddit, flair, and linked domain. Disable this when category fields are not needed.

## `maxPosts` (type: `integer`):

Choose the maximum number of archived submissions to save across all search phrases and monthly archive windows. Results are pushed as each month finishes, so longer runs show dataset progress while the actor continues searching older months.

## `mcpConnectors` (type: `array`):

Choose optional MCP connectors for compatible Apify workflows. Archive records still go to the default dataset and run summaries go to the key-value store. The current actor does not send the full Reddit dataset through MCP.

## Actor input object example

```json
{
  "queries": [
    "red car",
    "how to make a cheesecake",
    "best electric bike"
  ],
  "sort": "relevance",
  "subredditKeywords": [
    "launch feedback",
    "pricing problem"
  ],
  "subredditSort": "relevance",
  "timeframe": "all",
  "includeNsfw": false,
  "strictSearch": false,
  "strictTokenFilter": false,
  "sentiment_analysis": true,
  "content_analysis": true,
  "maxPosts": 100,
  "mcpConnectors": []
}
```

# Actor output Schema

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

No description

## `archiveSummary` (type: `string`):

No description

## `runSummary` (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 = {
    "queries": [
        "red car",
        "how to make a cheesecake",
        "best electric bike"
    ],
    "subredditKeywords": [
        "launch feedback",
        "pricing problem"
    ],
    "maxPosts": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("fatihtahta/reddit-scraper-fast").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 = {
    "queries": [
        "red car",
        "how to make a cheesecake",
        "best electric bike",
    ],
    "subredditKeywords": [
        "launch feedback",
        "pricing problem",
    ],
    "maxPosts": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("fatihtahta/reddit-scraper-fast").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 '{
  "queries": [
    "red car",
    "how to make a cheesecake",
    "best electric bike"
  ],
  "subredditKeywords": [
    "launch feedback",
    "pricing problem"
  ],
  "maxPosts": 100
}' |
apify call fatihtahta/reddit-scraper-fast --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/DX98zGnfE54lmTszL/builds/zxtuog1PjjwXYzcGh/openapi.json
