← back to Interiordesignershowroom
Scaled CJ catalog ingest (48 categories, image-required) -> 2697 real products/27 brands incl. appliances; idempotent, swaps in tracked links as advertisers activate
365ba46f74dbaf1947fef00d776c534d980f6e85 · 2026-08-01 20:14:50 -0700 · Steve Abrams
Files touched
A scripts/ingest-cj-catalog.js
Diff
commit 365ba46f74dbaf1947fef00d776c534d980f6e85
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Sat Aug 1 20:14:50 2026 -0700
Scaled CJ catalog ingest (48 categories, image-required) -> 2697 real products/27 brands incl. appliances; idempotent, swaps in tracked links as advertisers activate
---
scripts/ingest-cj-catalog.js | 56 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 56 insertions(+)
diff --git a/scripts/ingest-cj-catalog.js b/scripts/ingest-cj-catalog.js
new file mode 100644
index 0000000..1517a11
--- /dev/null
+++ b/scripts/ingest-cj-catalog.js
@@ -0,0 +1,56 @@
+// Scaled CJ catalog ingest for the Room Builder. Pulls a broad, image-required
+// set across furniture / lighting / rugs / decor / appliances, normalizes, and
+// UPSERTs into products. Idempotent (network+external_id key) so re-runs refresh
+// prices AND swap in tracked links as advertisers get joined in CJ.
+//
+// Usage: node scripts/ingest-cj-catalog.js [--per=60] [--only=sofa,desk]
+try { require('dotenv').config(); } catch (_) {}
+const db = require('../lib/db');
+const cj = require('../lib/adapters/cj');
+const { normalizeProduct, UPSERT_SQL, upsertParams } = require('../lib/normalize');
+
+const arg = (n, d) => { const h = process.argv.find(a => a.startsWith(`--${n}=`)); return h ? h.split('=')[1] : d; };
+const sleep = ms => new Promise(r => setTimeout(r, ms));
+
+// Category -> search keyword. Broad home-furnishing coverage + appliances.
+const CATEGORIES = [
+ 'sofa', 'sectional sofa', 'loveseat', 'accent chair', 'recliner', 'ottoman',
+ 'coffee table', 'console table', 'side table', 'media console', 'tv stand',
+ 'office chair', 'ergonomic office chair', 'standing desk', 'writing desk', 'bookcase',
+ 'bed frame', 'upholstered headboard', 'nightstand', 'dresser', 'wardrobe',
+ 'dining table', 'dining chair', 'bar stool', 'counter stool', 'sideboard buffet', 'bar cart',
+ 'area rug', 'runner rug', 'floor lamp', 'table lamp', 'pendant light', 'chandelier', 'wall sconce',
+ 'wall mirror', 'framed wall art', 'decorative vase', 'throw pillow', 'throw blanket', 'wall clock',
+ 'planter', 'bookshelf', 'bench', 'vitamix blender', 'stand mixer', 'espresso machine', 'air purifier',
+];
+
+async function main() {
+ await db.query('SELECT 1');
+ if (!cj.enabled(process.env)) { console.error('CJ not configured (need CJ_TOKEN/CJ_COMPANY_ID/CJ_WEBSITE_ID)'); process.exit(1); }
+ const per = parseInt(arg('per', '60'), 10);
+ const only = (arg('only', '') || '').split(',').filter(Boolean);
+ const cats = only.length ? CATEGORIES.filter(c => only.some(o => c.includes(o))) : CATEGORIES;
+
+ let total = 0, withImg = 0, tracked = 0;
+ for (const cat of cats) {
+ let raws = [];
+ try { raws = await cj.fetch(process.env, { limit: per, keywords: cat }); }
+ catch (e) { console.log(` ${cat}: ERROR ${e.message}`); continue; }
+ let ok = 0;
+ for (const raw of raws) {
+ if (!raw.image_url) continue; // Room Builder needs images
+ withImg++;
+ if (/cj\.com|dpbolvw|anrdoezrs|kqzyfj|tkqlhce|jdoqocy/.test(raw.affiliate_url || '')) tracked++;
+ const norm = normalizeProduct(raw, 'cj');
+ if (!norm) continue;
+ try { await db.query(UPSERT_SQL, upsertParams(norm)); ok++; total++; } catch (_) {}
+ }
+ console.log(` ${cat.padEnd(24)} -> ${ok} upserted (of ${raws.length})`);
+ await sleep(400); // pace the API
+ }
+ const { rows } = await db.query(`SELECT count(*) n, count(image_url) img FROM products WHERE network='cj'`);
+ console.log(`\nDONE. this run: ${total} upserted, ${tracked} with tracked links.`);
+ console.log(`catalog now: ${rows[0].n} CJ products (${rows[0].img} with images).`);
+ await db.pool.end();
+}
+main().catch(e => { console.error(e); process.exit(1); });
← 145b8c5 auto-save: 2026-08-01T20:09:07 (1 files) — lib/adapters/cj.j
·
back to Interiordesignershowroom
·
Room Builder: tray+GO, collapsed left tabs (trending/style/h 1e3d7b1 →