> ## Documentation Index
> Fetch the complete documentation index at: https://notifizz.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Notification Center Widget

> In-app notification widget for React, Angular, and Vanilla JS — bell icon, unread count, real-time delivery.

# Notification Center widget

The Notification Center is Notifizz's in-app notification widget — a bell icon with an unread badge and a dropdown list of notifications. It ships in three SDKs (React, Angular, Vanilla JS) that all wrap the same underlying widget and expose the same capabilities through framework-idiomatic APIs.

## TL;DR

* **One widget, three SDKs.** Pick the package that matches your frontend stack — `@notifizz/react`, `@notifizz/angular`, or `@notifizz/vanilla`. The wire format and capabilities are identical.
* **Real-time via real-time stream.** New messages stream into the widget over the real-time SDK — no SSE, no polling.
* **Three auth modes.** `firebase`, `backendToken`, and `none` (dev-only). A fourth, `PubliclySignedJwt`, is configured server-side via the dashboard.
* **Programmatic control.** Every SDK exposes `open()`, `close()`, `toggle()`, and a state observable so you can drive the widget from outside its default bell.
* **Custom bell** — replace the default UI with your own component while Notifizz keeps managing data.

## Widget lifecycle

Every SDK follows the same lifecycle:

1. **Load** — the SDK injects the Notifizz widget script (`/v1/widget.js` from `widget.notifizz.com`) into the page.
2. **Authenticate** — the widget signs the user in based on your `authType` configuration.
3. **Ready** — the widget signals it's ready (`notifizz:ready` window event), and the `isReady` state flips to `true`.
4. **Active** — the widget keeps the notification list current via real-time stream and emits `notifizz:state` events on every change.
5. **Destroy** (optional) — the widget is removed from the DOM and all listeners are cleaned up.

<Note>
  Real-time updates use the real-time stream listener — the widget subscribes to the user's notification document and the backend delivers new messages to the inbox. The dashboard activity log uses SSE for a different purpose — don't confuse the two.
</Note>

## Positioning and styling

Control where the bell appears with the `position` option:

| Value          | Description                        |
| -------------- | ---------------------------------- |
| `top-right`    | Upper-right corner of the viewport |
| `top-left`     | Upper-left corner of the viewport  |
| `bottom-right` | Lower-right corner of the viewport |
| `bottom-left`  | Lower-left corner of the viewport  |

Fine-tune placement with `bellStyles` and `notificationCenterStyles`:

```javascript theme={null}
{
  position: "top-right",
  bellStyles: { marginRight: "20px", marginLeft: "10px" },
  notificationCenterStyles: { marginTop: "50px" },
}
```

## State model

All SDKs expose the same `NotifizzState` object:

| Property      | Type       | Description                                                   |
| ------------- | ---------- | ------------------------------------------------------------- |
| `isReady`     | `boolean`  | `true` once the widget has loaded and authenticated.          |
| `isOpen`      | `boolean`  | `true` when the notification center dropdown is open.         |
| `unreadCount` | `number`   | Current number of unread notifications.                       |
| `lastUpdated` | `number`   | Timestamp (ms) of the last state change.                      |
| `hasError`    | `boolean?` | `true` if the widget encountered an error (auth, network, …). |
| `errorCode`   | `string?`  | Error identifier when `hasError` is `true`.                   |

### How to read state

<Tabs>
  <Tab title="React">
    ```jsx theme={null}
    const { unreadCount, isOpen, isReady } = useNotifizz();
    ```
  </Tab>

  <Tab title="Angular">
    ```typescript theme={null}
    constructor(private notifizz: NotifizzService) {}

    ngOnInit() {
      this.notifizz.state$.subscribe((state) => {
        console.log(state.unreadCount);
      });
    }
    ```
  </Tab>

  <Tab title="Vanilla JS">
    ```javascript theme={null}
    notifizz.onStateChange((state) => {
      console.log(state.unreadCount);
    });
    ```
  </Tab>
</Tabs>

## Programmatic control

All SDKs let you drive the widget from outside its default bell:

| Method     | Description                                     |
| ---------- | ----------------------------------------------- |
| `open()`   | Opens the notification center.                  |
| `close()`  | Closes the notification center.                 |
| `toggle()` | Toggles the notification center open or closed. |

Use this to trigger the panel from a header button, a keyboard shortcut, or an in-app event.

## Custom bell

Every SDK supports replacing the default bell with your own UI element:

* **React** — `renderBell` prop with a render function that receives `NotifizzBellContext`.
* **Angular** — content projection via `<ng-content>` with the `#customBellIcon` template reference.
* **Vanilla JS** — `setBellElement(element)` attaches click handling and keeps a `data-unread` attribute in sync.

See each SDK's reference page for implementation details.

## Default URLs

| Option       | Default value                    |
| ------------ | -------------------------------- |
| `serverUrl`  | `https://widget.notifizz.com`    |
| `apiUrl`     | `https://eu.api.notifizz.com/v1` |
| `widgetPath` | `/v1/widget.js`                  |

You should not need to change these unless instructed by Notifizz support — for staging or regional endpoints, override per environment.

## Authentication options

All frontend SDKs accept the same authentication fields:

| Option      | Type                                     | Required                       | Description                            |
| ----------- | ---------------------------------------- | ------------------------------ | -------------------------------------- |
| `apiKey`    | `string`                                 | yes                            | Your Front API Key from the dashboard. |
| `authType`  | `'firebase' \| 'backendToken' \| 'none'` | yes                            | Authentication strategy.               |
| `token`     | `string`                                 | for `firebase`, `backendToken` | Auth token from your backend.          |
| `userId`    | `string`                                 | for `backendToken`, `none`     | The user's unique identifier.          |
| `userEmail` | `string`                                 | for `backendToken`, `none`     | The user's email address.              |

A fourth auth mode, `PubliclySignedJwt`, is configured server-side via the dashboard `notificationCenterSetup` dev-task and reaches the widget without an SDK shorthand. See [authentication overview](/docs/sdks/authentication/overview) for the full picture.

## FAQ

<AccordionGroup>
  <Accordion title="Which SDK should I pick?">
    The one that matches your frontend stack: `@notifizz/react` for React, `@notifizz/angular` for Angular standalone components, `@notifizz/vanilla` for any other setup (plain JS, Vue, Svelte, server-rendered pages with islands, …). They wrap the same widget — the only differences are framework idioms.
  </Accordion>

  <Accordion title="The widget loads but the bell stays empty (`isReady: true`, `unreadCount: 0`).">
    Three things to check in order: (1) `userId` matches the recipient identifier the campaign emits — most "empty bell" cases are auth working but `userId` mismatch; (2) the campaign actually fired (look at delivery history in the dashboard); (3) the user has an existing inbox recordument — first-ever load lazily creates it, so emit one event before opening the widget.
  </Accordion>

  <Accordion title="`isReady` never flips to `true`.">
    Auth failed. Check the browser console — the widget logs the auth error. Common causes: stale `token` (regenerate from your backend), wrong `authType` (e.g. passing a Firebase token in `backendToken` mode), or expired Front API Key. Inspect `state.hasError` / `state.errorCode` for a typed signal.
  </Accordion>

  <Accordion title="Can I read unread count without rendering the default bell?">
    Yes — that's the headless mode. In React, wrap your tree in `NotifizzProvider` and call `useNotifizz()` from anywhere. In Angular, inject `NotifizzService` and subscribe to `state$`. In Vanilla, call `createNotifizz(...)`, then `mount()` or `setBellElement()` and read `getState()` / subscribe via `onStateChange()`.
  </Accordion>

  <Accordion title="What happens if I call `open()` before `notifizz:ready`?">
    The command is dropped silently. Always wait for `state.isReady === true` before driving the widget programmatically. The React/Angular/Vanilla APIs already guard against this — the bell context exposes `isReady` precisely so your UI can stay disabled until the widget is live.
  </Accordion>

  <Accordion title="Multiple users on the same browser — how do I switch?">
    Call `destroy()` on the current instance, then mount a new one with the new `userId` + `token`. The widget caches real-time state per session — without a clean destroy, the new mount will briefly show the previous user's notifications.
  </Accordion>
</AccordionGroup>

## See also

<CardGroup cols={2}>
  <Card title="React SDK" icon="react" href="/docs/sdks/notification-center/react">
    Full API reference for `@notifizz/react`.
  </Card>

  <Card title="Angular SDK" icon="angular" href="/docs/sdks/notification-center/angular">
    Full API reference for `@notifizz/angular`.
  </Card>

  <Card title="Vanilla JS SDK" icon="js" href="/docs/sdks/notification-center/vanilla-js">
    Full API reference for `@notifizz/vanilla`.
  </Card>

  <Card title="Authentication overview" icon="key" href="/docs/sdks/authentication/overview">
    Pick the right widget auth mode.
  </Card>
</CardGroup>
