In-app notification inbox
Add a real-time notification inbox to a web app without building the pipeline. The Inbox component, HMAC-signed subscribers, tabs, preferences and the REST feed.
The in-app channel gives your product a notification center without any external provider, and without a message pipeline of your own to build: notifications land in a per-subscriber feed and are pushed to connected clients in real time by Notifly's dedicated websocket service. You add one Inbox component to your app; storage, the feed API, live updates, read state and subscriber preferences are already hosted.
How it works
- A workflow with an in-app step is triggered for a subscriber.
- The delivery worker renders the message and stores it in the subscriber's feed.
- The websocket service pushes the new notification to any of the subscriber's connected sessions instantly. Unread counts and feed contents update live.
- Read, seen, archived and snoozed state is tracked per notification, and the feed is queryable over the REST API (
notificationsandmessagesendpoints).
The Inbox UI
Notifly inherits Novu's embeddable Inbox component: a prebuilt notification-center UI (bell, feed, read states) that connects to the API and websocket service. The JavaScript, React and Next.js SDKs ship the inbox component; the React Native SDK ships the data hooks. These client SDKs are open source.
The React component is published on npm as @notiflyio/react. The React notification inbox guide covers adding it to an app, signing each subscriber with HMAC so a feed only opens for its own user, theming, localization and tabs, and when building your own UI on the REST API is the better call. The other client packages are listed in the SDK notes on the API page.
Pass socketUrl: 'https://ws.notifly.io' explicitly (the socketUrl prop on <Inbox> or NovuProvider): @notiflyio/js, @notiflyio/react, @notiflyio/nextjs and @notiflyio/react-native releases before 3.19.2 connect to Novu's socket host when it is omitted, so live updates never arrive. From 3.19.2 it is the default.
Add the Inbox to a React app
Install the package, then render Inbox where the bell should appear:
npm install @notiflyio/react@3.17.1import { Inbox } from '@notiflyio/react';
export function NotificationCenter({ userId, subscriberHash }: { userId: string; subscriberHash: string }) {
return (
<Inbox
applicationIdentifier="<app-identifier>"
subscriber={userId}
subscriberHash={subscriberHash}
socketUrl="https://ws.notifly.io"
/>
);
}applicationIdentifier is the Application Identifier on the dashboard's API Keys page. subscriber is the same subscriber ID your backend triggers workflows for. subscriberHash is that ID signed on your server, as described next. The component talks to https://api.notifly.io by default.
Sign each subscriber with HMAC
The Application Identifier is public, so without a check anyone could open any subscriber's feed. The check is Security HMAC encryption on the environment's in-app integration: with it on, the Inbox only opens a session whose subscriberHash is the subscriber ID signed with your environment's secret key, and refuses a missing or wrong hash. New Production environments have it on by default and the Development environment starts with it off. An environment created before that default can still have it off, so check the switch on its in-app integration before going live.
Compute the hash on your server and pass it to the component. The secret key must never reach the browser:
// npm install @notiflyio/api@0.1.26
import { computeSubscriberHash } from '@notiflyio/api';
const secretKey = process.env.NOTIFLY_SECRET_KEY;
if (!secretKey) throw new Error('NOTIFLY_SECRET_KEY is not set');
const subscriberHash = await computeSubscriberHash(secretKey, user.id);computeSubscriberHash is HMAC-SHA256 of the subscriber ID, returned as lowercase hex.
Tabs, preferences and read state
- Tabs. The
tabsprop splits the feed by workflow tags, by data object values, or by severity. Each tab'sfilterruns on the server. - Preferences. The built-in
Preferencesview lets each subscriber choose which workflows and channels reach them, and workflows check those choices before they send. A workflow marked Critical workflow, such as a password reset, ignores the subscriber's choices and its switch is disabled in the view. - Read state. A notification can be marked read or unread, archived or unarchived, snoozed or unsnoozed, and deleted, one at a time or in bulk. The same operations exist on the REST API.
- Appearance. Colors, element styles, icons, the dark theme and your own item markup are covered in Inbox styling.
Reading the feed over REST
Because the inbox is backed by ordinary API resources, you can also build a fully custom notification UI: list a subscriber's notifications, mark them read, and page through history. With your environment's secret key:
curl "https://api.notifly.io/v2/subscribers/<subscriber-id>/notifications?limit=10&read=false" \
-H "Authorization: ApiKey $NOTIFLY_SECRET_KEY"GET /v2/subscribers/{subscriberId}/notifications filters by tags, read, archived, snoozed, seen, data, severity and a created-at range, and pages with limit (up to 100), offset or after. GET .../notifications/count counts notifications that match one or more filters, and PATCH .../notifications/{notificationId}/read marks one notification read. Every operation is in the interactive API reference.
Frequently asked questions
What is the simplest way to add a notification inbox to a web app?
Render the Inbox component from @notiflyio/react (or Inbox from @notiflyio/nextjs) with your Application Identifier and a subscriber ID, and add an in-app step to a workflow. There is no feed table, API or websocket server to build: Notifly stores the feed and pushes new notifications live.
Do I need my own backend or message pipeline for the inbox?
No. The delivery worker writes each in-app message to the subscriber's feed and the websocket service pushes it to open sessions. Your server only does two things: trigger workflows, and, when HMAC is on, compute subscriberHash for the signed-in user.
How do I make sure one user cannot open another user's inbox?
Turn on Security HMAC encryption for the environment's in-app integration and pass a server-computed subscriberHash to the component. The API refuses an Inbox session whose hash does not match the subscriber ID signed with the environment's secret key.
Can I use the inbox without React?
Yes. @notiflyio/js is the framework-free client behind the React component, and @notiflyio/nextjs exports the same Inbox for the App Router and Pages Router. Or skip the SDKs and use the REST endpoints above.
Why does my inbox not update live?
Pass socketUrl="https://ws.notifly.io" explicitly. Client releases before 3.19.2 fall back to a Novu socket host when it is omitted, so live updates never arrive. See the note above.
Can I filter the inbox into tabs?
Yes. Each entry in tabs has a label and a filter on tags, data or severity, for example a Comments tab for workflows tagged comments. See Inbox data object for filtering on your own fields.
Related guides
- React notification inbox guide: build versus buy, theming and localization.
- Inbox styling: the appearance prop, the dark theme, icons and render props.
- Inbox data object: custom fields on a notification,
notification.dataand tab filters.
HTTP request step signing
Every call from an HTTP Request step carries a signed header. See its format, what is signed and how to verify it on your server with a short Node example.
Inbox styling
Restyle the Inbox with the appearance prop. Set color and size variables, style any element by key, apply the dark theme, swap icons and render your own items.