Skip to main content

Overview

Many Roblox APIs return paginated results with a cursor for fetching additional pages. RoZod provides helper functions to make pagination simple.

Fetching all pages at once

The fetchApiPages function automatically fetches all pages and returns an array of results:
import { fetchApiPages } from 'rozod';
import { getGroupsGroupidWallPosts } from 'rozod/lib/endpoints/groupsv2';

// Automatically fetches all pages
const allPosts = await fetchApiPages(
  getGroupsGroupidWallPosts, 
  { groupId: 11479637 }
);

console.log(`Found ${allPosts.length} wall posts`);
fetchApiPages continues fetching until there are no more pages or the limit is reached.

Limiting pages

You can limit the maximum number of pages to fetch:
import { fetchApiPages } from 'rozod';
import { getGroupsGroupidWallPosts } from 'rozod/lib/endpoints/groupsv2';

// Fetch at most 5 pages
const posts = await fetchApiPages(
  getGroupsGroupidWallPosts,
  { groupId: 11479637 },
  undefined, // requestOptions
  5          // limit
);

Processing pages incrementally

For large datasets, use fetchApiPagesGenerator to process pages one at a time:
import { fetchApiPagesGenerator } from 'rozod';
import { getGroupsGroupidWallPosts } from 'rozod/lib/endpoints/groupsv2';

// Process pages as they arrive
const pages = fetchApiPagesGenerator(
  getGroupsGroupidWallPosts, 
  { groupId: 11479637 }
);

for await (const page of pages) {
  console.log(`Processing page with ${page.data.length} posts`);
  
  // Process this page's data
  page.data.forEach(post => {
    console.log(`Post by ${post.poster.username}: ${post.body}`);
  });
}
The generator approach is memory-efficient for large datasets since it only keeps one page in memory at a time.

Complete examples

import { fetchApiPages, isAnyErrorResponse } from 'rozod';
import { getGroupsGroupidWallPosts } from 'rozod/lib/endpoints/groupsv2';

async function getAllGroupPosts(groupId: number) {
  const posts = await fetchApiPages(
    getGroupsGroupidWallPosts,
    { groupId }
  );

  if (isAnyErrorResponse(posts)) {
    console.error('Failed to fetch posts:', posts.message);
    return [];
  }

  // Flatten all pages into a single array
  return posts.flatMap(page => page.data);
}

const allPosts = await getAllGroupPosts(11479637);
console.log(`Total posts: ${allPosts.length}`);

Advanced pagination

Custom request options

You can pass request options to pagination functions:
import { fetchApiPages } from 'rozod';
import { getGroupsGroupidWallPosts } from 'rozod/lib/endpoints/groupsv2';

const posts = await fetchApiPages(
  getGroupsGroupidWallPosts,
  { groupId: 11479637 },
  {
    retries: 3,
    retryDelay: 1000,
    headers: {
      'Cookie': '.ROBLOSECURITY=your_cookie'
    }
  }
);

Early termination

With the generator, you can stop fetching at any time:
import { fetchApiPagesGenerator } from 'rozod';
import { getGroupsGroupidWallPosts } from 'rozod/lib/endpoints/groupsv2';

const pages = fetchApiPagesGenerator(
  getGroupsGroupidWallPosts,
  { groupId: 11479637 }
);

let foundTarget = false;

for await (const page of pages) {
  for (const post of page.data) {
    if (post.body.includes('important keyword')) {
      console.log('Found the post we were looking for!');
      foundTarget = true;
      break;
    }
  }
  
  if (foundTarget) break; // Stop fetching more pages
}
Always handle potential errors when using pagination. Network issues or API changes can cause failures mid-pagination.

Pagination vs batch processing

Use pagination when

  • The API returns results with nextPageCursor
  • You need all results from a multi-page response
  • You want to process results as they arrive

Use batch processing when

  • You have a large array of inputs
  • The API has limits on input array size
  • You need to split requests to avoid rate limits
Learn about batch processing →

Understanding cursors

Roblox APIs use cursor-based pagination:
  1. The initial request returns the first page and a nextPageCursor
  2. Pass the cursor in subsequent requests to get the next page
  3. When nextPageCursor is null, there are no more pages
RoZod handles this automatically in fetchApiPages and fetchApiPagesGenerator.
// Manual cursor handling (not recommended)
let cursor = '';

while (true) {
  const page = await fetchApi(
    getGroupsGroupidWallPosts,
    { groupId: 11479637, cursor }
  );
  
  if (isAnyErrorResponse(page)) break;
  
  console.log(page.data);
  
  if (!page.nextPageCursor) break;
  cursor = page.nextPageCursor;
}
We recommend using fetchApiPages or fetchApiPagesGenerator instead of manual cursor handling.

Next steps

Batch processing

Learn how to split large requests into batches

Basic requests

Back to basic request concepts

Build docs developers (and LLMs) love