--- name: novu-manage-preferences description: Configure notification preferences in Novu at the workflow and subscriber level. Set default channel preferences (email, SMS, push, chat, in-app), mark preferences as read-only or subscriber-editable, and manage subscriber-specific overrides. Use when setting up notification opt-in/opt-out, configuring per-channel delivery preferences, or building a preferences management UI. inputs: - name: NOVU_SECRET_KEY description: "Server-side API key from https://dashboard.novu.co/api-keys. Used by @novu/api." required: true type: secret --- # Manage Preferences Novu has a two-level preference system: 1. **Workflow defaults** — configured in the dashboard for UI based workflows or via code in framework based workflows, apply to all subscribers. 2. **Subscriber overrides** — set by end users, override workflow defaults ## Workflow-Level Preferences Set default preferences when defining a workflow with `@novu/framework`: ```typescript import { workflow } from "@novu/framework"; const alertWorkflow = workflow("system-alert", execute, { preferences: { all: { enabled: true, readOnly: false }, channels: { email: { enabled: true }, sms: { enabled: false }, push: { enabled: true }, chat: { enabled: false }, inApp: { enabled: true }, }, }, }); ``` > Authoring workflows in code? See [`framework-integration`](../framework-integration) for the full Framework setup, Bridge Endpoint, step controls, and deployment. ### Channel Types | Channel | Description | | --- | --- | | `email` | Email notifications | | `sms` | SMS text messages | | `push` | Mobile/web push notifications | | `chat` | Slack, Discord, Teams, etc. | | `inApp` | In-app Inbox notifications | ### Read-Only Preferences Set `readOnly: true` to **hide a workflow's channels from the Preferences UI** — subscribers can't toggle them on or off: ```typescript const criticalAlertWorkflow = workflow("critical-alert", execute, { preferences: { all: { enabled: true, readOnly: true }, // subscriber CANNOT disable }, }); ``` ### `readOnly` vs `critical` — pick the right one These are different mechanisms with different guarantees. See [`design-workflow/references/severity-and-critical.md`](../design-workflow/references/severity-and-critical.md) for the full matrix. | Flag | What it does | | ------------------------------------ | ------------------------------------------------------------------------------------------- | | `preferences.all.readOnly: true` | **UI only.** Hides the workflow from the Preferences UI so subscribers can't toggle it. | | `critical: true` (workflow-level) | **Runtime.** Bypasses subscriber preferences, skips digest, runs without delays. | If you need the notification to **always be delivered** (account suspended, security alert, password reset), set `critical: true` — `readOnly: true` alone won't override existing subscriber overrides at runtime. ### Optional (Subscriber-Editable) Preferences ```typescript const marketingWorkflow = workflow("weekly-newsletter", execute, { preferences: { all: { enabled: true, readOnly: false }, // subscriber CAN disable channels: { email: { enabled: true }, sms: { enabled: false }, // off by default, subscriber can enable }, }, }); ``` ## Subscriber-Level Preferences Subscribers can override workflow defaults (unless `readOnly: true`). ### Get Subscriber Preferences ```typescript import { Novu } from "@novu/api"; const novu = new Novu({ secretKey: process.env.NOVU_SECRET_KEY, }); const preferences = await novu.subscribers.preferences.list({ subscriberId: "subscriber-123", }); ``` ### Update Subscriber Preferences ```typescript await novu.subscribers.preferences.update( { workflowId: "weekly-newsletter", channels: { email: false, // opt out of email inApp: true, // keep in-app }, }, "subscriber-123" ); ``` ### Global Preferences Update preferences across all workflows by omitting `workflowId`: ```typescript await novu.subscribers.preferences.update( { channels: { sms: false, // disable SMS for all workflows }, }, "subscriber-123" ); ``` ## Preference Resolution Order When Novu determines whether to deliver a notification: 1. **Subscriber workflow preference** (most specific) — subscriber's override for this specific workflow 2. **Subscriber global preference** — subscriber's default across all workflows 3. **Workflow default** — developer-defined default in code 4. **System default** — all channels enabled The most specific preference wins. If a subscriber disables email for a specific workflow, that takes precedence even if their global email preference is enabled. ## Preferences UI Component ### React ```tsx import { Inbox } from "@novu/react"; function App() { return ( {/* The Preferences panel is built into the Inbox */} ); } ``` The `` component includes a built-in Preferences panel accessible via the settings icon. ### Standalone Preferences Use the `` component independently: ```tsx import { Inbox, Preferences } from "@novu/react"; function PreferencesPage() { return ( ); } ``` ## Common Patterns ### Critical Alerts (Always On) ```typescript preferences: { all: { enabled: true, readOnly: true }, } ``` Subscribers cannot opt out. Use for security alerts, payment notifications, legal notices. ### Marketing (Opt-Out Friendly) ```typescript preferences: { all: { enabled: true, readOnly: false }, channels: { email: { enabled: true }, sms: { enabled: false }, }, } ``` Subscribers can toggle channels. SMS is off by default. ### In-App Only by Default ```typescript preferences: { all: { enabled: false }, channels: { inApp: { enabled: true }, }, } ``` Only in-app is on. Subscribers can enable other channels if desired. ## Common Pitfalls 1. **`readOnly: true` is per-workflow, not per-channel** — you set `readOnly` on the `all` level. Individual channels inherit it. 2. **Subscriber overrides don't apply to `readOnly` workflows** — if the workflow is read-only, subscriber preferences are ignored. 3. **`enabled: false` in the workflow default means the channel is off** — subscribers can still enable it (unless `readOnly: true`). 4. **The Preferences UI only shows non-readOnly workflows** — read-only workflows are hidden from the subscriber's preference panel. 5. **Global preferences apply across all non-readOnly workflows** — they're a convenient "disable all email" setting, but workflow-specific preferences take precedence. ## References - [Workflow Preferences Examples](./references/workflow-preferences-examples.md) - [Subscriber Preferences Examples](./references/subscriber-preferences-examples.md) - [Preferences UI Examples](./references/preferences-ui-examples.md)