Skip to main content
Some apps limit what one user can keep or do: how many photos they store, how many posts they make a day. Each limit is a quota with a key in the form app.name, for example photos.items or shout.posts. The limit you read already includes the user’s plan and anything granted to them on top. Show it as you receive it. Never hard-code a number in your app: the same quota can be 100 for one user and 500 for another.

useQuota

Reads one quota by key.
string
required
The quota’s key, app.name.
string
For a quota that applies to one container rather than the whole account, such as the items in one list, the container’s id.
boolean
default:"true"
Set to false to hold the request.
number | null
The user’s limit. null means no limit.
number | null
How much is used and how much is left. null when the quota is per container and you didn’t pass parentId.
'count' | 'bytes' | 'seconds' | 'credits'
What the numbers count. Format bytes and seconds before showing them.
'stock' | 'period'
stock is what the user holds; deleting something frees room. period is what they use per day, week or month.
string | null
For a period quota, the ISO time it starts over. Daily quotas reset at the user’s own midnight. null for stock quotas.
boolean
true when a paid plan would raise this limit. Use it to decide whether to mention upgrading.
Usage changes as the user creates and deletes things, sometimes from another device. Call useRefreshQuotas() after your app changes what a quota counts, and after a refusal.

useQuotas

useQuotas() returns { plan, quotas }: the user’s plan (free, plus or pro) and every quota your app can read. Use it for a usage screen. Your app sees its own quotas and the pools that all apps share, such as AI credits. It never sees another app’s quotas. An app with no quotas of its own gets only the shared pools.

Handling a refusal

A request over a quota fails, and its body carries a quota object with code: 'QUOTA_EXCEEDED'. quotaExceeded(error) returns that object, or null for any other error. It has the same fields as useQuota, plus the key that refused. Read the refusal with quotaExceeded rather than from the HTTP status or the top-level code. Those differ from app to app; the quota object is the same everywhere. Running out of AI credits answers 402 and is read with aiCreditsExhausted, not quotaExceeded. Without React, use getQuota(key, options) and getQuotas().