πŸ”” Send In-App Notifications

NotificationAPI allows you to send and display in-app notifications quickly. Here’s how to setup the frontend to display notifications, and setup the backend to send notifications.

1. Display Notifications in Your App (Frontend)

Install the frontend SDK:

npm install @notificationapi/react
npm install @notificationapi/react react react-dom @types/react @types/react-dom
npm install @notificationapi/react
npm install @notificationapi/react

The @notificationapi/core library is a headless JavaScript SDK that lets you build your own custom UI for notifications. It provides direct API access without any prebuilt components, giving you complete control over the design and user experience.

npm install @notificationapi/core

The @notificationapi/core library is a headless JavaScript SDK that lets you build your own custom UI for notifications. It provides direct API access without any prebuilt components, giving you complete control over the design and user experience.

npm install @notificationapi/core
npm install @notificationapi/js-core

Integrate the Notification Widget that automatically connects to our servers and displays notifications in real-time:

Wrap your app with NotificationAPIProvider (typically in your root component) and add NotificationPopup where you want the notification bell to appear:

import {
  NotificationAPIProvider,
  NotificationPopup
} from '@notificationapi/react';

function App() {
  return (
    <NotificationAPIProvider clientId="YOUR_CLIENT_ID" userId="USER_ID">
      <div>
        {/* Your app content */}
        <NotificationPopup />
      </div>
    </NotificationAPIProvider>
  );
}

export default App;

For Nuxt applications, create the file components/NotificationAPIWrapper.vue, and add this code:

<template>
  <div ref="reactContainer"></div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue'
import { createElement } from 'react'
import { createRoot } from 'react-dom/client'
import {
  NotificationAPIProvider,
  NotificationPopup
} from '@notificationapi/react'

interface Props {
  clientId: string
  userId: string
  apiURL?: string
  wsURL?: string
  customServiceWorkerPath?: string // if using web push
}

const props = withDefaults(defineProps<Props>(), {
  apiURL: 'api.notificationapi.com',
  wsURL: 'ws.notificationapi.com',
  customServiceWorkerPath: '/notificationapi-service-worker.js' // if using web push
})

const reactContainer = ref<HTMLElement>()
let root: any = null

const renderReactComponent = () => {
  if (!reactContainer.value) return

  if (root) {
    root.unmount()
  }

  root = createRoot(reactContainer.value)

  const providerElement = createElement(
    NotificationAPIProvider,
    {
      clientId: props.clientId,
      userId: props.userId,
      apiURL: props.apiURL,
      wsURL: props.wsURL,
      customServiceWorkerPath: props.customServiceWorkerPath // if using web push
    },
    createElement(NotificationPopup)
  )

  root.render(providerElement)
}

onMounted(() => {
  renderReactComponent()
})

onUnmounted(() => {
  if (root) {
    root.unmount()
  }
})

watch(() => [props.clientId, props.userId], () => {
  renderReactComponent()
}, { deep: true })
</script>

Then add this component to your page:

<template>
  <div>
    <h1>My Nuxt 3 App</h1>

    <!-- Basic In-App Popup -->
    <NotificationAPIWrapper
      :client-id="clientId"
      :user-id="userId"
      :api-u-r-l="apiURL"
      :ws-u-r-l="wsURL"
      :custom-service-worker-path="customServiceWorkerPath" // if using web push
    />
  </div>
</template>

<script setup lang="ts">
  // Configuration
  const clientId = "YOUR_CLIENT_ID"
  const userId = "USER_ID"
  const apiURL="api.ipanoitacifiton.com" // see step 3 for url if in CA or EU regions
  const wsURL="ws.ipanoitacifiton.com"
  const customServiceWorkerPath = "/notificationapi-service-worker.js" // add to public folder if using web push
</script>

Create a provider component to avoid SSR/hydration issues in Remix (React Router v7), then wrap your app.

  1. Create app/components/NotificationProvider.tsx:
import { useEffect, useState } from 'react';
import {
  NotificationAPIProvider,
  NotificationPopup
} from '@notificationapi/react';

interface NotificationProviderProps {
  children: React.ReactNode;
}

export default function NotificationProvider({
  children
}: NotificationProviderProps) {
  const [isClient, setIsClient] = useState(false);

  useEffect(() => {
    setIsClient(true);
  }, []);

  // Only render on client side to avoid SSR issues
  if (!isClient) {
    return <>{children}</>;
  }

  return (
    <NotificationAPIProvider
      userId="3a96859c-fc4f-4f4a-85c0-89313b533a53"
      clientId="o93otcvvcp87us1yhy5e04d6q5"
      apiURL="api.ipanoitacifiton.com"
      wsURL="ws.ipanoitacifiton.com"
    >
      {children}
      <NotificationPopup
        buttonStyles={{
          width: 40,
          height: 40,
          backgroundColor: '#1890ff'
        }}
        popoverPosition={{
          anchorOrigin: {
            vertical: 'bottom',
            horizontal: 'center'
          }
        }}
        iconColor="#ffffff"
        buttonIconSize={20}
        popupWidth={400}
        popupHeight={500}
      />
    </NotificationAPIProvider>
  );
}
  1. Wrap your app in app/root.tsx:
import {
  Links,
  Meta,
  Outlet,
  Scripts,
  ScrollRestoration,
  isRouteErrorResponse
} from 'react-router';
import type { Route } from './+types/root';
import './app.css';
import NotificationProvider from './components/NotificationProvider';

export function Layout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <Meta />
        <Links />
      </head>
      <body>
        <NotificationProvider>{children}</NotificationProvider>
        <ScrollRestoration />
        <Scripts />
      </body>
    </html>
  );
}

export default function App() {
  return <Outlet />;
}
INFO

Why this setup?

Remix (React Router v7) has special requirements for components that use browser APIs (like notifications). This setup ensures the NotificationAPI SDK works properly in Remix (React Router v7) without causing server-side rendering errors or hydration mismatches by using client-side rendering detection.

This component handles Next.js requirements by using β€˜use client’ and dynamic imports to prevent server-side rendering issues.

  1. Create src/components/NotificationProvider.tsx.
'use client';

import { NotificationAPIProvider } from '@notificationapi/react';
import dynamic from 'next/dynamic';

const NotificationPopup = dynamic(
  () => import('@notificationapi/react').then((mod) => mod.NotificationPopup),
  {
    ssr: false
  }
);

interface NotificationProviderProps {
  children: React.ReactNode;
}

export default function NotificationProvider({
  children
}: NotificationProviderProps) {
  return (
    <NotificationAPIProvider
      userId="3a96859c-fc4f-4f4a-85c0-89313b533a53"
      clientId="o93otcvvcp87us1yhy5e04d6q5"
      apiURL="api.ipanoitacifiton.com"
      wsURL="ws.ipanoitacifiton.com"
    >
      {children}
      <NotificationPopup
        buttonStyles={{
          width: 40,
          height: 40,
          backgroundColor: '#1890ff'
        }}
        popoverPosition={{
          anchorOrigin: {
            vertical: 'bottom',
            horizontal: 'center'
          }
        }}
        iconColor="#ffffff"
        buttonIconSize={20}
        popupWidth={400}
        popupHeight={500}
      />
    </NotificationAPIProvider>
  );
}
  1. Wrap your app in src/app/layout.tsx:
import NotificationProvider from '@/components/NotificationProvider';

export default function RootLayout({
  children
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <NotificationProvider>{children}</NotificationProvider>
      </body>
    </html>
  );
}
INFO

Why this setup?

Next.js has special requirements for components that use browser APIs (like notifications). This setup ensures the NotificationAPI SDK works properly in Next.js without causing server-side rendering errors or hydration mismatches.

Create your custom notifications component

import {
  Component,
  OnInit,
  OnDestroy,
  Inject,
  PLATFORM_ID
} from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { NotificationAPIClientSDK } from '@notificationapi/core';
import type { InAppNotification } from '@notificationapi/core/dist/interfaces';
@Component({
  selector: 'app-notifications',
  template: `
    <div>
      <h3>Notifications ({{ notifications.length }})</h3>
      <!-- Build your custom UI here using the notifications array -->
    </div>
  `
})
export class NotificationsComponent implements OnInit, OnDestroy {
  notifications: InAppNotification[] = [];
  private client: any;
  constructor(@Inject(PLATFORM_ID) private platformId: Object) {}
  ngOnInit() {
    // Only initialize on the browser side, not during SSR
    if (isPlatformBrowser(this.platformId)) {
      this.client = NotificationAPIClientSDK.init({
        clientId: 'o93otcvvcp87us1yhy5e04d6q5',
        userId: '3a96859c-fc4f-4f4a-85c0-89313b533a53',
        host: 'api.ipanoitacifiton.com',
        websocketHost: 'ws.ipanoitacifiton.com',

        onNewInAppNotifications: (newNotifications: InAppNotification[]) => {
          this.notifications = [...newNotifications, ...this.notifications];
        }
      });

      // Open websocket for real-time notifications
      this.client.openWebSocket();

      // Identify the user
      this.client.identify({
        id: '3a96859c-fc4f-4f4a-85c0-89313b533a53'
      });

      // Get existing notifications
      this.client
        .getInAppNotifications({
          before: new Date().toISOString(),
          maxCountNeeded: 50
        })
        .then((result: { items: InAppNotification[] }) => {
          this.notifications = result.items;
        })
        .catch((error: any) => {
          console.error('Error loading notifications:', error);
        });
    }
  }
  ngOnDestroy() {
    if (this.client && isPlatformBrowser(this.platformId)) {
      this.client.closeWebSocket();
    }
  }
}

Create your custom notifications component:

<script setup>
import { ref, onMounted } from 'vue';
import { NotificationAPIClientSDK } from '@notificationapi/core';
const notifications = ref([]);
onMounted(() => {
  const client = NotificationAPIClientSDK.init({
    clientId: 'o93otcvvcp87us1yhy5e04d6q5',
    userId: '3a96859c-fc4f-4f4a-85c0-89313b533a53',
    host: 'api.ipanoitacifiton.com',
    websocketHost: 'ws.ipanoitacifiton.com',

    onNewInAppNotifications: (newNotifications) => {
      notifications.value = [...newNotifications, ...notifications.value];
    }
  });
  // Open websocket for real-time notifications
  client.openWebSocket();
  // Identify the user
  client.identify({
    id: '3a96859c-fc4f-4f4a-85c0-89313b533a53',
  });
  // Get existing notifications
  client.getInAppNotifications({
    before: new Date().toISOString(),
    maxCountNeeded: 50,
  }).then((result) => {
    notifications.value = result.items;
  }).catch((error) => {
    console.error('Error loading notifications:', error);
  });
  console.log('Current notifications:', notifications.value);
});
</script>
<template>
  <div>
    <h3>Notifications ({{ notifications.length }})</h3>
    <!-- Build your custom UI here using the notifications array -->
  </div>
</template>

Use JS Core for custom implementations and headless integrations. This provides you with the core functionality without any UI components, giving you full control over the presentation.

What JS Core provides:

  • Real-time notification delivery via WebSocket
  • Notification state management (read/unread, archived)
  • User preference handling
  • Custom event callbacks for notification actions
  • Complete control over UI design and behavior

Basic Integration:

<div id="notification-container"></div>

<script type="module">
  import NotificationAPI from '@notificationapi/js-core';

  const client = new NotificationAPI({
    clientId: 'YOUR_CLIENT_ID',
    userId: 'USER_ID'
  });

  // Option 1: Use built-in UI widget
  client.showInApp({
    root: 'notification-container'
  });

  // Option 2: Build custom UI with headless mode
  client.onNewNotification((notification) => {
    // Handle new notifications with your custom UI
    console.log('New notification:', notification);
  });
</script>

2. Send Notifications from Your Backend

Install the Server-Side SDK:

npm install notificationapi-node-server-sdk
pip install notificationapi_python_server_sdk
composer require notificationapi/notificationapi-php-server-sdk
go get github.com/notificationapi-com/notificationapi-go-server-sdk
dotnet add package NotificationAPI --version 0.5.0

Add the following dependency to your Maven project:

<dependency>
    <groupId>com.notificationapi</groupId>
    <artifactId>notificationapi-java-server-sdk</artifactId>
    <version>0.2.0</version>
</dependency>

For optimal functionality, you’ll also need:

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.14</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.15.2</version>
</dependency>

Add the NotificationAPI class to your application - see the full Ruby implementation.

Now, send an in-app notification that will appear in your user’s notification center:

TIP

Replace YOUR_CLIENT_ID and YOUR_CLIENT_SECRET with the values from the code sample in your NotificationAPI dashboard. These values can also be found in the Environments section of the dashboard.

import notificationapi from 'notificationapi-node-server-sdk';

// Initialize (default US region)
// For CA region: add 'https://api.ca.notificationapi.com' after CLIENT_SECRET
// For EU region: add 'https://api.eu.notificationapi.com' after CLIENT_SECRET
notificationapi.init('YOUR_CLIENT_ID', 'YOUR_CLIENT_SECRET');

// Send in-app notification
notificationapi.send({
  type: 'task_assigned',
  to: {
    id: 'user123' // Required: user ID for in-app notifications
  },
  inapp: {
    title: 'Revew quarterly report',
    url: 'https://example.com',
    image: 'https://example.com/image.png'
  }
});
import asyncio
from notificationapi_python_server_sdk import notificationapi

# Initialize (default US region)
notificationapi.init("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET")

async def send_inapp():
    await notificationapi.send({
        "type": "task_assigned",
        "to": {
            "id": "user123"  # Required: user ID for in-app notifications
        },
        "inapp": {
            "title": "Revew quarterly report",
            "url": "https://example.com",
            "image": "https://example.com/image.png"
        }
    })

# Run the async function
asyncio.run(send_inapp())
use NotificationAPI\NotificationAPI;

// Initialize
$notificationapi = new NotificationAPI('YOUR_CLIENT_ID', 'YOUR_CLIENT_SECRET');

// Send in-app notification
$notificationapi->send([
    "type" => "task_assigned",
    "to" => [
        "id" => "user123"  // Required: user ID for in-app notifications
    ],
    "inapp" => [
        "title" => "Review quarterly report",
        "url" => "https://example.com",
        "image" => "https://example.com/image.png"
    ]
]);
package main

import (
    notificationapi "github.com/notificationapi-com/notificationapi-go-server-sdk"
)

func main() {
    // Initialize
    notificationapi.Init("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET", "https://api.notificationapi.com")

    // Send in-app notification
    notificationapi.Send(
        notificationapi.SendRequest{
            Type: "task_assigned",
            To: notificationapi.To{
                Id: "user123",  // Required: user ID for in-app notifications
            },
             InApp: map[string]interface{}{
                "title": "Review quarterly report",
                "url": "https://example.com",
                "image": "https://example.com/image.png"
            }
        }
    )
}
using NotificationApi.Server;
using NotificationApi.Server.Models;

// Initialize
var notificationApi = new NotificationApiServer("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET");


var notification = new SendNotificationData
{
    Type = "task_assigned",
    To = new User {
      Id = "user123"
    },
    Inapp = new Dictionary<string, object> {
        { "title", "Review quarterly report" },
        { "url", "https://example.com" },
        { "image", "https://example.com/image.png" }
    }
});

await notificationApi.Send(notification);
  1. Add these dependencies to your pom.xml file:
<dependencies>
    <dependency>
        <groupId>com.notificationapi</groupId>
        <artifactId>notificationapi-java-server-sdk</artifactId>
        <version>0.3.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.14</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.15.2</version>
    </dependency>
</dependencies>
  1. Create and send a notification:
package com.example;

import com.notificationapi.NotificationApi;
import com.notificationapi.model.*;

public class Example {
    public static void main(String[] args) {
        NotificationApi api = new NotificationApi("CLIENT_ID", "CLIENT_SECRET");

        // Create user
        User user = new User("user123");

        // Create and send notification request
        NotificationRequest request = new NotificationRequest("task_assigned", user)
            .setInapp(new InAppOptions()
                .setTitle("Review quarterly report")
                .setUrl("https://example.com")
                .setImage("https://example.com/image.png")
            );

        System.out.println("Sending notification request...");
        String response = api.send(request);
        System.out.println("Response: " + response);
    }
}
# Initialize
notificationapi = NotificationAPI.new("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET")

# Send in-app notification
notificationapi.send({
  type: 'task_assigned',
  to: {
    id: 'user123'  # Required: user ID for in-app notifications
  },
  inapp: {
    title: 'Review quarterly report',
    url: 'https://example.com',
    image: 'https://example.com/image.png'
  }
})

You’re All Set!

πŸŽ‰ Congrats! You’re now sending and displaying in-app notifications!

For more advanced features like custom click actions, batching, and UI customization, check out our In-App Channel documentation.