429 after Retry-After seconds, and runs from cron.
The Query API needs the Starter plan or higher and an API key with the Query API permission.
Read Query API.
Files
The script uses the global
fetch of Node.js 18 or newer and has no runtime dependency.
.env.
GRAIN_REQUESTS_PER_MINUTE sets the pace. The limit is 120 requests per minute for the whole
workspace, so 60 leaves room for other clients. Read the pace section below.
The API client
send makes one request. On 429 it waits Retry-After seconds and retries, up to
MAX_RETRIES times. On a network error it waits with exponential backoff. On any other error
status it throws at once, because a retry cannot change a 401, a 403, or a 404.
The script
The script counts the events first, then reads pages of 1,000 with a growingoffset. Between
two requests it waits 60 / GRAIN_REQUESTS_PER_MINUTE seconds. The CSV has one column per
event field and one column per property key that appears in the export.
filterSet to request in main. Read
Filters.
Pace and budget
An export ofN events costs 1 + ceil(N / 1000) requests: one count and one request per page.
The rate limit is 120 requests per minute for the whole workspace, on every plan. There is no
daily limit.
At
120, every other client of the workspace gets 429 while the export runs. Keep the value
at 60 or lower.
Scheduled run
Run the script from cron at a fixed time. The line below exports yesterday every day at 02:00 and appends the log toexport.log.
- Load
.envin the cron environment. Cron does not read your shell profile. Usenode --env-file=.env(Node.js 20.6 or newer) or export the variables in the crontab. - Leave a gap between two scheduled exports of one workspace. Both count against one limit.
- Make sure that a run finishes before the next one starts. An export of 100,000 events takes about 2 minutes at 1 second per page.
Errors
Limits
Read Custom dashboard for a Next.js page that polls the
same endpoints.