How to scrape Reddit
Extract Reddit post title, score, comment count, subreddit, author and posted time as typed JSON. Use old.reddit.com and respect Reddit's API terms.
- Site:
- reddit.com
- Difficulty:
- Medium
- Rendering:
- JavaScript-rendered
- Anti-bot:
- Aggressive per-IP rate limiting that returns HTTP 429 once request volume climbs, Bot-detection interstitials and 'you've been blocked' pages on the modern www.reddit.com app, JavaScript-heavy single-page rendering on the redesign that hides post data behind hydration, Datacenter IP ranges are throttled or served degraded responses faster than residential traffic
What you can extract from Reddit
These are the fields teams most often pull from reddit.com, and why a hand-written selector for each one tends to break over time.
| Field | Type | Why selectors break |
|---|---|---|
| title | string | On old.reddit the title lives in a.title, but the redesign wraps it in hashed, build-generated class names that rotate on every deploy, so a selector keyed to the modern markup silently returns null after the next front-end release. |
| score | number | The upvote count is exposed as a data-score attribute on old.reddit but the visible number on the redesign is shortened to forms like '12.4k', so a selector that grabs the rendered text yields a string that needs parsing rather than the true integer. |
| comment_count | number | Comment totals appear in a data-comments-count attribute on old.reddit yet render as free text such as '342 comments' on the new UI, so any selector targeting the link label captures words and punctuation instead of a clean numeric value. |
| subreddit | string | The subreddit is encoded in a /r/name link and also in a data-subreddit attribute, but on multireddit, search and home feeds the same selector matches several posts at once, so a naive query returns the wrong row's community. |
| author | string | Author sits in a.author on old.reddit, but deleted or suspended accounts replace that node with plain '[deleted]' text and no anchor, so a selector expecting the link element breaks or returns null exactly on the posts you most need to flag. |
| posted_time | string | The timestamp is in a time element's datetime attribute on old.reddit, while the redesign shows only a relative label like '5h' with the absolute time tucked into a title tooltip, so a text selector captures fuzzy relative ages that drift every time the page is fetched. |
The schema-first approach
Instead of maintaining selectors, you hand Extracto a JSON schema describing the shape you want. Here is a schema that works for Reddit:
{
"title": "string",
"score": "number",
"comment_count": "number",
"subreddit": "string",
"author": "string",
"posted_time": "string"
} - 1
Describe the Reddit fields you want
Write a small JSON schema listing the fields to pull from reddit.com (for example title, score, comment_count). No CSS selectors or XPath needed.
- 2
Send the URL and schema to Extracto
POST the Reddit page URL and your schema to the Extracto API. Extracto renders the page in a real browser, handling JavaScript and dynamic content automatically.
- 3
Get schema-validated JSON back
Extracto returns JSON that matches your schema exactly, validated before it leaves the API, so your pipeline never receives broken or partial data.
Common pitfalls when scraping Reddit
- Pointing extraction at www.reddit.com pulls the JavaScript redesign whose hashed class names rotate on every front-end deploy; targeting old.reddit.com gives stable a.title, a.author and data-score markup that survives much longer.
- Scores and comment counts render as abbreviated strings like '12.4k' or '342 comments' on the new UI, so define them as number in your schema and let validation flag the abbreviated cases rather than storing noisy text.
- Deleted or suspended posts and authors render as plain '[deleted]' or '[removed]' with no link node, which is exactly why returning null for a missing field beats a guessed username when you are auditing moderation or removed content.
- Reddit rate-limits hard and returns HTTP 429 once volume climbs, so a one-URL-per-call tool with modest pacing fits its limits far better than a crawler hammering many listing pages in parallel.
- Listing feeds (home, search, multireddits) repeat the same selectors across many posts, so extracting from a single post permalink avoids accidentally pulling a neighboring post's score or subreddit.
Is it legal to scrape Reddit?
Reddit's User Agreement and its Public Content Policy restrict automated access, and the Data API now requires registration with rate limits (roughly 100 queries per minute per authenticated OAuth client as of 2026). Reddit's robots.txt disallows most generic crawlers and points commercial and bulk users toward licensed data access, and the company has publicly tightened terms since 2023 to require pre-approval for commercial use of its content. Scraping public post metadata at modest volume for research or monitoring is technically possible via old.reddit.com, but it remains governed by these terms. Treat Reddit's API as the sanctioned path for anything at scale, keep request volume low, identify your traffic honestly, never collect private or deleted content, and obtain written permission before commercial use. This page is educational and not legal advice; review Reddit's current terms and robots.txt before extracting anything.
Extracto follows robots.txt by default and rate-limits politely. You are responsible for compliance with Reddit's terms and applicable law (GDPR, CCPA) in your use case.