Migrating to CLAJAMA is ridiculously easy

Upload your Shopify CSV or WooCommerce XML. We normalize everything β€” variants, images, collections, customers. No mapping. No scripting. No data loss.

The old way vs. CLAJAMA

😰

Shopify / WooCommerce / Custom CSV

  • βœ—
    Denormalized CSV exports

    Each variant is a separate row. Good luck reconstructing products programmatically.

  • βœ—
    CDN-locked images

    Your product images are on Shopify's CDN with expiring URLs. Migration breaks them.

  • βœ—
    Proprietary API formats

    Each platform has a different REST API, auth scheme, and rate limiting.

  • βœ—
    No validation before import

    Upload β†’ hope it works. If it doesn't, you get a generic error with no way to fix it.

  • βœ—
    Lock-in to their ecosystem

    Once you're on their platform, moving your data out is painful by design.

⚑

CLAJAMA

  • βœ“
    Normalized schema

    Products with multiple variants collapse into one clean record. Slug, title, variants, images β€” all structured.

  • βœ“
    Auto image re-hosting

    We download Shopify CDN images to your local filesystem. No broken images after migration.

  • βœ“
    Adapter pattern β€” one interface

    Shopify, WooCommerce, custom CSV β€” all return the same Product/Variant schema. Swap sources in one line.

  • βœ“
    Validation with error reports

    Dry-run first. See exactly which products have issues (missing title, negative prices, no images). Fix, then import.

  • βœ“
    Open source β€” zero lock-in

    Your data is in a portable SQLite store. No proprietary formats. You own it.

How the pipeline works

The cleanest migration system you'll ever use. Three stages, zero surprises.

1

Extract

Upload your Shopify CSV. Our adapter handles the denormalized format β€” variant rows, option axes, image URLs, customer data. All in one pass.

# One adapter per source. Same output format.
adapter = ShopifyAdapter()
result = adapter.extract("products_export.csv")
2

Validate

Every product is checked: required fields, price integrity, SKU uniqueness, image presence. Errors block, warnings advise. Nothing slips through.

# Dry-run first to preview issues
result = Validator().validate(result)
# result.errors β†’ what's broken
# result.warnings β†’ what's advisory
# result.skipped β†’ how many were rejected
3

Store

Products land in a normalized SQLite store. The EcommercePlugin reads from this store β€” it never touches raw Shopify data. Swapping sources is a pipeline change, not a plugin change.

# Full import
python -m cli.migrate products.csv --from shopify

# Delta β€” only new products
python -m cli.migrate new_export.csv --from shopify --delta

# Adding WooCommerce to same store
python -m cli.migrate woo_export.xml --from woocommerce

Feature comparison

Shopify WooCommerce Custom CSV CLAJAMA
Export format Denormalized CSV WXR XML REST API JSON Single normalized schema
Image handling CDN URLs Attachment IDs CDN URLs Auto re-host to local
Multi-variant products 1 row per variant Variable products Variant objects Single record, variants array
Import validation None None None Dry-run + error reports
Delta imports Full re-export only Plugin required API-based Built-in delta tracking
Multi-source merge ❌ ❌ ❌ βœ… Import multiple sources
Data portability Locked in MySQL dump only Locked in Open SQLite + JSON
Cost to migrate out $$$ (apps + dev time) $$ (custom scripts) $$$ (API rate limits) $0 (open source)

Add a new source in ~30 minutes

The adapter pattern makes it trivial. Write one class, register one line:

# migration/adapters/custom_csv.py
class CustomCSVAdapter(AdapterBase):
    source_name = "custom"

    def extract(self, source, **kwargs) -> ImportResult:
        # Map any CSV columns to our schema
        products = self._parse_csv(source)
        # Only work is column mapping
        normalized = [self._to_product(row) for row in products]
        return ImportResult(products=normalized, ...)

# cli/migrate.py β€” one line to register
ADAPTERS["custom"] = CustomCSVAdapter

The ImportResult schema never changes. The Store never changes. The EcommercePlugin never changes. All migration work lives in the adapter.

Ready to migrate?

Upload your export, see what we catch, and get a clean store in minutes.