This guide is for teams planning a WooCommerce to Shopify migration who need to decide what happens to years of order history, not just move products and a theme. It's not for a plugin-by-plugin walkthrough, or stores where WordPress itself is staying and only checkout is changing.
A WooCommerce to Shopify migration usually gets scoped as a products-and-theme project. The part that decides whether the new store trades cleanly, keeps its search visibility, and doesn't flood your staff's inbox with years-old order confirmations is the order history: what belongs in Shopify as a live order, and what belongs in an archive you can query but never touch again. This guide covers the whole migration, but spends the most time there, because it's the part most tool-led checklists skip.
WooCommerce runs on WordPress, so for most stores a WordPress to Shopify migration and a WooCommerce to Shopify migration are the same project: the shop moves to Shopify, and the blog and marketing pages either move with it or stay on WordPress as a separate property. Either way, the decisions below apply.
What actually moves in a WooCommerce to Shopify migration, and how
Not everything crosses the same way. Some data has a built-in path, some needs an app, and some needs custom API work.
| What | How it moves | What gets lost or needs rework |
|---|---|---|
| Products and variants | Store Migration app (CSV or a direct connection) | Attribute combinations that don't map onto Shopify's option model need restructuring by hand |
| Customers | Store Migration app or CSV | Passwords never come across, from any platform |
| Historical orders | Migration app, or the Order and Transaction APIs | Not part of the built-in importer; its own workstream |
| Product reviews | A review app's own import tool | Depends on which review plugin you used and whether the destination app supports it |
| WordPress pages and blog posts | Manual move or a migration app, or they stay on WordPress | Nothing moves if the blog stays on WordPress; otherwise every post gets a new /blogs/ URL and needs a redirect |
| Gift cards | Migration app or the GiftCard API | Codes and remaining balances need reconciling against WooCommerce at cutover |
The Store Migration app supports Square, WooCommerce, Etsy, Wix, Amazon, eBay, Clover, and Lightspeed sources, but products and customers only. Historical orders are where most of the engineering work actually sits when you migrate to Shopify.
Decide what order history belongs in Shopify
The default assumption on most projects is that every order ever placed has to land inside Shopify. Question that before you commit to it, and walk through what order history is actually for once the new store is live.
Open and recent orders are operational data. They still get fulfilled, refunded, exchanged, or looked up by a support agent this week. That has to live inside Shopify, behaving like a normal order.
Orders older than your return and warranty window stop being operational and become reference data. Finance needs them at tax time; support needs to find one occasionally when a customer writes in about a years-old purchase. Nobody is fulfilling that order again, or needs it to look like a live Shopify order to get value from it.
We recommend importing the operational window, plus anything still inside a return or warranty period, as real Shopify orders. Everything older goes into a read-only archive instead: an export of the original order data, kept somewhere finance and support can query without Shopify access. That's a decision to make on purpose, not the path of least resistance. If a compliance obligation genuinely requires every order inside Shopify, import all of it, but say so deliberately, because importing everything through the Admin API carries a real cost.
In a migration audit, we map every product, customer, order, and URL before anything moves. Draw the order-history line explicitly at that stage, because "migrate everything" is rarely a written requirement once someone asks what the old orders are for.
Importing orders through the Shopify Admin API
The REST Admin API still works, but Shopify has been moving away from it: REST became a legacy API on October 1, 2024, and starting April 1, 2025, new public apps must be built exclusively on the GraphQL Admin API. Build the order import against GraphQL's orderCreate mutation instead. The rate limits favor it too: GraphQL restores 100 points a second on standard plans, 200 on Advanced, and 1,000 on Shopify Plus, against REST's flat 2 requests a second with a 40-request bucket (20 a second and 400 on Plus). Either way, build in throttling and backoff from the first request, not after you hit the ceiling.
One more constraint to plan around early: on a development or trial store, orderCreate is capped at 5 new orders a minute, which rules out a full rehearsal of years of history there. Run a representative sample on the dev store, fix what it reveals, then run the complete import against the paid store, with enough runway before launch.
orderCreate takes an order input and an options input. Get the options right first, because they control what your customers and staff experience during the import, not just the data:
sendReceiptandsendFulfillmentReceiptboth default tofalse, andinventoryBehaviourdefaults toBYPASS, so creating historical orders through the API doesn't, by itself, email customers or touch inventory. Set all three explicitly anyway: migration apps that wrap the Admin API sometimes apply their own defaults.- The real notification risk is your own team. Shopify's guidance on migrating historical orders is direct about this: any staff member with new-order notifications turned on gets an email for every order you import. Turn those off before the first real run, and back on once it finishes.
The order fields that matter most for historical data:
processedAtis, in Shopify's own words, "the date that appears on your orders and that's used in the analytic reports." Leave it out and years of history collapse onto import day, with a revenue spike on day one that never happened.financialStatus, if not specified, "will be derived through the given transactions." For orders already paid in full, set it toPAIDdirectly.fulfillmentStatusdefaults tounfulfilledif omitted, so orders already sent needFULFILLEDset explicitly, or they show up as open work.sourceIdentifieris "the ID of the order placed on the originating platform." Put the WooCommerce order ID there, and also in a tag so support can search for it, since Shopify's own sequential order names won't match what your team remembers.- Products that no longer exist become custom line items: a title and a price, no variant reference.
- Tax lines are set explicitly, not left for Shopify to recompute.
orderCreatesupports one discount code per order; stacked coupons need the extra discount folded into the line price, or recorded in a note instead.
A minimal, verified shape looks like this. Every field below is checked against Shopify's orderCreate reference and its linked input objects; nothing here is guessed.
mutation ImportHistoricalOrder(
$order: OrderCreateOrderInput!
$options: OrderCreateOptionsInput
) {
orderCreate(order: $order, options: $options) {
order {
id
name
}
userErrors {
field
message
}
}
}
{
"order": {
"email": "customer@example.com",
"sourceIdentifier": "wc-48213",
"processedAt": "2021-03-14T10:32:00Z",
"financialStatus": "PAID",
"fulfillmentStatus": "FULFILLED",
"note": "Imported from WooCommerce order 48213",
"tags": ["woocommerce-import"],
"customAttributes": [
{ "key": "woocommerce_order_id", "value": "48213" }
],
"lineItems": [
{
"title": "Discontinued item, Widget Pro",
"quantity": 1,
"taxable": true,
"priceSet": {
"shopMoney": { "amount": "42.00", "currencyCode": "USD" }
}
}
],
"transactions": [
{
"kind": "SALE",
"status": "SUCCESS",
"gateway": "woocommerce_import",
"test": false,
"amountSet": {
"shopMoney": { "amount": "42.00", "currencyCode": "USD" }
}
}
]
},
"options": {
"sendReceipt": false,
"sendFulfillmentReceipt": false,
"inventoryBehaviour": "BYPASS"
}
}
Build the import so a failure halfway doesn't duplicate orders
Treat the import as something that will fail partway through: a rate limit trips, one row has malformed data from a plugin the store stopped using years ago, a connection drops. The question isn't whether that happens, it's whether you can re-run the job without creating every order twice.
orderCreate won't protect you here, so the safety has to live in your own import code. Keep a ledger mapping each WooCommerce order ID to the Shopify order ID it produced, and check it before every create call. Already recorded? Skip it. Not there yet? Create it, then record the result. That turns a mid-import failure into a resumable job instead of a cleanup exercise.
-- Illustrative schema for a re-runnable import ledger, not a migration to run as-is
CREATE TABLE order_import_ledger (
woocommerce_order_id TEXT PRIMARY KEY,
shopify_order_id TEXT,
shopify_order_name TEXT,
imported_at TIMESTAMPTZ,
status TEXT NOT NULL DEFAULT 'pending', -- pending, done, or failed
last_error TEXT
);
Customers, passwords, and de-duplication
Import customers before orders, so each order attaches to an existing customer by email instead of creating a new one. Before that import, de-duplicate on email: the same person with a different email case, or a stray trailing space, creates two customer records and splits their history across both.
Passwords can't be migrated from any platform, WooCommerce included. Plan for account-invite emails rather than assuming customers can log in with their old credentials on day one, and warn the team fielding "I can't log in" messages in the first week.
Redirects and SEO for the storefront move
WooCommerce and Shopify structure URLs differently, and this is where a WooCommerce migration loses search visibility if nobody plans for it. WooCommerce's defaults are /product/<slug>/, /product-category/<slug>/, and /shop/. Shopify uses fixed paths: /products/<handle>, /collections/<handle>, /pages/<handle>, and /blogs/<blog-handle>/<article-handle>.
Every old URL that has earned search visibility needs a 301 to its new equivalent. Shopify URL redirects can be bulk-imported by CSV, so build the redirect map as a spreadsheet once you have the full list of old URLs, rather than writing redirects one at a time as broken links turn up after launch. WordPress permalinks vary by site settings, so export the actual URL list rather than assuming a pattern. Our WordPress migration checklist covers the redirect decision map and launch QA process in more depth.
From plugins to apps, and the storefront rebuild
The data migration and the storefront rebuild are separate workstreams; treating them as one is how timelines slip. Theme selection, Liquid or headless Hydrogen, is its own decision; we cover choosing between Liquid and Hydrogen separately, and what a Shopify development engagement includes once you're past the data.
Plan for the plugin-to-app translation too. Some free-plugin functionality has a paid app equivalent on Shopify, and that ongoing cost belongs in your comparison, not as a surprise after launch. Our Shopify development work covers this translation as part of the rebuild.
Cutover: keep trading while you migrate
The old store keeps trading while you build and test the new one; nothing here requires taking WooCommerce offline early. At cutover, run a final delta sync of orders and customers placed since your last test migration, switch DNS, and put the redirect map live in the same window. Then monitor Search Console, watch for unexpected 404s against your old URL list, and confirm orders are actually completing on the new checkout, not just that the storefront renders.
If this needs a second set of hands, our Shopify migration team runs this sequence end to end.
When you shouldn't move from WooCommerce to Shopify
A WooCommerce to Shopify migration is the right call often enough that it's easy to assume it always is. It isn't.
If the shop is a small side feature on a content-led WordPress site, and most traffic and value comes from articles or lead generation, a full replatform is a lot of risk for a small part of the business. Keeping WooCommerce, or scoping a smaller checkout fix, is often the better use of budget.
If your checkout or pricing logic does something Shopify's standard checkout can't express, such as conditional shipping rules or a checkout that branches on custom business logic, you may need Shopify Plus or a custom app. Confirm that's genuinely on the table before committing, not partway through building it.
Teams that need direct database access to their order data, for a data warehouse or a finance system that queries orders directly, lose that with Shopify. Everything goes through the API instead, a real change for whoever runs SQL against the WooCommerce database today.
And the ongoing cost is real. Some free-plugin functionality becomes a paid app subscription on Shopify, and Shopify also charges an additional transaction fee on most plans for a third-party payment gateway instead of Shopify Payments. Add both up before you commit.
Frequently Asked Questions
Can you migrate order history from WooCommerce to Shopify?
Yes, but not through Shopify's built-in store importer, which handles products and customers only. Historical orders come in through a migration app, or through the Order and Transaction APIs. Decide first which orders need to be live versus archived, since that determines how much API work the import needs.
Will I lose my Google rankings when I move from WooCommerce to Shopify?
Not if the URL change is handled deliberately. WooCommerce and Shopify use different URL patterns, so every page with search visibility needs a 301 to its Shopify equivalent. Skipping the redirect map, or guessing at the old structure instead of exporting it, is what causes ranking loss.
Can customers keep their passwords?
No. Passwords can't be migrated from any platform to Shopify, WooCommerce included. Plan for account-invite emails, and expect some "I can't log in" support volume in the first week.
Should I keep WordPress for my blog?
It depends how much of your traffic and lead generation comes through content versus the shop. Keeping WordPress as a separate property is common and avoids rebuilding editorial workflows, but means managing two systems with their own redirect plan. Moving the blog into Shopify keeps everything in one system, at the cost of less flexible blogging tools.
How long does a WooCommerce to Shopify migration take?
A straightforward migration with a standard theme usually takes 4 to 6 weeks. Larger catalogs, full order history, custom integrations, or a bespoke theme push that to 8 to 12 weeks. The order-history decision covered earlier is one of the biggest levers on where a project lands in that range.
Do I need to take my store offline?
No. WooCommerce can keep trading normally while the new Shopify store is built and tested. Most stores only need a short cutover window for the final delta sync, switching DNS, and putting the redirect map live.
What happens to my product reviews?
Reviews aren't part of Shopify's built-in migration path. They move through whichever review app you choose, using that app's own import tool, and what transfers depends on which WooCommerce review plugin generated the original data.
Does Shopify import my old order numbers?
Not by default. Imported orders get Shopify's own sequential order names, so they won't match the WooCommerce order numbers your team and customers remember. Store the original order ID in the order's source identifier and in a tag, so support and finance can still search for it.
If you're planning a WooCommerce to Shopify migration and want a second set of eyes on the order-history decision before you commit to an import approach, our Shopify migration team can walk through the audit, or you can get in touch directly.



