docs/platform/sdks/javascript.mdx
The Novu client provides methods to interact with notifications, preferences, and real-time events.
| Property | Type | Description |
|---|---|---|
backendUrl | string | |
applicationIdentifier | string | |
subscriberHash | string | |
contextHash | string | |
apiUrl | string | |
socketUrl | string | |
socketOptions | NovuSocketOptions | Custom socket configuration options. These options will be merged with the default socket configuration. Use socketType to explicitly select the socket implementation: 'cloud' for PartySocket or 'self-hosted' for socket.io. For socket.io-client connections, supports all socket.io-client options (e.g., path, reconnectionDelay, timeout, etc.). For PartySocket connections, options are applied to the WebSocket instance. |
useCache | boolean | |
defaultSchedule | DefaultSchedule | |
context | Partial<Record<string, ContextValue>> | |
subscriberId | string | |
subscriber | string | Subscriber |
const novu = new Novu({
subscriberId: "SUBSCRIBER_ID",
applicationIdentifier: "APPLICATION_IDENTIFIER",
});
```
const novu = new Novu({
subscriberId: "SUBSCRIBER_ID",
applicationIdentifier: "APPLICATION_IDENTIFIER",
apiUrl: "https://eu.api.novu.co",
socketUrl: "wss://eu.socket.novu.co",
});
```
const novu = new Novu({ applicationIdentifier: 'YOUR_APP_ID', subscriberId: 'user-123', context: { tenant: { id: 'org-123', data: { name: 'Acme Corp' } }, team: 'team-456', }, });
// Access the current context console.log(novu.context); // → { tenant: { id: 'org-123', data: { name: 'Acme Corp' } }, team: 'team-456' }
// Get a stable string key (used internally for caching/filtering) console.log(novu.contextKey); // → "team:team-456,tenant:org-123"
</Tab>
<Tab title="HMAC Encryption">
```typescript
import { Novu } from "@novu/js";
const novu = new Novu({
subscriberId: "SUBSCRIBER_ID",
applicationIdentifier: "APPLICATION_IDENTIFIER",
subscriberHash: "SUBSCRIBER_HASH_HMAC_ENCRYPTION",
});
```
</Tab>
</Tabs>
## Notifications
### Methods
#### list
Fetches a list of notifications based on provided filters.
| Property | Type | Description |
| --- | --- | --- |
| `tags` | `TagsFilter` | |
| `read` | `boolean` | |
| `archived` | `boolean` | |
| `snoozed` | `boolean` | |
| `seen` | `boolean` | |
| `data` | `Record<string, unknown>` | |
| `severity` | `SeverityLevelEnum \| SeverityLevelEnum[]` | |
| `createdGte` | `number` | |
| `createdLte` | `number` | |
```typescript
import { SeverityLevelEnum } from '@novu/js';
import dayjs from "dayjs";
const now = dayjs();
// convert to milliseconds
const startDate = now.subtract(60, "days").valueOf();
const endDate = now.valueOf();
const notifications = await novu.notifications.list({
limit: 30,
read: false,
seen: false,
archived: false,
tags: ['tag1', 'tag2'],
severity: SeverityLevelEnum.HIGH,
// data attributes
data: {
type: 'login',
},
offset: 0,
// fetch last 60 days notifications
createdGte: startDate,
createdLte: endDate,
});
The response will be of type:
| Property | Type | Description |
|---|---|---|
notifications | Notification[] | |
hasMore | boolean | |
filter | NotificationFilter |
Fetches the count of notifications based on filters.
| Property | Type | Description |
|---|---|---|
tags | TagsFilter | |
read | boolean | |
archived | boolean | |
snoozed | boolean | |
seen | boolean | |
data | Record<string, unknown> | |
severity | SeverityLevelEnum | SeverityLevelEnum[] | |
createdGte | number | |
createdLte | number |
Marks a notification as read.
await novu.notifications.read({ notificationId: 'NOTIFICATION_ID' });
Marks a notification as unread.
await novu.notifications.unread({ notificationId: 'NOTIFICATION_ID' });
Marks a notification as seen.
await novu.notifications.seen({ notificationId: 'NOTIFICATION_ID' });
Why no unseen method? Unlike read/unread which can be toggled, seen is designed as a one-way operation. Once a notification has been seen by a user, it remains seen. This reflects the natural user experience where visibility cannot be "undone". Use filtering with seen: false to get unseen notifications instead.
</Note>
Marks notifications as seen. You can filter them by notification IDs, tags, or data attributes.
// Mark specific notifications as seen
await novu.notifications.seenAll({
notificationIds: ['NOTIFICATION_ID_1', 'NOTIFICATION_ID_2']
});
// Mark notifications by tags as seen
await novu.notifications.seenAll({
tags: ['tag1', 'tag2']
});
// Mark notifications by data as seen
await novu.notifications.seenAll({
data: { type: 'login' }
});
// Mark all notifications as seen (no filters)
await novu.notifications.seenAll();
Archives a notification.
await novu.notifications.archive({ notificationId: 'NOTIFICATION_ID' });
Unarchives a notification.
await novu.notifications.unarchive({ notificationId: 'NOTIFICATION_ID' });
Marks all notifications as read. You can filter them by tags.
await novu.notifications.readAll({
tags: ['tag1', 'tag2'],
// data attributes
data: {
type: 'login',
},
});
Archives all notifications. You can filter them by tags.
await novu.notifications.archiveAll({
tags: ['tag1', 'tag2'],
// data attributes
data: {
type: 'login',
},
});
Archives all read notifications. You can filter them by tags.
await novu.notifications.archiveAllRead({
tags: ['tag1', 'tag2'],
// data attributes
data: {
type: 'login',
},
});
Deletes a single notification permanently.
await novu.notifications.delete({ notificationId: 'NOTIFICATION_ID' });
Deletes multiple notifications permanently. You can filter them by tags or data attributes.
// Delete specific notifications by tags
await novu.notifications.deleteAll({
tags: ['tag1', 'tag2'],
});
// Delete notifications by data attributes
await novu.notifications.deleteAll({
data: { type: 'login' },
});
// Delete all notifications (no filters)
await novu.notifications.deleteAll();
Snoozes a notification for a specified duration. Here snoozeUntil is ISO 8601 formatted string timestamp, representing the date and time the notification is un-snoozed, it should be a future date and time.
await novu.notifications.snooze({ notificationId: 'NOTIFICATION_ID', snoozeUntil: '2025-01-01T00:00:00.000Z' });
Unsnoozes a notification.
await novu.notifications.unsnooze({ notificationId: 'NOTIFICATION_ID' });
Marks primary action of a notification as completed.
await novu.notifications.completePrimary({ notificationId: 'NOTIFICATION_ID' });
Marks secondary action of a notification as completed.
await novu.notifications.completeSecondary({ notificationId: 'NOTIFICATION_ID' });
Reverts primary action of a notification to pending.
await novu.notifications.revertPrimary({ notificationId: 'NOTIFICATION_ID' });
Reverts secondary action of a notification to pending.
await novu.notifications.revertSecondary({ notificationId: 'NOTIFICATION_ID' });
Individual notification instances have their own methods for marking as seen, read, archived, etc. These methods are available directly on each notification object.
seen() - Marks the notification as seenread() - Marks the notification as readunread() - Marks the notification as unreadarchive() - Archives the notificationunarchive() - Unarchives the notificationdelete() - Deletes the notificationsnooze() - Snoozes the notificationunsnooze() - Unsnoozes the notificationcompletePrimary() - Marks primary action as completedcompleteSecondary() - Marks secondary action as completedrevertPrimary() - Reverts primary action to pendingrevertSecondary() - Reverts secondary action to pending<Note>The seen() method is only available on individual notification instances, not on the novu.notifications object. Use novu.notifications.seenAll() for bulk operations.</Note>
// Get notifications
const { data: notifications } = await novu.notifications.list();
// Mark a specific notification as seen using the instance method
await notifications[0].seen();
// Mark as read using the instance method
await notifications[0].read();
// Archive using the instance method
await notifications[0].archive();
// Snooze using the instance method
await notifications[0].snooze('2025-01-01T00:00:00.000Z');
// Unsnooze using the instance method
await notifications[0].unsnooze();
// Delete using the instance method
await notifications[0].delete();
Fetches the subscriber's notification preferences.
const { data: preferences } = await novu.preferences.list();
update method is available with each preference object.
const { data: preferences } = await novu.preferences.list();
// Update a single preference
await preferences[0].update({ channels: { email: false, sms: true } });
The response will be of type:
| Property | Type | Description |
|---|---|---|
level | PreferenceLevel | |
enabled | boolean | |
condition | RulesLogic | |
subscriptionId | string | |
channels | ChannelPreference | |
overrides | IPreferenceOverride[] | |
workflow | Workflow | |
schedule | { isEnabled: boolean; weeklySchedule?: WeeklySchedule; } |
Updates multiple workflow's channel preferences at once.
await novu.preferences.bulkUpdate([
{ workflowId: 'workflow_id', channels: { email: false, sms: true } },
{ workflowId: 'workflow_id_2', channels: { email: true, sms: false, in_app: true } },
]);
The preferences.schedule submodule lets you fetch and update a subscriber’s delivery schedule.
Fetches the subscriber’s schedule.
const novu = new Novu(...);
const { data: { schedule } } = await novu.preferences.schedule.get();
Updates the subscriber’s schedule. You can update the entire weekly schedule or only specific days.
const novu = new Novu(...);
// Update schedule via preferences
const { data: { schedule } } = await novu.preferences.schedule.update({
weeklySchedule: {
monday: {
isEnabled: true,
hours: [{ start: '09:00 AM', end: '05:00 PM' }],
},
},
});
// Or update directly from a Schedule instance
const { data: { schedule: updatedSchedule } } =
await schedule.update({ isEnabled: false });
A Schedule instance is returned when fetching or updating a schedule.
| Property | Type | Description |
|---|---|---|
isEnabled | boolean | |
weeklySchedule | WeeklySchedule | |
update | (args: UpdateScheduleArgs) => Result<Schedule> |
The Novu client provides real-time event handling through WebSocket connections.
notifications.notification_received: Triggered when a new notification is received.notifications.unread_count_changed: Triggered when the unread count changes.notifications.unseen_count_changed: Triggered when the unseen count changes.preferences.schedule.get.pending: Triggered when fetching a schedule starts.preferences.schedule.get.resolved: Triggered when fetching a schedule succeeds.preferences.schedule.update.pending: Triggered when updating a schedule starts.preferences.schedule.update.resolved: Triggered when updating a schedule succeeds.subscriptions.list.pending: Triggered when loading subscriptions starts.subscriptions.list.resolved: Triggered when subscriptions are loaded.subscriptions.get.pending: Triggered when fetching a subscription starts.subscriptions.get.resolved: Triggered when a specific subscription is fetched.subscriptions.create.pending: Triggered when creating a subscription starts.subscriptions.create.resolved: Triggered when a subscription is created.subscriptions.update.pending: Triggered when updating a subscription starts.subscriptions.update.resolved: Triggered when a subscription is updated.subscriptions.delete.pending: Triggered when deleting a subscription start.subscriptions.delete.resolved: Triggered when a subscription is deleted.
novu.on('session.initialize.resolved', ({ data }: { data: Session }) => {
console.log(data.unreadCount.total);
console.log(data.unreadCount.severity[SeverityLevelEnum.HIGH]);
});
novu.on('notifications.notification_received', (data) => {
console.log('New notification:', data);
});
novu.on('notifications.unread_count_changed', (data) => {
console.log('Unread count:', data);
});
novu.on('notifications.unseen_count_changed', (data) => {
console.log('Unseen count:', data);
});
novu.on('preferences.schedule.update.resolved', ({ data }) => {
console.log('Schedule updated:', data.schedule);
});
novu.on('subscriptions.create.resolved', ({ data: subscription }) => {
console.log('New subscription created:', subscription.identifier);
});
novu.on('subscriptions.list.resolved', ({ data: subscriptions }) => {
console.log('Loaded subscriptions:', subscriptions.length);
});
The Subscriptions module lets you manage a subscriber’s subscriptions to topics. A subscription represents a subscriber’s opt-in to a topic and defines which workflows within that topic they receive notifications from.
It supports creating conditional subscriptions where users only receive notifications if specific criteria (payload filters) are met.
Manage subscriptions at two levels:
novu.subscriptionsTopicSubscription objectFetches all subscriptions for a specific topic.
| Property | Type | Description |
|---|---|---|
topicKey | string |
const { data: subscriptions } = await novu.subscriptions.list({
topicKey: 'product-updates'
});
The response items are TopicSubscription instances.
Fetch a single subscription by topic and identifier.
| Property | Type | Description |
|---|---|---|
topicKey | string | |
identifier | string | |
workflowIds | string[] | |
tags | string[] |
const { data: subscription } = await novu.subscriptions.get({
topicKey: 'product-updates',
identifier: 'user-product-alert'
});
Create a new subscription to a topic. You can pass a list of preferences to filter specific workflows or tags.
| Property | Type | Description |
|---|---|---|
topicKey | string | |
topicName | string | |
identifier | string | |
name | string | |
preferences | PreferenceFilter[] |
const { data: subscription } = await novu.subscriptions.create({
topicKey: 'product-updates',
identifier: 'user-product-alert',
preferences: [
{
// Simple workflow toggle
workflowId: 'issue-created',
enabled: true
},
{
// Conditional filter
workflowId: 'price-alert',
condition: {
field: 'price',
operation: 'below',
value: 100
}
}
]
});
Updates an existing subscription.
| Property | Type | Description |
|---|---|---|
name | string | |
preferences | PreferenceFilter[] |
const { data: subscription } = await novu.subscriptions.update({
topicKey: 'product-updates',
subscriptionId: 'subscription-id-123',
preferences: [...]
});
Delete a subscription by topic and subscription ID.
await novu.subscriptions.delete({
topicKey: 'product-updates',
subscriptionId: 'product-updates-subscription',
});
A TopicSubscription instance represents a single subscription and provides methods for updating or deleting it, as well as managing its preferences.
| Property | Type | Description |
|---|---|---|
id | string | |
identifier | string | |
topicKey | string | |
preferences | SubscriptionPreference[] | |
update | { (args: BaseUpdateSubscriptionArgs): Result<TopicSubscription>; (args: InstanceUpdateSubscriptionArgs): Result<TopicSubscription>; } | |
updatePreference | { (args: BaseSubscriptionPreferenceArgs): Result<SubscriptionPreference>; (args: InstanceSubscriptionPreferenceArgs): Result<SubscriptionPreference>; } | |
bulkUpdatePreferences | { (args: Array<BaseSubscriptionPreferenceArgs>): Result<SubscriptionPreference[]>; (args: Array<InstanceSubscriptionPreferenceArgs>): Result<SubscriptionPreference[]>; } | |
delete | () => Result<void> |
Update subscription metadata or replace its preferences list. Use this method when updating the subscription as a whole. For granular preference updates, use preference-level methods instead.
const { data: subscription } =
await novu.subscriptions.get({
topicKey: 'product-updates',
identifier: 'product-updates-subscription',
});
await subscription.update({
preferences: [
{
workflowId: 'workflow-identifier',
enabled: true,
},
],
});
Each subscription contains a list of SubscriptionPreference objects that you can update individually.
| Property | Type | Description |
|---|---|---|
subscriptionId | string | |
workflow | Workflow | |
enabled | boolean | |
condition | RulesLogic | |
update | (args: { value: boolean | RulesLogic; }) => Result<SubscriptionPreference> |
subscription.preferences.map((preference) => {
const onChange = (value: boolean) => {
preference.update({ value });
};
return <Checkbox onChange={onChange} />;
});
await subscription.delete();
| Property | Type | Description |
|---|---|---|
id | string | |
transactionId | string | |
subject | string | |
body | string | |
to | Subscriber | |
isRead | boolean | |
isSeen | boolean | |
isArchived | boolean | |
isSnoozed | boolean | |
snoozedUntil | string | |
deliveredAt | string[] | |
createdAt | string | |
readAt | string | |
firstSeenAt | string | |
archivedAt | string | |
avatar | string | |
primaryAction | Action | |
secondaryAction | Action | |
channelType | ChannelType | |
tags | string[] | |
redirect | Redirect | |
data | NotificationData | |
workflow | Workflow | |
severity | SeverityLevelEnum | |
read | () => Result<Notification> | |
unread | () => Result<Notification> | |
seen | () => Result<Notification> | |
archive | () => Result<Notification> | |
unarchive | () => Result<Notification> | |
delete | () => Result<void> | |
snooze | (snoozeUntil: string) => Result<Notification> | |
unsnooze | () => Result<Notification> | |
completePrimary | () => Result<Notification> | |
completeSecondary | () => Result<Notification> | |
revertPrimary | () => Result<Notification> | |
revertSecondary | () => Result<Notification> | |
on | <Key extends EventNames>(eventName: Key, listener: EventHandler<Events[Key]>) => () => void | |
off | <Key extends EventNames>(eventName: Key, listener: EventHandler<Events[Key]>) => void |
| Property | Type | Description |
|---|---|---|
id | string | |
subscriberId | string | |
firstName | string | |
lastName | string | |
email | string | |
phone | string | |
avatar | string | |
locale | string | |
data | Record<string, unknown> | |
timezone | string |