Instagram Graph API Rate Limits Explained
Meta limits how many Graph API calls an app can make. This guide explains the two kinds of limit for Instagram and the headers that show your usage. It also lists the error codes and shows how to wait correctly.
The two kinds of limit
Meta uses two kinds of rate limit for the Graph API:
- Platform rate limits. They count the calls of an app in a rolling window of one hour. Meta gives the formula 200 × the number of users, where the number of users is the daily active users of the app.
- Business Use Case (BUC) rate limits. They count calls for one business object, such as an Instagram account. For Instagram, Meta gives the formula 4800 × the number of impressions in a rolling window of 24 hours. The impressions are the number of times that the account's content entered a person's screen in the last 24 hours.
Meta says that all Instagram Platform endpoints use the BUC limits, except Business Discovery and Hashtag Search. When both kinds of limit can apply to a call, the BUC limit applies.
Because of the BUC formula, a small account with few impressions has a smaller limit than a large account. A script that works on a large account can hit the limit on a small one.
Read your usage in the headers
Meta adds the current usage to the headers of each response. Add -i to a curl command to see them:
curl -i "https://graph.facebook.com/v25.0/$IG_USER_ID?fields=username" \
-H "Authorization: Bearer $TOKEN"x-app-usage shows the platform usage of the app:
x-app-usage: {"call_count":12,"total_cputime":3,"total_time":5}x-business-use-case-usage shows the BUC usage, with one list for each business object id:
x-business-use-case-usage: {"17841400000000000":[{"type":"instagram",
"call_count":40,"total_cputime":8,"total_time":11,
"estimated_time_to_regain_access":0}]}Each value is a percentage of the limit. Meta can throttle the calls when a value reaches 100. estimated_time_to_regain_access is the number of minutes until Meta accepts the calls again. It is 0 while you are not throttled.
The rate-limit error codes
When you pass a limit, the call fails with one of these error codes:
- 4. The app reached its rate limit.
- 17. The user reached the rate limit.
- 32. The user or the app reached the Pages API rate limit.
- 613. The call reached a custom rate limit of one API.
- 80001. Page calls with a Page or System User token reached the BUC limit.
- 80002. Instagram calls reached the BUC limit. This is the usual code for Instagram insights.
Do not mix these errors up with error 190, which means that the token is not valid. A new token does not remove a rate limit, and waiting does not repair a bad token. Meta lists every code on its rate limiting page.
What to do when Meta throttles you
- Stop all calls for that account. Meta says that more calls during a throttle push back the time when calls work again. Do not retry in a loop.
- Wait for the time in the header. Use
estimated_time_to_regain_accesswhen it is more than 0. If it is missing, wait some minutes before the next call, and wait longer after each new failure. - Make fewer calls. Ask only for the fields that you need. Save the results, and do not read the same data again. Use webhooks where Meta sends them, because each webhook replaces a call.
- Spread the calls. A job that reads 200 media in one minute makes a spike. Read them over a longer time.
Watch the headers before you reach 100. If a value passes about 75, slow down your job. Then you do not reach the limit at all.
A Node.js example
The free @storylinkpro/instagram-stories-api client reads the usage headers for you. ig.lastUsage holds the headers of the last response, and error.usage holds the headers of a failed call. The client does not retry, so your code decides when to call again:
import { createClient, InstagramApiError } from "@storylinkpro/instagram-stories-api";
const ig = createClient({
accessToken: process.env.INSTAGRAM_ACCESS_TOKEN,
igUserId: process.env.INSTAGRAM_USER_ID,
});
// The minutes to wait, from the BUC header. 0 when Meta gave no time.
function minutesToWait(usage) {
const lists = Object.values(usage?.businessUseCase ?? {});
return Math.max(0, ...lists.flat().map((u) => u.estimated_time_to_regain_access));
}
try {
const stories = await ig.stories();
console.log(stories.length, "stories, app usage:", ig.lastUsage?.app);
} catch (e) {
if (e instanceof InstagramApiError && e.isRateLimit) {
const wait = minutesToWait(e.usage) || 15;
console.error(`Throttled (code ${e.code}). Try again in ${wait} minutes.`);
process.exitCode = 1;
} else {
throw e;
}
}isRateLimit is true for the codes 4, 17, 32, 613, 80001 and 80002. The script stops at the first throttle and does not call again. Run it again from your scheduler after the wait.
How Storylink does it
Storylink calls the Graph API for many accounts, so it plans for these limits. When Meta returns a rate-limit error, Storylink stops the calls for that app, Page or Instagram account. It waits for the time in the BUC header when Meta sends one. During the wait, Storylink makes no calls for that scope, so the throttle does not get longer.
Storylink also reads the usage headers of each response, and it records a warning before a value reaches 100. With the Storylink API and MCP server, you read saved numbers from Storylink, so your own calls do not count against Meta's limits.
To get the token for the examples above, read Get an Instagram Graph API access token.
Put this into practice with Storylink
Free forever to start. No card required.