Cross-Platform
Android, Web, iOS support
Free Tier
Generous free message quota
Rich Messages
Images, actions, data payloads
Analytics
Delivery and engagement stats
Firebase Project Setup
Create and configure a Firebase project for push notifications:
Create Firebase Project
Go to the Firebase Console and click Add project. Follow the wizard to create your project.
Enable Cloud Messaging
In your project settings, navigate to Cloud Messaging tab. Enable the Firebase Cloud Messaging API if prompted.
Add Your App
Click Add app and select your platform (Web, Android, or iOS). Follow the setup instructions to register your app.
Get Configuration
Copy your Firebase configuration object. You'll need this for client-side integration.
// Your Firebase configuration (from Firebase Console)
const firebaseConfig = {
apiKey: "AIzaSy...",
authDomain: "your-app.firebaseapp.com",
projectId: "your-app",
storageBucket: "your-app.appspot.com",
messagingSenderId: "123456789",
appId: "1:123456789:web:abc123",
}Service Account Configuration
Generate a service account key for server-side push notifications:
Open Service Accounts
In Firebase Console, go to Project Settings → Service accounts.
Generate Private Key
Click Generate new private key. A JSON file will download containing your credentials.
Store Securely
Never commit this file to version control. Store it securely and reference via environment variables.
Security Warning
# Option 1: Path to service account file
FIREBASE_SERVICE_ACCOUNT_PATH=/path/to/service-account.json
# Option 2: Inline JSON (escape quotes)
FIREBASE_SERVICE_ACCOUNT='{"type":"service_account","project_id":"..."}'
# Option 3: Individual credentials
FIREBASE_PROJECT_ID=your-project-id
FIREBASE_CLIENT_EMAIL=firebase-adminsdk@your-project.iam.gserviceaccount.com
FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"Adding FCM to Console
Configure FCM credentials in the Sylphx dashboard:
Navigate to Settings
Go to App Settings → Notifications → Push Providers.
Add FCM Provider
Click Add Provider and select Firebase Cloud Messaging.
Upload Credentials
Upload your service account JSON file or paste the JSON contents directly.
Test Connection
Click Test Connection to verify your credentials are valid.
import { platform } from '@/lib/platform'
// FCM is automatically configured once added in the dashboard
// No additional SDK configuration needed
// Verify FCM is configured
const providers = await platform.notifications.getProviders()
console.log(providers.fcm) // { enabled: true, projectId: '...' }Sending Push via FCM
Send push notifications through FCM using the SDK:
import { platform } from '@/lib/platform'
// Send to a specific user (uses their registered FCM token)
await platform.notifications.send({
userId: user.id,
title: 'New message',
body: 'You have a new message from Sarah',
icon: '/icon-192.png',
data: {
url: '/messages/123',
messageId: '123',
},
})
// Send to specific FCM token directly
await platform.notifications.sendToToken({
token: 'fcm-device-token...',
title: 'Order Update',
body: 'Your order has shipped!',
data: {
orderId: '456',
},
})
// Send to multiple tokens
await platform.notifications.sendToTokens({
tokens: ['token1...', 'token2...', 'token3...'],
title: 'Flash Sale!',
body: '50% off for the next 2 hours',
})// Subscribe users to topics
await platform.notifications.subscribeToTopic({
tokens: [user1Token, user2Token],
topic: 'promotions',
})
// Send to all topic subscribers
await platform.notifications.sendToTopic({
topic: 'promotions',
title: 'Weekend Sale',
body: 'Save 30% on all items this weekend!',
data: {
saleId: 'weekend-2024',
},
})FCM Message Format
Understanding the FCM message structure:
await platform.notifications.send({
userId: user.id,
// Notification payload (shown to user)
title: 'Order Shipped!',
body: 'Your order #123 is on its way.',
icon: '/icons/shipping.png',
image: '/images/package.jpg', // Large image
badge: '/icons/badge.png',
// Click action
clickAction: 'https://myapp.com/orders/123',
// Android-specific options
android: {
channelId: 'orders',
priority: 'high',
ttl: 3600, // Seconds until message expires
collapseKey: 'order-updates',
notification: {
color: '#4F46E5',
sound: 'default',
tag: 'order-123', // Replaces existing with same tag
},
},
// Web-specific options
webpush: {
headers: {
TTL: '3600',
Urgency: 'high',
},
fcmOptions: {
link: '/orders/123',
},
},
// Custom data payload
data: {
orderId: '123',
status: 'shipped',
trackingUrl: 'https://tracking.example.com/123',
},
})Message Properties
| Property | Type | Description |
|---|---|---|
titlerequired | string | Notification title |
bodyrequired | string | Notification body text |
icon | string | Small icon URL |
image | string | Large image URL for expanded view |
badge | string | Badge icon (Android) |
clickAction | string | URL to open on click |
data | object | Custom key-value data |
android | object | Android-specific options |
webpush | object | Web push-specific options |
apns | object | iOS-specific options (when using FCM for iOS) |
Android Channel Options
| Property | Type | Description |
|---|---|---|
channelId | string | Notification channel ID (required for Android 8+) |
priority | "high" | "normal"= "normal" | Message priority |
ttl | number | Time-to-live in seconds |
collapseKey | string | Key for collapsing multiple messages |
sound | string= "default" | Sound to play |
color | string | Notification accent color (hex) |
tag | string | Tag for replacing existing notifications |
Troubleshooting FCM
Common issues and solutions:
Invalid registration tokenCause: Token expired or was never valid
Solution: Request a new token from the client and update your database
MismatchSenderIdCause: Token was generated for a different Firebase project
Solution: Ensure client and server use the same Firebase project credentials
NotRegisteredCause: App was uninstalled or token was invalidated
Solution: Remove the invalid token from your database
MessageTooBigCause: Payload exceeds 4KB limit
Solution: Reduce data payload size or use data-only messages
QuotaExceededCause: Too many messages sent in short time
Solution: Implement rate limiting and batch messages
import { platform } from '@/lib/platform'
// Listen for token errors
platform.notifications.onTokenError(async (error) => {
if (error.code === 'messaging/invalid-registration-token' ||
error.code === 'messaging/registration-token-not-registered') {
// Remove invalid token from database
await db.pushTokens.delete({
where: { token: error.token },
})
}
})
// Validate tokens before sending
const result = await platform.notifications.validateTokens({
tokens: ['token1...', 'token2...'],
})
console.log(result)
// {
// valid: ['token1...'],
// invalid: ['token2...'],
// }Debug Mode
SYLPHX_DEBUG=notifications node server.js