SocialCrawl

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:

  1. Pass next_cursor back as the EXACT string you received. Don't decode, trim, or re-encode it — these are upstream tokens.
  2. Stop when next_cursor is missing. The field is omitted from the envelope when there are no more pages. Don't check for empty string.

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.

Facebook

EndpointPathParamStyle
List Facebook Ad Library company adsGET /v1/facebook/adlibrary/company/adscursorcursor
Search Facebook Ad LibraryGET /v1/facebook/adlibrary/search/adscursorcursor
List Facebook post commentsGET /v1/facebook/post/commentscursorcursor
List Facebook profile photosGET /v1/facebook/profile/photoscursorcursor
List Facebook page postsGET /v1/facebook/profile/postscursorcursor
List Facebook profile reelsGET /v1/facebook/profile/reelscursorcursor

Google

EndpointPathParamStyle
List Google ads by companyGET /v1/google/company/adscursorcursor

Instagram

EndpointPathParamStyle
List Instagram post commentsGET /v1/instagram/post/commentscursorcursor
List Instagram user postsGET /v1/instagram/profile/postsnext_max_idcursor

LinkedIn

EndpointPathParamStyle
Search LinkedIn adsGET /v1/linkedin/ads/searchpaginationTokencursor
EndpointPathParamStyle
Search Naver BlogGET /v1/naver/blog/searchdisplay + startoffset
Search Naver BookGET /v1/naver/book/searchdisplay + startoffset
Search Naver Cafe articlesGET /v1/naver/cafearticle/searchdisplay + startoffset
Search Naver Academic Documents (전문자료)GET /v1/naver/doc/searchdisplay + startoffset
Search Naver EncyclopediaGET /v1/naver/encyc/searchdisplay + startoffset
Search Naver ImageGET /v1/naver/image/searchdisplay + startoffset
Search Naver KnowledgeiN (지식iN)GET /v1/naver/kin/searchdisplay + startoffset
Search Naver Local (장소 검색)GET /v1/naver/local/searchdisplay + startoffset
Search Naver NewsGET /v1/naver/news/searchdisplay + startoffset
Search Naver ShoppingGET /v1/naver/shop/searchdisplay + startoffset
Search Naver Web (웹문서)GET /v1/naver/webkr/searchdisplay + startoffset

Pinterest

EndpointPathParamStyle
Search Pinterest pinsGET /v1/pinterest/searchcursorcursor

Reddit

EndpointPathParamStyle
List Reddit post commentsGET /v1/reddit/post/commentscursorcursor
Search Reddit postsGET /v1/reddit/searchaftercursor
List Reddit subreddit postsGET /v1/reddit/subredditaftercursor
Search within a subredditGET /v1/reddit/subreddit/searchcursorcursor

TikTok

EndpointPathParamStyle
List TikTok post commentsGET /v1/tiktok/post/commentscursorcursor
List TikTok user videosGET /v1/tiktok/profile/videosmax_cursorcursor
Search TikTok videos by keywordGET /v1/tiktok/searchcursorcursor
Search TikTok by hashtagGET /v1/tiktok/search/hashtagcursorcursor
TikTok top search resultsGET /v1/tiktok/search/topcursorcursor
Search TikTok usersGET /v1/tiktok/search/userscursorcursor
List TikTok videos using a songGET /v1/tiktok/song/videoscursorcursor
List TikTok user followersGET /v1/tiktok/user/followersmin_timecursor
List TikTok user showcase productsGET /v1/tiktok/user/showcasecursorcursor
List TikTok comment repliesGET /v1/tiktok/video/comment/repliescursorcursor

Truth Social

EndpointPathParamStyle
List Truth Social user postsGET /v1/truthsocial/user/postsnext_max_idcursor

YouTube

EndpointPathParamStyle
List YouTube channel shortsGET /v1/youtube/channel/shortscontinuationTokencursor
List YouTube channel videosGET /v1/youtube/channel/videoscontinuationTokencursor
Search YouTube videosGET /v1/youtube/searchcontinuationTokencursor
Search YouTube by hashtagGET /v1/youtube/search/hashtagcontinuationTokencursor
List YouTube video commentsGET /v1/youtube/video/commentscontinuationTokencursor

See also

Pagination | Socialcrawl