# Reddit search API: 25 posts per credit (https://www.socialcrawl.dev/blog/reddit-api-more-per-credit)
> Reddit search API now returns 25 posts per credit on three English queries (was ~7). Korean search billed 1. Comments flattened 647 at 5 credits, depth 9.
On 5 September 2026, three English Reddit search API queries on `GET /v1/reddit/search` each returned **25 posts for 1 credit**. The 2026-09-03 labeled before was about **7** a page. A Korean query (`기계식 키보드`, `sort=new`) that used to return an empty, refunded page now returned **22 posts and billed 1 credit**. One advanced comments call flattened **647** comments, nested to `ext.depth` **9**, and billed **5 credits**.
Official Reddit docs document how to *ask* — [`GET /search`](https://www.reddit.com/dev/api), then loop [`GET /api/morechildren`](https://www.reddit.com/dev/api) — behind OAuth and [**100 queries per minute**](https://support.reddithelp.com/hc/en-us/articles/16160319875092-Reddit-Data-API-Wiki). They do not print `len(items)` or credits per page. This post is not [Devvit](https://developers.reddit.com/docs/capabilities/server/reddit-api), and it is not the official Data API. It is the measured page-size for SocialCrawl's Reddit search, plus the comments and subreddit field-density siblings. For the official reddit api landscape, including that 100 QPM figure, see [Reddit data API](/blog/reddit-data-api-2026). For keys, OAuth, and rate limits, see [Reddit API key limits](/blog/reddit-api-key-limits-alternatives-2026). The **$0.24 / 1,000** figure from June 2023 is historical; [current Data API Terms](https://redditinc.com/policies/data-api-terms) do not restate a per-call price.
**Stack:** Python 3.10+ · `requests` · `GET https://www.socialcrawl.dev/v1/reddit/…` · header `x-api-key`. Print `len(items)` and `credits_used`. Pagination is one billed page per call (`after` on search and subreddit; `cursor` on comments). Free plan: [100 credits, no card](/pricing). Live catalogue: [`/platforms/reddit`](/platforms/reddit). Per-path docs: [`/docs/reddit`](/docs/reddit).
Three English keyword searches on 5 September 2026 each returned **25** posts
for **1** credit (labeled before: about 7). Page size still varies — print
`len(items)`. Comments on this thread flattened **647** at **5** credits,
advanced, unchanged.
## How many posts does a Reddit search API return per credit?
Three English queries each returned **25** posts for **1** credit. Call the search path and print the length of `data.items` plus the envelope `credits_used`. Page size is not a caller `limit`. The platform decides; a thin result set returns a thin page.
Live numbers from the 2026-09-05 harvest (00:45–00:47 UTC, nine production calls, **13 credits**). The before-figure of about 7 a page is labeled from the 2026-09-03 summary and was **not** re-measured today. That is **25 vs about 7**, still 1 credit. With the "about" on that labeled before, 25 / 7 is about 3.57× — not a precise multiple.
| Query | page_len | credits_used | has_more | request_id |
| --- | ---: | ---: | --- | --- |
| `best mechanical keyboard` | **25** | 1 | true | `req-RZGwUkq5KzWaLMTD` |
| `python web scraping` | **25** | 1 | true | `req-3x4e9CmHOyfQbUss` |
| `best programming languages` | **25** | 1 | true | `req-MdeEthMIrO7GUhfE` |
English mean = **25**. All three hits sat on the ceiling this run. That is not a promise. Page size varies between calls — print `len(items)` every time. An optional `trim=true` contrast on the first query also returned **25** (24-id overlap with the full call). That is not a 7-vs-25 proof.
Official [`GET /search`](https://www.reddit.com/dev/api) is filed as a listing with `after` / `before`. No measured yield. [PRAW 8.0.3's `ListingGenerator`](https://praw.readthedocs.io/en/stable/code_overview/other/listinggenerator.html) defaults to 100 content entries and paginates under the hood; the [quick start](https://praw.readthedocs.io/en/stable/getting_started/quick_start.html) never calls `.search()`. We did not extract an official `limit` default or max from the live catalog body, so those numbers are not printed here.
Python `requests` against the first fixture:
```python
BASE = "https://www.socialcrawl.dev"
r = requests.get(
f"{BASE}/v1/reddit/search",
params={"query": "best mechanical keyboard"},
headers={"x-api-key": os.environ["SOCIALCRAWL_API_KEY"]},
timeout=60,
)
r.raise_for_status()
payload = r.json()
items = payload["data"]["items"]
pag = payload.get("pagination") or {}
print(len(items), payload.get("credits_used"), pag.get("has_more"))
# 25, 1, True
```
Curl twin of the same GET:
```bash
curl "https://www.socialcrawl.dev/v1/reddit/search?query=best%20mechanical%20keyboard" \
-H "x-api-key: YOUR_KEY"
```
This harvest recorded `credits_used=1`, `pagination.has_more=true`, and a `next_cursor` on the 25-row page (`request_id` `req-RZGwUkq5KzWaLMTD`). Pass `pagination.next_cursor` / `after` for page 2. This harvest did not fetch page 2.
Head row, `1w4c63y` on r/keyboards, under the unified schema — not a dump:
```json
{
"id": "1w4c63y",
"author": { "username": "freecoinsbabyhe" },
"engagement": { "likes": 6, "comments": 36, "shares": null },
"ext": {
"subreddit": "keyboards",
"title": "What's The Best Mechanical Keyboard In 2026? (Price, Switches)",
"upvote_ratio": 0.875,
"flair": "Discussion",
"content_language": "en"
}
}
```
`engagement.shares` is present on the search row and **null**. It is numeric on post detail. Do not average shares across a search page.
## Do Korean and other non-Latin Reddit searches still return empty?
Not on this reddit keyword search fixture. `query=기계식 키보드` with `sort=new` returned **22** posts, billed **1 credit**, `has_more=false` (the whole result set), `request_id` `req-CCL9dE8QRxgRDwJI`. The labeled before (2026-09-03) was **0** posts, refunded to **0** credits. A results page now bills the usual 1.
19 of 22 titles contain Hangul. The same query, in a different script, used to cost nothing because it returned nothing. We did not call Japanese, Arabic, or Cyrillic queries this run. Empty-page refunds used to hide those misses; a 22-row page at 1 credit is the working proof for Hangul `sort=new` only.
Field coverage on the newest `sort=new` leaves is thinner, which is not an empty page. `content_language` was `ko` on 5 rows, `en` on 7, and **null on 10**. Avatars were present on 15/22; `upvote_ratio` on 15/22. This harvest measured this Korean query only.
```python
r = requests.get(
f"{BASE}/v1/reddit/search",
params={"query": "기계식 키보드", "sort": "new"},
headers={"x-api-key": os.environ["SOCIALCRAWL_API_KEY"]},
timeout=60,
)
r.raise_for_status()
payload = r.json()
print(len(payload["data"]["items"]), payload.get("credits_used"))
# 22, 1
```
```bash
curl "https://www.socialcrawl.dev/v1/reddit/search?query=%EA%B8%B0%EA%B3%84%EC%8B%9D%20%ED%82%A4%EB%B3%B4%EB%93%9C&sort=new" \
-H "x-api-key: YOUR_KEY"
```
## How many comments does a Reddit comments API return for 5 credits?
This harvest flattened **647** comments for **5 credits** on one thread. `GET /v1/reddit/post/comments` is **always 5 credits**, `creditTier: advanced`. The wave did not change the price. One billed GET auto-expands the whole tree, which is why the path sits on advanced and why the meter did not move.
Official shape is two methods: [`GET /comments/`](https://www.reddit.com/dev/api) for the article id, then [`GET /api/morechildren`](https://www.reddit.com/dev/api). [PRAW's `MoreComments.comments()`](https://praw.readthedocs.io/en/stable/code_overview/models/more.html) is one extra round-trip per leftover node. If you want to scrape reddit comments yourself, that walk is the [how to scrape Reddit](/blog/how-to-scrape-reddit-2026) path. This harvest is one billed GET.
Live 2026-09-05, Xbox Cloud Gaming thread (`1w6p54w` on r/technology). Parent listing row reported **1,320** comments:
| | |
| --- | --- |
| Top-level `data.items` | 480 |
| Flattened tree | **647** |
| `ext.depth` max | **9** (histogram 479 / 62 / 44 / 19 / 18 / 12 / 5 / 4 / 3 / 1 at depths 0–9) |
| `data.truncated` | **false** |
| `next_cursor` | **null** |
| `credits_used` | **5** |
| `request_id` | `req-NZaBS71FJdlft25W` |
647 comments / 5 credits = **129.4 comments per credit** on this thread. Search = **25 posts per credit**. 647 is this thread, not a promise for every thread.
Labeled before, other threads, 2026-09-03: 168 on one; 687 / 949 / 1,553 on larger ones; nested to depth 8. A 2026-09-04 check returned 96 comments and billed 5. Live depth on *this* thread is **9**. Those counts are other threads, not a 4× on this one.
Comment bodies now arrive as Reddit's own markdown source. This tree had **8** comments with markdown bold markers and **2** with markdown links. First comment: `p7orkjh` / `@HG21Reaper` / "And that is the end of cloud gaming." / 7,568 likes / depth 0.
Two completeness caveats, then the flatten helper:
1. The bigger comment response is **not a superset** of the old one. On a large thread both responses are partial and they stop in different places. Labeled 2026-09-03: between 77 and 103 comments per thread that the previous response carried are absent from the new one. Do not diff two captures and treat missing ids as a regression.
2. `data.truncated` **can be true with no `next_cursor`**, which means the thread is incomplete and this endpoint cannot fetch the rest. This run was `truncated: false` with no cursor, and still only 647 of the listing's 1,320. Reddit's own count includes removed, deleted, and filtered replies that no listing returns.
```python
THREAD = (
"https://www.reddit.com/r/technology/comments/1w6p54w/"
"microsoft_announces_big_changes_to_xbox_cloud/"
)
def flatten_comments(nodes):
flat = []
for node in nodes or []:
flat.append(node)
flat.extend(flatten_comments(node.get("replies") or []))
return flat
r = requests.get(
f"{BASE}/v1/reddit/post/comments",
params={"url": THREAD},
headers={"x-api-key": os.environ["SOCIALCRAWL_API_KEY"]},
timeout=60,
)
r.raise_for_status()
payload = r.json()
flat = flatten_comments(payload["data"]["items"])
depths = [((c.get("ext") or {}).get("depth") or 0) for c in flat]
print(len(flat), payload.get("credits_used"), max(depths, default=0))
# 647, 5, 9
```
```bash
curl "https://www.socialcrawl.dev/v1/reddit/post/comments?url=https://www.reddit.com/r/technology/comments/1w6p54w/microsoft_announces_big_changes_to_xbox_cloud/" \
-H "x-api-key: YOUR_KEY"
```
Expect `647, 5` on this fixture. Other threads return other trees.
## What extra fields do Reddit search and subreddit rows now carry?
Row density did not move on subreddit listings. Field density did, on both the search path and the subreddit path. The reddit post api follow-up now reports shares as share counts, not crossposts. Counts below are non-null and non-empty. Link posts have no body, so `ext.selftext` is legitimately null on those rows.
| Call | n | selftext | avatar | media_urls | upvote_ratio | flair | content_language |
| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: |
| search `best mechanical keyboard` | 25 | 23 | 25 | 7 | 25 | 23 | 25 |
| search `python web scraping` | 25 | 25 | 25 | 1 | 25 | 11 | 25 |
| search `best programming languages` | 25 | 21 | 25 | 0 | 25 | 11 | 25 |
| search `기계식 키보드` `sort=new` | 22 | 14 | 15 | 8 | 15 | 14 | 12 |
| subreddit `technology` | 19 | 0 | 18 | 19 | 19 | 19 | 18 |
| subreddit `MechanicalKeyboards` | 24 | 1 | 22 | 24 | 24 | 24 | 19 |
On **search**, `content.media_urls` is an **array** (one mechanical-keyboard row had 14 image URLs). On **subreddit listings**, it is a **string**: the linked article on r/technology, a gallery or image URL on r/MechanicalKeyboards. Not every search row has images. Subreddit media is not always an array.
`include_body=true` still works and is **rarely needed** now, because bodies arrive on the rows themselves. When there is nothing extra to fetch, those extra credits refund in full. [`/docs/reddit`](/docs/reddit) still says feed and search leave the body out; that line is stale. The harvest is current.
Post detail on the same `1w4c63y` keyboard URL (`GET /v1/reddit/post`, `request_id` `req-Vh5FZG0Gdom8eiv7`): **1 credit**, `engagement.shares = 14` (numeric). Same field, different metric — **shares, not crossposts**. On every search row this run, `engagement.shares` was **null** (opportunistic; do not average). `ext.selftext` was 535 characters, likes 6, comments 36, upvote ratio 0.875, flair Discussion, content language `en`.
A labeled 2026-09-03 reliability note, not re-measured this run: peak post-detail failure was 12.64% and is now near zero.
### Why didn't subreddit listings get more rows?
They didn't. r/technology returned **19** rows (`request_id` `req-H65Zh8fV5urAVoLt`). r/MechanicalKeyboards returned **24** (`request_id` `req-t3g7LMCltAcNLgZ1`). Both still **1 credit**, both `has_more=true`. Both sit in the same **15–25** band as before.
Rows were **not** widened, on purpose. Fields are added to the rows you already get; rows are not. Those are **19 and 24**, not a new "up to 25" density claim. A wider page would mix promoted posts into the organic ranking with no field to separate them.
```python
r = requests.get(
f"{BASE}/v1/reddit/subreddit",
params={"subreddit": "technology"},
headers={"x-api-key": os.environ["SOCIALCRAWL_API_KEY"]},
timeout=30,
)
r.raise_for_status()
payload = r.json()
print(len(payload["data"]["items"]), payload.get("credits_used"))
# 19, 1
```
```bash
curl "https://www.socialcrawl.dev/v1/reddit/subreddit?subreddit=technology" \
-H "x-api-key: YOUR_KEY"
```
## How did we measure this — and can you reproduce it from Python?
The reddit api python path for this harvest is `requests`, one key, one billed page. [PRAW](https://praw.readthedocs.io/en/stable/getting_started/quick_start.html) still needs `client_id` / `client_secret` / `user_agent` even for public reads.
| | |
| --- | --- |
| Metric | Page length (or flattened comment count) per billed call |
| Formula (lists) | `page_len = Array.isArray(data.items) ? data.items.length : 0` |
| Formula (comments) | Walk `data.items` and every nested `replies[]`. Count each comment node once. Depth is `comment.ext.depth`. |
| Credits | Envelope `credits_used` (cache hits and refunds are 0; none of those this run) |
| Sample | 3 English search queries; 1 Korean search (`sort=new`); 2 subreddit listings; 1 post URL from a search row; 1 large comment thread from the r/technology listing; optional `trim=true` contrast |
| Date pulled | **2026-09-05** (00:45–00:47 UTC) |
| Endpoints | `/v1/reddit/search` (1 cr), `/v1/reddit/subreddit` (1 cr), `/v1/reddit/post` (1 cr), `/v1/reddit/post/comments` (5 cr, advanced). Not called: omni-search, transcript, ads. |
| This-run spend | **13 credits** (`credits_used` sum). Starting balance 140,193 → ending 140,021; the 172 delta is concurrent measurement on the same key, so this harvest is **13**, not 172. |
Anyone with a SocialCrawl API key can rerun `GET https://www.socialcrawl.dev/v1/reddit/search?query=best%20mechanical%20keyboard` with `x-api-key`, then `print(len(data["items"]), credits_used)` — expect a page around the mid-20s at 1 credit, **not a fixed 25**. Same call with `기계식 키보드` plus `sort=new` should return rows and bill 1. Flatten helper and the Korean GET are in the sections above.
Same density-wave family as [TikTok API documentation: 150 followers per credit](/blog/tiktok-api-more-per-credit).
## What do short pages, truncated threads, and refunds actually mean?
- **Page size varies.** Three English searches hit 25; Korean hit 22. Print `len(items)` in every sample.
- **Comments are not a superset of the old tree** (2026-09-03). Do not diff two captures and treat missing ids as a regression.
- **`data.truncated` can be true with no `next_cursor`.** This run: `truncated: false`, no cursor, still 647 of 1,320.
- **Korean search now bills 1 when it returns rows.** Empty pages used to refund to 0. Newest `sort=new` rows may lack avatar / upvote ratio / content language.
- **Subreddit listings were not widened.** Promoted-post mixing. Live: 19 and 24.
- **`engagement.shares` on search rows is opportunistic and was null on every search row this run.** Numeric on post detail (14). Do not average.
- **`trim=true` did not shorten the page this run.** Not a 7-vs-25 proof.
- **Comments cost 5 credits, advanced, unchanged.** Not 1.
No 4xx/5xx, no refunds, no cache hits this run. Cache hits bill 0; empty pages refund; bad params return 400 and are unbilled (product contract — not observed this harvest). Per-key limits: 600 requests/minute, 50 concurrent ([pricing](/pricing)).
## Where to go after the first 25-row search page
- Reddit endpoint catalogue: [`/docs/reddit`](/docs/reddit)
- Live platform page: [`/platforms/reddit`](/platforms/reddit)
- Official-API landscape: [Reddit data API](/blog/reddit-data-api-2026)
- DIY scrape path, including a reddit scraper api walkthrough: [how to scrape Reddit](/blog/how-to-scrape-reddit-2026)
- Vendor comparison: [best Reddit data APIs](/blog/best-reddit-data-apis-2026)
- Key / limits: [Reddit API key limits](/blog/reddit-api-key-limits-alternatives-2026)
- Sibling density post: [TikTok: 150 followers per credit](/blog/tiktok-api-more-per-credit)
Reproduce with four GETs: English search `best mechanical keyboard`, Korean `기계식 키보드` `sort=new`, subreddit `technology`, comments on the Xbox Cloud Gaming URL. Try the same GET in the visual explorer before writing a single line.
## Frequently asked questions
### How many posts does a Reddit search API return per credit?
Live **25** on three English queries (`best mechanical keyboard`, `python web scraping`, `best programming languages`), 1 credit each, 2026-09-05. Page size varies — read `len(items)`, do not assume 25. Korean `기계식 키보드` `sort=new` returned **22** at 1 credit.
### Did Reddit search page size change?
Yes. Labeled before (2026-09-03) was about **7** a page. Live **25** on three English queries, still **1 credit**. Harvest date 2026-09-05. Print `len(items)`.
### How many comments does 5 credits return now?
Live **647** flattened (`ext.depth` max **9**) on the r/technology Xbox Cloud Gaming thread, **5 credits**, advanced, unchanged. Listing count was 1,320; `truncated: false`. Never 1 credit. 647 is this thread, not a promise for every thread.
### Do Korean Reddit searches still come back empty?
No on this fixture. `기계식 키보드` `sort=new` returned **22** posts and billed **1** (2026-09-05). Labeled before: empty page, refunded to 0. 19/22 titles contain Hangul. Newest rows may lack `content_language` (null on 10/22).
### Did subreddit listings get more rows too?
No. r/technology **19**, r/MechanicalKeyboards **24**, still 1 credit — same 15–25 band. Fields added (avatar, media, upvote ratio, flair, content language). A wider page would mix promoted posts into the organic ranking with no field to separate them.
### Is `include_body` still required on search?
Rarely. Search and subreddit rows now carry `ext.selftext` when the post has a body (23/25 on the mechanical-keyboard page). `include_body=true` still works; unused extra credits refund in full.
### Why is a bigger comment page not a superset of the old one?
On a large thread both responses are partial and stop in different places. Labeled 2026-09-03: 77–103 comments per thread from the previous response are absent from the new one. `data.truncated` can be true with no `next_cursor`, meaning this endpoint cannot fetch the rest. This run's thread was `truncated: false` and still returned 647 of 1,320.