How to Import a Supplier Product Catalog Into Shopify or WooCommerce (Without Manually Typing Anything)
You just signed a deal with a new supplier. They send you a spreadsheet — 350 rows, each one a product with a UPC code, maybe a stock quantity, maybe a cost price. That is it.
No titles. No descriptions. No images. Just barcodes and prices.
This is a real scenario that every reseller, wholesale buyer, and dropshipper faces. And there is a right way to handle it that takes a few hours instead of a few weeks.
This guide walks through the complete workflow: taking a raw supplier CSV and turning it into a fully populated Shopify or WooCommerce product catalog.
What You Typically Get From a Supplier
Supplier product data quality varies enormously:
Best case (rare): Full product data CSV with titles, descriptions, images, weights, categories. Often called an "EDIXML feed" or "product data feed." Major brands and distributors have these.
Common case: SKU list with UPC/EAN, quantity, cost. Some have product names that are often abbreviated or incorrect. No images.
Worst case: A PDF price list. You have to manually type everything.
This guide focuses on the common case: you have UPCs, and you need everything else.
The Three-Step Process
Step 1: Enrich — Turn Barcodes Into Product Data
Step 2: Format — Convert to Shopify or WooCommerce Import Format
Step 3: Import — Bulk upload to your store
Step 1: Enrich Your Supplier Data With Barcode Lookup
Every barcode (UPC, EAN, or GTIN) maps to a global product record. Product data APIs maintain databases of these records, built from manufacturer feeds, GS1 data, and retailer catalog data.
Here is a Python script that takes your supplier CSV and enriches each row:
import csv
import json
import requests
import time
SKUMONSTER_KEY = "your-api-key"
def lookup_product(upc):
"""Retrieve product data from SkuMonster API."""
try:
resp = requests.get(
f"https://api.sku.monster/v1/product/{upc}",
headers={"x-api-key": SKUMONSTER_KEY},
timeout=10
)
if resp.status_code == 200:
return resp.json()
except Exception as e:
print(f"Error looking up {upc}: {e}")
return None
# Read your supplier CSV
enriched = []
not_found = []
with open("supplier_catalog.csv") as f:
reader = csv.DictReader(f)
for row in reader:
upc = row.get("upc") or row.get("barcode") or row.get("UPC")
if not upc:
continue
product = lookup_product(upc)
if product:
enriched.append({
"upc": upc,
"supplier_sku": row.get("sku", ""),
"cost": row.get("cost", ""),
"qty": row.get("qty", row.get("quantity", "")),
# Enriched fields from API
"title": product.get("title", ""),
"brand": product.get("brand", ""),
"description": product.get("description", ""),
"category": product.get("category", ""),
"weight": product.get("weight", ""),
"images": "|".join(product.get("images", [])[:3]),
})
else:
not_found.append(row)
print(f"Not found: {upc}")
time.sleep(0.1) # Be polite to the API
print(f"Enriched: {len(enriched)} products")
print(f"Not found: {len(not_found)} products")
What happens to "not found" products?
Coverage varies by API. SkuMonster covers 2.4M+ products — strong for US consumer goods, but you may find gaps in:
- Very niche industrial products
- Private-label or store-brand items
- Regional food and beverage products
- Products released in the last 30–90 days
For not-found products, your options are:
- Request product data directly from the supplier
- Manually enter the data (at least you know which ones need attention)
- Use a web scraper to find product data on Amazon or the brand's website
- Skip them for now and add later
Step 2a: Format for Shopify
Shopify's bulk import uses a specific CSV format. Here is how to generate it from your enriched data:
import csv
SHOPIFY_HEADERS = [
"Handle", "Title", "Body (HTML)", "Vendor", "Type",
"Tags", "Published", "Variant SKU", "Variant Barcode",
"Variant Price", "Variant Compare At Price",
"Variant Inventory Qty", "Variant Weight Unit",
"Image Src", "Image Position"
]
def to_shopify_row(product):
# Handle = URL slug from title
handle = product["title"].lower().replace(" ", "-")[:50]
return {
"Handle": handle,
"Title": product["title"],
"Body (HTML)": product["description"],
"Vendor": product["brand"],
"Type": product.get("category", "").split(">")[-1].strip(),
"Tags": product["brand"].lower(),
"Published": "TRUE",
"Variant SKU": product.get("supplier_sku") or product["upc"],
"Variant Barcode": product["upc"],
"Variant Price": product.get("cost", ""),
"Variant Compare At Price": "",
"Variant Inventory Qty": product.get("qty", "0"),
"Variant Weight Unit": "kg",
"Image Src": product["images"].split("|")[0] if product["images"] else "",
"Image Position": "1",
}
with open("shopify_import.csv", "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=SHOPIFY_HEADERS)
writer.writeheader()
for product in enriched:
writer.writerow(to_shopify_row(product))
print("Shopify CSV written to shopify_import.csv")
Importing into Shopify
- Go to Products in Shopify admin
- Click Import (top right)
- Upload your
shopify_import.csv - Shopify previews the first few rows — verify titles and prices look correct
- Click Import products
Large imports (1,000+ products) may take 10–30 minutes.
Note on images: Shopify downloads images from the URL in Image Src. Make sure these URLs are publicly accessible (no authentication required). URLs from a product data API are always publicly accessible.
Step 2b: Format for WooCommerce
WooCommerce uses a slightly different CSV format. Here is the equivalent:
WOOCOMMERCE_HEADERS = [
"ID", "Type", "SKU", "Name", "Published",
"Short description", "Description", "Categories",
"Regular price", "Stock quantity", "Backorders allowed",
"Weight (kg)", "Images", "Brands", "Tags"
]
def to_woocommerce_row(product):
return {
"ID": "", # Empty = new product
"Type": "simple",
"SKU": product.get("supplier_sku") or product["upc"],
"Name": product["title"],
"Published": "1",
"Short description": product["description"][:200] if product["description"] else "",
"Description": product["description"],
"Categories": product.get("category", ""),
"Regular price": product.get("cost", ""),
"Stock quantity": product.get("qty", ""),
"Backorders allowed": "0",
"Weight (kg)": product.get("weight", "").replace("g", "").strip(),
"Images": product["images"].replace("|", ", "),
"Brands": product.get("brand", ""),
"Tags": "",
}
with open("woocommerce_import.csv", "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=WOOCOMMERCE_HEADERS)
writer.writeheader()
for product in enriched:
writer.writerow(to_woocommerce_row(product))
print("WooCommerce CSV written to woocommerce_import.csv")
Importing into WooCommerce
- Go to Products > All Products in WordPress admin
- Click Import (top)
- Upload
woocommerce_import.csv - Map columns to WooCommerce fields (they usually auto-map correctly)
- Click Run the Importer
For large imports, increase your PHP max_execution_time and memory_limit first (edit wp-config.php or php.ini).
Step 3: Post-Import Checklist
After bulk import, do a quick quality check before making products live:
Check 5 random products:
- Title is accurate and not truncated
- Description is readable and not full of HTML artifacts
- Main image loads correctly (not a broken link)
- Price is correct (check cost vs. retail markup)
- Category is assigned correctly
- SKU/barcode field is populated
Common issues to fix:
- Encoding problems in titles (Unicode characters from descriptions)
- Images that are too small for the platform's requirements
- Descriptions with escaped HTML characters (& instead of &)
- Prices that need a markup applied (if you imported cost price)
Setting Your Retail Price
Your supplier CSV has cost prices. Your store needs retail prices. Quick markup formulas:
| Margin Target | Markup Formula | Example ($10 cost) |
|---|---|---|
| 30% margin | price = cost / 0.70 | $14.29 |
| 40% margin | price = cost / 0.60 | $16.67 |
| 50% margin | price = cost / 0.50 | $20.00 |
| 2.5x keystone | price = cost * 2.5 | $25.00 |
Add this to the enrichment script:
MARGIN = 0.40 # 40% margin target
def calculate_price(cost_str):
try:
cost = float(cost_str.replace("$", "").strip())
retail = round(cost / (1 - MARGIN), 2)
return str(retail)
except:
return ""
Handling Products Without Barcode Coverage
For the products where the API returned no results, here is a prioritization approach:
High-velocity SKUs (top 20% of your catalog): Worth manual entry or requesting data from supplier. These drive most of your revenue.
Mid-tier SKUs: Use AI (ChatGPT, Claude) to write product descriptions from a product name and partial data. Not perfect but functional.
Long-tail SKUs: Import with minimal data, set to draft. Update over time as you have capacity.
What to Do If the Supplier Sends New SKUs Monthly
Most supplier relationships involve regular catalog updates — new products, discontinued items, price changes. Automate this:
- Set up a recurring script that runs weekly
- It downloads the new supplier CSV (or processes an email attachment)
- Enriches new UPCs via API
- Creates new products in Shopify/WooCommerce via API (not CSV — use REST API for automated runs)
- Updates prices on existing products
- Flags discontinued products for manual review
This turns a monthly 8-hour manual task into a 15-minute automated process.
Conclusion
Importing a supplier catalog does not have to mean manual data entry. The workflow is:
- Enrich: Look up each UPC/EAN via product data API → get title, description, images
- Format: Convert to Shopify or WooCommerce CSV format
- Import: Bulk upload to your store
For a 300-SKU supplier catalog, the full process takes 2–4 hours including setup. For subsequent imports, under 30 minutes.
SkuMonster handles Step 1. Pass your supplier's UPCs to the API and get back structured product data — titles, descriptions, images, weights, brands, categories — ready to pipe directly into your Shopify or WooCommerce import CSV. Try your first 100 lookups free at sku.monster.
Ready to Try SKU Monster?
If you're managing product data at scale — whether you're on Amazon, Shopify, eBay, or WooCommerce — SKU Monster gives you structured titles, descriptions, images, and pricing for any EAN, UPC, or ASIN in seconds.
No manual entry. No scraping. Just clean product data via API.