Branch8

Shopify Plus to Headless Commerce Migration: APAC Playbook

Matt Li
October 8, 2026
13 mins read
Shopify Plus to Headless Commerce Migration: APAC Playbook - Hero Image

Key Takeaways

  • Keep Shopify checkout — it carries FPS, PayMe, GrabPay, PromptPay and wallet methods.
  • Run legacy Liquid and new storefront in parallel; ramp traffic by route and percentage.
  • Pin your Storefront API version before shipping any mobile binary.
  • Untyped metafields and Liquid-encoded content are the top migration blockers.
  • Headless rarely pays back for single-market brands with a healthy theme.

Quick Answer: A Shopify Plus to headless commerce migration means replacing only the storefront layer — typically React Native or Next.js — while Shopify keeps catalog, inventory and checkout. In APAC you must retain Shopify's hosted checkout to preserve local payment methods, and ramp traffic gradually rather than cutting over.


Most headless projects in Asia fail for a boring reason: the team treats it as a front-end rebuild when it is actually a payments and operations project. The React Native app is the easy part. The hard part is that your Hong Kong customers pay with FPS and PayMe, your Singapore customers want PayNow and GrabPay, your Thai customers want PromptPay and TrueMoney, and every one of those methods lives inside Shopify's hosted checkout — the one component you should not rebuild.

Related reading: Shopify Plus vs Adobe Commerce 2026 Cost: The APAC Verdict

Related reading: Salesforce CDP Genie Features 2026: An APAC Retail Reality Check

So the honest framing for a Shopify Plus to headless commerce migration in APAC is this: you are decoupling the storefront, not the commerce engine. You keep Shopify as the system of record for catalog, inventory, customers, discounts, tax and checkout. You replace only the presentation layer — a React Native app, a web storefront, or both — and you do it while the existing Liquid theme keeps taking orders.

Related reading: E-Commerce Platform Replatforming Guide 2026: The APAC Playbook

Related reading: DeepSeek v4 LLM Performance Benchmark: The APAC Cost Math

Related reading: Salesforce Marketing Cloud Next AI Agents: The APAC Ops Reality

This is the playbook we use. It assumes you already sell at volume, already have an operations team that depends on the Shopify admin, and cannot afford a weekend of downtime.

Why the Asia-Pacific case for headless is different

In the US and Europe, the usual headless argument is performance and design freedom. In APAC it is usually app-first behaviour. Mobile commerce dominates the region — Statista's e-commerce market data puts Asia well ahead of other regions in both absolute online retail sales and mobile share of transactions (Statista, E-commerce market data). A native app with push notifications, stored payment credentials and offline-tolerant browsing behaves very differently from a mobile web theme, and Shopify's Liquid storefront cannot produce one.

Speed still matters. Google's Core Web Vitals thresholds require Largest Contentful Paint under 2.5 seconds at the 75th percentile (web.dev, Web Vitals), and Deloitte's retail speed research found that improving mobile site speed by 0.1 seconds lifted retail conversion rates measurably (Deloitte, Milliseconds Make Millions). But if your Liquid theme already hits those thresholds, speed alone is a weak business case. App-first channels, multi-market storefronts from one backend, and content systems your merchandising team can actually use — those are the cases that survive a CFO review.

The trade-off you are buying: Shopify's own commerce-leader guidance is blunt that headless shifts maintenance of the storefront from Shopify to you (Shopify, Headless commerce). Theme updates, checkout extension compatibility, app script injection — all of that becomes your engineering backlog.

Prerequisites

Do not start until all of these exist. Half of the "Shopify Plus to headless commerce migration issues" people write about are missing prerequisites, not architecture flaws.

Commercial and operational

  • A Shopify Plus plan (or Advanced, for a smaller pilot). Plus gives you checkout extensibility, Shopify Functions for discount/delivery logic, and multiple Markets configurations.
  • A named owner for the storefront after launch. If nobody owns it, the theme rots.
  • An inventory of installed apps and which ones inject front-end scripts. Review apps, upsell widgets, and analytics snippets that rely on Liquid will not follow you into React Native.
  • A payment method matrix per market. For each country: which methods are live, which are enabled via Shopify Payments, and which come through a third-party gateway such as Airwallex, 2C2P, or Omise. Confirm each one against your payment provider's list, not a blog post.

Technical

  • Node.js 20+, pnpm or npm, and Git.
  • Shopify CLI 3.x installed (npm i -g @shopify/cli).
  • A custom app created in the Shopify admin with Storefront API and Customer Account API scopes.
  • An Expo-managed React Native project (Expo SDK 50+) or a bare React Native 0.73+ workspace.
  • A staging Shopify store that mirrors production catalog structure and metafield definitions.
  • Access to your DNS and CDN (Cloudflare, Fastly, or Shopify Oxygen) — you need this for the traffic-splitting step.

Data hygiene

  • Metafield definitions standardised and typed. Untyped metafields are the single most common cause of a headless build stalling in week three.
  • A full URL inventory of your current storefront, exported from Google Search Console and your sitemap, for redirect parity later.

Ready to Transform Your Ecommerce Operations?

Branch8 specializes in ecommerce platform implementation and AI-powered automation solutions. Contact us today to discuss your ecommerce automation strategy.

Step 1: Draw the boundary — what stays on Shopify

Write this down before any code. Our default split for APAC retailers:

Stays on Shopify: checkout, payments, tax, fraud, orders, inventory, customer accounts, discounts, shipping rates, Markets/multi-currency.

Moves to your layer: product listing and detail rendering, search and filtering UI, navigation, content pages, cart UI, personalisation, app-only features (push, wishlist, loyalty surfaces).

The reason checkout stays is regional. Shopify's hosted checkout is where locally acquired methods — Alipay HK, WeChat Pay, PayMe, FPS-backed rails, GrabPay, PayNow, PromptPay, Atome instalments — are presented, PCI-scoped and kept current. Rebuilding checkout means re-certifying every one of those integrations yourself, per market. Shopify's own documentation directs custom storefronts to hand off to the hosted checkout URL for exactly this reason (Shopify, Storefront API).

Step 2: Provision API access and pin your API version

Create a custom app in Settings → Apps and sales channels → Develop apps. Grant unauthenticated_read_product_listings, unauthenticated_read_product_inventory, unauthenticated_write_checkouts, and unauthenticated_read_customers.

Store the public Storefront access token in your app config — it is designed to be client-visible, but never ship an Admin API token into a mobile binary.

1# .env — mobile app
2EXPO_PUBLIC_SHOPIFY_DOMAIN=your-store.myshopify.com
3EXPO_PUBLIC_STOREFRONT_TOKEN=shpat_public_storefront_token
4EXPO_PUBLIC_STOREFRONT_API_VERSION=2025-01

Pin the version explicitly. Shopify releases quarterly API versions and supports each for one year (Shopify, API versioning). An unpinned client will break silently when a field is removed, and a mobile app cannot be hotfixed as fast as a website.

A thin client wrapper:

1// src/lib/storefront.ts
2const ENDPOINT = `https://${process.env.EXPO_PUBLIC_SHOPIFY_DOMAIN}/api/${process.env.EXPO_PUBLIC_STOREFRONT_API_VERSION}/graphql.json`;
3
4export async function storefront<T>(
5 query: string,
6 variables: Record<string, unknown> = {},
7 buyerIp?: string,
8): Promise<T> {
9 const res = await fetch(ENDPOINT, {
10 method: 'POST',
11 headers: {
12 'Content-Type': 'application/json',
13 'X-Shopify-Storefront-Access-Token': process.env.EXPO_PUBLIC_STOREFRONT_TOKEN!,
14 ...(buyerIp ? { 'Shopify-Storefront-Buyer-IP': buyerIp } : {}),
15 },
16 body: JSON.stringify({ query, variables }),
17 });
18
19 const json = await res.json();
20 if (json.errors) throw new Error(JSON.stringify(json.errors));
21 return json.data as T;
22}

Verify with a one-liner before writing any UI:

1curl -s -X POST \
2 "https://your-store.myshopify.com/api/2025-01/graphql.json" \
3 -H "X-Shopify-Storefront-Access-Token: $STOREFRONT_TOKEN" \
4 -H "Content-Type: application/json" \
5 -d '{"query":"{ shop { name primaryDomain { url } paymentSettings { enabledPresentmentCurrencies } } }"}' | jq

Expected output:

1{
2 "data": {
3 "shop": {
4 "name": "Your Store",
5 "primaryDomain": { "url": "https://your-store.com" },
6 "paymentSettings": {
7 "enabledPresentmentCurrencies": ["HKD", "SGD", "TWD", "AUD"]
8 }
9 }
10 }
11}

That enabledPresentmentCurrencies array is your first reality check on multi-market readiness.

Ready to Transform Your Ecommerce Operations?

Branch8 specializes in ecommerce platform implementation and AI-powered automation solutions. Contact us today to discuss your ecommerce automation strategy.

Step 3: Model the catalog query, including metafields and market context

APAC storefronts almost always need per-market pricing and localised content. The Storefront API takes an @inContext directive for country and language — use it from day one rather than retrofitting.

1query ProductByHandle(
2 $handle: String!
3 $country: CountryCode!
4 $language: LanguageCode!
5) @inContext(country: $country, language: $language) {
6 product(handle: $handle) {
7 id
8 title
9 descriptionHtml
10 featuredImage { url(transform: { maxWidth: 1200 }) altText }
11 options { name values }
12 variants(first: 100) {
13 nodes {
14 id
15 title
16 availableForSale
17 quantityAvailable
18 price { amount currencyCode }
19 compareAtPrice { amount currencyCode }
20 selectedOptions { name value }
21 }
22 }
23 sizeChart: metafield(namespace: "custom", key: "size_chart") { value type }
24 storePickup: metafield(namespace: "custom", key: "pickup_stores") { value type }
25 }
26}

Generate types instead of hand-writing them:

1npm i -D @graphql-codegen/cli @shopify/api-codegen-preset
2npx graphql-codegen --config codegen.ts
1// codegen.ts
2import { shopifyApiProject, ApiType } from '@shopify/api-codegen-preset';
3
4export default {
5 schema: 'https://shopify.dev/storefront-graphql-direct-proxy/2025-01',
6 documents: ['src/**/*.{ts,tsx}'],
7 projects: {
8 default: shopifyApiProject({
9 apiType: ApiType.Storefront,
10 apiVersion: '2025-01',
11 outputDir: './src/types',
12 }),
13 },
14};

One warning from experience on a Greater China multi-brand retail engagement: if your merchandising team has been encoding size charts, care instructions and store-pickup availability into theme sections rather than metafields, that content does not exist as data. Budget a content migration sprint. This is where "three-month" headless projects become six-month projects.

Step 4: Cart on the API, checkout on Shopify

Use the Cart API, not the deprecated Checkout API. A cart gives you a checkoutUrl that carries straight into the hosted checkout with all local payment methods intact.

1mutation CartCreate($lines: [CartLineInput!]!, $country: CountryCode!)
2@inContext(country: $country) {
3 cartCreate(input: { lines: $lines }) {
4 cart {
5 id
6 checkoutUrl
7 totalQuantity
8 cost { subtotalAmount { amount currencyCode } }
9 }
10 userErrors { field message }
11 }
12}
1// src/lib/cart.ts
2export async function addToCart(cartId: string, merchandiseId: string, quantity = 1) {
3 return storefront(CART_LINES_ADD, {
4 cartId,
5 lines: [{ merchandiseId, quantity }],
6 country: currentMarket(), // 'HK' | 'SG' | 'TW' | 'AU'
7 });
8}

Hand off to checkout from React Native with an in-app browser session, not a raw WebView. In-app browser sessions share cookies with Safari/Chrome, which keeps wallet app returns and 3-D Secure redirects working:

1import * as WebBrowser from 'expo-web-browser';
2import * as Linking from 'expo-linking';
3
4export async function openCheckout(checkoutUrl: string) {
5 const returnUrl = Linking.createURL('/order-confirmed');
6 const url = `${checkoutUrl}&return_to=${encodeURIComponent(returnUrl)}`;
7
8 const result = await WebBrowser.openAuthSessionAsync(url, returnUrl);
9 return result.type === 'success' ? result.url : null;
10}

The APAC-specific detail: Alipay HK, WeChat Pay and GrabPay complete payment by switching to the wallet app and then deep-linking back. Register your URL scheme and universal links before testing, or every wallet payment will appear to "hang" in QA. Test each method on a physical device in-market — emulator testing will not surface wallet app handoff failures. Confirm method availability per country against Shopify's payments documentation (Shopify Help Center, Payments) and your third-party gateway's own coverage list.

Do not treat the app's local order state as truth. Confirm orders from a server-side orders/create webhook:

1shopify app generate webhook --topic orders/create

Ready to Transform Your Ecommerce Operations?

Branch8 specializes in ecommerce platform implementation and AI-powered automation solutions. Contact us today to discuss your ecommerce automation strategy.

Step 5: Run both storefronts in parallel — the no-downtime mechanism

This is the step most guides skip, and it is the reason we have never needed a maintenance window for a storefront cutover.

The existing Liquid theme stays live and continues taking orders. The new storefront (web) deploys to a separate origin — Shopify Oxygen if you use Hydrogen, otherwise Vercel, Cloudflare Workers, or your own edge. Traffic moves by route and by percentage, not by DNS flip.

A Cloudflare Worker splitting by path and cookie:

1export default {
2 async fetch(request, env) {
3 const url = new URL(request.url);
4 const cookie = request.headers.get('cookie') || '';
5
6 const forced = cookie.includes('storefront=next')
7 ? 'next'
8 : cookie.includes('storefront=legacy')
9 ? 'legacy'
10 : null;
11
12 // Phase 1: only /collections/* on the new storefront, 10% of traffic
13 const eligible = url.pathname.startsWith('/collections/');
14 const sampled = Math.random() < 0.10;
15 const target = forced ?? (eligible && sampled ? 'next' : 'legacy');
16
17 const origin =
18 target === 'next' ? env.NEXT_ORIGIN : env.SHOPIFY_ORIGIN;
19
20 const res = await fetch(new Request(origin + url.pathname + url.search, request));
21 const out = new Response(res.body, res);
22 out.headers.append('Set-Cookie', `storefront=${target}; Path=/; Max-Age=86400`);
23 out.headers.set('X-Storefront-Variant', target);
24 return out;
25 },
26};

Verify the split is working:

1for i in $(seq 1 20); do
2 curl -s -o /dev/null -D - https://your-store.com/collections/new-arrivals \
3 | grep -i 'x-storefront-variant'
4done
5# x-storefront-variant: legacy
6# x-storefront-variant: legacy
7# x-storefront-variant: next
8# ...

Ramp order we use: /collections/* → /products/* → content pages → home → cart. Checkout never moves. If conversion or error rate on the new variant degrades against the legacy baseline, set the percentage to zero. Rollback is a config change, not a deploy.

For the React Native app, the equivalent control is a release channel plus a remote feature flag — ship the app to a TestFlight/internal track, then enable features per market. Expo's over-the-air updates let you correct a JS-layer bug without an app store review cycle (Expo, EAS Update).

Step 6: Protect SEO before you move a single public route

A headless migration is not a replatform, so your URLs should not change. Enforce that with a test, not a promise.

1# urls.txt: top 500 URLs by impressions from Search Console
2while read u; do
3 code=$(curl -s -o /dev/null -w '%{http_code}' -L "$u")
4 echo "$code $u"
5done < urls.txt | grep -v '^200' > broken.txt
6
7wc -l broken.txt # must be 0 before ramping above 10%

Then check the things Liquid gave you for free and your new storefront does not:

  • robots.txt and sitemap.xml served from the new origin, not the old
  • canonical tags, hreflang pairs for zh-Hant, zh-Hans, en-HK, en-SG, en-AU
  • JSON-LD Product with offers.priceCurrency matching the market context
  • structured data parity, validated with Google's Rich Results Test

Server-render or pre-render product and collection pages. A client-rendered catalog will get indexed eventually, but "eventually" is not a plan when organic drives a third of your revenue.

Ready to Transform Your Ecommerce Operations?

Branch8 specializes in ecommerce platform implementation and AI-powered automation solutions. Contact us today to discuss your ecommerce automation strategy.

Step 7: Instrument before you celebrate

Define the success metrics before launch, measured on the same cohort split you built in Step 5:

  • LCP, INP and CLS at the 75th percentile, per market, from real user monitoring — the thresholds are published at web.dev
  • add-to-cart rate and checkout-initiation rate by variant
  • checkout completion rate by payment method and market
  • Storefront API error rate and p95 latency

That last one matters more in APAC than in single-market builds. Requests from Jakarta or Ho Chi Minh City to a US-region edge function add latency that no amount of front-end optimisation recovers. Deploy your storefront functions to Singapore, Hong Kong and Sydney regions, and pass Shopify-Storefront-Buyer-IP on server-side calls so Shopify's rate limiting and localisation behave correctly.

On cart abandonment: Baymard Institute's ongoing research puts the average documented online shopping cart abandonment rate around 70% (Baymard Institute). Headless does not fix that. Checkout friction, shipping cost surprises and missing local payment methods do — which is precisely why you left checkout on Shopify.

Is headless e-commerce worth it?

Honest answer: for a single-market brand under roughly eight figures of GMV with a healthy Liquid theme, usually not. You will spend on engineering what you would otherwise spend on merchandising and acquisition, and the performance delta over a well-built Dawn-based theme is often small.

It becomes worth it when at least two of these are true:

  • You need a native app as a first-class channel, not a wrapper.
  • You sell across three or more APAC markets with different languages, currencies and payment mixes from one backend.
  • You have non-web surfaces — kiosk, POS-adjacent clienteling, WeChat Mini Program, marketplace feeds — that need the same catalog.
  • Your content model has outgrown Liquid sections and you are moving to a headless CMS anyway.

There is no "Shopify Plus to headless commerce migration tool" that does this for you. Shopify's Hydrogen and Oxygen stack (Shopify, Hydrogen) removes a meaningful amount of boilerplate for web, and the Storefront API is stable and well-documented. But the migration itself is a sequence of deliberate engineering decisions, most of them about data modelling and payments rather than rendering.

Ready to Transform Your Ecommerce Operations?

Branch8 specializes in ecommerce platform implementation and AI-powered automation solutions. Contact us today to discuss your ecommerce automation strategy.

What to do next

  1. Export your top 500 URLs from Search Console and your full metafield definition list. Both take an afternoon and both will tell you how big this project really is.
  2. Build the payment method matrix per market and confirm every method against your gateway's documentation.
  3. Stand up the Storefront API client and ship one route — a single collection page — behind a 5% traffic split. Measure it for two weeks.
  4. Only then decide whether the app comes next, or whether a well-optimised theme was the right answer all along.

Who this advice is not for: teams without a dedicated front-end owner post-launch, brands whose growth constraint is traffic rather than experience, and anyone hoping headless will fix conversion problems that are actually pricing, delivery or assortment problems. A Shopify Plus to headless commerce migration adds a permanent line item to your engineering budget. It pays back when you have channels that Liquid genuinely cannot serve — and not reliably before that.

If you are weighing this decision for a multi-market APAC rollout, Branch8's commerce engineering team can review your current architecture and payment coverage and tell you plainly whether the headless case holds. Talk to us.

Sources

FAQ

Yes. Shopify explicitly supports headless builds through the Storefront API, the Customer Account API, and its Hydrogen/Oxygen stack, so you can render your storefront in React Native, Next.js, or any client while Shopify remains the commerce backend. The recommended pattern is to keep checkout on Shopify's hosted flow and hand off via the Cart API's checkoutUrl, which preserves payments, tax, and fraud handling.

About the Author

Matt Li

Co-Founder & CEO, Branch8 & Second Talent

Matt Li is Co-Founder and CEO of Branch8, a Y Combinator-backed (S15) Adobe Solution Partner and e-commerce consultancy headquartered in Hong Kong, and Co-Founder of Second Talent, a global tech hiring platform ranked #1 in Global Hiring on G2. With 12 years of experience in e-commerce strategy, platform implementation, and digital operations, he has led delivery of Adobe Commerce Cloud projects for enterprise clients including Chow Sang Sang, HomePlus (HKBN), Maxim's, Hong Kong International Airport, Hotai/Toyota, and Evisu. Prior to founding Branch8, Matt served as Vice President of Mid-Market Enterprises at HSBC. He serves as Vice Chairman of the Hong Kong E-Commerce Business Association (HKEBA). A self-taught software engineer, Matt graduated from the University of Toronto with a Bachelor of Commerce in Finance and Economics.