Setup

Step 1. Install Raven SDK

Run the following commands your project root directory. Latest version is 1.0.3

npm i @ravenapp/raven-web-react-sdk

Step 2. Initialize Firebase

Firebase will get installed as part of Step 1 and you only need to initialize Firebase on App start/launch. You can get the FIREBASE_CONFIG object and FIREBASE_VAPID_KEY from the Firebase console.

import { initFirebase } from "@ravenapp/raven-web-react-sdk";

initFirebase(FIREBASE_CONFIG, FIREBASE_VAPID_KEY);

Step 3. Setup Push notifications

  1. Add the service worker to your public folder and name it as messaging-sw.js. You can place it under your own path in the public folder. Just replcae the FIREBASE_CONFIG object with the one retrieved from Firebase and RAVEN_APP_ID with your App Id on Raven console.
importScripts("https://www.gstatic.com/firebasejs/8.2.9/firebase-app.js");
importScripts("https://www.gstatic.com/firebasejs/8.2.9/firebase-messaging.js");

// Initialize the Firebase app in the service worker by passing in
// your app's Firebase config object.
// https://firebase.google.com/docs/web/setup#config-object

const FIREBASE_CONFIG = YOUR_FIREBASE_CONFIG_OBJECT;

const RAVEN_APP_ID = YOUR_RAVEN_APP_ID;

firebase.initializeApp(FIREBASE_CONFIG);

const messaging = firebase.messaging();

messaging.onBackgroundMessage((payload) => {
  console.log("[messaging-sw.js] Received background message ");
  onMessageReceived(payload);
});

function handleClick(event) {
  event.notification.close();
  console.log("[messaging-sw.js] Clicked message");
  onMessageClicked(event.notification);
}

self.addEventListener("notificationclick", handleClick);

const broadcast = new BroadcastChannel("display-notification");
broadcast.onmessage = (event) => {
  try {
    let payload = event.data;
    if (payload && payload["type"] === "DELIVERED") {
      onMessageReceived(payload);
    }

    if (payload && payload["type"] === "CLICKED") {
      onMessageClicked(payload);
    }
  } catch (err) {
    console.log("Broadcast display-notification error: " + err);
  }
};

function updateStatus(notificationId, type) {
  if (!notificationId || !type) {
    return;
  }

  var BASE_URL = `https://api.ravenapp.dev/v1/apps/${RAVEN_APP_ID}`;
  var SET_DELIVERY_STATUS = `${BASE_URL}/push/status`;

  //get user api
  fetch(SET_DELIVERY_STATUS, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      notification_id: notificationId,
      type: type,
      timestamp: Date.now(),
      current_timestamp: Date.now(),
    }),
  })
    .then((response) => {
      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }
    })
    .then((data) => {
      // console.log(data);
    })
    .catch((error) => {
      console.error("Error:", error);
    });
}

function renderNotification(reg, payload) {
  if (payload && payload["data"]) {
    //form action array
    var actions = [];
    for (var i = 1; i <= 4; i++) {
      if (payload["data"]["action" + i]) {
        var action = payload["data"]["action" + i];
        var title = payload["data"]["title" + i];
        var icon = payload["data"]["icon" + i];
        actions.push({ action: action, title: title, icon: icon });
      }
    }

    const notificationTitle = payload["data"]["title"];
    const notificationOptions = {
      body: payload["data"]["body"],
      icon: payload["data"]["icon"],
      data: payload["data"],
      image: payload["data"]["image"],
      actions: actions,
    };
    reg.showNotification(notificationTitle, notificationOptions);
  }
}

function onMessageReceived(payload) {
  renderNotification(self.registration, payload);
  setTimeout(() => {
    updateStatus(payload["data"]["raven_notification_id"], "DELIVERED");
  }, 2000);
}

function onMessageClicked(payload) {
  const clickBroadcast = new BroadcastChannel("click-notification");
  var action = payload["action"];
  if (!action) {
    action = payload["data"]["click_action"];
  }
  clickBroadcast.postMessage({
    click_action: action,
  });
  setTimeout(() => {
    updateStatus(payload["data"]["raven_notification_id"], "CLICKED");
  }, 2000);
}

Step 4. Server Side: API that returns a unique signature for the user

You will need an API on the server side that returns a unique signature for a user.

  • This is required to securely identify the user on Raven without exposing the Raven API Key on the client side.
  • The client requests from its server a hash of the userId and Raven API key. All subsequent requests from client to Raven will have this signature.
  • Following example shows how to generate a HMAC-SHA256 Signature (hash of your userId signed with your Raven API Key) in Java - Add this dependency to pom.xml for using HmacUtils to generate signature
pom.xml
<dependency>
  <groupId>commons-codec</groupId>
  <artifactId>commons-codec</artifactId>
  <version>1.16</version>
</dependency>
import org.apache.commons.codec.digest.HmacUtils;

private String hmacSha256Signature(String userId, String apiKey) {
     return (new HmacUtils("HmacSHA256", apiKey.getBytes()).hmacHex(userId));
}

Step 5. Initialize Raven

5.1 Before user logs in

  • You need to do this step if you want to send notifications to the user who has not logged in yet. You will have to use Firebase topics to send notifications which is described in detail in the Sending Messages section.

  • Now you can use the following method to initialize Raven before login.

import { initRavenBeforeLogin } from "@ravenapp/raven-web-react-sdk";

initRavenBeforeLogin(RAVEN_APP_ID, tokenHash);
  • You can get RAVEN_APP_ID from Settings in Raven. tokenHash is generated using the Firebase token. Use the token from Raven SDK in Step 3.2 and generate a hash of the token with the API created in Step 4. The idea is to use the Firebase token as a replacement for userId, till the user logs in.

5.2 After user logs in

  • Once the user logs in, you need to reinitialize Raven.

  • Now you can use the following method to initialize Raven before login.

import { initRavenAfterLogin } from "@ravenapp/raven-web-react-sdk";

initRavenAfterLogin(RAVEN_APP_ID, userIdHash, userId);
  • You can get RAVEN_APP_ID from Settings in Raven. userIdHash is generated by creating a hash of userId using the API created in Step 4.

Step 6. Handle notification clicks

Listen to the broadcast channel: click-notification. The clickAction variable will have the action string which you can use to open a window or take any specific action

useEffect(() => {
  //Click handling
  const broadcast = new BroadcastChannel("click-notification");
  broadcast.onmessage = (event) => {
    try {
      if (event.data) {
        let clickAction = event.data["click_action"];
        //Take action here
        console.log(clickAction);
      }
    } catch (err) {
      console.log("Broadcast click-notification error: " + err);
    }
  };
}, []);

Sending messages

Follow the Sending Push doc to setup Firebase and create an event on the Raven console. Once done you can use Raven API to send push notifications.

1. Sending 1:1 to a user

To send a notification directly to a user you can pass either the registered fcm_tokens of the user or just pass the userId. Sending to userId will work if you are using Raven to manage the Firebase tokens. In this case, Raven SDK takes care of managing tokens and will send the notification to all the tokens registered for the userId.

curl --location --request POST 'https://api.ravenapp.dev/v1/apps/{APP_ID}/events/send' \
--header 'Authorization: AuthKey {API_KEY}' \
--header 'Content-Type: application/json' \
--data-raw '{
    "event" : {EVENT_NAME},
    "user": {
        "fcm_tokens": [{LIST_OF_TOKENS}]
        "user_id": {USER_ID}
    }
}'

2. Sending to a group of users

To send to a group of users, you can use Firebase Topics. In this case, you will have to register the user to a topic using Raven SDK. The SDK has two methods:

import { subscribeFirebaseTopic, unsubscribeFirebaseTopic } from "@ravenapp/raven-web-react-sdk";

subscribeFirebaseTopic(["TOPIC_NAME"]);
unsubscribeFirebaseTopic(["TOPIC_NAME"]);

You can pass the list of topics to subscribe a user. Note that this can be done only once you have initialized Firebase, retrieved the Firebase token and initialized Raven. Once subscribed you can pass the fcm_topic in the Raven API -

curl --location --request POST 'https://api.ravenapp.dev/v1/apps/{APP_ID}/events/send' \
--header 'Authorization: AuthKey {API_KEY}' \
--header 'Content-Type: application/json' \
--data-raw '{
    "event" : {EVENT_NAME},
    "user": {
        "fcm_topic": {TOPIC_NAME}
    }
}'

You are all set! Just fire Raven API and you should see your web push notification 👍 If you are facing any issues, please email us on support@ravenapp.dev