Sneh Pandya Exploring the horizon with a knack for product management. Co-host of the NinjaTalks podcast and community organizer at Google Developers Group. Explorer, adventurer, traveler.

Managing multi-channel notification streams with Notifire

7 min read 1963

Managing Multi-Channel Notification Streams with Notifire

Nowadays, users are more likely to receive communication from multiple channels.

The fundamental reason for this is that consumers expect to be able to tailor communication channels to their own requirements—which compels developers to handle all of those APIs across the codebase. Notifications come in a variety of shapes and sizes; from Reddit to Facebook, Twitter, and beyond.

To customers, the notifications represent updates on their favorite people, businesses, and interests. A notification system, therefore, is a strong approach for web developers and SaaS marketers to get their goods in front of the people who matter.

There is a wealth of knowledge available, but people only have so much time and capacity to share, meaning only the most attractive services will be able to properly woo their target demographic.

Simultaneously, the popularity of native notification systems across online browsers and mobile operating systems is beneficial to organizations who can utilize them successfully for customer outreach. These timely messages can have a huge impact on client retention and engagement performance.

In this article, you will learn about Notifire, how it’s implemented, and its versatility in offering opportunities to target end users according to specific needs.

What is Notifire?

Notifire is a powerful and customizable open source notification infrastructure that uses a single API to manage multi-channel transactional notifications.

Benefits and features of Notifire:

  • All messaging services such as email, push notifications, and SMS use the same API
  • Easily manage multiple channels such as Twilio, SendGrid, Slack and many more
  • Highly customizable, template-focused engine for advanced layouts and designs
  • Built-in protection for missing variables
  • Ease of setup and integration
  • Written in TypeScript with predictable static types
  • Community driven and open source

Architecture and setup

Notifire is written in TypeScript; you can create a notification layer in just a few minutes with Notifire.

Before diving into the implementation, you need to understand the architecture behind the library in order to gain clarity on how notifications are supercharged with Notifire.

Notifire’s architecture focuses on the separation of concerns. According to this principle, transactional communication is made up of many independent elements, each of which is accountable for a certain job. In order for extra functionality to be readily incorporated and maintained, the communication layer must be modeled.

Have a look at the diagram below.

Notifire Flow Delivery Diagram


The following elements ensure the successful flow of delivering notifications to your end users:


Templates act as a blueprint and provide a skeleton or structure for each message. Each message is linked with a specific channel, for which a content template and coding rules—like filters, priority, and other metadata affecting the delivery of a given message—are supplied.


Providers are responsible for message delivery. They are in charge of providing alerts to end users via the designated channel. Notifire handles state and mediates all provider-specific customizations, since each provider is stateless and conforms to a specified interface.


The variables and data necessary to display the notification messages will be sent by each trigger. If a value is not present, the variable protection mode is activated and the message is not transmitted.

Triggers are responsible for informing the system that an event occurred, but not where and when the message will be delivered.

Communication engine

The communication engine is responsible for reading the template configurations, determining the necessary channels, connecting with the providers, and performing delivery of the alerts. Timing, priority, and channel are all maintained by the communication engine.

Template and provider stores

During runtime execution, these two layers manage the configuration and are saved in memory for further use. Each of the stores offer interfaces to query the providers and templates to be used by the communication engine.

Template-based approach

Let’s have a look at the template-based approach in Notifire.

More great articles from LogRocket:

Templates hold the necessary metadata for message delivery. These templates can be re-used and stored in the Template Store for access. It contains major sections such as subject, channel, template, and active switches.

Have a look at the simple example below:

const UpdateEmailTemplate = await notifire.registerTemplate({
  id: "update-email",
  messages: [
      subject: "Your email update request",
      channel: ChannelTypeEnum.EMAIL,           // Email Channel
      template: `
        Hi {{firstName}}!

        To update your email, click <a href="{{emailLink}}">here.</a>

        {{#if organization}}
            <img src="{{organization.logo}}" />
      channel: ChannelTypeEnum.SMS,             // SMS Channel
      template: ` 
        Hey {{firstName}}, here's the link to update your email: {{emailLink}}
      active: (trigger) => !trigger.$phone,

As you can see, the messages array holds a list of communication channels and corresponding message details to be sent to the users. You can personalize the channel experience by including channel-specific details similar to the above example.

channel specifies the medium through which the user needs to be informed. Based on the channel selected, an appropriate provider is used from the Provider Store.

The examples of channels can be: SMS, EMAIL, PUSH, DIRECT_MESSAGE, IN_APP. Each channel specified with its enum value holds its object block as shown in the above example.

The template variable holds the message content. Notifire makes use of Handlebars so you can write your templates in the Handlebars expression format, as demonstrated in the following example:

{{#each tasks}}
  {{#if done}}
    <span> Done </span>

The active switch is used to determine whether the message should be sent or not on the basis of boolean value provided. active is also used to send messages based on Triggers.

Benefits of the template-based approach:

  • Highly customizable and re-usable templates for communication
  • Scalable and fail-proof approach with variable protection
  • Target users on the basis of variables, functions, conditions, and behaviors

Integrating your favorite providers

Notifire provides a plug-and-play solution for providers which typically stays on standby mode once loaded in the Provider Store’s memory. Let’s have a look at the list of providers supported by Notifire:


Emails are one of the most common and widely used channels of communication. Notifire provides the below interface to implement your own version of channel:

export interface IProvider {
  id: string;                       // ID of the template
  channelType: ChannelTypeEnum;     // Type of channel such as EMAIL

export interface IEmailOptions {
  to: string | string[];            // One or multiple recepients
  subject: string;                  // Subject of the email
  html: string;                     // Content body of the email
  from?: string;                    // Email ID of the sender
  text?: string;                    // Plain text content body of the email

export interface IEmailProvider extends IProvider {
  channelType: ChannelTypeEnum.EMAIL;

  sendMessage(options: IEmailOptions): Promise<any>;        // Method to be overridden to send email message

Popular email providers—including SendGrid, Mailgun, AWS SES, Postmark, NodeMailer, Mailjet, Mandrill, SendinBlue, EmailJS—are currently supported and the number of supported providers is constantly growing.

To register a specific email provider, you need to register it with the Notifire library as shown below:

import { SESEmailProvider } from "@notifire/ses"        // Import your required provider

const provider = new SESEmailProvider({                 // Declare your provider
    region: "eu-west-1",                                ////
    accessKeyId: "AWS_ACCESS_KEY_ID",                   ////    Provide configuration details to register your provider
    secretAccessKey: "AWS_SECRET_ACCESS_KEY",           ////
    from: "[email protected]",                             ////
});                                                     //

import { MailgunEmailProvider } from '@notifire/mailgun';   // Mailgun email provider

const provider = new MailgunEmailProvider({
  apiKey: process.env.MAILGUN_API_KEY,
  domain: process.env.MAILGUN_DOMAIN,
  username: process.env.MAILGUN_USERNAME,

import { SendinblueEmailProvider } from './sendinblue.provider';    //  SendinBlue email provider

const provider = new SendinblueEmailProvider({
  apiKey: process.env.SENDINBLUE_API_KEY


Just like email, Notifire allows SMS providers as well. Below is the interface used to implement the SMS provider:

export interface IProvider {
  id: string;                           // ID of the template
  channelType: ChannelTypeEnum;         // Type of communication channel

export interface ISmsOptions {
  to: string;                           // Number on which SMS needs to be sent
  content: string;                      // Content body to be sent in the SMS
  from?: string;                        // Number of the sender

export interface ISmsProvider extends IProvider {
  sendMessage(options: ISmsOptions): Promise<any>;      // Method to be overridden to send email message

  channelType: ChannelTypeEnum.SMS;

Popular SMS providers including Twilio, AWS SNS, and Plivo are currently supported and the number of supported SMS providers is also growing. To register a specific SMS provider, you need to register it with the Notifire library as shown below:

import { TwilioSmsProvider } from '@notifire/twilio';   // Twilio SMS provider

const provider = new TwilioSmsProvider({
  accountSid: process.env.TWILIO_ACCOUNT_SID,
  authToken: process.env.TWILIO_AUTH_TOKEN,
  from: process.env.TWILIO_FROM_NUMBER,                 // a valid twilio phone number

import { SNSSmsProvider } from "@notifire/sns"          // AWS SNS provider

const provider = new SNSSmsProvider({
    region: "eu-west-1",
    accessKeyId: "AWS_ACCESS_KEY_ID",
    secretAccessKey: "AWS_SECRET_ACCESS_KEY",

import { PlivoSmsProvider } from '@notifire/plivo';      // Plivo SMS provider

const provider = new PlivoSmsProvider({
  accountSid: process.env.PLIVO_ACCOUNT_ID,
  authToken: process.env.PLIVO_AUTH_TOKEN,
  from: process.env.PLIVO_FROM_NUMBER,

More providers

As you can see, it is straightforward to plug-and-play your favorite provider as per your need; all you need to do is register the provider with Notifire using the configuration and start using the templates declared.

Apart from email and SMS providers, Notifire will expand in the future to allow for setting up providers for direct messages, push notifications, and in-app messages.

This will include providers ranging from Slack, Microsoft Teams, Discord, PagerDuty, AWS SNS, and many more.

Scaling your implementation

Many organizations today use a variety of different communication platforms and things start to get messy as the list of such platforms continues to grow. Notifire has solved this issue quite intelligently by making use of components like templates in the architecture.

When scaling your product or service, your implementation needs to handle the scale of users and communication as well.

Below are a few best practices that you should follow to ensure a great experience for your users.

Avoid using generic content

Using generic, lengthy, and impersonal material in a push message is a significant error that can overwhelm and upset the recipient. Such alerts may cause the mobile app linked with that particular push message to be uninstalled.

Avoid bombarding your users

Sending notifications or communication without sufficient business intelligence (BI) and consumer behavior analysis might result in a poor user experience and you might end up targeting non-relevant users.

Avoid targeting at inopportune times

One of the most common mistakes marketers make when utilizing push notifications is delivering them at the wrong time. It is not a good idea to send messages during hectic work hours or late at night. This may irritate users, and as a result, they may stop using your product or services.

Make use of personalization

In many situations, marketers make this error by sending generic notifications without doing a sufficient behavioral analysis of behavioral traits, personal data, location information, and client interest.

There are several sorts of users that respond to alerts in various ways. A large majority of users, 57 percent, read and open the app to answer instantly if the message is suitably tailored.

Send a welcome notification

When users have been thoroughly onboarded, you may send them a push notice welcoming them to the app. Alternatively, you may get them off to a good start by providing a discount coupon for a product you offer. Also, as a taster, provide them with some free goodies—anything to offer them a taste of your software and entice them to use it more.


Targeting users with appropriate notifications and communication is crucial in today’s digital marketplace.

It goes without saying that notifications have surpassed all other modes of communication between apps, products, services, and their users.

As a result, a modern organization’s presence requires a strong notification strategy.

Notifire provides a platform to build and scale your notification infrastructure with amazing capabilities.

As the use cases grow and expand, Notifire is set to provide a plethora of options and provider implementations for you to seamlessly incorporate in your workflow.

This solution aims to act as a hassle-free solution for developers with promising capabilities.

Get setup with LogRocket's modern error tracking in minutes:

  1. Visit to get an app ID.
  2. Install LogRocket via NPM or script tag. LogRocket.init() must be called client-side, not server-side.
  3. $ npm i --save logrocket 

    // Code:

    import LogRocket from 'logrocket';
    Add to your HTML:

    <script src=""></script>
    <script>window.LogRocket && window.LogRocket.init('app/id');</script>
  4. (Optional) Install plugins for deeper integrations with your stack:
    • Redux middleware
    • ngrx middleware
    • Vuex plugin
Get started now
Sneh Pandya Exploring the horizon with a knack for product management. Co-host of the NinjaTalks podcast and community organizer at Google Developers Group. Explorer, adventurer, traveler.

Leave a Reply