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

# Inbox with Context

> Use contexts in the Novu Inbox component to filter and personalize notifications for subscribers by tenant, workspace, or other scopes.

*Contexts* let you scope each `<Inbox />` instance to a specific environment, tenant, or app within your product. When combined with workflow-level contexts, they ensure that each `<Inbox />` displays only the notifications relevant to that specific context.

<Note>
  If you’re new to contexts, start from [Contexts](/platform/concepts/contexts) to understand how contexts are created, managed in Novu, and used in workflows.
</Note>

<Warning>
  **Context on triggers must match context on `<Inbox />`.** By default, an Inbox initialized without a `context` prop only shows notifications triggered **without** context. If you add `context` to workflow triggers but do not pass the same context to `<Inbox />`, in-app jobs can still report success while notifications never appear in that Inbox session.
</Warning>

## How context works in `<Inbox/>`

The [`<Inbox />`](/platform/inbox/configuration/inbox-with-context) filters notifications by context **type and id**. Each entry in the context object resolves to a key like `tenant:acme`. The Inbox only shows notifications whose trigger used the same set of keys.

Nested `data` is optional metadata for personalization. It is stored on the context entity but **does not** affect which notifications appear in the Inbox.

* If workflow is triggered with a context but Inbox is initialized without a context, the notification will not be delivered to that Inbox session.
* If workflow is triggered without a context but Inbox is initialized with a context, the notification will not be delivered to that Inbox session.
* If workflow is triggered with a context but Inbox is initialized with a different context, the notification will not be delivered to that Inbox session.

| Workflow Context                                             | Inbox Context                    | Displayed? |
| ------------------------------------------------------------ | -------------------------------- | ---------- |
| `{ "tenant": "acme" }`                                       | `{ "tenant": "acme" }`           | Yes        |
| `{ "tenant": { "id": "acme", "data": { "name": "Acme" } } }` | `{ "tenant": { "id": "acme" } }` | Yes        |
| `{ "tenant": "acme" }`                                       | `{ "tenant": { "id": "acme" } }` | Yes        |
| `{}`                                                         | `{}`                             | Yes        |
| `{}`                                                         | `{ "tenant": "acme" }`           | No         |
| `{ "tenant": "acme" }`                                       | `{ "tenant": "globex" }`         | No         |
| `{ "tenant": "acme" }`                                       | `{}`                             | No         |
| `{ "tenant": "acme", "app": "first" }`                       | `{ "tenant": "acme" }`           | No         |

### Creating context via `<Inbox/>`

If a new context is passed from the [`<Inbox />`](/platform/inbox/configuration/inbox-with-context) 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.

If a context already exists, Inbox session initialization reuses it without updating stored `data`. This prevents unintentional overwrites from the client. To change existing context metadata, update it through the [Contexts API](/api-reference/contexts/context-schema), Novu dashboard, or a server-side workflow trigger with inline `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 [`<Inbox />`](/platform/inbox/configuration/inbox-with-context) notifications to a specific context, by passing a context prop to the [`<Inbox />`](/platform/inbox/configuration/inbox-with-context) component.

This prop's value defines the filter for that session, and it will only request and show notifications that match this context.

```tsx theme={null}
import { Inbox } from '@novu/react';

<Inbox
  applicationIdentifier="APPLICATION_IDENTIFIER"
  subscriber="SUBSCRIBER_ID"
  context={{
    tenant: {
      "id": "acme-corp",
      "data": {
        "name": "Acme Corporation",
        "plan": "enterprise",
      }
    },
  }}
/>
```

When a workflow is triggered with the same context type and id, as seen below

<img src="https://mintcdn.com/novu-c5de82d9/fr_WdUr8GzinjS5o/images/inbox/context-trigger.png?fit=max&auto=format&n=fr_WdUr8GzinjS5o&q=85&s=8d2275464dab205f26e22b3a14e97488" alt="Context in trigger" width="4816" height="2724" data-path="images/inbox/context-trigger.png" />

Then, the notifications will be delivered to the [`<Inbox />`](/platform/inbox/configuration/inbox-with-context).

<img src="https://mintcdn.com/novu-c5de82d9/fr_WdUr8GzinjS5o/images/inbox/context.png?fit=max&auto=format&n=fr_WdUr8GzinjS5o&q=85&s=c47a3ba60d7b16626a8f982df7fbe9cc" alt="Inbox with context" width="4824" height="2724" data-path="images/inbox/context.png" />

<Note>
  To learn how to use context with the Novu SDKs, visit the [`Context`](/platform/sdks/javascript) documentation.
</Note>

## 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 fetch the context details and contextHash from your server and pass them to the Inbox component.

When HMAC is enabled on your in-app integration, `subscriberHash` is always required. `contextHash` is also required if you pass a `context` prop to `<Inbox />`. If you do not pass `context`, you only need `subscriberHash`.

`contextHash` is separate from notification matching. It verifies the exact `context` object you pass to `<Inbox />`, including any `data` fields. Hash the same object you send to the component.

<Note>
  Use `canonicalize` when computing `contextHash`. Context is a dynamic object, and `canonicalize` serializes JSON so key order and whitespace do not change the hash. The library should be based on [RFC-8259](https://datatracker.ietf.org/doc/html/rfc8259).
</Note>

```ts title="utils/context-hash.ts" theme={null}
import { createHmac } from 'crypto';
import { canonicalize } from '@tufjs/canonical-json';

const context = {
  tenant: {
    id: "acme-corp",
    data: {
      name: "Acme Corporation",
      plan: "enterprise",
    },
  },
};

const contextHash = createHmac('sha256', "NOVU_SECRET_KEY")
  .update(canonicalize(context))
  .digest('hex');
```

```tsx title="components/InboxWithContextHash.tsx" theme={null}
import { Inbox } from '@novu/react';

const { user } = currentUser();
const subscriberHash = user?.novuSubscriberHash;
const contextHash = user?.novuContextHash;

const context = {
  tenant: {
    id: "acme-corp",
    data: {
      name: "Acme Corporation",
      plan: "enterprise",
    },
  },
};

<Inbox
  applicationIdentifier="YOUR_APPLICATION_IDENTIFIER"
  subscriber="YOUR_SUBSCRIBER_ID"
  subscriberHash={subscriberHash}
  context={context}
  contextHash={contextHash}
/>
```

<Note>
  Learn how to secure your [`<Inbox />`](/platform/inbox/configuration/inbox-with-context) with HMAC encryption, refer to the [Prepare for Production](/platform/inbox/prepare-for-production) documentation.
</Note>

## Frequently asked questions

Frequently asked questions related to context in the Inbox component.

<AccordionGroup>
  <Accordion title="Why are in-app notifications sent successfully but not showing in the Inbox?">
    The Inbox filters by context **type and id**. The `context` prop on `<Inbox />` must include the same type/id pairs used when the workflow was triggered. Nested `data` does not need to match.

    A common cause: you started passing `context` on workflow triggers but did not update `<Inbox />` to use the same context ids. The in-app channel job can still complete with status "Success" in the activity feed, but the notification is scoped to a different context and will not appear in an Inbox session that does not match.

    Check that:

    1. If you trigger **with** context, initialize `<Inbox />` with the **same** context type/id pairs.
    2. If you trigger **without** context, do not pass a `context` prop to `<Inbox />`.
    3. When a user switches tenants or orgs in your app, re-render `<Inbox />` with the updated context.

    See the context matching table above for all combinations.
  </Accordion>

  <Accordion title="Does nested context data need to match between trigger and Inbox?">
    No. Matching is on **type and id** only. For example, `{ tenant: { id: "123" } }` on the Inbox matches a trigger with `{ tenant: { id: "123", data: { name: "foo" } } }`.

    `data` is optional metadata stored on the context. Use it for personalization, not for filtering.

    If you use `contextHash`, hash the exact `context` object you pass to `<Inbox />`. That is separate from notification matching.
  </Accordion>
</AccordionGroup>
