Migrating JellyBean Tanning from Wix to Shopify Without Losing a Single Order

JellyBean Tanning is a self-tan brand that outgrew Wix. The new Shopify storefront was the visible part of the project. The harder part was moving its customer accounts and full order history across without losing anything, double-importing anything, or emailing and charging anyone by accident.

This is how we built that migration: a small, purpose-built Node tool, a dry-run-first process, and an independent verification step after every batch.

Why we built a tool instead of using an app

Off-the-shelf migration apps work well for simple catalogs. JellyBean's history was not simple. Orders carried custom sachet lines, discount combinations, partial and full refunds, and customers whose account details differed from the person the parcel was shipped to.

We needed full control over how every one of those cases was mapped, and we needed proof afterwards that each record arrived correctly. So we wrote our own: roughly 2,100 lines of JavaScript across 14 focused modules covering Wix exports, CSV parsing, SKU mapping, Shopify imports and verification.

Two rules shaped the design from day one:

  • Wix stays read-only. The tool never writes back to the old store, so the source of truth can't be damaged mid-migration.
  • Shopify writes are opt-in. Every command runs as a dry run unless an explicit write switch is passed, so a typo can't turn an audit into an import.

The Pipeline

Every run moves through the same stages: export, normalize, map, audit, import and verify.

If the dry-run audit finds anything the mapping can't handle, we fix the mapping and run the audit again. Nothing is written to Shopify until the audit comes back clean.

Each stage saves a receipt, so any batch can be traced from the original Wix record to the Shopify object it became.

Six-step Wix to Shopify migration: export, clean, map, dry run, import, verify.

Cleaning the data before it moves

Customer exports rarely arrive clean. Before anything was imported, the tool prepared every customer record with names, emails, phones, addresses, tags and marketing consent, then:

  • Deduplicated customers and their addresses, so the same person didn't arrive as several accounts.
  • Normalized UK phone numbers into a format Shopify accepts consistently.
  • Kept the account holder separate from the billing and shipping recipient. Gifts and work addresses are common in beauty, and merging the two would have quietly rewritten customer profiles.
  • Reported errors per record instead of failing the whole batch, so one malformed row never blocked the rest.

Products were matched to Shopify variants by SKU. Any order line whose SKU didn't resolve was flagged in the audit rather than guessed.

Imports That Can't Double-Write

Migrations rarely finish in one clean run. Rate limits, network blips and late-arriving orders all mean you'll run the same batch more than once.

Every imported order is keyed by its original Wix order ID in a persistent ID map. Before creating anything, the tool checks the map: if the order already exists, it's logged and skipped. That's how we caught an order that had already been imported during a delta run, instead of creating a duplicate.

Writes use retry handling and pacing to stay inside Shopify's API limits, and the ID maps make every batch resumable from where it stopped.

Each order is checked against its original Wix ID: skipped if already imported, otherwise created, with no emails, charges or stock changes.

Dry runs catch what imports would hide

Before the final cutover batch, we ran full dry-run audits against the latest Wix data. They surfaced four problem types that would otherwise have ended up as silently wrong orders:

  1. Refund statuses with no direct Shopify equivalent.
  2. Custom sachet lines that didn't correspond to a catalog product.
  3. Discounts that needed to be represented on the order, not just reflected in the total.
  4. SKU mismatches between historical orders and the current catalog.

Each one got an explicit mapping rule. Then the audit ran again, and only a clean audit unlocked the import.

Reconciling payments without charging anyone

Historical orders need a payment history that matches reality, but you never want a migration to charge or refund a real card. The tool records past payments and refunds as historical transactions only, with no payment capture and no refund issued.

We then audited the previously imported history against Wix payment and refund records. Most orders matched automatically. Every exception, whether a missing payment, an unrecorded refund or an incorrect total, was repaired and then independently checked against Wix totals, received amounts and refunds.

What survived the move

For the final batch, every order was independently verified with zero duplicates and zero unresolved errors. Each order kept:

  • Its original order number and date.
  • Prices, quantities, product options and discounts.
  • VAT, shipping, the customer link and fulfillment state.
  • Tracking details and merchant comments.

The tool also stored complete Wix order, payment, refund, activity and fulfillment snapshots in Shopify metadata. Where Shopify assigns its own import-time timestamps, for example for cancellations, the original Wix timestamps live in that metadata.

During the import, customer notifications were switched off and inventory adjustments were disabled. Afterwards we checked that linked variants kept their stock levels and archived status exactly as before.

Storefront Work Alongside the Move

While the data moved, we shipped the storefront changes the new store needed:

  • Product composition callout images driven by metafields, so the team can edit them without a developer.
  • Free-shipping and free-gift progress messages that follow the configured thresholds.
  • Cart refreshes when discount codes change, and duplicate discount badges filtered out, including B2B pricing.
  • Long discount labels that no longer overlap product information in the cart.
  • Corrected Swedish currency formatting for international shoppers.
JellyBean Tanning product page on Shopify showing the Intensifying Tanning Cream with scent variants and discounted price.

29,500+

Theme lines changed across Liquid, JavaScript and CSS.

130

Theme files touched to support the new storefront.

2,100+

Lines in the purpose-built Node migration tool.

Making Third-Party Apps Play Nicely

JellyBean relies on live chat, a loyalty program and a bundle builder. Each of these injects its own UI, and together they competed for the same corners of the screen.

  • The cart drawer now stacks above the chat and loyalty launchers instead of sitting behind them.
  • Launcher sizes are consistent on desktop and mobile.
  • Chat is hidden on the bundle-builder routes, where it covered key controls.
  • The mobile social-video carousel and the desktop FAQ tabs were realigned.
JellyBean Tanning collection page on Shopify showing tanning cream products and a build-your-own-bundle promotion.

What we'd tell anyone planning a Wix to Shopify migration

  1. Treat the old platform as read-only. Your rollback plan depends on it.
  2. Make writes opt-in. Dry runs should be the default, not a flag you have to remember.
  3. Key everything by the original ID. Idempotent imports turn reruns from a risk into routine.
  4. Audit before you import. Every edge case found in a dry run is one you won't be cleaning up by hand later.
  5. Verify independently. Check totals, refunds and links against the source after import, using separate checks from the ones that did the import.
  6. Switch side effects off. Notifications, payments and inventory should never fire for historical data.

Planning a replatform of your own? See the full JellyBean Tanning case study, or talk to us about your migration.

Technical Deep DiveSpell&Sell
Spell&Sell
  • Zero Duplicate Orders
  • Every Batch Verified
6 min read