← Shopify App BuilderCONTENT HISTORYWHAT CHANGED · RULE-BASED ANALYSIS
Update to Shopify App Builder
Snapshot Sep 30, 2026 · 23:13 UTC · version 1.4.1
Collection source: not recorded for this historical snapshot.
First saved snapshot
No earlier snapshot is available to establish a change.
Compare saved observations
Download comparison JSONFull technical diff · 0 changed fields
Full snapshot data
{
"description": "Build customer-facing storefront applications with Shopify Storefront API. Access product catalogs, collections, checkout flows, cart management, and customer accounts using public/private tokens. Includes GraphQL queries, Market directives, Customer Account API, and TypeScript examples. Triggers include: 'storefront api', 'customer-facing shopify', 'shopping cart api', 'product catalog query', 'checkout flow', 'customer account api', 'market directive', 'storefront token'.",
"included_files": [],
"name": "storefront-api",
"skill_md_contents": "---\nname: storefront-api\ndescription: \"Build customer-facing storefront applications with Shopify Storefront API. Access product catalogs, collections, checkout flows, cart management, and customer accounts using public/private tokens. Includes GraphQL queries, Market directives, Customer Account API, and TypeScript examples. Triggers include: 'storefront api', 'customer-facing shopify', 'shopping cart api', 'product catalog query', 'checkout flow', 'customer account api', 'market directive', 'storefront token'.\"\n---\n\n## When to Use Storefront API\n\nUse **Storefront API** for customer-facing applications:\n- Building custom storefronts (headless commerce)\n- Shopping cart and checkout flows\n- Product browsing and search\n- Customer account management (orders, addresses)\n- Subscription management\n- Market-specific pricing and inventory (with Market directives)\n- Cart line operations (add, remove, update)\n- Customer authentication and profiles\n\n**DO NOT use for:** store management, admin operations, or internal tools (use Admin API instead).\n\n---\n\n## Token Types & Scopes\n\n### Public Access Tokens\n**Use for:** Frontend applications, public data access\n\n```javascript\nconst publicToken = 'Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; // Public token\nconst shopDomain = 'mystore.myshopify.com';\nconst endpoint = `https://${shopDomain}/api/2026-01/graphql.json`;\n\nconst headers = {\n 'Content-Type': 'application/json',\n 'X-Shopify-Storefront-Access-Token': publicToken,\n};\n```\n\n**Scopes enabled with public token:**\n- Read products\n- Read product collections\n- Read shop information\n- Read customer information (requires customer login)\n- Create shopping carts\n- Manage shopping carts\n- Access checkout URLs\n\n### Private Access Tokens (Storefront)\n**Use for:** Backend/server-side access with elevated permissions\n\n```javascript\nconst privateToken = process.env.SHOPIFY_STOREFRONT_PRIVATE_TOKEN;\n\nconst headers = {\n 'Content-Type': 'application/json',\n 'X-Shopify-Storefront-Access-Token': privateToken,\n};\n```\n\n**Additional scopes with private token:**\n- Full customer account access\n- All storefront operations\n- No rate limiting (unlike public token: 2 requests/second per IP)\n\n---\n\n## Headers & Configuration\n\n**Standard Storefront Headers:**\n```javascript\nconst headers = {\n 'Content-Type': 'application/json',\n 'X-Shopify-Storefront-Access-Token': accessToken,\n};\n```\n\n**TypeScript Headers Interface:**\n```typescript\ninterface StorefrontHeaders {\n 'Content-Type': 'application/json';\n 'X-Shopify-Storefront-Access-Token': string;\n 'Accept-Language'?: string; // For locale-specific data\n}\n```\n\n**Add Market/Localization (Market Directive):**\n```javascript\nconst headers = {\n 'Content-Type': 'application/json',\n 'X-Shopify-Storefront-Access-Token': accessToken,\n 'Accept-Language': 'en-US', // for Market resolution\n};\n```\n\n---\n\n## Product Queries\n\n### Get Product by Handle\n\n```graphql\nquery GetProduct($handle: String!) {\n product(handle: $handle) {\n id\n title\n description\n handle\n vendor\n productType\n images(first: 10) {\n edges {\n node {\n url\n altText\n }\n }\n }\n priceRange {\n minVariantPrice {\n amount\n currencyCode\n }\n maxVariantPrice {\n amount\n currencyCode\n }\n }\n variants(first: 100) {\n edges {\n node {\n id\n title\n sku\n price {\n amount\n currencyCode\n }\n availableForSale\n quantityAvailable\n compareAtPrice {\n amount\n currencyCode\n }\n selectedOptions {\n name\n value\n }\n }\n }\n }\n collections(first: 5) {\n edges {\n node {\n title\n handle\n }\n }\n }\n }\n}\n```\n\n**Variables:**\n```json\n{\n \"handle\": \"wireless-headphones\"\n}\n```\n\n### List Products (Paginated)\n\n```graphql\nquery ListProducts($first: Int!, $after: String, $query: String) {\n products(first: $first, after: $after, query: $query) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n node {\n id\n title\n handle\n priceRange {\n minVariantPrice {\n amount\n currencyCode\n }\n }\n images(first: 1) {\n edges {\n node {\n url\n }\n }\n }\n }\n }\n }\n}\n```\n\n### Search Products\n\n```graphql\nquery SearchProducts($query: String!, $first: Int) {\n products(first: $first, query: $query) {\n edges {\n node {\n id\n title\n handle\n description\n }\n }\n }\n}\n```\n\n---\n\n## Collection Queries\n\n### Get Collection Products\n\n```graphql\nquery GetCollection($handle: String!, $first: Int) {\n collection(handle: $handle) {\n id\n title\n description\n image {\n url\n altText\n }\n products(first: $first) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n node {\n id\n title\n handle\n priceRange {\n minVariantPrice {\n amount\n currencyCode\n }\n }\n }\n }\n }\n }\n}\n```\n\n### List Collections\n\n```graphql\nquery ListCollections($first: Int, $after: String) {\n collections(first: $first, after: $after) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n node {\n id\n title\n handle\n image {\n url\n }\n }\n }\n }\n}\n```\n\n---\n\n## Cart & Checkout Workflow\n\n### Create Cart\n\n```graphql\nmutation CreateCart($input: CartInput!) {\n cartCreate(input: $input) {\n cart {\n id\n checkoutUrl\n lines(first: 10) {\n edges {\n node {\n id\n quantity\n merchandise {\n ... on ProductVariant {\n id\n title\n price {\n amount\n currencyCode\n }\n }\n }\n }\n }\n }\n cost {\n subtotalAmount {\n amount\n currencyCode\n }\n totalAmount {\n amount\n currencyCode\n }\n }\n }\n userErrors {\n field\n message\n }\n }\n}\n```\n\n### Add to Cart\n\n```graphql\nmutation AddToCart($cartId: ID!, $lines: [CartLineInput!]!) {\n cartLinesAdd(cartId: $cartId, lines: $lines) {\n cart {\n id\n lines(first: 10) {\n edges {\n node {\n id\n quantity\n merchandise {\n ... on ProductVariant {\n id\n title\n price {\n amount\n currencyCode\n }\n }\n }\n }\n }\n }\n }\n userErrors {\n field\n message\n }\n }\n}\n```\n\n**Variables:**\n```json\n{\n \"cartId\": \"gid://shopify/Cart/abc123\",\n \"lines\": [\n {\n \"merchandiseId\": \"gid://shopify/ProductVariant/123456\",\n \"quantity\": 2\n }\n ]\n}\n```\n\n### Update Cart Line\n\n```graphql\nmutation UpdateCartLine($cartId: ID!, $lines: [CartLineUpdateInput!]!) {\n cartLinesUpdate(cartId: $cartId, lines: $lines) {\n cart {\n id\n }\n userErrors {\n field\n message\n }\n }\n}\n```\n\n### Remove from Cart\n\n```graphql\nmutation RemoveFromCart($cartId: ID!, $lineIds: [ID!]!) {\n cartLinesRemove(cartId: $cartId, lineIds: $lineIds) {\n cart {\n id\n }\n userErrors {\n field\n message\n }\n }\n}\n```\n\n### Get Checkout URL\n\n```graphql\nquery GetCart($cartId: ID!) {\n cart(id: $cartId) {\n checkoutUrl\n }\n}\n```\n\n---\n\n## Customer Account API\n\n### Get Current Customer\n\n```graphql\nquery GetCurrentCustomer {\n customer {\n id\n email\n firstName\n lastName\n phone\n createdAt\n updatedAt\n addresses(first: 10) {\n edges {\n node {\n id\n firstName\n lastName\n address1\n address2\n city\n province\n country\n zip\n isDefaultBillingAddress\n isDefaultShippingAddress\n }\n }\n }\n orders(first: 10) {\n edges {\n node {\n id\n orderNumber\n processedAt\n totalPrice {\n amount\n currencyCode\n }\n financialStatus\n fulfillmentStatus\n lineItems(first: 10) {\n edges {\n node {\n title\n quantity\n price {\n amount\n currencyCode\n }\n }\n }\n }\n }\n }\n }\n }\n}\n```\n\n### Update Customer\n\n```graphql\nmutation UpdateCustomer($customer: CustomerInput!) {\n customerUpdate(customer: $customer) {\n customer {\n id\n email\n firstName\n lastName\n }\n userErrors {\n field\n message\n }\n }\n}\n```\n\n### Create Address\n\n```graphql\nmutation CreateAddress($address: MailingAddressInput!) {\n customerAddressCreate(address: $address) {\n customerAddress {\n id\n address1\n city\n country\n province\n zip\n }\n userErrors {\n field\n message\n }\n }\n}\n```\n\n---\n\n## Market Directives (Multi-Region)\n\nMarkets enable locale-specific product data, pricing, and availability.\n\n### Query with Market Context\n\n```graphql\nquery GetProductByMarket($handle: String!, $country: CountryCode!, $language: LanguageCode) @inContext(country: $country, language: $language) {\n product(handle: $handle) {\n id\n title\n priceRange {\n minVariantPrice {\n amount\n currencyCode\n }\n }\n variants(first: 10) {\n edges {\n node {\n id\n availableForSale\n quantityAvailable\n }\n }\n }\n }\n}\n```\n\n**Variables (for Canadian French market):**\n```json\n{\n \"handle\": \"wireless-headphones\",\n \"country\": \"CA\",\n \"language\": \"FR\"\n}\n```\n\n### Supported Markets\n\n```typescript\nenum CountryCode {\n US = \"US\",\n CA = \"CA\",\n GB = \"GB\",\n AU = \"AU\",\n JP = \"JP\",\n DE = \"DE\",\n FR = \"FR\",\n IT = \"IT\",\n // ... and 150+ more\n}\n\nenum LanguageCode {\n EN = \"EN\",\n FR = \"FR\",\n DE = \"DE\",\n IT = \"IT\",\n JA = \"JA\",\n ES = \"ES\",\n // ... and 20+ more\n}\n```\n\n---\n\n## TypeScript Client Example\n\n```typescript\ninterface StorefrontConfig {\n shop: string;\n token: string;\n apiVersion: string;\n}\n\ninterface Product {\n id: string;\n title: string;\n handle: string;\n description: string;\n priceRange: {\n minVariantPrice: MoneyV2;\n maxVariantPrice: MoneyV2;\n };\n variants: ProductVariant[];\n}\n\ninterface ProductVariant {\n id: string;\n title: string;\n sku: string;\n price: MoneyV2;\n availableForSale: boolean;\n quantityAvailable: number;\n}\n\ninterface MoneyV2 {\n amount: string;\n currencyCode: string;\n}\n\nclass StorefrontClient {\n private endpoint: string;\n private headers: Record<string, string>;\n\n constructor(config: StorefrontConfig) {\n this.endpoint = `https://${config.shop}/api/${config.apiVersion}/graphql.json`;\n this.headers = {\n 'Content-Type': 'application/json',\n 'X-Shopify-Storefront-Access-Token': config.token,\n };\n }\n\n async query<T>(query: string, variables?: Record<string, any>): Promise<T> {\n const response = await fetch(this.endpoint, {\n method: 'POST',\n headers: this.headers,\n body: JSON.stringify({ query, variables }),\n });\n\n const data = await response.json();\n\n if (data.errors) {\n throw new Error(`GraphQL error: ${data.errors[0].message}`);\n }\n\n return data.data;\n }\n\n async getProduct(handle: string): Promise<Product> {\n const query = `\n query GetProduct($handle: String!) {\n product(handle: $handle) {\n id\n title\n handle\n description\n priceRange {\n minVariantPrice {\n amount\n currencyCode\n }\n maxVariantPrice {\n amount\n currencyCode\n }\n }\n variants(first: 100) {\n edges {\n node {\n id\n title\n sku\n price {\n amount\n currencyCode\n }\n availableForSale\n }\n }\n }\n }\n }\n `;\n\n const result = await this.query(query, { handle });\n return result.product;\n }\n\n async createCart(variantId: string, quantity: number = 1) {\n const mutation = `\n mutation CreateCart($input: CartInput!) {\n cartCreate(input: $input) {\n cart {\n id\n checkoutUrl\n lines(first: 10) {\n edges {\n node {\n id\n quantity\n }\n }\n }\n }\n }\n }\n `;\n\n const input = {\n lines: [\n {\n merchandiseId: variantId,\n quantity,\n },\n ],\n };\n\n return this.query(mutation, { input });\n }\n}\n\n// Usage\nconst client = new StorefrontClient({\n shop: 'mystore.myshopify.com',\n token: 'public_token_here',\n apiVersion: '2026-01',\n});\n\nconst product = await client.getProduct('wireless-headphones');\nconsole.log(`Product: ${product.title} - $${product.priceRange.minVariantPrice.amount}`);\n\nconst cart = await client.createCart('gid://shopify/ProductVariant/123456', 2);\nconsole.log(`Cart created: ${cart.cart.checkoutUrl}`);\n```\n\n---\n\n## Rate Limiting\n\n**Public token rate limits:**\n- 2 requests per second per IP address\n- 4 requests per second per user token (if customer logged in)\n\n**Private token rate limits:**\n- No rate limiting (server-side access)\n\n**Handling rate limits:**\n```javascript\nasync function executeWithRetry(query, variables, maxRetries = 3) {\n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n const response = await fetch(endpoint, {\n method: 'POST',\n headers,\n body: JSON.stringify({ query, variables }),\n });\n\n if (response.status === 429) {\n const waitTime = Math.pow(2, attempt - 1) * 1000;\n await new Promise(resolve => setTimeout(resolve, waitTime));\n continue;\n }\n\n return response;\n }\n}\n```\n\n---\n\n## Common Errors & Solutions\n\n| Error | Cause | Solution |\n|-------|-------|----------|\n| **Unauthorized** | Invalid or expired token | Verify token in X-Shopify-Storefront-Access-Token header |\n| **Field not available** | Token doesn't have scope | Use private token for full access, or request scope |\n| **Product not found** | Wrong product handle | Verify handle exists; check product published to sales channel |\n| **Cart checkoutUrl null** | Cart hasn't been created properly | Ensure cartCreate mutation completed successfully |\n| **Customer is null** | User not logged in | Authenticate customer first (requires customer token) |\n| **Variant not available** | Out of stock | Check availableForSale and quantityAvailable fields |\n\n---\n\n## Reference URLs\n\n- [Shopify Storefront API Docs](https://shopify.dev/api/storefront/2026-01)\n- [Storefront GraphQL Queries](https://shopify.dev/api/storefront/2026-01/queries)\n- [Storefront GraphQL Mutations](https://shopify.dev/api/storefront/2026-01/mutations)\n- [Customer Account API](https://shopify.dev/api/customer/2026-01)\n- [Market Directives Guide](https://shopify.dev/api/storefront/2026-01/guide-markets)\n- [Cart Operations Guide](https://shopify.dev/api/storefront/2026-01/guide-cart)\n- [Authentication Flows](https://shopify.dev/api/storefront/2026-01/guide-authentication)\n- [Rate Limiting Documentation](https://shopify.dev/api/storefront/2026-01#rate-limits)\n"
}SHA-256 of public snapshot: fa9d66883b4aa2acc22b2a3bfcfe35ae69ca3075bf3c6f23e094e10be56824a5