Reddit Historical Archive Scraper | Enterprise Grade avatar

Reddit Historical Archive Scraper | Enterprise Grade

Under maintenance

Pricing

$11.99/month + usage

Go to Apify Store
Reddit Historical Archive Scraper | Enterprise Grade

Reddit Historical Archive Scraper | Enterprise Grade

Under maintenance

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.

Pricing

$11.99/month + usage

Rating

5.0

(1)

Developer

Fatih Tahta

Fatih Tahta

Maintained by Community

Actor stats

5

Bookmarked

49

Total users

2

Monthly active users

35 days

Issues response

4 days ago

Last modified

Share

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

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:

{
"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:

{
"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.

ParameterTypeDescriptionDefault
queriesstring[]One or more phrases to search for in archived Reddit submissions. When both query fields are populated, this field takes priority.โ€“
sortstringOrder candidates inside each monthly keyword-search batch by relevance, recency, hot engagement, score, or comments.relevance
subredditNamestringSubreddit without the r/ prefix. With no keywords, collects every indexed post from that subreddit in the selected date window.โ€“
subredditKeywordsstring[]Optional query list for narrowing a subreddit search. Leave empty for the complete subreddit listing.โ€“
subredditSortstringCandidate ordering for subreddit-focused runs. Overrides sort when subredditName is present.relevance
timeframestringInclusive 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
dateFromstringEarliest UTC archive date to include, formatted as YYYY-MM-DD. Takes priority over timeframe.โ€“
dateTostringLatest UTC archive date to include, formatted as YYYY-MM-DD.Current UTC date
strictSearchbooleanCompatibility control that enables full-query token verification on the indexed archive path.false
strictTokenFilterbooleanRequire every word from the originating query to appear in the saved post title, body, or canonical URL.false
minimumScoreintegerOnly save posts with at least this archived Reddit score.โ€“
minimumCommentsintegerOnly save posts with at least this reported comment count.โ€“
includeNsfwbooleanInclude posts marked NSFW or 18+.false
sentiment_analysisbooleanAdd deterministic sentiment scores, confidence, and labels.true
content_analysisbooleanAdd deterministic content-category labels and taxonomy paths when evidence is strong enough.true
maxPostsintegerMaximum number of unique records saved across all queries and month windows. Omit it to continue until the selected archive range is exhausted.โ€“
mcpConnectorsstring[]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

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

Subreddit-focused research

{
"subredditName": "technology",
"subredditKeywords": [
"artificial intelligence",
"AI regulation"
],
"timeframe": "year",
"maxPosts": 250
}
{
"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

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

Rolling weekly monitoring

{
"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

{
"queries": [
"remote work"
],
"dateFrom": "2019-01-01",
"dateTo": "2024-12-31",
"minimumScore": 100,
"minimumComments": 50,
"maxPosts": 500
}
{
"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

{
"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

{
"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:

{
"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:

kind + ":" + id

For example:

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:

FieldMeaning
queriesEffective archive search phrases.
subredditNameApplied subreddit filter, or null.
dateFrom / dateToEffective inclusive UTC archive window.
maxPostsRequested save limit, or null when omitted.
recordsFoundRecords returned by the archive before local filters and deduplication.
recordsFilteredRecords removed by NSFW, strict-token, score, or comment-count filters.
recordsDuplicateRepeated Reddit identities removed across archive pages or months.
recordsSavedUnique dataset rows successfully saved.
monthsRequestedNumber of UTC month windows planned.
monthsCheckedNumber of month windows completed or recorded.
monthsIncompleteNumber of requested month windows that timed out or had no available index.
monthSummariesPer-month and per-page search details.
stopReasonWhy collection ended.
brokerMetadataOperational source metadata useful for support.
traceIdBroker 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:

{
"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:

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.

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:

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.

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.