Firebase Cloud Messaging Setup Guide
Complete instructions for implementing push notifications in Snappy English
1. Go to Firebase Console
https://console.firebase.google.com2. Create a new project or select existing
Project name: snappy-english
3. Enable Cloud Messaging
Go to: Project Settings → Cloud Messaging → Enable API
4. Generate Web Push Certificates
Cloud Messaging → Web Configuration → Generate key pair
📝 Save these credentials:
- • Server Key (for backend)
- • VAPID Key (for frontend)
- • Sender ID
Go to your Base44 app dashboard → Settings → Secrets and add:
FIREBASE_SERVER_KEY
The Server Key from Firebase Console (starts with "AAAA...")
FIREBASE_VAPID_KEY
The Web Push certificate public key
FIREBASE_PROJECT_ID
Your Firebase project ID (e.g., "snappy-english-123")
FIREBASE_SENDER_ID
The Sender ID from Firebase (numeric)
Create firebase-config.js in your project:
import { initializeApp } from 'firebase/app';
import { getMessaging, getToken, onMessage } from 'firebase/messaging';
const firebaseConfig = {
apiKey: "YOUR_API_KEY", // From Firebase Console
authDomain: "snappy-english-123.firebaseapp.com",
projectId: "snappy-english-123",
storageBucket: "snappy-english-123.appspot.com",
messagingSenderId: "123456789",
appId: "YOUR_APP_ID"
};
const app = initializeApp(firebaseConfig);
const messaging = getMessaging(app);
export { messaging, getToken, onMessage };Get Firebase Config Values
Firebase Console → Project Settings → General → Your apps → Web app
Create public/firebase-messaging-sw.js:
importScripts('https://www.gstatic.com/firebasejs/10.7.1/firebase-app-compat.js');
importScripts('https://www.gstatic.com/firebasejs/10.7.1/firebase-messaging-compat.js');
firebase.initializeApp({
apiKey: "YOUR_API_KEY",
authDomain: "snappy-english-123.firebaseapp.com",
projectId: "snappy-english-123",
storageBucket: "snappy-english-123.appspot.com",
messagingSenderId: "123456789",
appId: "YOUR_APP_ID"
});
const messaging = firebase.messaging();
// Handle background messages
messaging.onBackgroundMessage((payload) => {
console.log('Received background message:', payload);
const notificationTitle = payload.notification.title;
const notificationOptions = {
body: payload.notification.body,
icon: '/icon-192x192.png',
badge: '/badge-72x72.png'
};
self.registration.showNotification(notificationTitle, notificationOptions);
});Use this React component to request notification permissions:
import { useEffect } from 'react';
import { messaging, getToken } from './firebase-config';
import { base44 } from '@/api/base44Client';
import { toast } from 'sonner';
export function useNotifications() {
useEffect(() => {
requestPermission();
}, []);
const requestPermission = async () => {
try {
const permission = await Notification.requestPermission();
if (permission === 'granted') {
const token = await getToken(messaging, {
vapidKey: 'YOUR_VAPID_KEY'
});
if (token) {
// Save token to backend
await base44.functions.invoke('savePushToken', {
token: token,
device: navigator.userAgent
});
toast.success('Notifications enabled!');
}
} else {
console.log('Permission denied');
}
} catch (error) {
console.error('Notification error:', error);
}
};
}
// In your App.jsx or Layout.jsx:
// import { useNotifications } from './hooks/useNotifications';
// useNotifications();Create functions/sendPushNotification.js:
import { createClientFromRequest } from 'npm:@base44/sdk@0.8.4';
Deno.serve(async (req) => {
try {
const base44 = createClientFromRequest(req);
const user = await base44.auth.me();
if (!user || user.role !== 'admin') {
return Response.json({ error: 'Unauthorized' }, { status: 401 });
}
const { title, body, target_user_email } = await req.json();
// Get user's FCM token
const subscriptions = await base44.entities.PushSubscription.filter({
user_email: target_user_email,
is_active: true
});
if (subscriptions.length === 0) {
return Response.json({
success: false,
message: 'No active subscriptions'
});
}
const serverKey = Deno.env.get('FIREBASE_SERVER_KEY');
// Send to Firebase
const results = await Promise.all(
subscriptions.map(async (sub) => {
const response = await fetch(
'https://fcm.googleapis.com/fcm/send',
{
method: 'POST',
headers: {
'Authorization': `key=${serverKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
to: sub.fcm_token,
notification: {
title: title,
body: body,
icon: '/icon-192x192.png',
click_action: window.location.origin
}
})
}
);
return response.json();
})
);
return Response.json({
success: true,
sent: results.length,
results
});
} catch (error) {
return Response.json({
error: error.message
}, { status: 500 });
}
});1. Test from Firebase Console
Firebase Console → Cloud Messaging → Send test message
2. Test from your backend function
Call sendPushNotification from your app
3. Test on different devices
- Desktop (Chrome, Firefox, Edge)
- Mobile web (PWA installed)
- Background vs foreground
🎯 Use Cases:
- Daily idiom reminder (7am user's timezone)
- Practice streak protection (missed practice alert)
- New assignment from teacher
- Treasure chest unlocked
- Voucher claim approved
- Study circle session starting soon