How cursor pagination works

A cursor is an opaque continuation token. Do not decode it, increment it, or treat it as a page number. Send it back exactly as received.

Every TwitterXAPI collection response uses the same pagination object.

Response shape
{
  "items": ["..."],
  "count": 20,
  "pagination": {
    "next_cursor": "DAABCgAB...",
    "has_more": true
  }
}

Request the next page

Add the returned value as the cursor query parameter. URL encode it when your client does not handle query parameters.

cURL
curl --get "https://twitterxapi.com/api/v1/users/marclou/tweets" \
  -H "Authorization: Bearer $TWITTERXAPI_KEY" \
  --data-urlencode "level=moderate" \
  --data-urlencode "cursor=DAABCgAB..."

Paginate in JavaScript

This async generator yields one item at a time. Callers can stop early without changing the page loop.

JavaScript
async function* items(path, apiKey) {
  let cursor;
  do {
    const url = new URL(path, "https://twitterxapi.com/api/");
    url.searchParams.set("level", "moderate");
    if (cursor) url.searchParams.set("cursor", cursor);
    const r = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } });
    if (!r.ok) throw new Error(`HTTP ${r.status}`);
    const page = await r.json();
    yield* page.items;
    cursor = page.pagination.has_more ? page.pagination.next_cursor : null;
  } while (cursor);
}

Stop safely

Stop when has_more is false or next_cursor is empty. Guard against the same cursor appearing twice.

  • Retry temporary 429 and 5xx responses with backoff.
  • Checkpoint the cursor after saving the page.
  • Deduplicate item IDs when paging through a changing live timeline.
  • Do not send a limit parameter. Live routes return one upstream page.

Questions

What is a Twitter API cursor?

It is an opaque token that tells the API where to continue.

When should the loop stop?

Stop when has_more is false or next_cursor is empty.

Can I choose the page size?

No. Live TwitterXAPI collection routes return one upstream page.