AI-powered community-driven parcel tracking. Predict delivery dates with confidence intervals using machine learning and collective shipment data.
More people track = more data = better predictions for everyone.
- 25+ International Carriers — USPS, UPS, FedEx, DHL, Royal Mail, Canada Post, and more
- AI ETA Predictions — XGBoost-powered delivery predictions with confidence intervals
- Route Analysis — Historical route patterns and carrier performance stats
- Cyber-themed UI — Dark mode, neon accents, maps, and real-time updates
- Google OAuth — Secure authentication, no passwords
- Community Intelligence — Every tracked shipment improves the model
- Self-hosted — Full Docker stack, deploy anywhere
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Traefik │────▶│ Next.js │────▶│ Python ML │
│ (Proxy/SSL) │ │ (Frontend + │ │ (Predictions│
│ │ │ Node API) │ │ + Scraping)│
└──────────────┘ └──────┬───────┘ └──────┬───────┘
│ │
┌──────▼─────────────────────▼──────┐
│ PostgreSQL + TimescaleDB │
│ (Shipments, Predictions, │
│ Routes, Events) │
└────────────────────────────────────┘
│
┌──────▼───────┐
│ Redis │
│ (Cache/Queue) │
└──────────────┘
- Docker + Docker Compose
- Google OAuth credentials (setup guide)
git clone https://github.com/YOUR_USERNAME/ParcelStats.git
cd ParcelStats
cp .env.example .envDOMAIN=localhost
DB_PASSWORD=your_secure_password
NEXTAUTH_SECRET=openssl rand -base64 32
NEXTAUTH_URL=https://your-domain.com
# Shared secret between frontend and ML service (openssl rand -hex 32)
INTERNAL_API_KEY=your_internal_api_key
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret
# Optional carrier API credentials. Required for reliable USPS, UPS, and FedEx tracking.
USPS_WEB_TOOLS_USER_ID=your_usps_web_tools_user_id
UPS_CLIENT_ID=your_ups_client_id
UPS_CLIENT_SECRET=your_ups_client_secret
FEDEX_CLIENT_ID=your_fedex_client_id
FEDEX_CLIENT_SECRET=your_fedex_client_secretdocker compose up -dVisit https://localhost (or your domain).
docker exec -i parcelstats-postgres psql -U parcelstats -d parcelstats < database/seed/carriers.sql- Go to Google Cloud Console
- Create a new project
- Enable "Google+ API"
- Go to Credentials → Create Credentials → OAuth Client ID
- Application type: Web application
- Add authorized redirect URI:
https://your-domain.com/api/auth/callback/google - Copy the Client ID and Client Secret to your
.env
ParcelStats is designed to run as a Docker stack on Unraid:
- Install the Compose Manager plugin on Unraid
- Upload the project to your preferred location (e.g.,
/mnt/user/appdata/parcelstats/) - Copy and edit
.envas described above - In the Unraid UI, go to the Compose tab and deploy
Every push to main publishes images to GHCR
(ghcr.io/kurue/parcelstats-frontend, ghcr.io/kurue/parcelstats-ml-service).
Use docker-compose.prod.yml to pull them instead
of building locally:
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -dThe repo checkout is still needed for the compose file and the
database/*.sql init scripts, but no Node/Python build happens on the
server. If the GHCR packages are private, run
docker login ghcr.io with a GitHub token (read:packages) first.
All data persists in Docker volumes. Back up the postgres-data volume regularly.
- Point your domain's DNS at the server and terminate TLS at your reverse proxy (Traefik, NPM, or SWAG on Unraid), forwarding to the frontend on port 3000.
- Set in
.env:NEXTAUTH_URL=https://ps.kurue.comNEXTAUTH_SECRET(generate:openssl rand -base64 32)INTERNAL_API_KEY(generate:openssl rand -hex 32)GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRETwith redirect URIhttps://ps.kurue.com/api/auth/callback/googleADMIN_EMAILS=you@gmail.com— grants access to the/admindashboard- A strong
DB_PASSWORD
- The compose file binds Postgres, Redis, and the ML service to
127.0.0.1only; the frontend (port 3000) is the only service your proxy needs to reach.
Users listed in ADMIN_EMAILS see an Admin link in the navbar
(/admin) with system stats, scraper health, model versions and accuracy,
prediction volume by model version, and retrain controls.
| Carrier | Method | Countries |
|---|---|---|
| USPS | Web Tools API | US |
| UPS | OAuth Track API | US |
| FedEx | OAuth Track API | US |
| DHL Express | API + Scrape | Global |
| Royal Mail | Playwright | UK |
| Canada Post | Playwright | CA |
| Australia Post | Playwright | AU |
| Deutsche Post | Playwright | DE |
| DHL Parcel DE | Playwright | DE |
| GLS | Playwright | EU |
| Hermes | Playwright | DE |
| China Post | Playwright | CN |
| Yanwen | Playwright | CN |
| Japan Post | Playwright | JP |
| India Post | Playwright | IN |
| Correos | Playwright | ES |
| Poste Italiane | Playwright | IT |
| La Poste | Playwright | FR |
| PostNord | Playwright | SE/DK/NO/FI |
| Swiss Post | Playwright | CH |
| An Post | Playwright | IE |
| NZ Post | Playwright | NZ |
| Singapore Post | Playwright | SG |
| Pos Malaysia | Playwright | MY |
| Thai Post | Playwright | TH |
Adding a new carrier: Open a Carrier Request issue or submit a PR with a new scraper in ml-service/services/scraper/.
Carrier API notes: USPS, UPS, and FedEx block or redirect unauthenticated server-side tracking requests in many environments. Set USPS_WEB_TOOLS_USER_ID, UPS_CLIENT_ID + UPS_CLIENT_SECRET, and FEDEX_CLIENT_ID + FEDEX_CLIENT_SECRET before starting the stack. Without those values, matching shipments are marked carrier_setup_required instead of retrying into tracking_exception.
UPS defaults to the production API host https://onlinetools.ups.com. Set UPS_BASE_URL=https://wwwcie.ups.com for the UPS customer integration environment. FedEx defaults to https://apis.fedex.com; set FEDEX_BASE_URL=https://apis-sandbox.fedex.com for sandbox credentials.
- Data Collection — Every tracked shipment's events, origin, destination, carrier, and timing are stored
- Feature Engineering — Carrier, regions, service type, weight, seasonal patterns, day of week
- Training — Three XGBoost models predict:
- Median ETA — Most likely delivery date
- P10 bound — 10th percentile (optimistic)
- P90 bound — 90th percentile (conservative)
- Confidence Score — Calculated from the spread between P10 and P90
- Retraining — Automatic weekly retraining as data grows
ParcelStats does not create fallback, synthetic, or baseline ETAs. If there is not enough real completed shipment history for a carrier or lane, the app shows no prediction until enough user-submitted shipments have been delivered and used for training.
- Track more real packages → more training data
- Different carriers and routes → better generalization
- Delivered shipments with real carrier events are the only training source
- Over time, confidence intervals narrow as the model learns patterns
ParcelStats/
├── docker-compose.yml # Full Docker stack
├── frontend/ # Next.js app
│ ├── src/
│ │ ├── app/ # Pages + API routes
│ │ ├── components/ # React components
│ │ └── lib/ # Auth, DB, utilities
│ ├── drizzle.config.ts # ORM config
│ └── Dockerfile
├── ml-service/ # Python FastAPI
│ ├── routers/ # API endpoints
│ ├── services/
│ │ ├── predictor.py # ML inference
│ │ ├── trainer.py # Model training
│ │ └── scraper/ # Carrier scrapers
│ ├── database/ # SQLAlchemy models
│ └── Dockerfile
├── database/
│ ├── init.sql # Schema
│ └── seed/ # Carrier data
└── traefik/ # Reverse proxy config
| Component | Technology |
|---|---|
| Frontend | Next.js 14, React, TailwindCSS |
| Backend API | Next.js API Routes, Drizzle ORM |
| ML Service | Python, FastAPI, XGBoost, scikit-learn |
| Database | PostgreSQL + TimescaleDB |
| Scraping | Playwright, httpx, BeautifulSoup |
| Auth | NextAuth.js v5 (Google OAuth) |
| Maps | Leaflet + OpenStreetMap |
| Cache | Redis |
| Proxy | Traefik |
| Deployment | Docker Compose |
cd frontend
npm install
npm run devcd ml-service
python -m venv venv
source venv/bin/activate # or venv\Scripts\activate on Windows
pip install -r requirements.txt
playwright install chromium
uvicorn main:app --reload --port 8000cd frontend
npm run db:generate # Generate migration from schema changes
npm run db:migrate # Apply migrations- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
See CONTRIBUTING.md for details.
MIT License — see LICENSE for details.
- WebSocket real-time tracking updates
- Email/push notifications
- Mobile app (React Native)
- Public API for third-party integrations
- Route map visualization with animated paths
- Carrier reliability scores
- Neural network models for complex routes
- Multi-language support
- Dark/light theme toggle
- Package photo OCR for auto-tracking-number detection