यह लेख वर्तमान में केवल अंग्रेज़ी में उपलब्ध है। अनुवाद जल्द आ रहा है।
Shopify Storefront API: Headless Checkout, Cart, and Customer 2026
Headless Shopify is now the default architecture for any merchant doing more than $5M GMV who wants brand control over the front end. The Storefront API exposes products, collections, the Cart object, and the customer account surface to a web or mobile client without going through Shopify's hosted theme. With API version 2026-01, Cart fully replaced the legacy Checkout object, and the new Customer Account API replaced the password-based customer endpoints. This guide is the production playbook we use when migrating clients to headless Hydrogen, Next.js, or native mobile.
Key Takeaways
- The Storefront API uses a public token (
X-Shopify-Storefront-Access-Token) and a separate cost bucket from the Admin API- The Cart object is the only supported model in 2026 —
checkoutCreateis deprecated and removed- Hand-off to checkout uses
cart.checkoutUrl, which carries identity, discounts, and attributes intact- Customer Account API uses OAuth + PKCE — no more
customerAccessTokenCreatewith password- Storefront rate limit is 60 requests/sec per IP for unauthenticated, 200 req/sec with public token
- Hydrogen, Next.js with
@shopify/hydrogen-react, and SwiftUI/Compose all share the same query schema
Storefront API vs Admin API
Different surface, different auth, different cost bucket.
| Aspect | Storefront API | Admin API |
|---|---|---|
| Audience | End shoppers | Merchant/staff |
| Token | Public Storefront Access Token | Per-shop OAuth/admin token |
| Auth | Token in header, optional Customer Access Token | OAuth + scopes |
| Cost model | Request-based (60-200/sec) | Calculated cost (2,000 bucket) |
| Mutations | Cart, Customer, Metaobject create | Everything |
| PII access | Customer's own data only | Shop-wide |
Never put an Admin API token in client-side code. Storefront tokens are designed to be public and only expose a deliberately limited surface.
The Cart API
A cart is a long-lived object (typically 7 days) that holds line items, attributes, discount codes, buyer identity, and delivery preferences. You create it once and update it on every interaction.
mutation CartCreate {
cartCreate(input: {
lines: [{ merchandiseId: "gid://shopify/ProductVariant/123", quantity: 1 }]
buyerIdentity: { countryCode: US }
}) {
cart {
id
checkoutUrl
cost { totalAmount { amount currencyCode } }
lines(first: 100) { nodes { id quantity merchandise { ... on ProductVariant { id title } } } }
}
userErrors { field message code }
}
}
Subsequent line additions, removals, and quantity changes use cartLinesAdd, cartLinesRemove, cartLinesUpdate. Each returns the full updated cart, so there's no need to re-fetch.
Cart attributes
Attributes are arbitrary key-value pairs you attach to a cart that flow through to the order. Useful for gift messages, delivery instructions, B2B PO numbers, or referral source tracking.
mutation {
cartAttributesUpdate(
cartId: "gid://shopify/Cart/abc"
attributes: [{ key: "gift_message", value: "Happy birthday!" }]
) { cart { id attributes { key value } } userErrors { field message } }
}
Hand-off to checkout
In headless, you do not build the checkout UI. You build everything up to it, then redirect to cart.checkoutUrl. Shopify hosts the checkout (PCI-compliant, fraud-protected, supports Shop Pay, Apple Pay, Google Pay). On checkout completion, the customer redirects back to your site if you configure a post-purchase redirect.
Common mistake: trying to render checkout in an iframe. Shopify blocks this with frame-ancestors CSP. The supported flow is full-page redirect, period.
function CheckoutButton({ cart }) {
return (
<a href={cart.checkoutUrl} className="btn btn-primary">
Checkout — {formatMoney(cart.cost.totalAmount)}
</a>
);
}
Customer accounts in 2026
The customerAccessTokenCreate mutation (password + email) was removed in API version 2025-04. The Customer Account API is its replacement: OAuth 2.0 with PKCE, runs on a separate domain (shopify.com/authentication), and supports passwordless via Shop ID, magic link, and SMS.
// Step 1: Redirect to authorization endpoint
const params = new URLSearchParams({
client_id: process.env.SHOPIFY_CUSTOMER_CLIENT_ID,
scope: 'openid email customer-account-api:full',
response_type: 'code',
redirect_uri: `${process.env.SITE_URL}/auth/callback`,
state: csrfToken,
code_challenge: pkceChallenge,
code_challenge_method: 'S256',
});
window.location.href =
`https://shopify.com/${shopId}/auth/oauth/authorize?${params}`;
// Step 2: Server exchanges code for access token
const tokenRes = await fetch(`https://shopify.com/${shopId}/auth/oauth/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
code,
client_id: process.env.SHOPIFY_CUSTOMER_CLIENT_ID,
redirect_uri: `${process.env.SITE_URL}/auth/callback`,
code_verifier: pkceVerifier,
}),
});
Once you have the access token, you call the Customer Account API directly with Bearer <token>. Endpoints include customer { orders, addresses, paymentMethods } and mutations for profile updates and address book management.
Caching strategy
The Storefront API has aggressive cache hints. Use them:
- Product and collection queries are safely cacheable for 60 seconds at the edge.
- Cart queries must never be cached (per-user state).
- Customer queries must never be cached.
In Next.js App Router, this lines up with the cache directives:
export async function getProduct(handle: string) {
return shopifyFetch({
query: PRODUCT_QUERY,
variables: { handle },
cache: 'force-cache',
next: { revalidate: 60, tags: [`product:${handle}`] },
});
}
Tag-based revalidation lets you invalidate single products via webhook (products/update) instead of busting the entire cache.
Multi-currency and Markets
If the merchant runs Shopify Markets, every Storefront API request must include the buyer's country. Prices, taxes, and even product visibility can vary.
query Product($handle: String!, $country: CountryCode!) @inContext(country: $country) {
productByHandle(handle: $handle) {
title
priceRange { minVariantPrice { amount currencyCode } }
}
}
The @inContext directive is mandatory. Without it, you get the shop's primary market pricing, which can be wrong by 20-40% in regional markets. For more on this, see our Shopify Markets pricing and tax guide.
Performance benchmarks
On a Plus shop with 5,000 products and 30,000 variants, our typical headless site (Next.js 16, RSC, edge runtime) hits these numbers:
| Metric | Value |
|---|---|
| TTFB (cached product page) | 45 ms |
| TTFB (uncached product page) | 320 ms |
| Time to LCP | 0.9 s on 4G |
| Largest Storefront query | 18 KB response |
| Cart-add latency | ~210 ms |
The biggest wins came from edge caching collection queries, server-rendering above-the-fold content, and lazy-loading variant selectors.
Common pitfalls
- Forgetting
buyerIdentity.countryCode: prices wrong outside primary market. - Server-side cart: don't store cart ID in session — use
httpOnlycookies. Cart IDs are stable for 7 days. - Inventory at
carttime: inventory is checked at cart-line-add and again at checkout. A product can sell out between the two; handle thecart.lines[].merchandise.availableForSalefield on every render. - Customer auth on edge runtimes: PKCE requires
crypto.subtle, which is available on edge runtimes — but you must not store the verifier in cookie-only sessions. Use a server-side store keyed bystate.
Frequently Asked Questions
Can I bypass Shopify's checkout entirely?
No. Only Shopify Plus merchants on Headless plans, with manual approval, get access to the Cart Permissions API and even then they hand off to a Shopify-hosted checkout. PCI compliance and fraud protection are bundled with the platform.
How do I migrate from Checkout to Cart?
Replace checkoutCreate with cartCreate, replace checkoutLineItemsAdd with cartLinesAdd, etc. The data shapes are similar but Cart is more capable (delivery groups, buyer identity, attributes). Hydrogen 2024+ ships with Cart helpers that abstract this.
What is the rate limit on Storefront API?
60 requests/sec/IP for anonymous, 200 req/sec for an authenticated public token. Plus shops can request a higher limit. Cost is request-based, not query-cost-based — but very deeply nested queries still time out at the resolver level after ~10 seconds.
Can I use the Storefront API with theme code (Liquid)?
Yes — use ?{shop}.myshopify.com/api/2026-01/graphql.json from a <script> tag with the public token. But you usually don't need to: Liquid renders products natively. Storefront API in themes is mostly for complex interactive widgets like personalized recommendations.
ECOSIRE has built 40+ headless Shopify storefronts on Hydrogen and Next.js, including custom Cart, Customer Account, and B2B portals. Our Shopify headless team handles auth, performance budgets, and Markets integration end-to-end.
लेखक
ECOSIRE TeamTechnical Writing
The ECOSIRE technical writing team covers Odoo ERP, Shopify eCommerce, AI agents, Power BI analytics, GoHighLevel automation, and enterprise software best practices. Our guides help businesses make informed technology decisions.
ECOSIRE
अपने शॉपिफाई स्टोर को स्केल करें
उच्च विकास वाले ईकॉमर्स के लिए कस्टम विकास, अनुकूलन और माइग्रेशन सेवाएं।
संबंधित लेख
Shopify App Bridge 4 Tutorial: Build Embedded Apps in 2026
Build Shopify embedded admin apps with App Bridge 4: session tokens, token exchange, navigation, modals, resource pickers, and Polaris React 13 setup.
Shopify Functions 2026: Discounts, Delivery, Payment Customization
Build Shopify Functions for discounts, delivery rate customization, payment method filtering, and cart validation. Rust + JavaScript examples.
Shopify GraphQL Admin API 2026: Complete Developer Guide
Master the Shopify Admin GraphQL API: queries, mutations, OAuth, calculated query cost, rate limits, bulk operations, and production code examples.