π¨ The easiest way to add Web Push Notifications to your Meteor app β with full iOS (Safari) support, no paid service required!
Modern, production-ready PWA template with Meteor, React, push notifications, and real-time features.
π Live Demo β’
Features β’
Quick Start β’
Why Star?
If you like this project, please star it on GitHub β it helps others discover it and motivates further development!
Live Demo: https://pwameteor.meteorapp.com/dashboard
A comprehensive Progressive Web App built with Meteor 3.3, featuring real-time notifications, authentication, state management, and user tracking.
- π Secure Authentication - Email/password authentication with rate limiting
- π Real-time Notifications - Personalized and broadcast push notifications
- β‘ Live Tracking - Real-time user activity and presence tracking
- π± PWA Support - Service workers, offline capability, installable app
- π― State Management - Zustand for client-side state management
- π‘οΈ Security - CSRF protection, input validation, secure headers
- π Real-time Data - Live updates using Meteor's reactive data layer
- π Auto-Install Prompt - Professional PWA installation experience
git clone <your-repo-url>
cd PWA
npm install
For push notifications, you need VAPID keys. Generate them using:
npx web-push generate-vapid-keys
Copy the example settings file:
cp settings-example.json settings.json
Update settings.json
with your VAPID keys:
{
"vapid": {
"email": "mailto:your-email@example.com",
"publicKey": "your-vapid-public-key",
"privateKey": "your-vapid-private-key"
},
"public": {
"vapidPublicKey": "your-vapid-public-key",
"appName": "PWA Notification App"
}
}
meteor run --settings settings.json
The app will be available at http://localhost:3000
- Visit the app and click "Sign Up" to create an account
- Or "Login" if you already have an account
- Rate limiting protects against brute force attacks
- After logging in, enable push notifications in the dashboard
- Test different notification types:
- Personal notifications - sent to specific users
- Broadcast notifications - sent to all users
- Urgent pings - high-priority notifications with actions
The app automatically prompts users to install it as a native app:
- Automatic Detection - App detects when installation is available
- Install Button - Clean "π± Install App" button appears in dashboard
- Professional Flow - Uses browser's native installation prompt
- Install Status - Shows "β App Installed" when completed
- Standalone Mode - Runs like a native app once installed
- Online users - See who's currently active
- Live activity - Track user actions in real-time
- Presence detection - Online/away/offline status
- Instant updates - All data updates in real-time
- Zustand stores for client-side state
- AuthStore - Authentication state and user management
- NotificationStore - Notifications and toast messages
- TrackingStore - User activity and presence tracking
- Meteor Publications - Server-side data publishing
- Reactive subscriptions - Client-side data synchronization
- Live queries - Automatic UI updates on data changes
- Rate limiting on login attempts and API calls
- Input validation and sanitization
- CSRF protection and secure headers
- Session management with configurable expiration
- Service Workers for offline functionality and push notifications
- Web App Manifest for native app installation
- Push API for background notifications with VAPID authentication
- Background Sync for offline actions and data synchronization
- Install Prompts for professional app installation experience
- Standalone Mode - Runs like a native mobile/desktop app
The service worker (/public/sw.js
) provides:
// Install: Immediate activation for faster updates
self.addEventListener("install", (event) => {
self.skipWaiting(); // Force immediate activation
});
// Activate: Clean up old caches and claim clients
self.addEventListener("activate", (event) => {
self.clients.claim(); // Take control immediately
// Clean up old cache versions
});
// Receive and display push notifications
self.addEventListener("push", (event) => {
const data = event.data.json();
// Advanced notification options based on priority
const options = {
body: data.body,
icon: "/icons/icon-192x192.svg",
badge: "/icons/icon-192x192.svg",
tag: data.tag,
requireInteraction: data.priority === "urgent",
silent: data.priority === "low",
vibrate:
data.priority === "urgent" ? [200, 100, 200, 100, 200] : [100, 50, 100],
actions: data.actions || [],
};
self.registration.showNotification(data.title, options);
});
// Handle notification clicks
self.addEventListener("notificationclick", (event) => {
event.notification.close();
// Focus existing window or open new one
event.waitUntil(
clients.matchAll({ type: "window" }).then((clients) => {
// Smart window management
})
);
});
// Handle offline actions when back online
self.addEventListener("sync", (event) => {
if (event.tag === "background-sync") {
// Sync offline notifications/actions
}
});
sequenceDiagram
participant User
participant Browser
participant ServiceWorker
participant App
participant Server
participant PushService
User->>Browser: Opens PWA
Browser->>ServiceWorker: Registers SW
App->>User: Shows "Enable Notifications"
User->>App: Clicks Enable
App->>Browser: Request permission
Browser->>User: Shows permission dialog
User->>Browser: Grants permission
Browser->>ServiceWorker: Creates subscription
App->>Server: Stores subscription (Meteor method)
Note over Server,PushService: Later: Sending notification
Server->>PushService: Send encrypted payload
PushService->>ServiceWorker: Delivers push event
ServiceWorker->>User: Shows notification
User->>ServiceWorker: Clicks notification
ServiceWorker->>App: Opens/focuses app
sequenceDiagram
participant User
participant Browser
participant App
participant PWAInstaller
User->>Browser: Uses app multiple times
Browser->>Browser: Meets PWA criteria
Browser->>App: Fires 'beforeinstallprompt'
App->>PWAInstaller: Shows install button
User->>PWAInstaller: Clicks "π± Install App"
PWAInstaller->>Browser: Calls prompt()
Browser->>User: Shows install dialog
User->>Browser: Confirms installation
Browser->>App: Fires 'appinstalled' event
App->>PWAInstaller: Shows "β
App Installed"
βββ client/ # Client entry point
βββ imports/
β βββ api/ # Server-side API and methods
β β βββ collections.ts # MongoDB collections
β β βββ notifications.ts # Notification methods
β βββ stores/ # Zustand state stores
β β βββ authStore.ts # Authentication state
β β βββ notificationStore.ts # Notification & toast state
β β βββ trackingStore.ts # User activity tracking
β βββ ui/ # React components
β βββ UltraCompactDashboard.tsx # Main dashboard
β βββ MinimalNotificationManager.tsx # Notification controls
β βββ PWAInstaller.tsx # Install prompt component
β βββ Login.tsx # Authentication UI
β βββ Profile.tsx # User profile
β βββ NotificationCenter.tsx # Notification history
βββ public/ # Static assets and PWA files
β βββ manifest.json # PWA manifest
β βββ sw.js # Service worker
β βββ icons/ # PWA icons
βββ server/ # Server entry point
βββ settings.json # Configuration (create from example)
For production, use environment variables instead of settings.json:
export VAPID_PUBLIC_KEY="your-public-key"
export VAPID_PRIVATE_KEY="your-private-key"
export VAPID_EMAIL="mailto:your-email@example.com"
Meteor uses MongoDB by default. The app creates the following collections:
users
- User accounts and authenticationnotifications
- Notification historysubscriptions
- Push notification subscriptionsuserActivity
- User activity trackingonlineUsers
- Real-time presence data
- Never commit
settings.json
with real keys to version control - Use environment variables for production deployments
- Regularly rotate VAPID keys
- Configure proper CORS and security headers
- Use HTTPS in production for push notifications
meteor deploy your-app.meteorapp.com --settings settings.json
meteor build --directory ../build
cd ../build
docker build -t pwa-app .
docker run -p 3000:3000 pwa-app
notifications.send(userId, notification)
- Send personal notificationnotifications.sendBroadcast(notification)
- Send to all users (alias for broadcast)notifications.broadcast(notification)
- Send to all usersnotifications.markAsRead(notificationId)
- Mark as readnotifications.remove(notificationId)
- Delete notification
Note: Notification counters and unread counts are always real-time and accurate, powered by Meteor 3 async methods and Zustand state sync. All notification state is kept in sync with the server using a custom hook (
useNotificationsSync
).
tracking.updateStatus(status, sessionId)
- Update user statustracking.logActivity(activity)
- Log user actiontracking.heartbeat(sessionId)
- Maintain online presence
subscriptions.add(subscription, userId)
- Register push subscriptionsubscriptions.remove(userId)
- Remove subscriptionsubscriptions.clearAll()
- Remove all subscriptions (admin)
beforeinstallprompt
- Browser ready to show install promptappinstalled
- App successfully installedprompt()
- Trigger installation dialog
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
MIT License - see LICENSE file for details
If you encounter issues:
- Check the browser console for errors
- Verify VAPID keys are configured correctly
- Ensure HTTPS is used in production
- Check that service workers are registered
For push notification issues:
- Verify browser support for Push API
- Check notification permissions
- Ensure service worker is active
- Validate VAPID key format
For PWA installation issues:
- Ensure app is served over HTTPS (required for installation)
- Check that manifest.json is properly configured
- Verify service worker is registered successfully
- Ensure app meets PWA installability criteria:
- Has a web app manifest
- Has a registered service worker
- Is served over HTTPS
- Has proper icons (192px and 512px minimum)
- Stay Updated: Get notified of new features and improvements
- Support Open Source: Your star motivates further development
- Boost Discoverability: More stars = more visibility for the project
- Join the Community: Be part of a growing Meteor/React/PWA community
- Share this repo on Twitter, Reddit, Dev.to, or your favorite dev community!
- Submit issues and feature requests β your feedback is welcome
- Open a PR for bug fixes, docs, or new features
- Add a badge to your own project if you use this template!