\n {% break %}\n {% endif %}\n{% endfor %}","targetProduct":"Shopify"},{"@type":"SoftwareSourceCode","name":"Pre-Launch SEO Audit","programmingLanguage":"text/plain","codeSampleType":"snippet","text":"Trigger: Manual workflow start or scheduled daily at 2 AM\n\nCondition: Check if \"migration_stage\" metafield equals \"pre_launch\"\n\nActions:\n 1. Send HTTP request to Heroku crawl service:\n POST /crawl/validate-redirects\n Body: { legacy_domain: \"original-site.com\", shopify_domain: \"new-site.myshopify.com\" }\n 2. Wait for response; parse redirect_success_count and redirect_fail_urls\n 3. If redirect_fail_urls.length > 0:\n → Slack notification: \"Redirect audit failed on {{redirect_fail_urls.count}} URLs — review dashboard\"\n 4. If all pass:\n → Email store owner: \"Pre-launch audit passed. Safe to flip DNS.\"","targetProduct":"Shopify"}]}
\n {% break %}\n {% endif %}\n{% endfor %}"}]},{"@type":"HowToStep","position":3,"name":"Historical Order Archive","text":"Stores your complete order history in a secure, queryable archive with original timestamps and customer data intact, accessible to your team without cluttering Shopify's native order interface. (Paste target: Postgres archive schema.)"},{"@type":"HowToStep","position":4,"name":"Pre-Launch SEO Audit","text":"Runs an automated crawl of your live legacy site, builds the redirect map, tests every 301 response, and flags broken or missing mappings before you cut over DNS. (Paste target: Shopify Flow editor: When → Then.)","itemListElement":[{"@type":"HowToDirection","text":"Trigger: Manual workflow start or scheduled daily at 2 AM\n\nCondition: Check if \"migration_stage\" metafield equals \"pre_launch\"\n\nActions:\n 1. Send HTTP request to Heroku crawl service:\n POST /crawl/validate-redirects\n Body: { legacy_domain: \"original-site.com\", shopify_domain: \"new-site.myshopify.com\" }\n 2. Wait for response; parse redirect_success_count and redirect_fail_urls\n 3. If redirect_fail_urls.length > 0:\n → Slack notification: \"Redirect audit failed on {{redirect_fail_urls.count}} URLs — review dashboard\"\n 4. If all pass:\n → Email store owner: \"Pre-launch audit passed. Safe to flip DNS.\""}]}]}
Brief · Anonymized case study
WooCommerce to Shopify Plus Migration
I'd approach this as a four-phase build: pull the product catalog and inventory via WooCommerce's REST API into Shopify using the Admin GraphQL, store the original WC product IDs as metafield references for traceability; build a URL router that intercepts old paths and serves proper 301 responses to preserve SEO signals; archive the full order history in a queryable Postgres schema outside Shopify (the Admin API has no archive layer); and run an automated pre-launch crawl that validates every redirect and flags breaks before you flip DNS. The merchant gets a clean inventory handoff, zero broken links, and a searchable record of every legacy transaction.
A mid-market DTC merchant with eight years of operational history on WooCommerce needed to migrate to Shopify Plus without losing SEO equity, breaking legacy URLs, or severing access to historical order records. The challenge combined technical scope—preserving 301 redirect chains at scale, importing orders with original timestamps, and maintaining inventory accuracy—with the business risk of downtime and organic traffic loss during cutover.
Four pieces
Migration
Product & Inventory Import
Pulls your product catalog, SKUs, pricing, inventory, and custom fields from the legacy platform into Shopify Plus, storing the original product IDs as reference data so you can trace any discrepancies later.
Custom Shopify app + Heroku backend
Admin GraphQL explorer
graphql
# Admin GraphQL — bulk product + metafield import
query GetProductsForImport($first: Int!) {
products(first: $first) {
edges {
node {
id
title
handle
productType
vendor
variants(first: 100) {
edges {
node {
id
sku
barcode
price
inventoryQuantity
}
}
}
metafields(first: 100, namespace: "wc_legacy") {
edges {
node {
id
namespace
key
value
}
}
}
}
}
pageInfo { hasNextPage endCursor }
}
}
mutation ImportProduct($input: ProductInput!) {
productCreate(input: $input) {
product {
id
title
handle
}
userErrors { field message }
}
}
Pair with a CSV or JSON export from the legacy REST API; use metafieldsSet to store original product IDs under a custom namespace for traceability.
Migration
URL Redirect Router
Maps every product, category, and page URL from your legacy platform to its new Shopify equivalent, serving 301 redirects that search engines recognize and preserving all backlink authority.
Shopify Plus theme extension + Heroku redirect service
theme/snippets/legacy-redirect-check.liquid
liquid
{% comment %}
Legacy URL redirect checker — intercept old URLs and 301 them to new Shopify ones.
Store redirect map in a JSON metafield on the store's settings.
{% endcomment %}
{% assign legacy_redirects = shop.metafields.migrations.url_map | parse_json %}
{% assign current_path = request.path | downcase %}
{% for mapping in legacy_redirects %}
{% if current_path == mapping.old_path %}
{% comment %} Match found; render 301 redirect {% endcomment %}
<meta http-equiv="refresh" content="0; url={{ mapping.new_url }}" />
<script>
if (navigator.userAgent.indexOf('Googlebot') !== -1 || navigator.userAgent.indexOf('bingbot') !== -1) {
window.location.href = '{{ mapping.new_url }}';
}
</script>
{% break %}
{% endif %}
{% endfor %}
For true HTTP 301 responses (not meta-refresh), use a Heroku middleware that intercepts requests and returns the proper status code; upload the redirect map as a Shopify metafield CSV.
Operations
Historical Order Archive
Stores your complete order history in a secure, queryable archive with original timestamps and customer data intact, accessible to your team without cluttering Shopify's native order interface.
Postgres database + custom admin dashboard
Migration
Pre-Launch SEO Audit
Runs an automated crawl of your live legacy site, builds the redirect map, tests every 301 response, and flags broken or missing mappings before you cut over DNS.
Crawl service + Heroku validation job
Shopify Flow editor: When → Then
flow
Trigger: Manual workflow start or scheduled daily at 2 AM
Condition: Check if "migration_stage" metafield equals "pre_launch"
Actions:
1. Send HTTP request to Heroku crawl service:
POST /crawl/validate-redirects
Body: { legacy_domain: "original-site.com", shopify_domain: "new-site.myshopify.com" }
2. Wait for response; parse redirect_success_count and redirect_fail_urls
3. If redirect_fail_urls.length > 0:
→ Slack notification: "Redirect audit failed on {{redirect_fail_urls.count}} URLs — review dashboard"
4. If all pass:
→ Email store owner: "Pre-launch audit passed. Safe to flip DNS."
Got a similar problem?
Sketch your build in 30 seconds — voice, type, or attach a screenshot.
Sketch the build →