Data Migration — Final Report
Sixteen years of catalog, customers and order history have been migrated from BigCommerce to Shopify, verified record-for-record against the source data, and every old web address redirected to its new home. This report accounts for everything that moved.
At a glance
| Phase | Scope | Status |
|---|---|---|
| 1 · Products | 745 products, 2,505 variants, 54 collections, 1,681 images | Complete & verified |
| 2 · Customers | 5,720 accounts, 3,634 addresses, marketing consent | Complete & verified |
| 3 · Orders | 6,277 orders, payments, refunds, 1,541 tracking numbers | Complete & verified |
| 4 · Catalog restructure | 745 listings consolidated to 192 shopper-facing products | Complete & verified |
| 5 · Redirects | 1,455 old web addresses mapped to their new pages | Complete & verified |
1 · Products
The complete catalog was migrated and checked item-for-item against BigCommerce. Products hidden on the old store arrived as drafts — nothing hidden went live, and nothing live went missing.
Catalog status in Shopify, mirroring the source store exactly.
How 745 products became 2,505 variants
| Step | Count |
|---|---|
| Products with a single version (no options) | 325 |
| Products with options (color, size, insert, …) | 420 |
| Option combinations those produce | 2,508 |
| Combinations discontinued in BigCommerce — excluded | −3 |
| Purchasable variants live in Shopify | 2,505 |
- Option pricing preserved. Per-color and per-size price adjustments are baked into each variant’s price — shoppers pay exactly what they did before. 144 products on sale kept their sale price with the original shown struck through.
- Largest product intact: a sampler product carrying all 729 type-and-color combinations imported without loss.
- 55 products with custom fields (measurements, personalization) had those fields carried across as structured data, ready to be shown on the new product pages.
- Store structure rebuilt: all 54 BigCommerce categories — three levels deep — exist as Shopify collections with 1,267 product placements, matching the old category assignments one-for-one.
- 1,681 images transferred: 1,388 gallery photos plus 293 color-swatch photos attached to the matching color variant, so picking a color changes the photo.
2 · Customers
Email marketing consent. 81.1% of customers had said yes to marketing email on BigCommerce. Their opt-in carried over exactly — nobody was subscribed who didn’t ask to be, and nobody who opted in was lost.
Where every record went
The export contained 5,728 rows. This is the full reconciliation down to the 5,720 live accounts — nothing is unaccounted for.
| Step | Change | Running total |
|---|---|---|
| Rows in the BigCommerce customer export | 5,728 | |
| BigCommerce’s built-in demo account removed (not a real customer) | −1 | 5,727 |
| Duplicate rows merged (4 customers appeared twice; profiles and addresses combined) | −4 | 5,723 |
| Same-person email variants merged (one account existed with and without a stray space) | −1 | 5,722 |
| Invalid email addresses — cannot be imported | −2 | 5,720 |
| Customer accounts live in Shopify | 5,720 |
Data cleaned up along the way
Fifteen years of store history accumulates noise. Rather than copy problems into the new store, we repaired what was safely fixable and filtered out what wasn’t.
| Phone numbers | Count | |
|---|---|---|
| Valid numbers migrated | 4,935 | |
| Shared / duplicate numbers | 392 | |
| Incomplete fragments | 178 | |
| Failed Shopify validation | 22 |
Shopify requires each phone number to belong to only one customer. Notably, 217 accounts shared a single placeholder number — a telltale sign of bot signups, common on older stores. Excluded numbers are logged and recoverable if ever needed.
- Addresses de-duplicated — 3,763 entries reduced to 3,634 unique ones (129 exact repeats removed, so no customer sees the same address twice at checkout).
- 3 accounts repaired and recovered — two email addresses with typos and one profile with spam text injected into the name, all fixed and imported.
- International addresses normalized — 39 countries represented, including military APO addresses and US territories, all mapped to Shopify’s format so tax and shipping calculate correctly.
- History preserved — every profile carries its original BigCommerce customer ID and join date (the earliest customers date to March 2010), which is what lets order history link to the right customer and makes “customer since” segments possible.
3 · Order history
Every order kept its original number, its original date, its payment and refund state, and its link to the customer who placed it. Past invoices and customer conversations still make sense.
| What was imported | Count |
|---|---|
| Orders paid | 6,197 |
| Orders with a fulfillment record | 5,875 |
| Refunds reproduced (full and partial) | 270 |
| Canceled orders | 329 |
| Declined / voided payments | 59 |
| Orders left awaiting payment (accurate — payment never completed) | 21 |
| Guest checkouts (no account) | 760 |
| Orders carrying a discount or coupon | 317 |
| Orders imported | 6,277 |
- Totals reconcile. 6,270 orders match BigCommerce to the cent. The remaining 7 differ only by the store credit applied at the time, which BigCommerce nets out of its own total — those are recorded in Shopify as a second payment, so the order reads correctly and nothing is left showing an unpaid balance.
- Line items: 4,049 order lines matched to live products and variants. A further 4,021 lines are for products deleted from the catalog over sixteen years — those are preserved on the order by name, SKU and price-at-time-of-sale, so the order history stays complete and accurate.
- Discounts recovered. BigCommerce does not export order discounts at all. We derived the exact discount on each order arithmetically (line totals + shipping + tax against the recorded order total, net of store credit and gift certificates) and applied it — 317 orders, all reconciling to the cent.
- Tracking preserved per parcel. Split shipments were imported as separate fulfillments, so an order that shipped in three boxes shows all three tracking numbers, exactly as the carrier recorded them.
- Silent by design. No confirmation emails, no shipping notifications, and no impact on live inventory. One order in sixteen years was marked “partially shipped” with no surviving record of which items shipped; it was imported as paid-but-unfulfilled rather than guessed at.
Verified scenario by scenario before the full run
Before importing 6,277 orders, we imported a deliberately difficult sample — one of every order type in the store’s history — and audited each against the source.
| Scenario tested | Year | Result |
|---|---|---|
| The store’s very first order | 2010 | Paid, fulfilled, tracked |
| Most recent shipped order | 2026 | Paid, fulfilled, tracked |
| Multi-item order with tracking | 2020 | Paid, fulfilled, tracked |
| Order with product options | 2011 | Paid, fulfilled, tracked |
| Guest checkout (no account) | 2020 | Paid, fulfilled, tracked |
| Early-era order (before tracking records) | 2010 | Paid, fulfilled |
| Fully refunded order | 2010 | Shows refunded |
| Partially refunded order | 2017 | Shows partially refunded |
| Canceled order | 2010 | Shows canceled |
| Declined payment | 2014 | Shows voided |
| Open order awaiting fulfillment | 2010 | Paid, awaiting fulfillment |
| Order paid partly with store credit | 2012 | Both payments recorded |
| Order with a coupon code | 2010 | Total correct, coupon noted |
| Order with sales tax | 2015 | Tax itemized, total exact |
| Order for a since-deleted product | 2010 | Item preserved by name & price |
| Largest order (7+ products) | 2010 | Every line item correct |
4 · Catalog restructure
With the migration verified, the catalog was restructured so that shoppers browse products rather than colors. 605 separate color listings became variants of 52 combined products, each with a color picker. The old listings are archived — hidden from shoppers, order history fully preserved, and every one redirected.
| What happened to the 745 listings | Count |
|---|---|
| Color listings combined into 52 products (photo, price, SKU and stock kept per color) | 605 |
| Already set up with color variants — untouched | 25 |
| One-of-a-kind products — no change | 97 |
| Kept as-is by design (made-to-measure items and the sampler) | 18 |
5 · 301 redirects
Every web address the old store ever published now lands on the right page in Shopify — BigCommerce-era paths, Shopify-era product handles, category pages, blog posts and the platform’s own system URLs. Search rankings and any link anyone has ever shared are protected.
| Redirect type | Count | |
|---|---|---|
| Product pages | 1,351 | |
| — of which land with the right color pre-selected | 1,176 | |
| Collection / category pages | 59 | |
| Blog and journal posts | 28 | |
| Content pages (about, contact, policies) | 10 | |
| Legacy platform system URLs (cart, login, account, search) | 7 | |
| Permanent redirects live | 1,455 |
- Old links keep working, with the color already chosen. A shopper or a search result following an old color-specific link lands on the combined product with that color selected and its photo showing — not on a generic page they have to navigate again.
- Second-level category paths included. Migration tools routinely redirect child categories under a flat address that the old store never actually served, which leaves those pages 404ing while the totals still appear to balance. Each redirect here was built from the address the old store genuinely published, then tested against the live domain.
- Tested, not just created. Redirects were confirmed in Shopify and spot-checked in a real browser: old links land on the new page, with the right color and photo.
- Delivered as a spreadsheet too — the full old-address to new-address map is handed over as a CSV for the client’s own records and for their SEO team.
What was preserved
How this was verified
- A full offline dry run before the live import. Every order was built exactly as the importer would build it, without writing anything, and validated: totals reconciliation, variant matching, shipment matching, country mapping, email validity, date parsing, status coverage. Issues were fixed and the dry run re-run until only source-data facts remained.
- A signed-off sample before scale. Twenty deliberately awkward records per phase — refunded, canceled, guest, multi-parcel, foreign currency, taxed, coupon, store-credit, deleted-product — imported and audited first.
- Query-back verification. After every import, records were read back out of Shopify and diffed against the source values: totals to the cent, tracking sets, consent states, outstanding balances.
- The live storefront as the source of truth for money. Where a platform’s own APIs and exports disagree with what its storefront actually charges, we take the storefront’s figure. This is what surfaced the hidden option pricing above.
- A reconciliation ledger for every phase — source rows in, exclusions itemized, live records out. Nothing is left unexplained.
Items for the client’s decision
A migration surfaces things only the business owner can settle. These are deliberately left undecided and presented as clear choices — a typical set is below.
