Connect FlutterFlow to an existing Shopify store using the Storefront API (GraphQL) with a Storefront Access Token. Set up an API Group with base URL https://{store}.myshopify.com/api/2024-01/graphql.json and the X-Shopify-Storefront-Access-Token header. Query products, build a cart with checkoutCreate and checkoutLineItemsAdd mutations, then Launch URL to the Shopify-hosted checkout webUrl for payment.
Build a native Shopify storefront in FlutterFlow using GraphQL
If you already have a Shopify store, you do not need to rebuild your product catalog or payment system in FlutterFlow. Shopify's Storefront API lets you query your live products, create carts, and hand off to Shopify's PCI-compliant hosted checkout — all from a FlutterFlow app. This tutorial walks through creating the API Group in FlutterFlow's API Manager, writing the GraphQL queries and mutations for products and checkout, binding the results to product list and detail pages, and launching the Shopify checkout URL when the customer is ready to pay.
Prerequisites
- An active Shopify store with at least one published product
- A Shopify Storefront Access Token — create it in Shopify Admin → Settings → Apps → Develop apps → Create an app → Configure Storefront API scopes
- A FlutterFlow project (Firebase not required for read-only product display)
- Basic understanding of FlutterFlow's API Manager and Backend Query widgets
Step-by-step guide
Create the Shopify API Group in FlutterFlow's API Manager
Create the Shopify API Group in FlutterFlow's API Manager
In FlutterFlow, go to API Manager → Add API Group. Name it ShopifyStorefront. Set the Base URL to https://YOUR-STORE.myshopify.com/api/2024-01/graphql.json — replace YOUR-STORE with your Shopify store handle (visible in your Shopify admin URL). Set the Method on the group level to POST (all Storefront API calls are POST requests). Under Headers, add one header: Name: X-Shopify-Storefront-Access-Token, Value: your Storefront Access Token. Store the token value in FlutterFlow Secrets (Settings → Secrets → Add Secret named SHOPIFY_STOREFRONT_TOKEN) and reference it as [secretName] in the header value field rather than pasting it directly. Set Content-Type: application/json as a second header. Save the API Group.
Expected result: ShopifyStorefront API Group is configured with the base URL and authentication headers.
Add the products query and bind to a product ListView
Add the products query and bind to a product ListView
In the ShopifyStorefront API Group, add an endpoint named getProducts. The request body (JSON field named 'query') contains the GraphQL products query: {"query": "{ products(first: 20) { edges { node { id title description images(first: 1) { edges { node { url } } } variants(first: 10) { edges { node { id title price { amount currencyCode } availableForSale } } } } } } }"}. Click Test to verify the response. FlutterFlow will parse the JSON response — navigate to the response structure and mark the fields you need: products.edges[].node.id, title, description, images.edges[0].node.url, and the first variant's price.amount. Create a ProductCatalog page, add a Backend Query using the getProducts API call. Add a ListView bound to the query result's products.edges array using Generate Dynamic Children. Each child is a ProductCard Component with: an Image widget bound to node.images.edges[0].node.url, a Text for node.title, and a Text for the price formatted with a Custom Function.
Expected result: The product catalog page displays your Shopify products with images, names, and prices.
Build the product detail page with variant selection
Build the product detail page with variant selection
Add a getProductById endpoint to the ShopifyStorefront API Group. Request body: {"query": "{ product(id: \"PRODUCT_ID\") { id title descriptionHtml images(first: 5) { edges { node { url } } } variants(first: 20) { edges { node { id title price { amount currencyCode } availableForSale inventoryQuantity } } } } }"} with a variable PRODUCT_ID. Create a ProductDetail page with a Page Parameter named productId (String). Add a Backend Query using getProductById, passing productId as the PRODUCT_ID variable. Add a PageView or Stack widget with images bound to the images.edges array for a swipeable image gallery. Add a DropDown widget for variant selection bound to the variants.edges array — display variant.title and store the selected variant.id in a Page State variable named selectedVariantId. Add an Add to Cart Button — On Tap: store {variantId: selectedVariantId, quantity: 1, productTitle: title, price: selectedVariant.price.amount} to App State cartItems (List of JSON).
Expected result: Product detail page shows image gallery, variant selector, and Add to Cart button that saves the selected variant to App State.
Create the checkout with checkoutCreate and checkoutLineItemsAdd
Create the checkout with checkoutCreate and checkoutLineItemsAdd
Add two endpoints to ShopifyStorefront: createCheckout and addLineItems. createCheckout request body: {"mutation": "mutation checkoutCreate { checkoutCreate(input: {}) { checkout { id webUrl } checkoutUserErrors { message } } }"}. This returns a checkout.id and checkout.webUrl. addLineItems request body: {"mutation": "mutation addItems($checkoutId: ID!, $lineItems: [CheckoutLineItemInput!]!) { checkoutLineItemsAdd(checkoutId: $checkoutId, lineItems: $lineItems) { checkout { id webUrl subtotalPrice { amount currencyCode } lineItems(first: 10) { edges { node { title quantity variant { price { amount } } } } } } checkoutUserErrors { message } } }"} with variables checkoutId and lineItems (array of {variantId, quantity}). Create a Cart page displaying the App State cartItems. Add a Checkout Button with an Action Flow: call createCheckout to get the checkoutId, then call addLineItems passing checkoutId and the cart items array mapped to [{variantId, quantity}] format using a Custom Function. Save the returned webUrl to App State checkoutUrl.
1// Custom Function: buildLineItemsPayload2// Converts App State cartItems List<dynamic> to Shopify lineItems format3List<dynamic> buildLineItemsPayload(List<dynamic> cartItems) {4 return cartItems.map((item) => {5 'variantId': item['variantId'],6 'quantity': item['quantity'] ?? 1,7 }).toList();8}910// Custom Function: formatPrice11// Formats '29.99' + 'USD' → '$29.99'12String formatPrice(String amount, String currencyCode) {13 final value = double.tryParse(amount) ?? 0.0;14 return '\$${value.toStringAsFixed(2)}';15}Expected result: Cart page creates a Shopify checkout session and stores the webUrl pointing to the Shopify-hosted payment page.
Launch Shopify checkout and handle order confirmation via webhook
Launch Shopify checkout and handle order confirmation via webhook
On the Cart page, add a Proceed to Checkout Button. In its Action Flow: call the createCheckout and addLineItems mutations (from Step 4), then add a Launch URL action using the checkoutUrl stored in App State. Shopify handles all payment, address entry, and order confirmation on their hosted page — PCI compliance and fraud detection are fully managed by Shopify. For order confirmation back in your app: create a Cloud Function with an HTTPS trigger and register its URL as a webhook in Shopify Admin → Settings → Notifications → Webhooks → Add webhook, Topic: orders/create. The Cloud Function receives the order JSON and writes to a Firestore orders/{orderId} collection. Back in FlutterFlow, show an OrderConfirmation page that queries the Firestore orders collection filtered by the customer's email from Firebase Auth.
Expected result: Customers are redirected to Shopify's checkout page for payment, and orders appear in Firestore via webhook for in-app order history.
Complete working example
1API Group: ShopifyStorefront2├── Base URL: https://{store}.myshopify.com/api/2024-01/graphql.json3├── Method: POST4└── Headers:5 ├── X-Shopify-Storefront-Access-Token: [SHOPIFY_STOREFRONT_TOKEN]6 └── Content-Type: application/json78Endpoints:9├── getProducts10│ └── Query: products(first: 20) { edges { node {11│ id, title, description,12│ images(first: 1) { edges { node { url } } },13│ variants(first: 10) { edges { node {14│ id, title, price { amount currencyCode },15│ availableForSale } } } } } }16│17├── getProductById18│ └── Query: product(id: $PRODUCT_ID) { ... full fields ... }19│20├── createCheckout21│ └── Mutation: checkoutCreate(input: {})22│ └── Returns: checkout { id webUrl }23│24└── addLineItems25 └── Mutation: checkoutLineItemsAdd(26 checkoutId: $checkoutId,27 lineItems: $lineItems // [{variantId, quantity}]28 )29 └── Returns: checkout { id webUrl subtotalPrice lineItems }3031Page Architecture:32├── ProductCatalog33│ └── ListView (Backend Query: getProducts)34│ └── ProductCard Component35│ ├── Image (images.edges[0].node.url)36│ ├── Text (title, bold)37│ └── Text (price, formatted)38│39├── ProductDetail (param: productId)40│ ├── PageView (images gallery)41│ ├── DropDown (variant selector → Page State: selectedVariantId)42│ └── Button: Add to Cart → App State cartItems.add()43│44├── Cart45│ ├── ListView (App State cartItems)46│ └── Button: Checkout47│ └── Action Flow:48│ 1. createCheckout → get checkoutId49│ 2. addLineItems → get webUrl50│ 3. Launch URL → webUrl51│52App State:53├── cartItems: List<JSON> [{variantId, quantity, title, price}]54├── checkoutId: String55└── checkoutUrl: String5657Cloud Function: shopifyOrderWebhook58└── Receives orders/create from Shopify59 └── Writes to Firestore: orders/{orderId}Common mistakes
Why it's a problem: Using the Admin API token instead of the Storefront Access Token in client API headers
How to avoid: Create a dedicated custom app in Shopify Admin → Apps → Develop apps and only grant the Storefront API scopes you need (unauthenticated_read_product_listings, unauthenticated_write_checkouts). Use the resulting Storefront Access Token, which is scoped to customer-facing read operations only.
Why it's a problem: Trying to build a custom payment form instead of using the Shopify checkout webUrl
How to avoid: Always use the checkout.webUrl from the checkoutCreate mutation to launch Shopify's hosted checkout. Shopify handles PCI compliance, payment processing, fraud detection, and all checkout UX. Your FlutterFlow app just needs to display products and build the cart.
Why it's a problem: Using REST API endpoints instead of the Storefront GraphQL API
How to avoid: All FlutterFlow API calls for storefront operations go to the single GraphQL endpoint: https://{store}.myshopify.com/api/2024-01/graphql.json via POST with the query or mutation in the request body.
Best practices
- Store your Storefront Access Token in FlutterFlow Secrets, not hardcoded in the API Group headers — it is safe to include in client requests but should not be in source code
- Always check availableForSale on variants before showing Add to Cart — sold-out variants should display as Out of Stock with the button disabled
- Use the checkoutCreate mutation with an empty input first, then addLineItems separately — this allows you to add items incrementally as the user builds their cart
- Cache product data in Firestore for your most popular items to reduce Storefront API calls and improve load times on slower connections
- Implement a Shopify orders/create webhook via Cloud Function so customers can see order history in your app without needing Shopify's order status page
- Test your full checkout flow with Shopify's test payment gateway before going live — enable it in Shopify Admin → Settings → Payments → Test mode
- Use the 2024-01 API version explicitly in your base URL rather than unstable — Shopify deprecates API versions annually and you want a predictable upgrade schedule
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I am building a FlutterFlow app that connects to a Shopify store using the Storefront API (GraphQL). Write me the GraphQL queries and mutations I need for: (1) fetching a list of products with title, first image URL, and first variant price, (2) fetching a single product by ID with all variants including price and availableForSale, (3) creating a checkout with checkoutCreate, and (4) adding line items with checkoutLineItemsAdd. Include the request body format I need to use in FlutterFlow's API Manager.
Create a product catalog page connected to my ShopifyStorefront API Group's getProducts endpoint. Display products in a ListView with each item showing the product image, title, and price. Make each item tappable to navigate to a ProductDetail page passing the product ID as a parameter.
Frequently asked questions
What Shopify API scopes do I need for the Storefront Access Token?
For a read-only product catalog: unauthenticated_read_product_listings and unauthenticated_read_product_inventory. To create and manage checkouts: add unauthenticated_write_checkouts and unauthenticated_read_checkouts. If you want to create customer accounts or let customers log in: add unauthenticated_write_customers. In Shopify Admin → Apps → Develop apps → your app → Configuration → Storefront API access scopes, select only the scopes you need.
How do I handle product variants like size and color in FlutterFlow?
Shopify returns all variants in the variants.edges array in the product query. Each variant has a title (e.g., 'Small / Blue'), a price, and an availableForSale boolean. In FlutterFlow, use a DropDown widget bound to the variants array and store the selected variant's id in a Page State variable. When the user clicks Add to Cart, use the selected variant id in the checkoutLineItemsAdd mutation. For separate size and color selectors, you need to parse the variant options from the product.options array and build the selector logic with Custom Functions.
Can customers log in to their existing Shopify account from my FlutterFlow app?
Yes, using the Storefront API Customer mutations: customerCreate (new account), customerAccessTokenCreate (login), and customerAccessTokenRenew (refresh). Store the customerAccessToken in FlutterFlow App State or Secure Storage. Pass it in the checkoutCreate mutation with email to associate the order with the account. Note: Shopify customer authentication is separate from Firebase Auth — you manage two auth systems if your app uses both.
What is the difference between Shopify Storefront API and Admin API?
The Storefront API is designed for customer-facing apps — it allows product browsing, cart creation, and checkout. It uses a Storefront Access Token that is safe to include in client apps. The Admin API has full access to your store (orders, customers, analytics, settings) and uses a secret Admin token that must never appear in client code. For FlutterFlow integrations, always use the Storefront API.
How do I show order history to customers in my FlutterFlow app?
The cleanest approach is to use a Shopify orders/create webhook. When an order is placed, Shopify sends the full order data to your Cloud Function, which writes it to Firestore orders/{orderId} with the customer email. In FlutterFlow, query the orders collection filtered by the logged-in user's email. Alternatively, use the Storefront API customer query with the customerAccessToken to fetch orders directly — this requires customer authentication as described in the previous FAQ.
Can RapidDev help build a custom Shopify mobile app in FlutterFlow?
Yes. A production-ready Shopify mobile app with customer authentication, order history, wishlist, reviews, push notifications for order updates, and Shopify Metafields for custom data requires both GraphQL expertise and FlutterFlow Custom Actions and Cloud Functions beyond a basic integration. RapidDev can build the full storefront.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation