ParcelRouter is a local-first package tracking and delivery event router for your inbox.
It reads shipping emails from your mailbox, extracts tracking numbers, stores package metadata locally, and can sync deliveries to Parcel or your own automations. The goal is not to be another shopping app. The goal is to give you a private package event router you control.
- Self-hosting users who want package tracking without handing order emails to another cloud service.
- Home automation users who want package events in webhooks, Home Assistant, reminders, or chat.
- Heavy online shoppers who want a searchable delivery history.
- Developers who want a local delivery-event API.
- Monitors iCloud Mail over IMAP.
- Polls INBOX and Archive folders on a schedule.
- Extracts tracking numbers for UPS, FedEx, USPS, Amazon Logistics, DHL, OnTrac, and LaserShip.
- Generates cleaner package titles from sender, subject, retailer, and tracking context.
- Scores detections with high, medium, or low confidence.
- Sends medium and low confidence detections to a review queue before they become deliveries.
- Stores packages and polling state in SQLite.
- Shows a local dashboard.
- Exposes a small REST API.
- Optionally syncs detected packages to the Parcel app through the Parcel API.
- Optionally emits package and review events to a webhook endpoint.
- Runs with Docker Compose.
git clone https://github.com/steveafrost/parcelrouter.git parcelrouter
cd parcelrouterFast path:
curl -fsSL https://parcelrouter.com/install.sh | bashIf you already cloned the repo:
./install.shOr configure it manually:
cp .env.example .envEdit .env:
IMAP_HOST=imap.mail.me.com
IMAP_PORT=993
IMAP_USER=your.email@icloud.com
IMAP_PASS=your-apple-app-specific-password
PARCEL_TRACKER_AUTH_TOKEN=replace-with-a-long-random-token
PARCEL_API_KEY=
WEBHOOK_URL=
WEBHOOK_SECRET=
POLL_INTERVAL=3600Dashboard and API requests, except /health, must include Authorization: Bearer <PARCEL_TRACKER_AUTH_TOKEN>. Keep the service bound to localhost or behind an authenticated proxy if you do not want to enter a bearer token in front of it.
You need:
- An iCloud app-specific password.
- Optionally, a Parcel Premium API key if you want Parcel sync.
- Optionally, a webhook endpoint if you want delivery events in Home Assistant, n8n, Zapier, ntfy bridges, or your own tools.
See SETUP.md for the full setup guide.
Check your configuration before starting the app:
npm ci
npm run setup:checkdocker-compose up -d --buildOpen:
http://localhost:9001
The dashboard shows:
- Service health.
- Emails scanned.
- Packages found.
- Parcel sync mode: local-only or enabled.
- Recent deliveries.
- Review queue for uncertain detections.
- Confidence indicators for each detection.
Medium and low-confidence detections wait in the review queue before they become deliveries.
| Endpoint | Method | Description |
|---|---|---|
/health |
GET | Health check |
/stats |
GET | Email and package counts |
/packages |
GET | List tracked packages |
/packages/:id |
GET | Get one package |
/packages/:id |
DELETE | Remove a package from the local tracker |
/review |
GET | List pending review items |
/review/:id/approve |
POST | Approve a review item and create a package |
/review/:id/ignore |
POST | Ignore a review item |
Set WEBHOOK_URL to receive package and review events:
WEBHOOK_URL=https://example.com/parcelrouter-webhook
WEBHOOK_SECRET=choose-a-long-random-secret
WEBHOOK_TIMEOUT_MS=5000Each event is sent as JSON:
{
"event": "package.created",
"timestamp": "2026-05-19T12:00:00.000Z",
"data": {
"package": {
"trackingNumber": "1Z999AA10123456784",
"carrier": "UPS"
}
}
}Supported events:
package.createdpackage.deletedreview.createdreview.approvedreview.ignoredparcel.syncedparcel.sync_failed
When WEBHOOK_SECRET is set, requests include X-Parcel-Tracker-Signature with a sha256= HMAC of the JSON body.
npm ci
npm run setup:check
npm test
npm run test:e2e:install
npm run test:e2e
npm run build
npm run devIntegration tests are skipped by default unless credentials are present.
SKIP_IMAP_TESTS=true SKIP_PARCEL_TESTS=true npm test -- --runInBandThe E2E suite runs the static marketing site and the ParcelRouter dashboard through Playwright. It verifies marketing navigation/assets/mobile overflow plus dashboard approve, ignore, delete, and API persistence flows against an isolated test database.
The crawlable static marketing page lives in site/index.html and is published at parcelrouter.com. It is intentionally plain static HTML/CSS so it can be hosted anywhere and indexed easily.
See docs/product-strategy.md for the product positioning, competitive map, and roadmap.
The short version:
Your private package event router. Automatically find packages from your email, review uncertain matches, and sync delivery events to the tools you already use.
ParcelRouter has an optional Stripe-hosted "Buy us a coffee" link on the marketing site. See docs/stripe-support-link.md for the live link and Stripe object IDs.
IMAP mailbox
-> Email poller
-> Parser and tracking extractor
-> High confidence packages or review queue
-> SQLite database
-> Local dashboard and REST API
-> Optional Parcel sync / webhooks and automations
MIT