Marketplace Cart

Node.js and Express app for collecting, organizing, and sharing secondhand marketplace listings with normalized data and accurate deduplicated totals.

Node.jsExpressMongoDBMongooseEJSPassport.jsPuppeteerCheerioAxiosexpress-validator
Marketplace Cart preview

The problem

I kept losing track of listings across OfferUp and Facebook Marketplace, with links spread across notes, tabs, and messages. Marketplace Cart pulls listings into one place, lets you organize them into categories, and calculates totals you can trust.

The core challenge is handling unreliable scraped inputs in a way the rest of the app can safely depend on.


What I built

Listing ingestion and preview

  • Scrapes OfferUp and Facebook Marketplace listings
  • Uses a two-step preview then confirm workflow before saving
  • Reuses cached preview data on save to avoid re-scraping

Data normalization

  • Maps raw condition strings into 5 canonical values: New, Like New, Good, Fair, Poor
  • Standardizes item shape so filtering, sorting, and totals stay consistent
  • Filters by availability and condition
  • Sorts by price, title, condition, and date added
  • Searches across titles and descriptions

Categories and sharing

  • Supports custom categories for projects, rooms, and wishlists
  • Allows multi-category assignment from item cards
  • Supports sharing roles: Viewer (read-only) and Editor (can add items)
  • Supports public/private visibility per category

Cost calculations

  • Computes platform-level subtotals
  • Deduplicates repeated items across categories
  • Returns accurate grand totals

Architecture decisions

  • Service layer in itemService centralizes preview, create, normalization, and platform detection
  • Scraper registry routes URLs by pattern to platform-specific scrapers
  • OfferUp uses Axios + Cheerio while Facebook uses Puppeteer
  • Shared Puppeteer singleton reduces browser startup overhead
  • Validation middleware enforces safe input handling across auth, item, and category flows

Engineering challenges solved

  • Isolating scraper volatility so brittle marketplace HTML does not leak into business logic
  • Keeping collaboration permissions correct when categories are shared between users
  • Guaranteeing totals are accurate when the same listing appears in multiple category views

These constraints pushed the architecture toward strict boundaries, strong normalization, and explicit validation.


Tech stack

  • Backend: Node.js, Express.js
  • Database: MongoDB + Mongoose
  • Templating: EJS
  • Authentication: Passport.js (local strategy, session-based)
  • Scraping: Axios + Cheerio (OfferUp), Puppeteer (Facebook Marketplace)
  • Validation: express-validator

Finished Reading?