Read query cost and throttle status
Every Admin API response reports its cost and the remaining bucket in extensions.cost. Use it to pace requests and handle THROTTLED errors.
- API
- Admin GraphQL API
- Where
- extensions.cost in every response
- Restore rate
- 100 points/s Standard, 200 Advanced, 1,000 Plus, 2,000 Commerce Components
- Replaces (REST)
- The X-Shopify-Shop-Api-Call-Limit header
- API version
- 2026-10
- Last checked
In short
The Admin GraphQL API limits apps by query cost, not request count. Every response has extensions.cost with requestedQueryCost, actualQueryCost and throttleStatus (maximumAvailable, currentlyAvailable, restoreRate). Before the next query, check that currentlyAvailable covers its cost; if not, wait for the bucket to refill at restoreRate points per second. A single query can’t cost more than 1,000 points.
How to use it
- Read extensions.cost from each response; requested cost is reserved before the query runs and the unused part is refunded.
- Before the next request, compare its expected cost with currentlyAvailable and wait if needed (wait-for-budget.js).
- On a THROTTLED error, wait and retry the same request; Shopify recommends backing off for at least one second.
- Send the Shopify-GraphQL-Cost-Debug: 1 header to see how much each field adds to the cost.
Code
products-with-cost.graphqlquery RecentProducts($first: Int!) {
products(first: $first, sortKey: UPDATED_AT, reverse: true) {
nodes {
id
title
variants(first: 5) {
nodes {
id
sku
}
}
}
}
}
products-with-cost.variables.json{
"first": 50
}
products-with-cost.response.json{
"data": {
"products": {
"nodes": [
{
"id": "gid://shopify/Product/1234567890",
"title": "Linen shirt",
"variants": {
"nodes": [
{"id": "gid://shopify/ProductVariant/1111111111", "sku": "LS-S"}
]
}
}
]
}
},
"extensions": {
"cost": {
"requestedQueryCost": 302,
"actualQueryCost": 14,
"throttleStatus": {
"maximumAvailable": 2000.0,
"currentlyAvailable": 1986,
"restoreRate": 100.0
}
}
}
}
throttled.json{
"errors": [
{
"message": "Throttled",
"extensions": {
"code": "THROTTLED",
"documentation": "https://shopify.dev/api/usage/limits#rate-limits"
}
}
],
"extensions": {
"cost": {
"requestedQueryCost": 302,
"actualQueryCost": null,
"throttleStatus": {
"maximumAvailable": 2000.0,
"currentlyAvailable": 120,
"restoreRate": 100.0
}
}
}
}
wait-for-budget.js// Waits until the bucket has room for the next query, using the throttle
// status Shopify returns in extensions.cost of every Admin API response.
const MS_PER_SECOND = 1000;
/** Milliseconds to wait before a query that will request `nextCost` points. */
export function waitBeforeNext(cost, nextCost) {
const {currentlyAvailable, restoreRate} = cost.throttleStatus;
if (currentlyAvailable >= nextCost) return 0;
return Math.ceil(((nextCost - currentlyAvailable) / restoreRate) * MS_PER_SECOND);
}
/** True when the response failed only because the bucket was empty. */
export function isThrottled(body) {
return Array.isArray(body.errors) && body.errors.some((e) => e.extensions?.code === 'THROTTLED');
}
Written by Lintel. MIT license: free to use in your own store and in client work.
Limits and edge cases
- Default costs: scalars and enums 0, objects 1, mutations 10, connections sized by first or last. Shopify can set other costs on some fields.
- Requested cost assumes full pages. Smaller first values and fewer nested connections lower it the most.
- A query above 1,000 requested points fails with MAX_COST_EXCEEDED before it runs. Split it or use a bulk operation.
- Limits apply per app and store: other apps don’t use your bucket.
- Input arrays are capped at 250 items on every Shopify API.
Questions
- What is the Shopify GraphQL rate limit?
- It is cost-based: 100 points per second on Standard plans, 200 on Advanced, 1,000 on Plus and 2,000 on Commerce Components, with a maximum of 1,000 points per query.
- How do I avoid THROTTLED errors?
- Ask only for the fields and page sizes you need, track currentlyAvailable, wait when it’s low, and move large reads and writes to bulk operations.
- Why is requested cost higher than actual cost?
- Requested cost assumes every connection returns a full page. Actual cost counts what came back, and the difference is refunded to your bucket.
Shopify documentation
- Validated against the Admin or Storefront API schema for version 2026-10 on the date shown. Check the version in your request URL.
- IDs and store addresses in the examples are placeholders. Replace them with your own.
- Admin API calls need an access token from your app. Never put an Admin API token in a storefront or theme.
- MIT license. Use the code in your own store or in client work.
Need this built, tested and maintained for your store? See API integrations.
