Back to Novu

Context

docs/platform/workflow/advanced-features/contexts.mdx

3.18.014.3 KB
Original Source

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.

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, [email protected], 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.

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.

Without context

<Tabs> <Tab title="Node.js"> ```ts import { Novu } from "@novu/api"

const novu = new Novu({ secretKey: "<YOUR_SECRET_KEY_HERE>" });

// Notion Email notification await novu.trigger({ workflowId: "workflowId", to: { subscriberId: "[email protected]" }, payload: { title: "You have 1 new email" }, });

// Notion Calendar notification await novu.trigger({ workflowId: "workflowId", to: { subscriberId: "[email protected]" }, payload: { title: "You have a new meeting invite" }, });

  </Tab>
  <Tab title="Python">
```python
import os
import novu_py
from novu_py import Novu

with Novu(secret_key=os.getenv("NOVU_SECRET_KEY", "")) as novu:
    novu.trigger(trigger_event_request_dto=novu_py.TriggerEventRequestDto(
        workflow_id="workflowId",
        to={"subscriber_id": "[email protected]"},
        payload={"title": "You have 1 new email"},
    ))

    novu.trigger(trigger_event_request_dto=novu_py.TriggerEventRequestDto(
        workflow_id="workflowId",
        to={"subscriber_id": "[email protected]"},
        payload={"title": "You have a new meeting invite"},
    ))
</Tab> <Tab title="Go"> ```go import ( "context" "os"
novugo "github.com/novuhq/novu-go"
"github.com/novuhq/novu-go/models/components"

)

s := novugo.New(novugo.WithSecurity(os.Getenv("NOVU_SECRET_KEY")))

s.Trigger(context.Background(), components.TriggerEventRequestDto{ WorkflowID: "workflowId", To: components.CreateToSubscriberPayloadDto(components.SubscriberPayloadDto{ SubscriberID: "[email protected]", }), Payload: map[string]any{"title": "You have 1 new email"}, }, nil)

s.Trigger(context.Background(), components.TriggerEventRequestDto{ WorkflowID: "workflowId", To: components.CreateToSubscriberPayloadDto(components.SubscriberPayloadDto{ SubscriberID: "[email protected]", }), Payload: map[string]any{"title": "You have a new meeting invite"}, }, nil)

  </Tab>
  <Tab title="PHP">
```php
use novu;
use novu\Models\Components;

$sdk = novu\Novu::builder()
    ->setSecurity('<YOUR_SECRET_KEY_HERE>')
    ->build();

$sdk->trigger(
    triggerEventRequestDto: new Components\TriggerEventRequestDto(
        workflowId: 'workflowId',
        to: new Components\SubscriberPayloadDto(subscriberId: '[email protected]'),
        payload: ['title' => 'You have 1 new email'],
    ),
);

$sdk->trigger(
    triggerEventRequestDto: new Components\TriggerEventRequestDto(
        workflowId: 'workflowId',
        to: new Components\SubscriberPayloadDto(subscriberId: '[email protected]'),
        payload: ['title' => 'You have a new meeting invite'],
    ),
);
</Tab> <Tab title=".NET"> ```csharp using Novu; using Novu.Models.Components; using System.Collections.Generic;

var sdk = new NovuSDK(secretKey: "<YOUR_SECRET_KEY_HERE>");

await sdk.TriggerAsync(triggerEventRequestDto: new TriggerEventRequestDto() { WorkflowId = "workflowId", To = To.CreateSubscriberPayloadDto(new SubscriberPayloadDto() { SubscriberId = "[email protected]", }), Payload = new Dictionary<string, object>() { { "title", "You have 1 new email" }, }, });

await sdk.TriggerAsync(triggerEventRequestDto: new TriggerEventRequestDto() { WorkflowId = "workflowId", To = To.CreateSubscriberPayloadDto(new SubscriberPayloadDto() { SubscriberId = "[email protected]", }), Payload = new Dictionary<string, object>() { { "title", "You have a new meeting invite" }, }, });

  </Tab>
  <Tab title="Java">
```java
import co.novu.Novu;
import co.novu.models.components.*;
import java.util.Map;

Novu novu = Novu.builder()
    .secretKey("<YOUR_SECRET_KEY_HERE>")
    .build();

novu.trigger()
    .body(TriggerEventRequestDto.builder()
        .workflowId("workflowId")
        .to(To2.of(SubscriberPayloadDto.builder()
            .subscriberId("[email protected]")
            .build()))
        .payload(Map.of("title", "You have 1 new email"))
        .build())
    .call();

novu.trigger()
    .body(TriggerEventRequestDto.builder()
        .workflowId("workflowId")
        .to(To2.of(SubscriberPayloadDto.builder()
            .subscriberId("[email protected]")
            .build()))
        .payload(Map.of("title", "You have a new meeting invite"))
        .build())
    .call();
</Tab> <Tab title="cURL"> ```bash curl -L -g -X POST 'https://api.novu.co/v1/events/trigger' \ -H 'Content-Type: application/json' \ -H 'Accept: application/json' \ -H 'Authorization: ApiKey <NOVU_SECRET_KEY>' \ -d '{ "name": "workflowId", "to": { "subscriberId": "[email protected]" }, "payload": { "title": "You have 1 new email" } }'

curl -L -g -X POST 'https://api.novu.co/v1/events/trigger'
-H 'Content-Type: application/json'
-H 'Accept: application/json'
-H 'Authorization: ApiKey <NOVU_SECRET_KEY>'
-d '{ "name": "workflowId", "to": { "subscriberId": "[email protected]" }, "payload": { "title": "You have a new meeting invite" } }'

  </Tab>
</Tabs>

### With context

<Tabs>
  <Tab title="Node.js">
```ts
import { Novu } from "@novu/api"

const novu = new Novu({ secretKey: "<YOUR_SECRET_KEY_HERE>" });

// Notion Email notification
await novu.trigger({
  workflowId: "workflowId",
  to: { subscriberId: "[email protected]" },
  payload: { title: "You have 1 new email" },
  context: {
    app: "notion-email",
    branding: { logo: "url_for_email_logo.png" },
  },
});

// Notion Calendar notification
await novu.trigger({
  workflowId: "workflowId",
  to: { subscriberId: "[email protected]" },
  payload: { title: "You have a new meeting invite" },
  context: {
    app: "notion-calendar",
    branding: { logo: "url_for_calendar_logo.png" },
  },
});
</Tab> <Tab title="Python"> ```python import os import novu_py from novu_py import Novu

with Novu(secret_key=os.getenv("NOVU_SECRET_KEY", "")) as novu: novu.trigger(trigger_event_request_dto=novu_py.TriggerEventRequestDto( workflow_id="workflowId", to={"subscriber_id": "[email protected]"}, payload={"title": "You have 1 new email"}, context={ "app": "notion-email", "branding": {"logo": "url_for_email_logo.png"}, }, ))

novu.trigger(trigger_event_request_dto=novu_py.TriggerEventRequestDto(
    workflow_id="workflowId",
    to={"subscriber_id": "[email protected]"},
    payload={"title": "You have a new meeting invite"},
    context={
        "app": "notion-calendar",
        "branding": {"logo": "url_for_calendar_logo.png"},
    },
))
  </Tab>
  <Tab title="Go">
```go
import (
    "context"
    "os"

    novugo "github.com/novuhq/novu-go"
    "github.com/novuhq/novu-go/models/components"
)

s := novugo.New(novugo.WithSecurity(os.Getenv("NOVU_SECRET_KEY")))

s.Trigger(context.Background(), components.TriggerEventRequestDto{
    WorkflowID: "workflowId",
    To: components.CreateToSubscriberPayloadDto(components.SubscriberPayloadDto{
        SubscriberID: "[email protected]",
    }),
    Payload: map[string]any{"title": "You have 1 new email"},
    Context: map[string]any{
        "app":      "notion-email",
        "branding": map[string]any{"logo": "url_for_email_logo.png"},
    },
}, nil)

s.Trigger(context.Background(), components.TriggerEventRequestDto{
    WorkflowID: "workflowId",
    To: components.CreateToSubscriberPayloadDto(components.SubscriberPayloadDto{
        SubscriberID: "[email protected]",
    }),
    Payload: map[string]any{"title": "You have a new meeting invite"},
    Context: map[string]any{
        "app":      "notion-calendar",
        "branding": map[string]any{"logo": "url_for_calendar_logo.png"},
    },
}, nil)
</Tab> <Tab title="PHP"> ```php use novu; use novu\Models\Components;

$sdk = novu\Novu::builder() ->setSecurity('<YOUR_SECRET_KEY_HERE>') ->build();

$sdk->trigger( triggerEventRequestDto: new Components\TriggerEventRequestDto( workflowId: 'workflowId', to: new Components\SubscriberPayloadDto(subscriberId: '[email protected]'), payload: ['title' => 'You have 1 new email'], context: [ 'app' => 'notion-email', 'branding' => ['logo' => 'url_for_email_logo.png'], ], ), );

$sdk->trigger( triggerEventRequestDto: new Components\TriggerEventRequestDto( workflowId: 'workflowId', to: new Components\SubscriberPayloadDto(subscriberId: '[email protected]'), payload: ['title' => 'You have a new meeting invite'], context: [ 'app' => 'notion-calendar', 'branding' => ['logo' => 'url_for_calendar_logo.png'], ], ), );

  </Tab>
  <Tab title=".NET">
```csharp
using Novu;
using Novu.Models.Components;
using System.Collections.Generic;

var sdk = new NovuSDK(secretKey: "<YOUR_SECRET_KEY_HERE>");

await sdk.TriggerAsync(triggerEventRequestDto: new TriggerEventRequestDto() {
    WorkflowId = "workflowId",
    To = To.CreateSubscriberPayloadDto(new SubscriberPayloadDto() {
        SubscriberId = "[email protected]",
    }),
    Payload = new Dictionary<string, object>() {
        { "title", "You have 1 new email" },
    },
    Context = new Dictionary<string, object>() {
        { "app", "notion-email" },
        { "branding", new Dictionary<string, object>() {
            { "logo", "url_for_email_logo.png" },
        } },
    },
});

await sdk.TriggerAsync(triggerEventRequestDto: new TriggerEventRequestDto() {
    WorkflowId = "workflowId",
    To = To.CreateSubscriberPayloadDto(new SubscriberPayloadDto() {
        SubscriberId = "[email protected]",
    }),
    Payload = new Dictionary<string, object>() {
        { "title", "You have a new meeting invite" },
    },
    Context = new Dictionary<string, object>() {
        { "app", "notion-calendar" },
        { "branding", new Dictionary<string, object>() {
            { "logo", "url_for_calendar_logo.png" },
        } },
    },
});
</Tab> <Tab title="Java"> ```java import co.novu.Novu; import co.novu.models.components.*; import java.util.Map;

Novu novu = Novu.builder() .secretKey("<YOUR_SECRET_KEY_HERE>") .build();

novu.trigger() .body(TriggerEventRequestDto.builder() .workflowId("workflowId") .to(To2.of(SubscriberPayloadDto.builder() .subscriberId("[email protected]") .build())) .payload(Map.of("title", "You have 1 new email")) .context(Map.ofEntries( Map.entry("app", TriggerEventRequestDtoContextUnion.of("notion-email")), Map.entry("branding", TriggerEventRequestDtoContextUnion.of( TriggerEventRequestDtoContext2.builder() .id("branding") .data(Map.of("logo", "url_for_email_logo.png")) .build())))) .build()) .call();

novu.trigger() .body(TriggerEventRequestDto.builder() .workflowId("workflowId") .to(To2.of(SubscriberPayloadDto.builder() .subscriberId("[email protected]") .build())) .payload(Map.of("title", "You have a new meeting invite")) .context(Map.ofEntries( Map.entry("app", TriggerEventRequestDtoContextUnion.of("notion-calendar")), Map.entry("branding", TriggerEventRequestDtoContextUnion.of( TriggerEventRequestDtoContext2.builder() .id("branding") .data(Map.of("logo", "url_for_calendar_logo.png")) .build())))) .build()) .call();

  </Tab>
  <Tab title="cURL">
```bash
curl -L -g -X POST 'https://api.novu.co/v1/events/trigger' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: ApiKey <NOVU_SECRET_KEY>' \
-d '{
    "name": "workflowId",
    "to": { "subscriberId": "[email protected]" },
    "payload": { "title": "You have 1 new email" },
    "context": {
        "app": "notion-email",
        "branding": { "logo": "url_for_email_logo.png" }
    }
}'

curl -L -g -X POST 'https://api.novu.co/v1/events/trigger' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: ApiKey <NOVU_SECRET_KEY>' \
-d '{
    "name": "workflowId",
    "to": { "subscriberId": "[email protected]" },
    "payload": { "title": "You have a new meeting invite" },
    "context": {
        "app": "notion-calendar",
        "branding": { "logo": "url_for_calendar_logo.png" }
    }
}'
</Tab> </Tabs>

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.