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
Filtering, sorting, and search
- 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
itemServicecentralizes 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


