Track product prices on any website. Get live WebSocket alerts the moment a price drops. Built with Django + Celery for background scraping and Django Channels for real-time push.
Browser ──REST──► Django API (DRF + Channels)
▲ │ enqueue
│ WebSocket push ▼
│ Celery Worker ──HTTP──► External URL (Amazon, Flipkart…)
│ │ save
│ ▼
Redis ◄──────── PostgreSQL (trackers + price_history)
(broker +
channel layer)
Data flow:
- User creates a tracker via
POST /api/v1/trackers/ - An immediate scrape task is enqueued → price saved to DB
- Celery Beat fires
scrape_all_active_trackersevery N seconds - Each worker fetches the URL, parses the price, compares to last known
- If the price changed → saves a
PriceHistoryrow + pushes a WebSocket message - Any browser connected to
ws://.../ws/trackers/<id>/receives the update live
git clone https://github.com/YOUR_USERNAME/price-tracker.git
cd price-tracker
cp .env.example .env
docker compose up --buildIn a second terminal:
docker compose exec api python manage.py migrate
docker compose exec api python manage.py createsuperuserOpen http://localhost:8000/api/docs/ — Swagger UI is live.
Open templates/trackers/demo.html in your browser to test WebSocket in real time.
| Service | What it does |
|---|---|
api |
Django + Channels via Uvicorn (HTTP + WebSocket) |
worker |
Celery worker — runs scrape tasks |
beat |
Celery Beat — schedules periodic scrapes |
db |
PostgreSQL 15 |
redis |
Redis 7 — task broker + WebSocket channel layer |
| Method | Path | Description |
|---|---|---|
| POST | /api/v1/auth/token/ |
Get JWT tokens |
| POST | /api/v1/auth/token/refresh/ |
Refresh access token |
| GET/POST | /api/v1/trackers/ |
List or create trackers |
| GET/PATCH/DELETE | /api/v1/trackers/<id>/ |
Get, update or delete |
| GET | /api/v1/trackers/<id>/history/ |
Full price history |
| POST | /api/v1/trackers/<id>/trigger/ |
Manually trigger a scrape |
| POST | /api/v1/trackers/<id>/pause/ |
Pause / resume a tracker |
ws://localhost:8000/ws/trackers/<tracker-uuid>/
Connect with a valid session (the AuthMiddlewareStack checks Django session auth). The server pushes JSON on every price check:
{
"type": "price_update",
"tracker_id": "...",
"tracker_name": "RTX 4090",
"event": "price_update",
"new_price": "79999.00",
"old_price": "89999.00",
"currency": "INR",
"drop_pct": 11.11,
"should_alert": true,
"raw_text": "₹79,999"
}# 1. Get a token
curl -X POST http://localhost:8000/api/v1/auth/token/ \
-H "Content-Type: application/json" \
-d '{"username": "you@example.com", "password": "yourpass"}'
# 2. Create a tracker
curl -X POST http://localhost:8000/api/v1/trackers/ \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"url": "https://www.amazon.in/dp/B09V3KXJPB",
"name": "RTX 4090",
"alert_threshold_pct": 5,
"check_interval": 300
}'
# 3. Trigger a manual scrape
curl -X POST http://localhost:8000/api/v1/trackers/<id>/trigger/ \
-H "Authorization: Bearer <access_token>"Leave price_selector blank for auto-detection (works on Amazon India and Flipkart). For other sites, inspect the page and pass a CSS selector:
{ "price_selector": "span.a-price-whole" }| Layer | Technology |
|---|---|
| Framework | Django 4.2 + DRF 3.15 |
| WebSockets | Django Channels 4.1 + channels-redis |
| Background jobs | Celery 5.3 + Celery Beat |
| Message broker | Redis 7 |
| Database | PostgreSQL 15 |
| Scraping | requests + BeautifulSoup4 + lxml |
| Container | Docker + Docker Compose |
MIT