A local RSS-based listing scraper. You configure filter presets (feed URLs, price range, keywords, locations), scraper sources, and how often runs should happen; when listings match, the app can POST to a webhook (Discord, Slack, or similar). There are no cloud services or deployment targets — everything runs on your machine with Node.js and a SQLite file.
- Frontend: Vite + React SPA in
src/for scrapers, filter presets, schedule, settings, and run history. - Backend: A single Node.js + Hono app in
server/listens on port 3001 by default (PORToverrides). It serves the built SPA fromdist/, handles/api/*, and uses better-sqlite3 with a file database (defaultdata/house_hunter.sqlite, override withDATABASE_PATH). - Schema: SQL files in
migrations/are applied automatically on server startup (tracked inschema_migrations). - Scheduling: While the server process is running, node-cron checks every minute against the
scheduletable (same interval and on/off flag as the Schedule UI). For one-off or OS-level automation, usenpm run scrapefrom cron, Task Scheduler, or systemd. - Notifications: When the pipeline finds matches, it POSTs JSON to the webhook URL from Settings (if webhooks are enabled).
Data flow: timer or npm run scrape → pipeline loads filter presets from SQLite → fetches each RSS/Atom feed (and configured Redfin sources) → parses and applies filters → stores runs in SQLite → if there are matches, POSTs to the webhook.
- Node.js 18+
- Native build toolchain for better-sqlite3 (e.g. Xcode CLI tools on macOS,
build-essentialon Linux, or Visual Studio Build Tools on Windows) ifnpm installfails while compiling the native module
- Install dependencies:
npm install - API:
npm run server:dev - UI:
npm run dev— open http://localhost:5173. Vite proxies/apito http://localhost:3001 (vite.config.ts).
The Node server creates data/house_hunter.sqlite if needed and applies migrations from migrations/.
Builds the SPA into dist/, then serves UI + API on 3001:
npm startOpen http://localhost:3001.
Run the full pipeline once (opens DB, migrates, runs all presets, exits):
npm run scrapeUse your OS scheduler to invoke that command on whatever cadence you want, or rely on the in-process scheduler when npm start or npm run server:dev is running.
PM2 is a dev dependency. Build the SPA once, then start the server under PM2 (port 3001 is set in ecosystem.config.cjs so an ambient PORT such as 3100 does not override it).
npm run build
npm run pm2:start # npx tsx server/index.ts
npm run pm2:status
npm run pm2:logs
npm run pm2:stopWhen House Hunter runs under PM2 on Windows, Node does not show the usual “allow through firewall?” prompt because PM2 starts it non-interactively, so inbound TCP on your PORT (default 3001) may be blocked. Run once in an elevated PowerShell:
New-NetFirewallRule -DisplayName "House Hunter (PM2)" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 3001Optional: pm2 save and pm2 startup so processes survive reboot (see PM2 docs). Set DATABASE_PATH or DISABLE_SCHEDULED_SCRAPES in ecosystem.config.cjs env or via pm2 start … --update-env if needed.
Environment
| Variable | Purpose |
|---|---|
PORT |
HTTP port (default 3001) |
DATABASE_PATH |
SQLite file path (default data/house_hunter.sqlite) |
DISABLE_SCHEDULED_SCRAPES |
Set to 1 to disable the node-cron scheduler (e.g. Playwright sets this for npm start) |
End-to-end tests use Playwright (playwright.config.ts, specs under qa/). With nothing on port 3001, tests start the app via npm start.
npm test
npm run test:list.vscode/launch.json includes:
- House Hunter: Frontend (GUI refinement) — Vite on :5173. Run
npm run server:devin another terminal for/api. - House Hunter: Local full stack — runs the Build frontend task (
npm run build), then startsserver/index.tswith the debugger; app at http://localhost:3001.
- Scrapers: Open Scrapers. Under Websites, configure Redfin (stingray) params and add sources; under RSS Feeds, add URLs. See
REDFIN_API_GUIDE.mdfor Redfin parameters. - Filters: Create presets with feed URLs and price/keyword/location rules. The pipeline uses those URLs when it runs.
ISC (see package.json).