Skip to main content
How tenant context works covers the concepts behind this page.
The user determines who receives the message. The tenant determines which of that user’s contexts Courier builds it from: whose brand, whose defaults, whose content. You can target a single user in a tenant’s context, fan out to every member of a tenant, or walk a tenant hierarchy up or down. The tenant goes in one of two places, and both behave identically. Put it on the recipient as to.tenant_id, or on the message as context.tenant_id. Pick one and put it behind a shared helper, because tracking down a message that rendered with the wrong brand is a great deal harder when two call sites disagree about where the tenant lives.

Prerequisites

Send to a user with tenant context

Set context.tenant_id on a recipient to attach the tenant’s metadata, preferences, and branding to their message. User-level preferences and profile data take precedence over the tenant’s. The template holds the content. Pass the variables it expects in data, and reference tenant values like {$.tenant.name} from inside the template, where the tenant context resolves them.
A user doesn’t need to be a member of the tenant to receive a message in its context. This is useful when the tenant holds branding or credentials but you aren’t fanning out to members.

Send to every member of a tenant

Put a tenant_id in to and Courier looks up the tenant’s members and sends to each one.

Send to multiple users with shared context

When sending to an array of users, set a shared tenant at the message level with message.context.tenant_id. Every recipient inherits it. Override it for a specific recipient by setting context.tenant_id on that entry, which takes precedence over the message-level context.
Here user_123 and user_456 get Acme Corp’s context, while user_456 gets Beta Inc’s.

Handle users in multiple tenants

Courier infers the tenant for a user who belongs to exactly one tenant, so specifying it is optional for them. A user with two or more memberships must have context.tenant_id set, or the send returns Tenant Context Not Found.
In the tenant/<template_id> format, tenant is the literal word rather than your tenant ID, which goes in context.tenant_id. Create & manage tenant templates has the full format.

Fan out across a hierarchy

Set include_children: true to also send to users in a tenant’s descendant tenants, or include_parent: true to walk upward through its ancestors.
Courier traverses up to four levels of the hierarchy in either direction. Every recipient in a fan-out is evaluated in the tenant you sent to. Courier checks each member against that tenant’s default_preferences, not those of the tenant they belong to. A member whose own tenant opts in to a topic is still filtered out when the tenant you sent to opts out. When child tenants keep their own preferences, send to each child tenant directly instead of using include_children.
On Go and C#, include_children and include_parent aren’t in the typed recipient models yet, so the tabs above set them as extra fields on the recipient. Every other operation on this page has a fully typed Go and C# form.

Segment delivery data by customer

Courier records the tenant on the message at providers[].reference.tenantId, so you can group logs and delivery data by customer after the fact. Read it from the message record or from a delivery webhook. A send that never named a tenant carries no reference, which is one more reason to route every multi-tenant send through the same helper.

How tenant context resolves

  • Courier can apply a tenant you didn’t name. If the user belongs to exactly one tenant and the send specifies none, Courier loads that tenant’s context anyway. See auto-infer, and turn it off in Settings → Tenants if you would rather send unscoped.
  • A tenant-scoped inbox message appears only to a client signed in with that tenant. Signing in without it shows only messages sent without a tenant, so this one stays hidden even though the send reports success. Pass the same tenantId to signIn that your sends carry.
  • Hierarchy traversal stops at four levels. The window starts at the tenant you sent to rather than at the root, so a fifth ancestor’s settings don’t apply to the message.

Verify

1

Send with a branded tenant

Send with a tenant that has a brand_id set, and confirm the message renders with that tenant’s brand (see brand selection).
2

Check the message log

Confirm the send used the tenant’s preferences, not the workspace defaults.
3

Confirm fan-out delivery

For a fan-out send, confirm each expected member received a copy.