diff --git a/content/docs/platform/inbox/configuration/inbox-with-context.mdx b/content/docs/platform/inbox/configuration/inbox-with-context.mdx new file mode 100644 index 000000000..99a71b1a4 --- /dev/null +++ b/content/docs/platform/inbox/configuration/inbox-with-context.mdx @@ -0,0 +1,79 @@ +--- +pageTitle: 'Using contexts for Inbox personalization' +title: 'Inbox with context' +description: 'Learn how to use contexts in the Inbox component to filter and personalize notifications for your subscribers.' +icon: 'Package' +--- + +_Contexts_ let you scope each `` instance to a specific environment, tenant, or app within your product. When combined with workflow-level contexts, they ensure that each `` displays only the notifications relevant to that specific context. + +If you’re new to contexts, start from the [Contexts](/platform/workflow/contexts) section to understand how contexts are created, managed in Novu and how they used in workflows. + +## How context works in `` + +The {``} uses exact-match context filtering to determine which notifications to display. This means the context provided to the {``} must match all the key-value pairs of the context used when the workflow was triggered. + +This creates predictable isolation and ensures notifications can't accidentally leak across boundaries. If the contexts do not match exactly, the notification will not be delivered to that Inbox session. + +| Workflow Context | Inbox Context | Displayed? | +| ------------------------------------------ | ------------------------ | ---------- | +| `{ "tenant": "acme" }` | `{ "tenant": "acme" }` | ✅ Yes | +| `{ "tenant": "acme" }` | `{ "tenant": "globex" }` | ❌ No | +| `{ "tenant": "acme", "app": "dashboard" }` | `{ "tenant": "acme" }` | ❌ No | +| `{}` | `{}` | ✅ Yes | + + +### Creating context via `` + +If a new context is passed from the {``} that doesn’t already exist, Novu will automatically find or create it. This means you don’t have to manually set up contexts before using them, they are created just in time. + +However, if a context already exists, its data won’t be updated automatically. This prevents unintentional overwrites of stored context data. + +This is particularly useful for: + +- **Dynamic tenants or organizations**: When users join or switch organizations. +- **Feature-specific dashboards**: Where each section of your app has its own notification scope. + +You can view all automatically created contexts under the Contexts section of your Novu dashboard. + +## Applying context to the Inbox + +You can filter the {``} notifications to a specific context, by passing a context prop to the {``} component. + +This prop's value defines the filter for that session, and it will only request and show notifications that match this context. + +```tsx +import { Inbox } from '@novu/react'; + + +``` + +When a workflow with these exact context is triggered, as seen below + +![Context in trigger](/images/inbox/context-trigger.png) + +Then, the notifications will be delivered to the {``}. + +![Inbox with context](/images/inbox/context.png) + +To learn how to use context with the Novu SDKs, visit the {`Context`} documentation. + +## How to secure your context + +Because the context prop is set on the client-side, a malicious user could potentially tamper with it to view notifications from a different tenant. + +To prevent this, you must validate the session using HMAC encryption. This ensures that the context data comes from your server and has not been altered. + +Learn how to secure your {``} with HMAC encryption, refer to the [Prepare for Production](/platform/inbox/prepare-for-production) documentation. \ No newline at end of file diff --git a/content/docs/platform/inbox/configuration/meta.json b/content/docs/platform/inbox/configuration/meta.json index c17290c27..314df2fea 100644 --- a/content/docs/platform/inbox/configuration/meta.json +++ b/content/docs/platform/inbox/configuration/meta.json @@ -1,6 +1,6 @@ { "title": "Customize and configure", "icon": "SlidersHorizontal", - "pages": ["styling", "icons", "tabs", "preferences", "data-object"], - "description": "Learn how to configure your inbox with styling, tabs, preferences, data objects, and snooze functionality" + "pages": ["styling", "tabs", "preferences", "data-object", "inbox-with-context", "icons"], + "description": "Learn how to configure your inbox with styling, tabs, preferences, data objects, icons and context functionality" } diff --git a/content/docs/platform/meta.json b/content/docs/platform/meta.json index 9216a570b..101bf4a1b 100644 --- a/content/docs/platform/meta.json +++ b/content/docs/platform/meta.json @@ -22,6 +22,7 @@ "workflow/step-conditions", "workflow/tags", "workflow/translations", + "workflow/contexts", "---Channels---", "...integrations", "---Account---", diff --git a/content/docs/platform/sdks/javascript/index.mdx b/content/docs/platform/sdks/javascript/index.mdx index f4f5debd3..94be9e7a8 100644 --- a/content/docs/platform/sdks/javascript/index.mdx +++ b/content/docs/platform/sdks/javascript/index.mdx @@ -26,6 +26,13 @@ The Novu client provides methods to interact with notifications, preferences, an "description": "", "type": "string" }, + "context": { + "description": "A context object to filter notifications for this session.", + "type": "object" + }, + "contextHash": { + "description": "The HMAC-SHA256 hash of the context object. Required if context is provided and HMAC is enabled.", "type": "string" + }, "apiUrl": { "description": "", "type": "string" @@ -50,7 +57,7 @@ The Novu client provides methods to interact with notifications, preferences, an ### Usage - + ```typescript import { Novu } from "@novu/js"; @@ -73,6 +80,30 @@ The Novu client provides methods to interact with notifications, preferences, an }); ``` + + Learn how Context is used to filter Inbox notifications in the [Inbox with Context](/platform/inbox/customization-and-configuration/inbox-with-context) guide. + ```tsx + import { Novu } from '@novu/js'; + + 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" + + ``` + ```typescript import { Novu } from "@novu/js"; diff --git a/content/docs/platform/sdks/react/hooks/novu-provider.mdx b/content/docs/platform/sdks/react/hooks/novu-provider.mdx index 05d7cca0f..af4ad78ee 100644 --- a/content/docs/platform/sdks/react/hooks/novu-provider.mdx +++ b/content/docs/platform/sdks/react/hooks/novu-provider.mdx @@ -24,6 +24,14 @@ Usually, it's placed somewhere in the root of your application, which makes the type: "string", description: "HMAC encryption hash for the subscriber", }, + context: { + type: "object", + description: "Defines contextual attributes (for example, tenant, app, team) for filtering and personalizing notifications.", + }, + contextHash: { + type: "string", + description: "The HMAC-SHA256 hash of the context object. Required if context is provided and HMAC is enabled." + }, apiUrl: { type: "string", description: "Custom backend URL for self-hosted instances", @@ -43,7 +51,7 @@ Usually, it's placed somewhere in the root of your application, which makes the ## Example Usage - + ```tsx import { NovuProvider } from '@novu/react'; @@ -80,6 +88,33 @@ Usually, it's placed somewhere in the root of your application, which makes the ``` + + Learn how to use Context for filtering and personalization in the [Inbox withContext](/platform/inbox/configuration/inbox-with-context) guide. + ```tsx + import { NovuProvider, useNovu } from '@novu/react'; + + function App() { + return ( + + + + ); + } + + // In child components + const MyComponent = () => { + const novu = useNovu(); + console.log(novu.context); + // Logs: { tenant: { id: "org-123" } } + }; + ``` + Read more about [HMAC Encryption](/platform/inbox/prepare-for-production#secure-your-inbox-with-hmac-encryption). @@ -102,4 +137,4 @@ Usually, it's placed somewhere in the root of your application, which makes the ``` - + \ No newline at end of file diff --git a/content/docs/platform/workflow/contexts/contexts-in-workflows.mdx b/content/docs/platform/workflow/contexts/contexts-in-workflows.mdx new file mode 100644 index 000000000..b2dafd762 --- /dev/null +++ b/content/docs/platform/workflow/contexts/contexts-in-workflows.mdx @@ -0,0 +1,81 @@ +--- +pageTitle: 'Personalize workflows and templates in Novu using context' +title: 'Applying context' +description: 'Learn how to use contexts in Novu to personalize notification templates, control workflow logic, and customize the Inbox. Understand supported data formats and how to debug context usage from the activity feed.' +--- + +Contexts let you personalize how notifications are rendered and delivered by making contextual data available inside template editors, step conditions, and the {``} component. + +## How to use context + +Once a context is created either through the Novu dashboard or API, its data becomes available for use in your templates editors, step conditions, and for customizing the {``} component. + +### Using context data in the template editor + +Use the `{{context}}` Handlebars helper to access context data in any template editor. The context key you provide while creating the context (for example, tenant, region) becomes the accessor. + + +For example, if a context with this data is created: + +```json +{ + "context": { + "tenant": { + "id": "acme-corp", + "data": { + "name": "Acme Corporation", + "plan": "enterprise" + } + } + } +} +``` + +You can access the `name` and `plan` in your in-app, email, SMS, or push template like this: + +```html +

Welcome, new user from {{context.tenant.data.name}}!

+

Your account is on the {{context.tenant.data.plan}} plan.

+``` +Or + +```text +Welcome, new user from {{context.tenant.data.name}}! +Your account is on the {{context.tenant.data.plan}} plan. +``` + +![Using context data in the template editor](/images/workflows/contexts/context.gif) + +Refer to the Inbox documentation, to learn how to use context in the {``} component. + +### Using context in step conditions + +You can use context variables in the **Step conditions** tab of a workflow step to add conditional logic to your notifications. For example, only send a "Feature X is now enabled" email if `context.tenant.data.plan` is `enterprise`. +![Context step conditions](/images/workflows/context-step-conditions.png) + +To learn how contexts are structured or how to define them, refer to the [Managing Contexts](/platform/workflow/contexts/manage-contexts) documentation. + +## Viewing and debugging contexts + +Once you start using contexts in your workflows, Novu provides full observability so you can monitor and debug your context usage after a workflow has been triggered. + +### Searching for workflow runs + +You can filter your workflow runs to find all executions associated with a specific context. + +1. Navigate to the **Activity Feed** in your Novu dashboard. +2. Select the **Workflow Runs** tab. +3. In the search bar, click **Context** and enter the context `type` and `id` using the format `type:id`. + +![Searching for workflow runs](/images/workflows/search-context-activityfeed.png) + +### Verifying the resolved context + +To confirm that Novu received and processed your context data correctly, you can inspect the API traces for a specific run. + +1. From the **Activity Feed**, select the relevant workflow run from the list in the **Requests** tab. +2. In the workflow run details, go to the **API Traces** tab. + +Here, you will see the full context object that was resolved and attached to that specific workflow execution. + +![Verifying the resolved context](/images/workflows/resolved-context.png) \ No newline at end of file diff --git a/content/docs/platform/workflow/contexts/index.mdx b/content/docs/platform/workflow/contexts/index.mdx new file mode 100644 index 000000000..7884e2ff4 --- /dev/null +++ b/content/docs/platform/workflow/contexts/index.mdx @@ -0,0 +1,72 @@ +--- +pageTitle: 'Context' +title: 'Context' +description: "Learn what Contexts are in Novu, how they differ from payloads, and how they help you organize and personalize notifications across workflows." +icon: 'Package' +--- + +_Contexts_ are flexible, user-defined data objects that help you organize and personalize your notifications. They let you attach metadata, such as tenant, region, or app details, and enable contextual behavior to workflows, notifications, and other entities across Novu. + +![Contexts](/images/inbox/Contexts.png) + +In simple terms, a context acts like an extended version of the payload. While the payload exists only for the duration of a single workflow execution, contexts are persistent and can be reused across multiple workflows or API calls. This makes them ideal for multi-tenant environments, dynamic branding, and use cases where notifications depend on shared or reusable data. + +## How context works + +Context solves the common problem of sending differentiated notifications to the same subscriber without creating duplicate subscriber records or complex workarounds. + +For example, if you have a single subscriber entity, `john@acme.com`, who uses two different applications you offer: "Notion Email" and "Notion Calendar". You want to send notifications specific to each application. + +Without context, you might have to create two different subscribers or use workarounds with subscriber ID prefixes to differentiate the notifications. + +```javascript +// Problem: How does Novu know which app is sending the notification? + +// Notion Email notification +await novu.trigger('new-email-received', { + to: 'john@acme.com', + payload: { title: 'You have 1 new email' } +}); + +// Notion Calendar notification +await novu.trigger('new-calendar-event', { + to: 'john@acme.com', + payload: { title: 'You have a new meeting invite' } +}); +``` + +However, with context, you can provide this metadata directly in the trigger. This allows you to use a single workflow and subscriber entity, while dynamically changing content or logic based on the context. + +```javascript +// Solution: Pass an 'app' context to differentiate triggers. + +// Notion Email notification +await novu.trigger('new-email-received', { + to: 'john@acme.com', + payload: { title: 'You have 1 new email' }, + context: { + app: 'notion-email', + branding: { + logo: "url_for_email_logo.png" + } + } +}); + +// Notion Calendar notification +await novu.trigger('new-calendar-event', { + to: 'john@acme.com', + payload: { title: 'You have a new meeting invite' }, + context: { + app: 'notion-calendar', + branding: { + logo: "url_for_calendar_logo.png" + } + } +}); +``` + +Here are some ways that you can use contexts: + +- **Multi-tenancy and app routing**: Use a tenant or app context to dynamically alter notification content, branding, or logic for different customers or applications from a single workflow. +- **A/B testing**: Pass a campaign identifier in a context (for example, campaign: 'new-welcome-email-v2'). Use this in a condition step to split users into different notification paths and measure which performs better. +- **Data residency and compliance**: Use a region context to tag notifications with their origin. This can help in applying data retention policies or filtering data for compliance audits. \ No newline at end of file diff --git a/content/docs/platform/workflow/contexts/manage-contexts.mdx b/content/docs/platform/workflow/contexts/manage-contexts.mdx new file mode 100644 index 000000000..7bd3ce567 --- /dev/null +++ b/content/docs/platform/workflow/contexts/manage-contexts.mdx @@ -0,0 +1,194 @@ +--- +pageTitle: 'Contexts' +title: 'Manage contexts' +description: 'Learn how to create, update, and delete contexts in Novu using the dashboard, or API.' +--- + +Novu lets you manage contexts through the Novu dashboard, or the Novu API. This lets you create, view, update, and delete context entities to suit your application's needs. + +You can pass a maximum of five contexts per workflow trigger and the serialized `data` object for each context is limited to 64KB. + +## Context object schema + +When defining contexts, Novu supports multiple formats per key-value pair that let you store and reference metadata relevant to your workflows and templates. + +Each context consists of: +- A `type` (for example, tenant, app, or region). +- An `id` that uniquely identifies the specific context instance. +- An optional `data` object that holds additional properties available to your templates. + +Supported data formats include: + +```typescript +await novu.trigger('welcome-email', { + to: 'user123', + payload: { userName: 'John' }, + context: { + // Simple string format + tenant: 'acme-corp', + + // Rich object format (ID only) + app: { id: 'jira' }, + + // Rich object format (ID + data) + region: { + id: 'us-east', + data: { + name: 'US East', + timezone: 'America/New_York', + currency: 'USD' + } + } + } +}); +``` + +## Create a Context + +You can create a new context via the Novu dashboard or API when you want to register reusable metadata. After creation, this context becomes available to all workflows and templates within your environment. + +### Create a context via dashboard + +Use the dashboard to manually define contexts that represent key business entities. + +1. Log in to the Novu dashboard +2. Click **Contexts** on the sidebar. +3. Click **Create context**. +![create context](/images/workflows/contexts/create-context.png) +4. Complete the following fields: + - **Identifier**: A unique identifier within that type (for example, acme-corp). + - **Context type**: A category such as tenant, app, or region. + - **Custom data (JSON)**: An optional JSON object that contains metadata, such as branding, plan, or region details. +5. Click **Create context** to save the context. +![create context](/images/workflows/contexts/create-contexts.png) + +### Create a context via API + +Novu provides an API to create a context. If a context with the same `type:id` combination already exists, then the request will fail. + +```bash +POST /v2/contexts +{ + "type": "tenant", + "id": "acme-corp", + "data": { + "name": "Acme Corporation", + "plan": "enterprise" + } +} +``` + +### Create a context via API (Just-in-time) + +Contexts can also be created automatically when you trigger a workflow that includes a new context object. If the specified `type:id` doesn’t exist, then Novu automatically creates it before running the workflow. + +```jsx +await novu.trigger('welcome-email', { + to: 'user@example.com', + payload: { userName: 'John' }, + context: { + tenant: 'acme-corp', // Created automatically if it doesn’t exist + app: 'jira' + } +}); +``` + +If a matching context already exists, Novu reuses it as-is without modifying any stored data. This behavior ensures consistency and avoids accidental changes to shared metadata. + +## Update a context + +You can update a context’s data payload at any time. The context `type` and `id` remain immutable. However, to change an existing context’s data, you must explicitly update it through the dashboard or API. + +#### Update a context via dashboard + +1. Log in to the Novu dashboard. +2. Click **Contexts** on the sidebar. +3. Click on the context you wish to edit from the context list on the Context page. +4. Modify its data object in the UI. +5. Click **Save changes**. + +### Update a context via API + +Novu provides an API to update an existing context. The `data` object is replaced entirely during updates (not merged). Include all fields you want to retain. + +```bash +PATCH /v2/contexts/tenant/acme-corp +{ + "data": { + "plan": "premium", + "region": "us-east" + } +} +``` + +## Retrieve a single context + +You can retrieve a context to verify its data, confirm its creation, or inspect the metadata it holds. + +### Retrieve a context via dashboard + +1. Log in to the Novu dashboard +2. Click **Contexts** on the sidebar to view the list of all existing contexts. +3. Click any context entry to see its details. + +### Retrieve a context via API + +Novu provides an API to retrieve a single, specific context by providing its `type` and `id` in the URL. + +```bash +GET /v2/contexts/:type/:id +``` + +Here is an example: +```bash +GET /v2/contexts/tenant/acme-corp +``` + +## List or search for contexts + +You can list all contexts in your environment or search for specific ones by context type or ID. + +### List or search for contexts via dashboard + +1. Log in to the Novu dashboard +2. Click **Contexts** on the sidebar to view all contexts. +3. Use the search bar to filter by context type or ID. + +### List or search for contexts via API + +Novu provides an API that lists or searches available contexts. Use pagination and search parameters to retrieve subsets efficiently. + +```bash +GET /v2/contexts +GET /v2/contexts?search=acme +``` + +## Delete a context + +Delete a context if it’s no longer needed. This action permanently removes the context from your Novu environment. + + Deleting a context cannot be undone. Ensure the context is no longer required by any active or historical workflows you might need to analyze. + +### Delete a context via dashboard + +1. Log in to the Novu dashboard. +2. Click **Contexts** on the sidebar. +3. Click the context or the **...** icon on the row you want to remove. +4. A confirmation menu will appear. +![Delete](/images/workflows/contexts/delete.png) +5. Select **Delete context** to confirm removal. +![Delete context](/images/workflows/contexts/delete-context.png) + +### Delete a context via API + +Novu provides an API that you can use to delete a context. Once deleted, the context will no longer be available for use in new workflow executions. + +```bash +DELETE /v2/contexts/:type/:id +``` + +Here is an example: + +```bash +DELETE /v2/contexts/tenant/acme-corp +``` diff --git a/content/docs/platform/workflow/contexts/meta.json b/content/docs/platform/workflow/contexts/meta.json new file mode 100644 index 000000000..01eacd84c --- /dev/null +++ b/content/docs/platform/workflow/contexts/meta.json @@ -0,0 +1,6 @@ +{ + "title": "Contexts", + "description": "Workflows", + "icon": "Package", + "pages": ["manage-contexts", "contexts-in-workflows"] +} diff --git a/public/images/inbox/Contexts.png b/public/images/inbox/Contexts.png new file mode 100644 index 000000000..76dcdf258 Binary files /dev/null and b/public/images/inbox/Contexts.png differ diff --git a/public/images/inbox/context-trigger.png b/public/images/inbox/context-trigger.png new file mode 100644 index 000000000..db1be47e4 Binary files /dev/null and b/public/images/inbox/context-trigger.png differ diff --git a/public/images/inbox/context.png b/public/images/inbox/context.png new file mode 100644 index 000000000..56d7230e9 Binary files /dev/null and b/public/images/inbox/context.png differ diff --git a/public/images/workflows/context-step-conditions.png b/public/images/workflows/context-step-conditions.png new file mode 100644 index 000000000..b2fdecfaa Binary files /dev/null and b/public/images/workflows/context-step-conditions.png differ diff --git a/public/images/workflows/contexts/context.gif b/public/images/workflows/contexts/context.gif new file mode 100644 index 000000000..50b1e2021 Binary files /dev/null and b/public/images/workflows/contexts/context.gif differ diff --git a/public/images/workflows/contexts/create-context.png b/public/images/workflows/contexts/create-context.png new file mode 100644 index 000000000..1542a4b02 Binary files /dev/null and b/public/images/workflows/contexts/create-context.png differ diff --git a/public/images/workflows/contexts/create-contexts.png b/public/images/workflows/contexts/create-contexts.png new file mode 100644 index 000000000..b4dab0591 Binary files /dev/null and b/public/images/workflows/contexts/create-contexts.png differ diff --git a/public/images/workflows/contexts/delete-context.png b/public/images/workflows/contexts/delete-context.png new file mode 100644 index 000000000..d8de59d6d Binary files /dev/null and b/public/images/workflows/contexts/delete-context.png differ diff --git a/public/images/workflows/contexts/delete.png b/public/images/workflows/contexts/delete.png new file mode 100644 index 000000000..5f019917d Binary files /dev/null and b/public/images/workflows/contexts/delete.png differ diff --git a/public/images/workflows/resolved-context.png b/public/images/workflows/resolved-context.png new file mode 100644 index 000000000..5718bc2c0 Binary files /dev/null and b/public/images/workflows/resolved-context.png differ diff --git a/public/images/workflows/search-context-activityfeed.png b/public/images/workflows/search-context-activityfeed.png new file mode 100644 index 000000000..a9ecbb182 Binary files /dev/null and b/public/images/workflows/search-context-activityfeed.png differ