A self-hosted, open-source webhook-to-push notification gateway built with Next.js, MySQL, and Web Push API.
SPOT transforms any webhook into instant mobile/desktop push notifications. Perfect for:
- Developers: Get alerts from CI/CD pipelines, monitoring tools, or custom scripts
- Self-Hosters: Own your notification pipeline without relying on third-party services
- Teams: Organize notifications by channels (e.g., "Production Errors", "Sales", "Deployments")
Existing notification services have several limitations:
| Issue | Traditional Services | SPOT |
|---|---|---|
| Data Privacy | Your data goes through third-party servers | 100% Self-Hosted - Your data stays on your servers |
| Customization | Limited customization options | Full Control - Modify source code as needed |
| Cost | Expensive for high-volume notifications | Free - No monthly fees or per-notification charges |
| Vendor Lock-in | Difficult to migrate away | Open Source - No vendor lock-in |
| Integration | Complex setup for custom integrations | Simple Webhook - Send from any service |
| Offline Support | Often requires internet connection | PWA Ready - Works offline with service workers |
| Channel Organization | Flat notification structure | Multi-Channel - Organize by category |
Unlike Pushover, Pushbullet, or similar services, SPOT is 100% self-hosted. Your notification data, subscriber information, and analytics stay on your own servers. No third-party data processing, no privacy concerns.
SPOT is designed as a webhook gateway. Any service that can send HTTP requests can trigger notifications:
- GitHub Actions
- GitLab CI/CD
- Jenkins
- AWS CloudWatch
- Sentry
- Datadog
- Custom scripts
- And thousands more!
Organize notifications by category with unique API keys per channel:
┌─────────────────────────────────────────────────────────┐
│ SPOT Instance │
├─────────────────────────────────────────────────────────┤
│ 🚀 Deployments → deploy_abc123... │
│ 🐛 Bugs → bugs_xyz789... │
│ 💰 Sales → sales_def456... │
│ 📊 Analytics → analytics_ghi012... │
└─────────────────────────────────────────────────────────┘
SPOT supports the full Web Push API specification:
- Large images
- Custom badges
- Action buttons (e.g., "View Dashboard", "Acknowledge")
- URL redirection
- Custom icons
No monthly fees, no per-notification charges, no tiered pricing. Host it on Vercel, Railway, or your own server for free.
- Simple REST API
- TypeScript support
- Comprehensive documentation
- Easy integration with existing tools
| Feature | Description |
|---|---|
| 📡 Multi-Channel System | Organize notifications with unique API keys per channel |
| 🖼️ Rich Notifications | Support for large images and custom badges |
| 🎯 Actionable Buttons | Add click-to-action buttons to notifications (e.g., "View Dashboard", "Acknowledge") |
| 📊 Analytics Dashboard | Track delivery rates, channel activity, and 7-day trends |
| ⏰ Scheduled Notifications | Cron-based scheduling with daily/weekly/monthly repeats |
| 🔒 Dual Authentication | Global API secret + per-channel keys |
| 💾 MySQL Persistence | All notifications and channels stored in your own database |
| 📱 PWA Ready | Install as a native app on mobile and desktop |
| Feature | Description |
|---|---|
| 🛡️ Rate Limiting | Prevent abuse with configurable request limits per IP |
| 🌐 CORS Control | Restrict API access to specific origins |
| 🚫 IP Filtering | Whitelist/Blacklist support with CIDR notation |
| 📋 Security Logging | Track all security events for monitoring |
| 🔐 Webhook Signature | Optional HMAC-SHA256 signature verification |
| 🔒 Security Headers | X-Content-Type-Options, X-Frame-Options, X-XSS-Protection |
| Feature | Description |
|---|---|
| 📋 Notification Templates | Create reusable notification templates with variables |
| 🔄 Pagination | Efficiently browse large lists of notifications and subscriptions |
| 🔍 Advanced Filtering | Filter by channel, status, date range, and search text |
| 👥 Subscription Management | View, enable/disable, and manage all subscriptions |
| 📊 User Agent Detection | Automatically detect browser/device type |
Note: Screenshots coming soon! Check CHANGELOG.md for detailed feature documentation.
- Node.js 18+
- MySQL database (we use Hostinger)
- Vercel account (for deployment)
Note: SPOT uses MySQL as the database. The
sqlite.dbfile in the project root is a legacy file and can be safely ignored.
git clone https://github.com/system-conf/SPOT.git
cd SPOT
npm installCreate .env file:
# MySQL Database (Hostinger or your own)
DATABASE_URL="mysql://user:password@host:3306/database"
# VAPID Keys (generate with: npx web-push generate-vapid-keys)
NEXT_PUBLIC_VAPID_PUBLIC_KEY="YOUR_PUBLIC_KEY"
VAPID_PRIVATE_KEY="YOUR_PRIVATE_KEY"
VAPID_EMAIL="mailto:your@email.com"
# API Security
API_SECRET="your-super-secret-key"
CRON_SECRET="your-cron-secret" # For scheduled notifications
# Security Configuration (Optional but recommended)
CORS_ALLOWED_ORIGINS="https://yourdomain.com,https://app.yourdomain.com"
IP_WHITELIST="192.168.1.0/24,10.0.0.0/8"
RATE_LIMIT_WINDOW="60000"
RATE_LIMIT_MAX_REQUESTS="100"
WEBHOOK_SECRET="your-webhook-secret-key"Run migration script:
npm run db:pushThis creates:
channels(notification categories)subscriptions(push subscribers)notifications(message history)scheduled_notifications(future messages)notificationTemplates(reusable templates)
npm run devVisit http://localhost:3000 and enable notifications!
Looking for code examples in your favorite programming language? Check out CODE_EXAMPLES.md for examples in Python, Node.js, Rust, Go, Ruby, Java, PHP, Bash, GitHub Actions, and Jenkins!
curl -X POST https://your-spot.vercel.app/api/notify \
-H "Authorization: Bearer YOUR_API_SECRET" \
-H "Content-Type: application/json" \
-d '{
"title": "Deployment Success",
"body": "v2.0 is now live in production!",
"url": "https://yourapp.com/dashboard",
"image": "https://example.com/large-image.jpg",
"badge": "https://example.com/badge.png",
"actions": [
{"title": "View Logs", "url": "/logs"},
{"title": "Rollback", "url": "/rollback"}
]
}'curl -X POST https://your-spot.vercel.app/api/notify \
-H "Authorization: Bearer YOUR_API_SECRET" \
-H "Content-Type: application/json" \
-d '{
"templateId": 1,
"variables": {
"message": "Database connection timeout",
"error": "Connection refused"
}
}'curl -X POST https://your-spot.vercel.app/api/schedule \
-H "Content-Type: application/json" \
-d '{
"title": "Daily Standup Reminder",
"body": "Team meeting in 10 minutes",
"scheduledAt": "2026-02-11T09:00:00Z",
"repeat": "daily",
"timezone": "Europe/Istanbul"
}'curl "https://your-spot.vercel.app/api/notifications?page=1&limit=20&status=success&channelId=1"curl "https://your-spot.vercel.app/api/subscriptions?page=1&limit=20&status=active"# Create template
curl -X POST https://your-spot.vercel.app/api/templates \
-H "Content-Type: application/json" \
-d '{
"name": "Error Alert",
"title": "Error: {{message}}",
"body": "An error occurred: {{error}}",
"icon": "⚠️",
"variables": [
{"name": "message", "description": "Error message"},
{"name": "error", "description": "Error details"}
]
}'
# List templates
curl https://your-spot.vercel.app/api/templates
# Update template
curl -X PATCH https://your-spot.vercel.app/api/templates \
-H "Content-Type: application/json" \
-d '{
"id": 1,
"name": "Updated Error Alert",
"title": "Error: {{message}}"
}'
# Delete template
curl -X DELETE https://your-spot.vercel.app/api/templates \
-H "Content-Type: application/json" \
-d '{"id": 1}'You can easily test your SPOT instance using the included script:
- Ensure your
.envhas correctAPI_SECRET. - Run test script:
node -r dotenv/config send-test-notification.jsThis sends a rich notification (with image and badge) to all subscribers of the global channel.
-
Push to GitHub
git remote add origin https://github.com/system-conf/SPOT.git git push -u origin main
-
Import to Vercel
- Go to vercel.com/new
- Select your SPOT repository
- Add environment variables from
.env
-
Setup Cron (Optional)
Create
vercel.json:{ "crons": [{ "path": "/api/cron/process-scheduled", "schedule": "*/5 * * * *" }] }This processes scheduled notifications every 5 minutes.
SPOT/
├── src/
│ ├── app/
│ │ ├── api/
│ │ │ ├── channels/ # Channel CRUD
│ │ │ ├── notify/ # Webhook endpoint
│ │ │ ├── stats/ # Analytics
│ │ │ ├── schedule/ # Scheduler CRUD
│ │ │ ├── subscription/ # Push subscription management
│ │ │ ├── subscriptions/ # Subscription list (pagination)
│ │ │ ├── notifications/ # Notification history (pagination)
│ │ │ ├── templates/ # Template management
│ │ │ ├── cron/ # Cron processor
│ │ │ ├── debug-env/ # Environment debug endpoint
│ │ │ └── debug-db/ # Database debug endpoint
│ │ └── page.tsx # Homepage
│ ├── components/
│ │ ├── ChannelManager.tsx # Channel UI
│ │ ├── AnalyticsDashboard.tsx # Analytics UI
│ │ ├── PushSetup.tsx # Subscriber UI
│ │ ├── TemplateManager.tsx # Template management UI (NEW)
│ │ ├── SubscriptionManager.tsx # Subscription management UI (NEW)
│ │ ├── NotificationHistory.tsx # Notification history UI (NEW)
│ │ ├── Pagination.tsx # Pagination component (NEW)
│ │ └── NotificationFilters.tsx # Filtering component (NEW)
│ ├── db/
│ │ ├── schema.ts # Drizzle schema
│ │ └── index.ts # MySQL client
│ └── lib/
│ ├── push.ts # Web Push logic
│ ├── security.ts # Security middleware (NEW)
│ ├── pagination.ts # Pagination helpers (NEW)
│ ├── filters.ts # Filtering helpers (NEW)
│ └── templates.ts # Template helpers (NEW)
├── public/
│ ├── custom-sw.js # Service Worker
│ └── manifest.json # PWA config
├── drizzle.config.ts
└── CHANGELOG.md # Version history (NEW)
- Use strong API secrets (32+ random characters)
- Enable HTTPS (automatic on Vercel)
- Rotate channel API keys regularly
- Restrict CRON_SECRET to Vercel's cron requests only
- Review notification logs in Analytics dashboard
- Configure CORS to restrict API access to trusted origins only
- Set up IP whitelist for production environments
- Enable webhook signature verification for external integrations
- Monitor security logs regularly for suspicious activity
- Configure rate limits appropriate for your use case
Add these environment variables to your .env file:
# CORS Configuration
CORS_ALLOWED_ORIGINS="https://yourdomain.com,https://app.yourdomain.com"
CORS_ALLOWED_METHODS="GET,POST,PUT,DELETE,OPTIONS"
# IP Filtering (CIDR notation supported)
IP_WHITELIST="192.168.1.0/24,10.0.0.0/8"
IP_BLACKLIST=""
# Rate Limiting
RATE_LIMIT_WINDOW="60000" # Time window in milliseconds (default: 1 minute)
RATE_LIMIT_MAX_REQUESTS="100" # Max requests per window
# Webhook Signature (optional, for external integrations)
WEBHOOK_SECRET="your-webhook-secret-key"All API responses include the following security headers:
X-Content-Type-Options: nosniffX-Frame-Options: DENYX-XSS-Protection: 1; mode=blockReferrer-Policy: strict-origin-when-cross-originPermissions-Policy: geolocation=(), microphone=(), camera=()
We welcome contributions! Here's how:
- 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
- Rate Limiting: Prevent abuse with per-channel limits ✓
- Notification Templates: Reusable message formats ✓
- Pagination: Efficient list browsing ✓
- Advanced Filtering: Filter by multiple criteria ✓
- Subscription Management: View and manage subscriptions ✓
- Integration Bridge: Discord/Telegram webhook mirroring
- Chrome Extension: "Send to SPOT" from any page
- Email-to-Push: Forward emails as notifications
- Mobile App: Native iOS and Android apps
MIT License - see LICENSE for details.
- Built with Next.js
- Database powered by Drizzle ORM
- Push notifications via web-push
- Hosted on Vercel
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Email: Create an issue for private inquiries
- CODE_EXAMPLES.md - Code examples in Python, Node.js, Rust, Go, Ruby, Java, PHP, Bash, GitHub Actions, and Jenkins
- CHANGELOG.md - Version history and release notes
- Project Structure - Detailed file organization
- API Usage - Complete API documentation
- Security Best Practices - Security guidelines
Made with ❤️ for developers who want full control over their notifications.