Skip to main content
Follow these and your integration will be fast, cheap, and resilient — and you’ll almost never see a 429.

Cache everything

The single biggest win. Responses are served from Cloudflare’s edge and carry Cache-Control + ETag. You should layer your own cache on top.

Respect Cache-Control

Trending changes slowly (5 min), detail pages medium (1 min), lists fast (30 s). Don’t re-fetch inside those windows.

Use ETags

Store the ETag and send If-None-Match. A 304 is free — it doesn’t count against your rate limit.

Sync, don’t re-scrape

If you maintain a local copy of the catalogue, never re-page through everything on a schedule. Pull only what changed:
1

Do one full backfill

Page through GET /v1/scripts with sortBy=updatedAt&order=asc using cursor, storing each script and the max updatedAt you see.
2

Then sync deltas

On a timer, call GET /v1/scripts?updatedSince=<lastSeen>&sortBy=updatedAt&order=asc and upsert the results. Advance lastSeen to the new max updatedAt.
3

Resolve specifics in bulk

Need to refresh a known set (e.g. the scripts a user saved)? Use POST /v1/scripts/batch instead of one request per script.

Execute with loadstring

Every script returns a loadstring URL — a stable, separately-cached execution endpoint at script.roscripts.io. Use it directly rather than fetching raw source and reconstructing the loader:
Only call loadstring on scripts the user explicitly chose to run, and surface the script’s key and patched flags first. Never auto-execute search results.

Filter server-side

Push filters into the query instead of fetching broadly and filtering on the client — it’s faster, cheaper, and paginates correctly:
Combine mode, key, universal, verified, patched, placeId, game, tag, ui, owner, minViews, and hasThumbnail freely. See the list endpoint.

Trim payloads with fields

Only need a few fields for a list view? Ask for them:
id is always included so you can correlate results.

Show quality signals

The catalogue carries trust signals — surface them so users make good choices:

Fail gracefully

Branch on error codes

Switch on the stable error.code, not the human message. See Errors.

Back off on 429/503

Honour Retry-After. Retry a handful of times with delay, then surface a friendly message.

Set a descriptive User-Agent

Identify your app (e.g. MyHub/2.1 (+https://myhub.example)). It helps us help you if something looks off, and keeps you clear of generic-bot heuristics.

Don’t

The catalogue isn’t real-time. Polling trending every second just burns your budget and serves you cached data anyway. Poll on the order of minutes.
The /raw endpoint is rate-limited harder and is for fetching the occasional script a user opened — not for mirroring source en masse.
Keys belong on a server. If you must call from a client, do it anonymously or proxy through your backend.
We add fields over time. Parse defensively, ignore unknown fields, and never index by position.