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

  1. Read extensions.cost from each response; requested cost is reserved before the query runs and the unused part is refunded.
  2. Before the next request, compare its expected cost with currentlyAvailable and wait if needed (wait-for-budget.js).
  3. On a THROTTLED error, wait and retry the same request; Shopify recommends backing off for at least one second.
  4. Send the Shopify-GraphQL-Cost-Debug: 1 header to see how much each field adds to the cost.

Code

products-with-cost.graphql
query 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.
  • 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.

Have something to build? Let’s talk it through.

Taking a limited number of projects at a time. Every brief is read by an engineer, not a salesperson.

Gencer KarakayaShopify Engineer

An engineer reads your brief, and we reply by email.