# Braze AI Agents + real-time signals: decisioning that actually ships

*By Kodie Critzer · January 29, 2026 · https://brcg.co/blog/braze-ai-agents-real-time-signals*

> Most teams hear “AI Agents” and jump straight to copy.

---

> **What this is:** agents making small, logged decisions that change routing, cadence, and variants.

> 

> **What this isn’t:** “AI writes your marketing for you.”

> 

> **If you do only one thing:** build a cadence governor.

Most teams hear “AI Agents” and jump straight to copy.

That’s not the win.

The win is using an agent to answer questions like:

- **Should we send anything right now?**
- **Which path should this user go down?**
- **What’s the single next action that matters?**
- **When should we stop automating and hand off?**

This is how you build AI into lifecycle without turning your CRM into a science experiment.

## The system (in one picture)

```text

Lifecycle moment

(entry event / trigger)

|

v

+--------------------+

| Fetch signals       |  Connected Content / Catalogs / event props / warehouse

| (latest context)    |

+--------------------+

|

v

+--------------------+

| Write snapshot      |  context_signals (structured)

| to user profile     |

+--------------------+

|

v

+--------------------+

| Agent decision      |  constrained JSON + 1-line reason

+--------------------+

|

v

+--------------------+

| Canvas adapts       |  routing + cadence + channel + variant

+--------------------+

|

v

+--------------------+

| Re-check on timer   |  30m / 24h / 7d

+--------------------+

```

Why this works: you’re not building infinite segments. You’re standardizing **decision points**.

## Where signals come from

The sources that usually matter most:

- **Connected Content** → call your internal endpoints
- **Canvas entry properties / event properties** → immediate behavioral context
- **Braze Catalogs** → eligibility + content mapping (great for variant selection)
- **Warehouse snapshots** → daily or near-real-time user state

If you can answer “what’s true right now?” you can build agent decisioning.

## The snapshot (one object, not attribute soup)

Create **one** object attribute as your source of truth. Keep it boring and readable.

```json

{

"context_signals": {

"as_of": "2026-01-29T17:30:00Z",

"source": "connected_content:user_state",

"fetch_ok": true,

"lifecycle_stage": "onboarding",

"locale": "en-US",

"time_zone": "America/New_York",

"last_message_at": "2026-01-28T20:10:00Z",

"last_open_at": "2026-01-28T20:32:00Z",

"last_key_action_at": "2026-01-28T21:05:00Z",

"quiet_hours": false,

"freq_cap_ok": true,

"consent_ok": true,

"friction": {

"verification_pending": false,

"payment_error": false,

"missing_setup_step": "add_payment_method"

},

"readiness": {

"activation_score": 42,

"fatigue_score": 18,

"support_risk": "low"

},

"eligibility": {

"can_send_sms": false,

"can_send_push": true,

"can_show_in_app": true

}

}

}

```

**Rule:** signals are for decisioning. Copy comes later.

## What agents should control (and what they should NOT)

### Agents SHOULD control

- **Routing:** which path the user enters next
- **Cadence:** how many touches and how quickly
- **Channel choice:** email vs push vs in-app vs wait
- **Variant selection:** pick from pre-built blocks
- **Escalation:** when to stop automating

### Agents should NOT control (without guardrails)

- Inventing offers
- Making product promises
- Changing legal/compliance language
- Freestyling segmentation logic without audit trails

## The agent contract (constrained JSON only)

If you want production safety, don’t let the agent freestyle.

```json

{

"route": "fix_setup" | "activate" | "expand" | "retain" | "recover" | "handoff",

"cadence": 0 | 1 | 3 | 5,

"channel": "email" | "push" | "sms" | "in_app" | "wait",

"message_variant_id": "string",

"focus": "one_thing",

"reason": "one sentence"

}

```

Two rules:

1) **Short menus only.** The agent chooses from allowed values.

2) **Always return `reason`.** If you can’t explain it, you can’t scale it.

## Connected Content example

Fetch a user state blob from your API and normalize it into `context_signals`.

```liquid

{% connected_content https://api.yourcompany.com/user_state?external_id={{${user_id}}}

:method get

:save user_state

:cache_max_age 900

:retry

%}

{

"attributes": [

{

"external_id": "{{${user_id}}}",

"context_signals": {

"fetch_ok": {% if user_state != nil %}true{% else %}false{% endif %},

"source": "connected_content:user_state",

"as_of": "{{ 'now' | date: '%Y-%m-%dT%H:%M:%SZ' }}",

"lifecycle_stage": "{{ user_state.lifecycle_stage | default: 'unknown' }}",

"quiet_hours": {{ user_state.quiet_hours | default: false }},

"freq_cap_ok": {{ user_state.freq_cap_ok | default: true }},

"friction": {

"verification_pending": {{ user_state.verification_pending | default: false }},

"payment_error": {{ user_state.payment_error | default: false }},

"missing_setup_step": "{{ user_state.missing_setup_step | default: '' }}"

}

}

}

]

}

```

## The Canvas build (visual routing)

```text

[Entry Event]

|

v

[User Update: fetch + write context_signals]

|

v

[Agent Step: write agent_decision]

|

+--> (route = fix_setup)  --> [Fix Setup Path]

|

+--> (route = activate)   --> [Activation Path]

|

+--> (route = retain)     --> [Retention Path]

|

+--> (route = handoff)    --> [Internal Escalation + Wait]

```

### Mapping (what the agent controls)

- `route` → branching and path selection (stops one-size-fits-all lifecycle)
- `cadence` → delays and message count (controls fatigue and contact pressure)
- `channel` → channel steps (meets the moment, not just the copy)
- `message_variant_id` → block/variant selection (personalization without risky freeform)
- `handoff` → internal event + pause (prevents brand damage)

## 7 implementable use cases (with control knobs)

### 1) The cadence governor (highest leverage)

**Controls:** `channel`, `cadence`

- If quiet hours or fatigue risk → `channel=wait`
- If attention is high → `cadence=1`
- If low intent / high risk → `cadence=0` (pause)

**Implementation tip:** store a simple pressure score in signals so this isn’t vibes.

### 2) Friction-first routing (fix the blocker)

**Controls:** `route=fix_setup`, `focus`, `message_variant_id`

- Agent picks the single missing step
- Canvas delivers one fix message
- Re-check signals 30–60 minutes later

### 3) Next-best-action single-threading

**Controls:** `focus`, `message_variant_id`

- Agent chooses exactly one CTA from an action library
- Hold the CTA across channels until completion or expiry

### 4) Proof-aware asks (celebrate vs ask)

**Controls:** `route`, `message_variant_id`

- If a success moment happened → “celebrate” variant
- If there’s friction/support risk → “stabilize” variant

### 5) Availability-aware variants (Catalogs + mapping)

**Controls:** `message_variant_id`

- Agent chooses a pre-approved block based on eligibility/availability
- You avoid invented promises

### 6) Repeat-user intelligence

**Controls:** `route`, `cadence`

- First-timers: higher guidance
- Repeat operators: fewer touches, higher signal-to-noise

### 7) Risk-aware escalation

**Controls:** `route=handoff`, `channel=wait`

- Trigger an internal event/task
- Pause outbound messaging until a human resolves the risk

## Minimum viable build (what to do next week)

**Day 1:** define `context_signals` + allowed routes

**Day 2:** Connected Content fetch in a User Update step (write snapshot)

**Day 3:** agent evaluates → writes `agent_decision`

**Day 4:** Canvas branches on `agent_decision.route`

**Day 5:** logging + review dashboard + shadow mode holdout

## What to measure (so you’re not guessing)

- Route distribution (% routed to each path)
- “Wait” rate (if it’s 0%, your agent isn’t allowed to be cautious)
- Message volume per user (contact pressure)
- Outcome by route (activation / conversion / retention)
- Complaint/unsub deltas

## If you do only one thing

Start with the **cadence governor** or **friction-first routing**.

They’re boring. They’re defensible. And they pay for themselves fast.

That’s the BRCG way: systems that ship, not decks that impress.

---

Source: Blue Ridge Consulting Group (BRCG) — https://brcg.co