Skip to main content

@notifizz/react SDK reference

@notifizz/react ships the React components and hooks for the Notifizz Notification Center widget — a NotifizzInbox component for the default bell, a NotifizzProvider for app-wide state access, and a useNotifizz hook for reading state and driving the widget from any descendant.

TL;DR

  • <NotifizzInbox options={...} /> — drop-in component that renders the bell + dropdown and authenticates the widget.
  • <NotifizzProvider options={...}> + useNotifizz() — share notification state across the app via context, or build a fully headless UI.
  • Three auth modes via authType: 'firebase', 'backendToken', 'none' (dev-only).
  • renderBell prop replaces the default bell with your own UI; useNotifizz exposes unreadCount, isOpen, isReady, open, close, toggle.

Installation

npm install @notifizz/react
yarn add @notifizz/react
pnpm add @notifizz/react

Components

NotifizzInbox

Default component. Mounts the widget, renders the bell, and listens for notifizz:ready / notifizz:state window events.
import NotifizzInbox from "@notifizz/react";

function App() {
  return (
    <NotifizzInbox
      options={{
        apiKey: "YOUR_FRONT_API_KEY",
        authType: "backendToken",
        token: "TOKEN_FROM_BACKEND",
        userId: "user_42",
        userEmail: "alice@example.com",
        position: "top-right",
      }}
      onReady={() => console.log("widget ready")}
      onStateChange={(state) => console.log("unread:", state.unreadCount)}
    />
  );
}

Props

PropTypeRequiredDefaultDescription
optionsNotifizzInboxOptionsyesAuthentication and display options.
renderBell(ctx: NotifizzBellContext) => ReactNodeno<DefaultBell />Custom bell render function.
onReady() => voidnoCalled once when the widget is ready.
onStateChange(state: NotifizzState) => voidnoCalled on every state change.
serverUrlstringnohttps://widget.notifizz.comWidget server URL.
apiUrlstringnohttps://eu.api.notifizz.com/v1API base URL.
widgetPathstringno/v1/widget.jsWidget script path.
mountIdstringnonotifizz-notificationsDOM id for the widget mount point.

NotifizzInboxOptions

OptionTypeRequiredDescription
apiKeystringyesYour Front API Key.
authType'firebase' | 'backendToken' | 'none'yesAuthentication strategy.
tokenstringfor firebase, backendTokenAuth token from your backend.
userIdstringfor backendToken, noneThe user’s unique identifier.
userEmailstringfor backendToken, noneThe user’s email address.
positionNotifizzPositionno'top-right' | 'top-left' | 'bottom-right' | 'bottom-left'.
notificationCenterStyles{ marginTop?: string }noNotification center style overrides.
bellStyles{ marginRight?: string; marginLeft?: string }noBell style overrides.

authType: "none" example (dev only)

<NotifizzInbox
  options={{
    apiKey: "YOUR_FRONT_API_KEY",
    authType: "none",
    userId: "dev_user_42",
    userEmail: "dev@example.com",
  }}
/>
authType: "none" ships unauthenticated widget access — anyone with the apiKey can read any user’s inbox. Use it for local development only. Production must use firebase or backendToken.

NotifizzProvider

Wraps a subtree to provide notification state via React context. Use it when multiple components need access to notification state, or when you want a fully headless UI.
import { NotifizzProvider } from "@notifizz/react";

function App() {
  return (
    <NotifizzProvider
      options={{
        apiKey: "YOUR_FRONT_API_KEY",
        authType: "backendToken",
        token: "TOKEN_FROM_BACKEND",
        userId: "user_42",
        userEmail: "alice@example.com",
      }}
    >
      <YourApp />
    </NotifizzProvider>
  );
}
PropTypeRequiredDescription
optionsNotifizzInboxOptionsyesAuthentication and display options.
serverUrlstringnoWidget server URL.
apiUrlstringnoAPI base URL.
widgetPathstringnoWidget script path.
mountIdstringnoDOM id for the widget mount point.
childrenReactNodeyesSubtree that gets context access.

Hooks

useNotifizz()

Read notification state and drive the widget from any component inside a NotifizzProvider.
import { useNotifizz } from "@notifizz/react";

function NotificationBadge() {
  const { unreadCount, isOpen, isReady, toggle } = useNotifizz();

  if (!isReady) return null;

  return (
    <button onClick={toggle}>
      Notifications {unreadCount > 0 && `(${unreadCount})`}
    </button>
  );
}

Return value: NotifizzBellContext

PropertyTypeDescription
unreadCountnumberCurrent unread notification count.
isOpenbooleanWhether the notification center is open.
isReadybooleanWhether the widget has loaded and authenticated.
toggle() => voidToggle the notification center.
open() => voidOpen the notification center.
close() => voidClose the notification center.
useNotifizz() must be called from inside a NotifizzProvider. Calling it outside throws.

Custom bell

Replace the default bell with your own component using the renderBell prop:
<NotifizzInbox
  options={{ /* ... */ }}
  renderBell={(ctx) => (
    <div className="my-custom-bell" onClick={ctx.toggle}>
      <span className="bell-icon">🔔</span>
      {ctx.unreadCount > 0 && (
        <span className="badge">{ctx.unreadCount}</span>
      )}
    </div>
  )}
/>
The ctx object is the same NotifizzBellContext that useNotifizz() returns.

Headless mode

Headless mode gives you full control over the notification UI while Notifizz handles real-time data and state. Pair it with your design system for a fully bespoke notification surface.
Use NotifizzProvider + useNotifizz without rendering NotifizzInbox:
function App() {
  return (
    <NotifizzProvider options={{ /* ... */ }}>
      <CustomNotificationUI />
    </NotifizzProvider>
  );
}

function CustomNotificationUI() {
  const { unreadCount, isOpen, toggle } = useNotifizz();

  return (
    <div>
      <button onClick={toggle}>
        {isOpen ? "Hide" : "Show"} notifications ({unreadCount})
      </button>
    </div>
  );
}

State shape

NotifizzState (read via onStateChange or useNotifizz):
PropertyTypeDescription
isReadybooleantrue once the widget has loaded and authenticated.
isOpenbooleantrue when the dropdown is open.
unreadCountnumberCurrent unread notification count.
lastUpdatednumberTimestamp (ms) of the last state change.
hasErrorboolean?true if the widget hit an auth or network error.
errorCodestring?Error identifier when hasError is true.

Exported types

import type {
  NotifizzInboxProps,
  NotifizzInboxOptions,
  NotifizzBellContext,
  NotifizzState,
} from "@notifizz/react";

FAQ

The component calling useNotifizz() is rendered outside the <NotifizzProvider> tree. Move the provider higher up — typically wrapping your whole app at the root layout. If you only need state in one place, you can use <NotifizzInbox onStateChange={...}> directly without a provider.
useNotifizz returns React state internally — re-renders are automatic. If your component is memoised (e.g. React.memo) and re-rendering only on prop changes, ensure you destructure the values you need from useNotifizz() directly inside the component body, not via a stale closure.
Yes — that’s the common pattern. The provider exposes state to descendant components, the inbox renders the bell. Mount the inbox inside the provider tree once.
React 18+ StrictMode intentionally runs effects twice in dev. The widget guards against duplicate mounts via cancelled flags and a readyFired ref — you should not see two bells, but you may see two ready callbacks fire briefly. Production builds run effects once.
This is almost always two copies of React loaded in your app, not a bug in the SDK. @notifizz/react declares react and react-dom as peer dependencies and uses yours — but a monorepo, a locally-linked package that ships its own React, a mismatched transitive version, or a misconfigured bundler can pull in a second one. React’s hook dispatcher then comes back null and any hook (including the SDK’s) crashes.First, confirm there’s really a duplicate — this should print a single version each:
npm ls react react-dom      # or: pnpm why react react-dom
Then force a single instance in your bundler:
// vite.config.ts
import { defineConfig } from 'vite';

export default defineConfig({
  resolve: { dedupe: ['react', 'react-dom'] },
});
// webpack.config.js
const path = require('path');

module.exports = {
  resolve: {
    alias: {
      react: path.resolve(__dirname, 'node_modules/react'),
      'react-dom': path.resolve(__dirname, 'node_modules/react-dom'),
    },
  },
};
// next.config.js — needed only when a linked/local package brings its own React
module.exports = { transpilePackages: ['@notifizz/react'] };
# .npmrc — hoist a single shared copy for peer dependencies
dedupe-peer-dependents=true
If a locally-linked dependency carries its own node_modules/react, deleting that nested copy also resolves it.
Pass new options.userId / options.token — the inbox effect is keyed on options.apiKey and options.authType, so changes to those re-authenticate. For a clean swap (no flash of the previous user’s inbox), conditionally render the provider so it unmounts/remounts when the user changes.
The widget is browser-only — NotifizzInbox and NotifizzProvider no-op when window is undefined. SSR your page normally; the widget hydrates and authenticates on the client. The rendered HTML contains the mount <div> but no widget content until the script loads.

See also

Notification Center overview

Lifecycle, state model, positioning, custom bell.

Authentication overview

Pick the right widget auth mode.

Frontend quickstart

Get the widget rendering in under five minutes.

Backend quickstart

Send the events the widget will display.