Car Sniper is the reconstructed monorepo for a multi-service car-search and alerting stack that originally lived across separate repositories. This open-source release is intended as a historical record of the system: what it did, how the services fit together, and how the code evolved over time.
At its peak, the stack was built to watch fresh private-party vehicle listings and live auctions, store them, let users search them on the website, and push updates over websockets. Later, a Go rewrite was started for some of the higher-volume by-owner sources.
car-site/: the customer-facing Express and EJS websitecar-socket/: the Socket.IO and MySQL event hubcar-scraper/: the original JavaScript scraper suitecar-image-server/: the small image ingest and hosting servicego-car-scraper/: the later Go rewrite for selected inventory sources
The preserved code shows a system with four major capabilities:
- Marketplace ingestion from many sources, especially private-seller inventory and enthusiast auction sites.
- Real-time fan-out over websockets, with a central hub that stored listings and rebroadcast new results.
- End-user search and workflow features such as filters, saved cars, hidden cars, login, and subscription pages.
- Operational scaling work, including a dedicated image service and a later Go ingestion pipeline with normalized make, model, and trim extraction.
The JavaScript scraper suite contains integrations for these marketplaces:
- Inventory feeds: Facebook Marketplace, AutoTrader, CarGurus, Cars.com, Craigslist, eBay Motors, and OfferUp
- Auction feeds: Bring a Trailer, Cars & Bids, Copart, and IAAI
Historical note: there is also a dupont/ folder, and the preserved dupont.js documents an AutoTrader-style scraper that lived under that historical folder name.
System relationships in plain text:
- Users interacted with
car-site. car-sitequeried MySQL for accounts, filters, cars, saved cars, and hidden cars.car-sitealso connected tocar-socketover Socket.IO for live events and user actions like save and hide.car-scrapersent new inventory and auction events intocar-socket.car-socketdeduplicated those events, wrote them into MySQL, and rebroadcast them to the website.car-socketalso sent some listing images tocar-image-server, which compressed and rehosted them.car-socketevaluated stored filters and sent Discord webhook alerts when a new listing matched.go-car-scraperwas a later parallel ingestion path that skipped the socket hub and wrote normalized data directly into PostgreSQL.
- Individual scrapers watched marketplaces and emitted either inventory events (
ou-scrape) or auction events (auction-scrape,auction-update,auction-delete-*) intocar-socket. car-socketcleaned the payload, applied source-specific dedupe logic, optionally mirrored images throughcar-image-server, inserted records into MySQL, and rebroadcast new listings to connected clients.- The website stored user filters and queried the
carstable for paged search results. It also kept track of saved and hidden cars. - When filters had webhook metadata attached,
car-socketcompared each new listing against those filter rules and pushed Discord webhook alerts. - The later Go service bypassed the websocket layer for three specific sources and wrote normalized rows directly into PostgreSQL.
A reasonable inference from the codebase is that Car Sniper moved well beyond the toy stage. The strongest signals are:
- A dedicated websocket hub existed because a single scraper process was no longer enough.
- A separate image service existed to normalize or mirror listing images instead of hotlinking them directly.
- The site had user accounts, saved cars, hidden cars, paged filtering, admin pages, and Stripe subscription plumbing.
- The JavaScript suite grew to cover at least 11 named marketplace integrations.
- A second-generation Go scraper was created for structured, large-area scanning across 662 ZIP codes.
None of that proves user counts or revenue, but it does show a system that was used hard enough to justify real operational architecture.
The customer-facing site. It handled login, registration, sessions, filter-based searching, and the dashboard experience around live listings and saved cars. It also carries surrounding business and operations code from the same company, including subscriptions, downloads, admin pages, and server-management screens.
The event switchboard. It accepted scraper traffic, wrote rows into MySQL, rebroadcast live events, tracked saved and hidden cars, and sent Discord webhook alerts for matching filters.
The original sprawling JavaScript scraper lab. Some modules use direct HTTP requests, some use Playwright, some reuse stored session state, and several keep sentHooks.json files to avoid re-emitting the same listing.
A very small service that accepted an external image URL, fetched it, resized and recompressed it, stored it locally, and returned a hosted URL. The archive captures the compression and hosting layer that supported the rest of the stack.
The beginning of a faster, more structured rewrite. It focused on Cars.com, CarGurus, and AutoTrader, scanned a broad ZIP-code list, normalized the titles into make, model, and trim fields, and inserted into PostgreSQL with confidence scores.
This repository is best read as a historical system snapshot that documents the architecture, workflows, and service boundaries of the original product.
- The public archive omits disposable runtime artifacts such as proxy credentials, HTML captures, and temp uploads, while preserving the application and service logic.
- The JavaScript scraper suite is documented most accurately as a set of individual long-running workers rather than a single central launcher.
- The repository centers on the application code and service interactions that defined how the system operated.
- Reuse is easiest when approached as reference material for the system design and implementation patterns captured here.
If you want the clearest picture of the system, read the subproject READMEs in this order: