About • Features • Installation • Quick Start • Usage • OpenCloud • Credits • Documentation
RoZod makes working with Roblox APIs simple and type-safe in TypeScript. With 695+ classic Roblox web API endpoints and 115+ OpenCloud endpoints (all code-generated from official Roblox documentation), you get comprehensive coverage of virtually every available Roblox API with full type safety.
Perfect for everything from small one-time NodeJS/Bun/Deno scripts to large-scale production applications. RoZod powers RoGold, a browser extension with 800,000+ active users, handling millions of API requests daily across both frontend extensions and backend workflows.
- ✨ Simple Interface - Easy to understand API with minimal boilerplate
- 🔒 Type Safety - Complete TypeScript type safety for requests and responses
- 📚 810+ Total Endpoints - 695+ classic web APIs + 115+ OpenCloud APIs, all code-generated from official docs
- 🚀 Production Ready - Battle-tested in applications serving 800,000+ users
- 🔄 Pagination Helpers - Easy tools for handling paginated responses
- 🔁 Batch Processing - Split large requests automatically to avoid API limits
- 🌐 Universal Runtime Support - Works seamlessly in NodeJS, Bun, Deno, and browsers
- 🔍 Custom Endpoints - Define your own endpoints with full type safety
- 🧩 Smart Error Handling - Choose between safe unions or throw-on-error
npm install rozod
# or
bun add rozod
# or
yarn add rozod
# or
pnpm add rozodimport { fetchApi, isAnyErrorResponse } from 'rozod';
import { getUsersUserid } from 'rozod/endpoints/usersv1';
// Fetch user details with full type safety
const userInfo = await fetchApi(getUsersUserid, { userId: 1 });
if (isAnyErrorResponse(userInfo)) {
return;
}
console.log(userInfo.displayName); // Properly typed!import { fetchApi, isAnyErrorResponse } from 'rozod';
import { getGamesIcons } from 'rozod/endpoints/thumbnailsv1';
const response = await fetchApi(getGamesIcons, { universeIds: [1534453623, 65241] });
if (!isAnyErrorResponse(response)) {
console.log(response.data);
}import { fetchApiPages, isAnyErrorResponse } from 'rozod';
import { getGroupsGroupidWallPosts } from 'rozod/endpoints/groupsv2';
// Automatically fetches all pages
const pages = await fetchApiPages(getGroupsGroupidWallPosts, { groupId: 11479637 });
if (!isAnyErrorResponse(pages)) {
console.log(`Fetched ${pages.length} pages of wall posts`);
}import { fetchApiPagesGenerator, isAnyErrorResponse } from 'rozod';
import { getGroupsGroupidWallPosts } from 'rozod/endpoints/groupsv2';
// Process pages as they arrive
const pages = fetchApiPagesGenerator(getGroupsGroupidWallPosts, { groupId: 11479637 });
for await (const page of pages) {
if (isAnyErrorResponse(page)) break;
console.log(`Processing page with ${page.data.length} posts`);
// Do something with this page
}import { fetchApiSplit } from 'rozod';
import { getGamesIcons } from 'rozod/endpoints/thumbnailsv1';
// Will automatically split into smaller batches of 100 universeIds per request
const data = await fetchApiSplit(
getGamesIcons,
{ universeIds: [1, 2, 3, 4, 5 /* many more IDs */] },
{ universeIds: 100 },
);
console.log(data);By default, requests return either the success type or a simple AnyError. Use the tiny helper to check:
import { fetchApi, isAnyErrorResponse } from 'rozod';
import { getGamesIcons } from 'rozod/endpoints/thumbnailsv1';
const res = await fetchApi(getGamesIcons, { universeIds: [1534453623] });
if (isAnyErrorResponse(res)) {
console.error(res.message);
} else {
console.log(res.data);
}Prefer a straight try/catch? Enable throwing:
try {
const res = await fetchApi(getGamesIcons, { universeIds: [1534453623] }, { throwOnError: true });
console.log(res.data);
} catch (err) {
console.error((err as Error).message);
}Need the raw Response? Use returnRaw: true:
const resp = await fetchApi(getGamesIcons, { universeIds: [1534453623] }, { returnRaw: true });
const json = await resp.json();RoZod supports Roblox's newer OpenCloud APIs with the same easy interface:
import { fetchApi, isAnyErrorResponse } from 'rozod';
import { v2 } from 'rozod/opencloud';
// Get universe details through OpenCloud
const universeInfo = await fetchApi(v2.getCloudV2UniversesUniverseId, {
universe_id: '123456789',
});
if (!isAnyErrorResponse(universeInfo)) {
// Access typed properties
console.log(universeInfo.displayName);
console.log(universeInfo.description);
}import { fetchApi } from 'rozod';
import { getCloudV2UniversesUniverseIdDataStoresDataStoreIdEntries } from 'rozod/opencloud/v2/cloud';
// Get DataStore entries with type safety
const dataStoreEntries = await fetchApi(getCloudV2UniversesUniverseIdDataStoresDataStoreIdEntries, {
universe_id: '123456789',
data_store_id: 'MyStore',
});RoZod handles Roblox authentication automatically with comprehensive security features:
In browsers, authentication works automatically when users are logged into Roblox:
import { fetchApi } from 'rozod';
import { getUsersUserid } from 'rozod/endpoints/usersv1';
// Cookies are sent automatically - no setup required!
const userInfo = await fetchApi(getUsersUserid, { userId: 123456 });For server environments, use configureServer() to set up authentication once:
import { configureServer, fetchApi } from 'rozod';
import { getUsersUserid } from 'rozod/endpoints/usersv1';
// Configure once at startup
configureServer({ cookies: 'your_roblosecurity_cookie_here' });
// All subsequent requests automatically include the cookie
const userInfo = await fetchApi(getUsersUserid, { userId: 123456 });Use multiple Roblox accounts for load distribution or fallback:
import { configureServer } from 'rozod';
// Multiple accounts with round-robin rotation (default)
configureServer({
cookies: [
'account1_roblosecurity_cookie',
'account2_roblosecurity_cookie',
'account3_roblosecurity_cookie',
],
});
// Requests automatically cycle through accounts: 1 → 2 → 3 → 1 → 2 → ...Control how cookies and user agents are selected:
import { configureServer } from 'rozod';
configureServer({
cookies: ['cookie1', 'cookie2', 'cookie3'],
cookieRotation: 'round-robin', // Cycle sequentially (default for multiple)
// cookieRotation: 'random', // Pick randomly per request
// cookieRotation: 'none', // Always use first cookie
userAgents: ['CustomBot/1.0', 'CustomBot/2.0'], // Optional custom UAs
userAgentRotation: 'none', // Consistent per session (default)
// userAgentRotation: 'random',
// userAgentRotation: 'round-robin',
});RoZod includes built-in browser user agents applied automatically in server environments. Customize or disable:
// Use custom user agents
configureServer({
cookies: '...',
userAgents: ['MyBot/1.0', 'MyService/2.0'],
userAgentRotation: 'round-robin',
});
// Disable user agent injection
configureServer({ cookies: '...', userAgents: [] });For OpenCloud endpoints (apis.roblox.com), set your API key once:
import { configureServer, fetchApi } from 'rozod';
import { v2 } from 'rozod/opencloud';
// Configure OpenCloud API key
configureServer({ cloudKey: 'your_opencloud_api_key_here' });
// All OpenCloud requests automatically include x-api-key header
const universeInfo = await fetchApi(v2.getCloudV2UniversesUniverseId, {
universe_id: '123456789',
});You can configure both classic API cookies and OpenCloud keys together:
configureServer({
cookies: ['account1', 'account2'], // For classic *.roblox.com APIs
cloudKey: 'your_opencloud_key', // For apis.roblox.com
});Note: The API key is only applied to OpenCloud endpoints (URLs containing
/cloud/). Cookies are applied to all other Roblox APIs, including undocumented cookie-based APIs onapis.roblox.com.
import { configureServer, clearServerConfig, getServerConfig } from 'rozod';
// Check current configuration
const config = getServerConfig();
console.log(config.cookies, config.cloudKey);
// Clear all server configuration
clearServerConfig();You can still pass headers manually per-request if needed:
const userInfo = await fetchApi(
getUsersUserid,
{ userId: 123456 },
{
headers: {
'Cookie': '.ROBLOSECURITY=your_cookie_here'
}
}
);Note: Manual headers take precedence over
configureServer()defaults.
RoZod automatically handles advanced Roblox security requirements:
- ✅ XCSRF Token Management - Automatic CSRF token retrieval and caching
- ✅ Hardware-Backed Authentication - Full HBA signature support
- ✅ Challenge Handling - Captchas, 2FA, and other authentication challenges
- ✅ Cookie Security - Secure cookie parsing and validation
- ✅ Cookie Rotation - Automatic handling of Roblox's cookie rotation
Roblox is gradually implementing .ROBLOSECURITY cookie rotation for improved security. RoZod automatically detects when cookies are rotated and can notify you to persist the new values:
import { configureServer, refreshCookie, getCookies } from 'rozod';
configureServer({
cookies: process.env.ROBLOX_COOKIE,
onCookieRefresh: async ({ oldCookie, newCookie, poolIndex }) => {
// Roblox rotated the cookie - persist the new value
await db.updateCookie(poolIndex, newCookie);
console.log('Cookie rotated and saved!');
}
});The internal cookie pool updates automatically, so the callback is only needed if you want to persist cookies across restarts.
You can also proactively refresh cookies before they expire:
// Refresh on a schedule or before important operations
const result = await refreshCookie(0);
if (result.success) {
await db.updateCookie(0, result.newCookie);
}
// Utility functions
const allCookies = getCookies(); // Get current cookie values
updateCookie(0, 'new_value'); // Manually update a cookieFor advanced authentication challenges (captchas, 2FA), set up a global challenge handler:
import { setHandleGenericChallenge } from 'rozod';
setHandleGenericChallenge(async (challenge) => {
// Handle captcha, 2FA, or other challenges
// Return the challenge response or undefined to skip
if (challenge.challengeType === 'captcha') {
const solution = await solveCaptcha(challenge.challengeId);
return {
challengeType: challenge.challengeType,
challengeId: challenge.challengeId,
challengeBase64Metadata: solution
};
}
});For Node.js environments requiring custom HBA keys:
import { changeHBAKeys } from 'rozod';
// Provide your own crypto key pair for HBA signatures
const keyPair = await crypto.subtle.generateKey(
{ name: 'ECDSA', namedCurve: 'P-256' },
true,
['sign', 'verify']
);
changeHBAKeys(keyPair);You can define custom endpoints for your specific needs:
import { z } from 'zod';
import { endpoint, fetchApi } from 'rozod';
const myCustomEndpoint = endpoint({
method: 'GET',
path: '/v1/custom/:customId',
baseUrl: 'https://my-api.example.com',
parameters: {
customId: z.string(),
optional: z.string().optional(),
},
response: z.object({
success: z.boolean(),
data: z.array(z.string()),
}),
});
const response = await fetchApi(myCustomEndpoint, { customId: '123' });This repository is maintained by Alrovi ApS, the company behind RoGold.
RoZod is not affiliated with, maintained, authorized, endorsed, or sponsored by Roblox Corporation or any of its affiliates.
