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

# Notification Brands and Variables

> Brands hold visual identity tokens; variables inject dynamic content into templates. Organisation-wide vs per-campaign scope, name-resolution rules.

# Brands and variables

Brands hold the **visual identity** that templates reuse (logo, colours, footer text); variables hold the **dynamic content** that renders per message (user name, order id, amount). Both are dashboard-managed and feed into the same template editor.

## TL;DR

* **Brand** is a top-level dashboard concept (`/org/:org/app/brand`). One per organisation, sometimes per environment.
* **Organisation variables** are global — defined once, reusable across every campaign.
* **Environment variables** (Notifizz's, distinct from your runtime env vars) are scoped per environment, edited inline from the campaign flow.
* Variables are referenced as `{{var:<id>}}` tokens; the catalog resolves names at render time.

## Brand

A brand groups visual identity tokens that every campaign template inherits:

| Token            | Example                                          |
| ---------------- | ------------------------------------------------ |
| Primary colour   | `#C923A6`                                        |
| Secondary colour | `#1A1A1A`                                        |
| Logo (light)     | `https://cdn.example.com/logo-light.svg`         |
| Logo (dark)      | `https://cdn.example.com/logo-dark.svg`          |
| Default font     | `Inter, system-ui, sans-serif`                   |
| Footer text      | `© Example Corp — Privacy · Terms · Unsubscribe` |
| Sender name      | `Example Notifications`                          |

Edit once, applies everywhere. Templates reference brand tokens via the editor's brand-aware controls — switching the brand re-renders every message that hasn't been sent yet.

The brand is one record per organisation (with the dashboard exposing optional per-environment overrides for staged rollouts). Templates that want to differ per campaign override at the template level.

## Variables — two scopes

The variable system supports two scopes:

### Organisation variables

Defined once at the organisation level, reusable across every campaign. Edited from organisation settings.

Common patterns:

| Variable                   | Why org-wide                                         |
| -------------------------- | ---------------------------------------------------- |
| `support_email`            | Same support address across every notification.      |
| `app_name`                 | Branded name used in subject lines.                  |
| `cta_url_base`             | Common URL prefix for in-app CTAs.                   |
| `unsubscribe_url_template` | Same unsubscribe pattern across marketing campaigns. |

Reference as `{{var:org.support_email}}` (or via the editor's variable picker). Resolution happens at message render time.

### Environment variables (Notifizz's)

Scoped per environment, edited inline from the campaign flow. Useful for environment-specific values that shouldn't pollute the organisation-wide list:

| Variable                     | Why per-env                             |
| ---------------------------- | --------------------------------------- |
| `dashboard_url`              | `dev.example.com` vs `app.example.com`  |
| `support_phone`              | Test number on dev, real number on prod |
| `region_specific_legal_text` | EU vs US compliance footer              |

Reference as `{{var:env.dashboard_url}}`. The render-time resolution picks the value for the environment where the message is being delivered.

<Note>
  Don't confuse Notifizz's "environment variables" (template tokens scoped to a Notifizz environment) with your application's runtime env vars (`process.env.X`). They live in different worlds — Notifizz variables don't interpolate from your shell, and your shell vars never leak into Notifizz templates.
</Note>

## Variable resolution

At message creation time:

<Steps>
  <Step title="Extract variable IDs from the template">
    The system walks the rendered config tree and collects every `{{var:<id>}}` token.
  </Step>

  <Step title="Build the variable catalog">
    For each id, look up the variable definition (org or env scope). Bundle into a small catalog object — only the variables actually used in this template, not the whole org's catalog.
  </Step>

  <Step title="Snapshot with the message">
    The catalog is stored alongside the rendered template on the message document. The widget resolves `{{var:<id>}}` to the runtime value without an extra API call.
  </Step>
</Steps>

This snapshot pattern means **renaming a variable doesn't rewrite past messages** — sent messages keep the value as it was at creation time. Only future messages pick up the new value.

## Name collisions

Org and env scopes can both define a variable with the same name. Resolution rules:

* IDs are serialised with their scope prefix (`org.foo` vs `env.foo`), so the variable picker never produces a collision.
* The editor warns if a template references a variable id that doesn't exist in either scope.

If you reference an undefined variable, the rendered message shows the literal token (`{{var:env.missing}}`) — easy to spot and fix.

## Usage count

Each variable tracks how many templates reference it. The count auto-increments when a template is saved with the variable referenced and decrements when a template removes the reference. Use it to find dead variables (`usageCount === 0`) before retiring.

The diff is best-effort — if the count gets out of sync (rare), the dashboard exposes a "recompute usage counts" maintenance action.

## Recipient fields vs variables

Don't confuse:

* **Recipient custom fields** (`{{ recipient.displayName }}`) — produced by the orchestrator, vary per recipient within a single workflow instance.
* **Variables** (`{{var:org.app_name}}`) — defined in the dashboard, same value for every recipient of a given template.

The template can use both. A subject line like `Hi {{ recipient.displayName }}, your {{ var:org.app_name }} order shipped` resolves the displayName per recipient and the app\_name from the org variable catalog.

## FAQ

<AccordionGroup>
  <Accordion title="Variable resolves to empty string — why?">
    Three causes: (1) the variable is defined but its value is empty (check the dashboard); (2) the template references a variable id that doesn't exist (the rendered output shows the literal `{{var:...}}` token in that case); (3) the variable was renamed after the template was saved — re-save the template to pick up the new id.
  </Accordion>

  <Accordion title="Variable scoped to one campaign?">
    Not directly — variables are org-wide or env-wide. For per-campaign data, use **recipient custom fields** (set in the orchestrator) or **event properties** (in `{{ event.foo }}` references). If you find yourself wanting many per-campaign variables, the right layer is probably the orchestrator's recipient list.
  </Accordion>

  <Accordion title="Preview a rendered notification with sample variables?">
    The dashboard's template editor exposes a preview pane with editable sample values for every referenced variable + a sample recipient object. Render the preview to see the rendered output before promoting to `Live`.
  </Accordion>

  <Accordion title="Name collision — org variable and env variable with the same name. Who wins?">
    Neither — they have distinct serialised IDs (`org.foo` vs `env.foo`). The editor's variable picker never produces an ambiguous reference. If you're hand-editing the template HTML and use `{{var:foo}}` without scope, the editor will flag it as invalid.
  </Accordion>

  <Accordion title="Store secrets as variables?">
    No. Variables are part of the message snapshot — anyone with access to delivery history can read them. Use them for non-sensitive values (URLs, copy, branding); never API keys or PII beyond what your privacy policy already covers.
  </Accordion>

  <Accordion title="What happens to past messages when I rename a variable?">
    Nothing — the variable name and value were snapshot on the message at creation time. Past messages render the same way they always did. Future messages pick up the new variable name and value.
  </Accordion>
</AccordionGroup>

## See also

<CardGroup cols={2}>
  <Card title="Channels (detail)" icon="bell-concierge" href="/docs/concepts/channels-detail">
    Where templates dispatch to.
  </Card>

  <Card title="Recipients" icon="user" href="/docs/concepts/recipients">
    Recipient custom fields vs variables.
  </Card>

  <Card title="Link routes" icon="link" href="/docs/concepts/link-routes">
    Variables inside tracked URLs.
  </Card>

  <Card title="Activity log" icon="clock-rotate-left" href="/docs/concepts/activity-log">
    Audit trail of variable edits.
  </Card>
</CardGroup>
