Navigation

Firebase Cloud Messaging Setup Guide

Complete instructions for implementing push notifications in Snappy English

Cross-Platform
Push Notifications
Progressive Web App
Step 1: Firebase Console Setup

1. Go to Firebase Console

https://console.firebase.google.com

2. 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
Step 2: Add Firebase Credentials to Base44

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)

Step 3: Frontend Firebase Config

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

Step 4: Service Worker Setup

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);
});
Step 5: Request Permission in App

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();
Step 6: Backend Function to Send Notifications

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 });
  }
});
Step 7: Testing Push Notifications

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