Pagination
How to iterate every list endpoint with one normalised `next_cursor` — and the per-platform param names you pass back.
Pagination
Every list endpoint (PostList, CommentList, SearchResult) returns the same envelope shape:
{
"data": {
"items": [ /* ... */ ],
"next_cursor": "eyJwYWdlIjoyfQ==",
"total": 1247
}
}You read data.next_cursor and pass it back as a query parameter on the next request. When next_cursor is missing or null, you've reached the end.
The catch: the name of the query parameter you pass it back as is different per platform. TikTok wants max_cursor, Instagram wants cursor or next_max_id, Reddit wants after. We normalise the response field name so your code stays simple, but the input param name still has to match the upstream. The table at the bottom of this page lists the exact param for every endpoint.
There's one exception: Naver is offset-based (start + display), not cursor-based. You increment start yourself.
How to iterate
The general loop, in pseudocode:
let cursor: string | undefined;
while (true) {
const url = new URL("https://api.socialcrawl.dev/v1/tiktok/profile/videos");
url.searchParams.set("handle", "mrbeast");
if (cursor) url.searchParams.set("max_cursor", cursor); // <-- platform-specific param name
const res = await fetch(url, { headers: { "x-api-key": process.env.SOCIALCRAWL_KEY! } });
const json = await res.json();
for (const item of json.data.items) {
// ... handle item
}
if (!json.data.next_cursor) break;
cursor = json.data.next_cursor; // <-- pass back verbatim
}Two rules:
- Pass
next_cursorback as the EXACT string you received. Don't decode, trim, or re-encode it — these are upstream tokens. - Stop when
next_cursoris missing. The field is omitted from the envelope when there are no more pages. Don't check for empty string.
Naver (offset-based)
Naver doesn't return a cursor. Increment start by display each iteration, and stop when items comes back shorter than display or when start + display > 1000 (Naver's hard cap):
const PAGE_SIZE = 100; // Naver `display` — cap 100
let start = 1; // 1-indexed offset — cap 1000
while (start <= 1000) {
const url = new URL("https://api.socialcrawl.dev/v1/naver/search/news");
url.searchParams.set("query", "삼성전자");
url.searchParams.set("display", String(PAGE_SIZE));
url.searchParams.set("start", String(start));
const res = await fetch(url, { headers: { "x-api-key": process.env.SOCIALCRAWL_KEY! } });
const json = await res.json();
for (const item of json.data.items) { /* ... */ }
if (json.data.items.length < PAGE_SIZE) break;
start += PAGE_SIZE;
}What about page size?
For every platform except Naver, upstream decides. You'll typically get 10–30 items per page. There is no limit or page_size query parameter — passing one is silently ignored. If you need fewer items, slice the array client-side; if you need more, iterate more pages.
Stale or malformed cursors
If you pass a cursor that the upstream rejects (expired, hand-edited, copied across endpoints), you'll get a 502 UPSTREAM_ERROR or 400 INVALID_PARAMETER envelope. Credits are refunded on upstream errors — see Credits → When are credits refunded?. Start over with no cursor.
What total means
data.total is included when the upstream returns a result count. It's the upstream's count, not ours, and can be:
- Exact (Reddit, Naver) — the precise number of items in the result set.
- Estimated (Instagram, TikTok search) — an upstream estimate that may not match the number you can actually paginate to.
- Missing — the upstream didn't tell us, so we don't either.
Don't use total to decide when to stop iterating. Use next_cursor for that — it's the only signal that's always correct.
Every paginatable endpoint
42 endpoints paginate today (31 cursor-based, 11 offset-based), grouped by platform.
| Endpoint | Path | Param | Style |
|---|---|---|---|
| List Facebook Ad Library company ads | GET /v1/facebook/adlibrary/company/ads | cursor | cursor |
| Search Facebook Ad Library | GET /v1/facebook/adlibrary/search/ads | cursor | cursor |
| List Facebook post comments | GET /v1/facebook/post/comments | cursor | cursor |
| List Facebook profile photos | GET /v1/facebook/profile/photos | cursor | cursor |
| List Facebook page posts | GET /v1/facebook/profile/posts | cursor | cursor |
| List Facebook profile reels | GET /v1/facebook/profile/reels | cursor | cursor |
| Endpoint | Path | Param | Style |
|---|---|---|---|
| List Google ads by company | GET /v1/google/company/ads | cursor | cursor |
| Endpoint | Path | Param | Style |
|---|---|---|---|
| List Instagram post comments | GET /v1/instagram/post/comments | cursor | cursor |
| List Instagram user posts | GET /v1/instagram/profile/posts | next_max_id | cursor |
| Endpoint | Path | Param | Style |
|---|---|---|---|
| Search LinkedIn ads | GET /v1/linkedin/ads/search | paginationToken | cursor |
Naver
| Endpoint | Path | Param | Style |
|---|---|---|---|
| Search Naver Blog | GET /v1/naver/blog/search | display + start | offset |
| Search Naver Book | GET /v1/naver/book/search | display + start | offset |
| Search Naver Cafe articles | GET /v1/naver/cafearticle/search | display + start | offset |
| Search Naver Academic Documents (전문자료) | GET /v1/naver/doc/search | display + start | offset |
| Search Naver Encyclopedia | GET /v1/naver/encyc/search | display + start | offset |
| Search Naver Image | GET /v1/naver/image/search | display + start | offset |
| Search Naver KnowledgeiN (지식iN) | GET /v1/naver/kin/search | display + start | offset |
| Search Naver Local (장소 검색) | GET /v1/naver/local/search | display + start | offset |
| Search Naver News | GET /v1/naver/news/search | display + start | offset |
| Search Naver Shopping | GET /v1/naver/shop/search | display + start | offset |
| Search Naver Web (웹문서) | GET /v1/naver/webkr/search | display + start | offset |
| Endpoint | Path | Param | Style |
|---|---|---|---|
| Search Pinterest pins | GET /v1/pinterest/search | cursor | cursor |
| Endpoint | Path | Param | Style |
|---|---|---|---|
| List Reddit post comments | GET /v1/reddit/post/comments | cursor | cursor |
| Search Reddit posts | GET /v1/reddit/search | after | cursor |
| List Reddit subreddit posts | GET /v1/reddit/subreddit | after | cursor |
| Search within a subreddit | GET /v1/reddit/subreddit/search | cursor | cursor |
TikTok
| Endpoint | Path | Param | Style |
|---|---|---|---|
| List TikTok post comments | GET /v1/tiktok/post/comments | cursor | cursor |
| List TikTok user videos | GET /v1/tiktok/profile/videos | max_cursor | cursor |
| Search TikTok videos by keyword | GET /v1/tiktok/search | cursor | cursor |
| Search TikTok by hashtag | GET /v1/tiktok/search/hashtag | cursor | cursor |
| TikTok top search results | GET /v1/tiktok/search/top | cursor | cursor |
| Search TikTok users | GET /v1/tiktok/search/users | cursor | cursor |
| List TikTok videos using a song | GET /v1/tiktok/song/videos | cursor | cursor |
| List TikTok user followers | GET /v1/tiktok/user/followers | min_time | cursor |
| List TikTok user showcase products | GET /v1/tiktok/user/showcase | cursor | cursor |
| List TikTok comment replies | GET /v1/tiktok/video/comment/replies | cursor | cursor |
Truth Social
| Endpoint | Path | Param | Style |
|---|---|---|---|
| List Truth Social user posts | GET /v1/truthsocial/user/posts | next_max_id | cursor |
YouTube
| Endpoint | Path | Param | Style |
|---|---|---|---|
| List YouTube channel shorts | GET /v1/youtube/channel/shorts | continuationToken | cursor |
| List YouTube channel videos | GET /v1/youtube/channel/videos | continuationToken | cursor |
| Search YouTube videos | GET /v1/youtube/search | continuationToken | cursor |
| Search YouTube by hashtag | GET /v1/youtube/search/hashtag | continuationToken | cursor |
| List YouTube video comments | GET /v1/youtube/video/comments | continuationToken | cursor |
See also
- Response schema → List endpoints — the envelope shape in one sentence.
- Endpoint pricing — every endpoint and what each call costs.
- Error handling — refund rules for stale-cursor errors.
