\n \n {% elsif shipping_country == 'CA' and current_store_region == 'us' %}\n
\n

You're shipping to Canada. Redirecting you to our Canadian store...

\n \n
\n {% endif %}\n{% endif %}","targetProduct":"Shopify"},{"@type":"SoftwareSourceCode","name":"Post-Purchase Event Hub","programmingLanguage":"text/plain","codeSampleType":"snippet","text":"Trigger: Order Created (fires on both US and CA stores)\n\nCondition: Always (no filter needed)\n\nActions:\n 1. Send HTTP POST to central event hub\n URL: https://your-backend.herokuapp.com/orders/dispatch\n Body: Include order.id, order.customer.id, order.name, order.billing_address.country_code\n \n 2. Send to Klaviyo (or your email platform)\n Event: \"order_placed\"\n Properties: order number, customer email, store region\n \n 3. Log to data warehouse (or Airtable)\n Create record with: Order ID, Store Region, Customer ID, Total\n\nResult: Every order lands in one place regardless of which store it came from.","targetProduct":"Shopify"}]} \n \n {% elsif shipping_country == 'CA' and current_store_region == 'us' %}\n
\n

You're shipping to Canada. Redirecting you to our Canadian store...

\n \n
\n {% endif %}\n{% endif %}"}]},{"@type":"HowToStep","position":4,"name":"Post-Purchase Event Hub","text":"Sends every order from both stores to a central log so email, fulfillment, and BI tools see one unified order stream. (Paste target: Shopify Flow editor: When → Then.)","itemListElement":[{"@type":"HowToDirection","text":"Trigger: Order Created (fires on both US and CA stores)\n\nCondition: Always (no filter needed)\n\nActions:\n 1. Send HTTP POST to central event hub\n URL: https://your-backend.herokuapp.com/orders/dispatch\n Body: Include order.id, order.customer.id, order.name, order.billing_address.country_code\n \n 2. Send to Klaviyo (or your email platform)\n Event: \"order_placed\"\n Properties: order number, customer email, store region\n \n 3. Log to data warehouse (or Airtable)\n Create record with: Order ID, Store Region, Customer ID, Total\n\nResult: Every order lands in one place regardless of which store it came from."}]}]}
Tom Sailors
Brief · Anonymized case study

US & Canada Split with Unified Customers

I'd build this as a multi-store sync problem, not a single-store problem. The merchant keeps two Shopify stores (one US, one CA) running in parallel, but stitches them together at three critical moments: on customer login, on inventory adjustment, and at checkout. A background job mirrors new signups and addresses across stores using metafields as link keys. A central inventory sync service pushes the same stock counts to both regions on schedule. A checkout redirect catches customers in the wrong store based on their shipping address and sends them home. All orders flow to one central log via Shopify Flow so fulfillment and email see one unified order stream.

A mid-market DTC with a customer base spanning both the US and Canada needed to split into two regional stores while keeping customer records in sync, maintaining inventory parity across locations, and routing customers to the correct store at checkout. The challenge was to avoid duplicate customer accounts, overselling across regions, and fragmented order records.
Four pieces
B2B / Wholesale

Unified Customer Sync

Keeps one customer record synced across both US and Canadian stores so they stay logged in and their order history is visible everywhere.

Custom Shopify app + Storefront API
Admin GraphQL explorer graphql
# Admin GraphQL - Sync customer to secondary store
mutation SyncCustomerAcrossStores($input: CustomerInput!) {
  customerUpdate(input: $input) {
    customer {
      id
      email
      firstName
      lastName
      defaultAddress {
        countryCode
        provinceCode
      }
      metafield(namespace: "sync", key: "paired_store_id") {
        value
      }
    }
    userErrors {
      field
      message
    }
  }
}

# Use this mutation to apply the same email/name to the paired store
# and set a metafield linking them
# Variables:
# {
#   "input": {
#     "id": "gid://shopify/Customer/123456",
#     "metafields": [
#       {
#         "namespace": "sync",
#         "key": "paired_store_id",
#         "type": "single_line_text",
#         "value": "us-store-id"
#       }
#     ]
#   }
# }
Run this on both stores to link paired accounts; a background job watches for new signups and auto-mirrors them to the secondary store.
Inventory

Shared Inventory Bridge

Reads stock from one central source and pushes the same quantities to both stores so products never oversell across regions.

Heroku backend + inventory sync service
Admin GraphQL explorer (run once per store location) graphql
# Admin GraphQL - Adjust inventory on both stores after central sync
mutation AdjustInventoryBothStores($input: InventoryAdjustQuantitiesInput!) {
  inventoryAdjustQuantities(input: $input) {
    inventoryAdjustmentGroup {
      id
      reason
      changes {
        delta
        quantityAfterChange
        item {
          id
          sku
        }
        location {
          id
          name
        }
      }
    }
    userErrors {
      field
      message
    }
  }
}

# Call this mutation twice — once for US store locations, once for Canadian
# Variables example for US location:
# {
#   "input": {
#     "name": "Sync from warehouse",
#     "reason": "central_stock_source",
#     "changes": [
#       {
#         "inventoryItemId": "gid://shopify/InventoryItem/456",
#         "locationId": "gid://shopify/Location/us-warehouse",
#         "delta": 42
#       }
#     ]
#   }
# }
The backend pulls from your warehouse system on schedule and calls this twice to sync US and CA locations in lockstep.
Storefront

Checkout Region Router

Detects a customer's shipping address at checkout and automatically redirects them to the correct store if they're in the wrong one.

Theme app extension + Checkout UI
theme/snippets/region-router.liquid, then include from theme.liquid liquid
{% comment %}
  Place in theme/snippets/region-router.liquid
  Called from checkout.liquid or cart drawer
{% endcomment %}

{% if customer %}
  {% assign shipping_country = customer.default_address.country %}
  {% assign current_store_region = shop.metafields.region.code | default: 'us' %}
  
  {% if shipping_country == 'US' and current_store_region == 'ca' %}
    <div class="region-notice">
      <p>You're shipping to the US. Redirecting you to our US store...</p>
      <script>
        window.location.href = 'https://us-store.myshopify.com' + window.location.pathname;
      </script>
    </div>
  {% elsif shipping_country == 'CA' and current_store_region == 'us' %}
    <div class="region-notice">
      <p>You're shipping to Canada. Redirecting you to our Canadian store...</p>
      <script>
        window.location.href = 'https://ca-store.myshopify.com' + window.location.pathname;
      </script>
    </div>
  {% endif %}
{% endif %}
Set shop metafield 'region.code' to 'us' or 'ca' on each store so the snippet knows which store it is.
Operations

Post-Purchase Event Hub

Sends every order from both stores to a central log so email, fulfillment, and BI tools see one unified order stream.

Shopify Flow + webhook dispatcher
Shopify Flow editor: When → Then flow
Trigger: Order Created (fires on both US and CA stores)

Condition: Always (no filter needed)

Actions:
  1. Send HTTP POST to central event hub
     URL: https://your-backend.herokuapp.com/orders/dispatch
     Body: Include order.id, order.customer.id, order.name, order.billing_address.country_code
     
  2. Send to Klaviyo (or your email platform)
     Event: "order_placed"
     Properties: order number, customer email, store region
     
  3. Log to data warehouse (or Airtable)
     Create record with: Order ID, Store Region, Customer ID, Total

Result: Every order lands in one place regardless of which store it came from.
Set up one flow on each store with the same HTTP endpoint; the backend dedupes by order ID.

Got a similar problem?

Sketch your build in 30 seconds — voice, type, or attach a screenshot.

Sketch the build →