You just inherited a spreadsheet with 5,000 barcodes and almost nothing else—no titles, no specs, and definitely no images. Manually looking up each product, writing descriptions, and sourcing a clean packshot per SKU would take weeks and cost a fortune. Here's how to do the whole thing as a batch job in Node.js against a barcode API, and get output your marketplaces will actually accept.
What You'll Learn
- How to structure a resilient Node.js batch-enrichment job for thousands of SKUs
- How to turn a bare EAN/UPC into structured product data plus studio-quality images
- Why per-channel image rules (Amazon, Walmart, eBay, Shopify) make image production the hard part
- How to handle errors, retries, and rate limits at scale without babysitting the run
- Where to verify endpoints and pricing before you commit a large batch
Why 5,000 SKUs Is an Image Problem, Not Just a Data Problem
Metadata is the easy half. The part that stalls catalog teams is imagery. Current marketplace comparison guides note that a single listing often needs several asset types per SKU—a hero packshot, angle views, detail shots, and sometimes scale or packaging images—so enriching thousands of SKUs is really an image-production pipeline problem, not a lookup problem.
And the rules differ per channel. Amazon requires the main image to have a pure white background, be a JPEG with the longest side between 500 and 10,000 pixels, and have the product fill at least 85% of the frame. Walmart is commonly specified with a pure white background and a 2,000 × 2,000 px minimum under 5 MB. eBay guidance in current summaries points to a 1,600 × 1,600 px minimum JPEG under about 12 MB. Shopify is more forgiving—clean background, a 2,048 × 2,048 px recommendation, JPEG or WebP—but still size-sensitive. Google Merchant Center will require images of at least 500 × 500 pixels beginning January 31, 2027 and recommends around 1500 × 1500 or above.
Marketplace checks also reject main images with text, logos, watermarks, borders, promo stickers, or props. So even if you scrape a supplier image, you often need automated cleanup before you can list. That's why a pipeline that both finds structured data and generates clean, white-background studio images from a barcode saves the most time at scale.
SKU Monster is built for exactly this: give it a GTIN and it finds and generates five studio-quality, white-background product images plus structured specs and pricing. Compared with traditional product photography (roughly $250–$1,500 per SKU) or manual data entry, running it as a batch is dramatically cheaper and faster.
Step 1: Confirm the Endpoints and Get a Key
Before writing a loop that fires thousands of times, verify the shape of a single response. Try the free lookup on the home page at sku.monster, then read the API docs so you know the real routes.
The endpoints you'll use for a bulk enrichment job:
GET /api/v1/barcode?code=<ean>— look up product data by barcodePOST /api/v1/images— generate studio images for an identifierPOST /api/v1/batch— bulk-process many barcodesGET /api/v1/usage— track consumption during a run
All requests use the base https://sku.monster/api/v1 with an x-api-key header. Grab a key from register.
Step 2: A Single, Verified Lookup
Start with one barcode so you understand the response shape before scaling. Use a generic identifier while testing:
const BASE = "https://sku.monster/api/v1";
const KEY = process.env.SKU_MONSTER_KEY;
async function lookup(code) {
const res = await fetch(`${BASE}/barcode?code=${encodeURIComponent(code)}`, {
headers: { "x-api-key": KEY }
});
if (!res.ok) throw new Error(`lookup ${code} failed: ${res.status}`);
return res.json();
}
const data = await lookup("0000000000000");
console.log(data);
An illustrative response shape (yours will differ—check the docs for the authoritative schema) looks roughly like:
{
"identifier": "0000000000000",
"name": "...",
"brand": "...",
"category": "...",
"specs": { },
"images": [ ]
}
Treat that as a shape, not real data. The point is to map the fields you'll write into your catalog before you run 5,000 of them.
Step 3: The Batch Loop with Concurrency and Retries
Don't fire 5,000 requests in parallel—you'll hit rate limits and you'll lose track of failures. The reliable pattern is a bounded worker pool with retry-with-backoff. Check the rate limits page for the current concurrency guidance and set your pool size to match.
import fs from "node:fs";
const codes = fs.readFileSync("skus.txt", "utf8")
.split("\n").map(s => s.trim()).filter(Boolean);
const CONCURRENCY = 5; // align with the rate-limits doc
const results = [];
const failures = [];
async function withRetry(fn, tries = 4) {
let lastErr;
for (let i = 0; i < tries; i++) {
try { return await fn(); }
catch (err) {
lastErr = err;
// exponential backoff: 0.5s, 1s, 2s, 4s
await new Promise(r => setTimeout(r, 500 * 2 ** i));
}
}
throw lastErr;
}
async function worker(queue) {
while (queue.length) {
const code = queue.pop();
try {
const data = await withRetry(() => lookup(code));
results.push(data);
} catch (err) {
failures.push({ code, error: String(err) });
}
}
}
const queue = [...codes];
await Promise.all(
Array.from({ length: CONCURRENCY }, () => worker(queue))
);
fs.writeFileSync("enriched.json", JSON.stringify(results, null, 2));
fs.writeFileSync("failures.json", JSON.stringify(failures, null, 2));
console.log(`done: ${results.length} ok, ${failures.length} failed`);
Key habits for a large run: write results to disk as you go so a crash doesn't cost you the whole batch, keep a separate failures file so you can re-run only the misses, and poll GET /api/v1/usage if you want to log consumption as the job progresses.
If you'd rather not manage the pool yourself, POST /api/v1/batch exists to bulk-process many barcodes in one call—reach for it once you've validated the single-lookup path and confirmed the request format in the docs.
Step 4: Generating Studio Images Per SKU
Structured data alone won't clear marketplace image checks. To produce clean, white-background packshots, call POST /api/v1/images for each identifier as part of the same pipeline. Because each channel enforces different minimums—Amazon's 500–10,000 px longest side, Walmart's 2,000 × 2,000, eBay's 1,600 × 1,600, Shopify's 2,048 × 2,048 recommendation—generating a clean master image is the step that removes the most manual work.
One more channel-specific gotcha to handle downstream: Amazon's filename rules are strict. The file name must be the product identifier plus a variant code and the extension, using periods as separators; spaces, dashes, or extra characters can block the upload. Bake that naming convention into your export step so your generated assets upload without manual renaming.
Step 5: Validate Before You Publish
After the run, do a quick QA pass on a sample: confirm titles and specs look right, spot-check images for a pure white background with no stray text or props, and verify each channel's size requirements against that marketplace's current published guidelines—these change, so treat the numbers above as a starting point and re-check before a bulk upload. Then feed your enriched.json into your Shopify, Amazon, Walmart, or eBay import flow.
Summary
To batch-enrich SKUs with Node.js, verify a single barcode lookup first, then wrap GET /api/v1/barcode in a bounded worker pool with retry-and-backoff, persist results and failures separately, and generate clean images with POST /api/v1/images (or bulk-process via POST /api/v1/batch). The hard part of enriching 5,000 SKUs isn't the metadata—it's producing white-background, correctly-sized imagery each marketplace will accept. A barcode-driven pipeline that returns both structured data and studio images collapses weeks of lookup and photography into a single automated run.
Ready to Try It?
Start with the free lookup, then grab an API key and enrich your first batch: register at sku.monster.