A self-hosted web change tracker. Add URLs, set a polling interval, and WatchBot will notify you whenever the content changes — with an AI-generated summary of what changed.
- Watch any URL — monitors visible text content and detects changes on a configurable interval
- AI change summaries — uses Claude (Anthropic) to summarise what changed in plain English
- WatchBot Resource Finder — describe a topic and get 30 curated URL suggestions to monitor
- Real-time updates — live push via Server-Sent Events; no page refresh needed
- Browser notifications — opt-in push notifications via Service Worker
- Change history — stacked per-tracker log of all detected changes with unread indicators
- Flag changes — pin individual change entries so they are never deleted; flagged entries survive bulk history deletes
- Expand / Collapse all — one-click toggle for all change history panels from the toolbar
- Drag-to-reorder — organise your WatchBots in any order
- User accounts — JWT-based auth with registration and login
- Admin panel — manage users, roles, tracker limits, impersonate users for debugging
- Dark mode — follows system preference (Material-style UI)
| Layer | Technology |
|---|---|
| Server | Node.js, Express |
| Database | SQLite (via better-sqlite3) |
| Auth | JWT in httpOnly cookies, bcrypt |
| Frontend | Vanilla JS, single-page (public/index.html) |
| AI | Anthropic Claude API (optional) |
| Push | Web Push / Service Worker |
- Node.js 18+
- An Anthropic API key (optional — AI summaries and resource finder are disabled gracefully without one)
git clone https://github.com/gbot/watchbot.git
cd watchbot
npm installcp .env.example .envEdit .env:
PORT=3000
JWT_SECRET=your_long_random_secret_here
ANTHROPIC_API_KEY=your_anthropic_api_key_here # optional
CHECK_CONCURRENCY=5 # optional: max parallel checks (default 5)
CORS_ALLOWED_ORIGINS=https://your-app.example.com # optional: comma-separated allowed origins for credentialed CORS
JWT_SECRETshould be a long random string. Generate one with:node -e "console.log(require('crypto').randomBytes(48).toString('hex'))"
npm startOr with auto-reload for development:
npm run dev # requires nodemonOpen http://localhost:3000.
On first start, an admin account is automatically created. Check the server console output for the credentials. Change the password immediately via the account settings after logging in.
watchbot/
├── server/
│ └── index.js # Express server, all API routes, scheduler
├── public/
│ ├── index.html # Single-page frontend application
│ ├── app.js # Frontend logic
│ ├── style.css # Styles
│ ├── sw.js # Service Worker for browser notifications
│ └── icon.svg # App icon
├── data/ # SQLite database (auto-created, git-ignored)
├── .env.example # Environment variable template
└── package.json
| Variable | Required | Description |
|---|---|---|
PORT |
No | HTTP port (default: 3000) |
JWT_SECRET |
Yes | Secret key for signing JWT tokens |
ANTHROPIC_API_KEY |
No | Enables AI change summaries and resource finder |
CHECK_CONCURRENCY |
No | Max parallel tracker checks (default: 5) |
CORS_ALLOWED_ORIGINS |
No | Comma-separated origin allowlist for credentialed CORS (e.g. https://app.example.com,https://admin.example.com). If unset, server allows only same-origin browser access; non-production also allows localhost on PORT. |
MIT