If you’ve ever missed a great local deal because you weren’t online at the right time, you know the pain. I set out to solve that with a small, reliable, and privacy-respecting script that watches Facebook Marketplace for you, filters the noise, and pings your phone only when the right items appear.
The Problem
- Marketplace deals move fast; manual refreshing is tedious.
- Search results include lots of noise: wrong items, overpriced listings, accessories instead of the product.
- You want immediate, actionable alerts on your phone with a link to buy.
The Solution
I built a Python service that:
- Periodically queries Facebook Marketplace for specific searches.
- Parses listings from the page’s embedded JSON (with an HTML fallback).
- Stores everything in SQLite to avoid repeat work/alerts.
- Filters items using per-query rules (like max price).
- Sends a push notification to your iPhone via Pushover or to any device via ntfy.
- Optionally runs AI image checks (Gemini) before alerting to ensure the listing actually shows the product you want.
Why This Is Handy
- Saves time: no more constant refreshing.
- Reduces noise: alerts are gated by price and optional image verification.
- Faster response: being first boosts your odds of snagging good deals.
- Portable: run it locally or deploy to a VPS and forget it.
Key Features
- Config-driven searches in
config.yamlwith per-query filters and AI prompts. - APScheduler-based periodic jobs or a one-shot CLI mode (
--once). - SQLite persistence (dedupe + skip logic for already-seen items).
- Notifications:
- Pushover: iOS-friendly, battle-tested.
- ntfy: simple, self-hostable, works across devices.
- AI image filter (Gemini): only alert if the main image looks like the actual product (e.g., Xbox One S/X).
- Robust scraping:
- Primary parsing from Marketplace’s embedded JSON.
- Fallback to HTML anchors for resilience.
- Debuggable:
LOG_LEVEL=DEBUGto see fetch timing, parse counts, filter decisions.- Proxy support (e.g.,
http://localhost:8080) for traffic inspection.
Technical Highlights
- Per-query
max_pricefiltering andai_promptoverrides. - JSON-first parsing from the app’s
application/jsonscript blocks. - AI prompt is configurable at the global or per-query level.
- Rate-limit backoff for Gemini: reads “retry in Xs” and waits before retrying.
- Only new items trigger notifications, and only if AI passes (when enabled).
- Every listing—pass or fail—is stored once with
ai_passandai_modelso it’s never reprocessed.
Privacy & Ethics
- You supply your own session cookies (optionally) and API keys.
- No external storage of secrets; everything is on your machine or server.
- Respect the site’s terms and your local laws. Use responsibly.
Deploy It Anywhere
- Local dev:
python main.py --onceto test, thenpython main.pyfor scheduled runs. - Server:
systemdservice for reliable background execution on Oracle Linux (ornohup,tmux).
Real-World Benefits
- Find underpriced items fast (e.g., “Xbox One under $50”).
- Avoid accessory-only listings through AI image checks.
- Keep a clean history of seen items and outcomes for auditing.
Future Ideas
- Multi-image analysis and “any image qualifies” logic.
- Region-aware price normalization.
- Web UI for logs, status, and manual triage.
- Slack/Discord notification channels.
How To Use (Quick Start)
- Set up Python venv and install requirements.
- Add your searches, headers, cookies, and notification settings to
config.yaml. - Optional: add Gemini
gemini_api_keyand customize the prompt. - Run once to test:
LOG_LEVEL=DEBUG python main.py --once- Run scheduled
python main.py(or set up a systemd service on your server).
Configuration
Edit `config.yaml` (example below). You can also use JSON, but YAML is recommended.
queries:
- query: "xbox one"
max_price: 50
ai_prompt: "Does this photo clearly show a Microsoft Xbox One S or Xbox One X console? Respond with only 'YES' or 'NO'."
check_interval_minutes: 10
database:
path: "marketplace.db"
notification:
service: "ntfy" # "pushover" or "ntfy"
pushover:
api_token: "YOUR_PUSHOVER_APP_TOKEN"
user_key: "YOUR_PUSHOVER_USER_KEY"
ntfy:
server: "https://ntfy.sh" # or your self-hosted server
topic: "your-topic-name"
facebook:
headers:
user_agent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36"
# You can paste a full raw Cookie header string or a key:value map
cookies: "c_user=...; xs=...; fr=...; datr=...; sb=..."
proxy: "http://localhost:8080" # optional; useful with tools like Burp
# Enable verbose item dump for debugging
debug:
dump_parsed_items: false
# AI image filter (optional) - filters notifications to qualifying images
ai:
gemini_api_key: "YOUR_GEMINI_API_KEY" # or set env var GEMINI_API_KEY
model: "gemini-2.5-flash"
prompt: "Does this photo clearly show a Microsoft Xbox One S or Xbox One X console? Respond with only 'YES' or 'NO'."
```
Closing Thoughts
This project turns Marketplace hunting from a manual chore into an automated assistant that works for you. It’s small, configurable, and designed to be extended. Whether you’re chasing a specific console, bike size, or niche tool, you get relevant, timely alerts—and more wins.
If you are interested in the code, send me a message.
