Cloudflare
Iterable Lifecycle Journey Re-engaging Dormant .edu Student Builders
GROWTH MARKETING · DRAFT v1

Re-engaging Dormant
.edu Student Builders

A milestone-based re-engagement journey that splits on persona (technical vs. non-technical) and drives every dormant student builder toward one north-star milestone: their first AI inference.

14,049Dormant .edu accounts (90d inactive)
21%Current active rate
~10%Target 30-day retention lift
7 maxEmails per user (capped)

The Mapping

Journey workflow in Iterable Studio

Users enter from a dynamic List, get classified into a persona lane, and climb the same 5-milestone ladder with persona-tailored copy. Milestone M3 — First Inference is the keystone. Always-on Exit Rules and a 7-email cap apply across the whole journey.

Entry Source
Filter (Yes/No split)
Message (Email)
Delay
User Update
Exit Rule
Entry Source · List Dormant .edu Student Builders
Dynamic list, re-evaluated daily. email ends_with .edu AND country = US AND no dashboard_opened in 90d
User Update Stamp persona & entry_segment
From BI + ZoomInfo enrichment → persona and entry_segment (account_setup / worker_deployed)
Filter · Persona Split Technical  /  Non-technical
Unknown → routed to Non-technical (lower-friction default)

Technical lane

CS / engineering / IT — peer-builder & portfolio framing

Filter · Entry Segment Segment B skips M2
Already deployed a Worker → enter near keystone
▶ start
Message · M1Return to Dash
"See what students like you are building with AI"
⏱ Delay 4d · skip on dashboard_opened
Message · M2First Worker deploy
"Deploy it and drop the link in your portfolio"
⏱ Delay 4d · skip on worker_deployed
Message · M3First Inference KEYSTONE
"Run your first AI model on the edge — free"
⏱ Delay 4d · skip on inference_run
Message · M4Adjacent product — AI Gateway
"Now put a gateway in front of your AI"
⏱ Delay 4d · skip on product_added
Message · M5Share the build
"Ship it loud" — X / GitHub badge / Discord

Non-technical lane

Business / founders / design — no-CLI, ship-fast framing

Filter · Entry Segment Segment B skips M2
Already deployed a Worker → enter near keystone
▶ start
Message · M1Return to Dash
"Build anything, fast — no terminal required"
⏱ Delay 4d · skip on dashboard_opened
Message · M2First Worker deploy
"Get it live" — Build deploys a real URL
⏱ Delay 4d · skip on worker_deployed
Message · M3First Inference KEYSTONE
"Add AI to your app in a few clicks"
⏱ Delay 4d · skip on inference_run
Message · M4Adjacent product — D1
"Make it more than a demo" — store real signups
⏱ Delay 4d · skip on product_added
Message · M5Share the build
"Take it further" — LinkedIn / X + CF for Students
Exit Rules · Always-on Eject immediately when…
Unsubscribed Hard bounce Spam complaint All milestones complete 7-email cap reached

In Iterable

How the journey looks on the Studio canvas

Users flow top-down from a single Start, hit the persona split, then run down one of two parallel lanes. Each lane is the same tile structure — Email → Time delay → Email — with delays set to skip ahead the moment the milestone event fires. M3 (first inference) is the keystone.

Keystone milestone — "first inference"
Inference = running data through a trained AI model to get a result (a prompt → an LLM response, audio → a transcript, etc.). It's the "use the model" step, not training it.
A student's first inference = their first successful Workers AI call — e.g. env.AI.run("@cf/meta/llama-3-8b-instruct", { prompt }) returning a result. It's the journey's north-star milestone (per Priyanshi's direction), tracked via the inference_run event, which lets the delay tiles skip ahead and counts as the primary conversion goal.
Tile ID 10970801
Start · Entry Source (List)
Dormant .edu Student Builders · daily eval
Tile ID 10970802
User Update
Set persona & entry_segment (BI + ZoomInfo)
Tile ID 10970803
Filter · Persona Split
Technical  |  Non-technical (unknown→NT)
TECHNICAL LANE
NON-TECHNICAL LANE
Tile ID 10970810
Filter · Entry segment
Segment B (already deployed) → skip to M3
Tile ID 10970830
Filter · Entry segment
Segment B (already deployed) → skip to M3
Tile ID 10970811
Email · M1 — Return to Dash
"See what students like you are shipping"
Tile ID 10970831
Email · M1 — Return to Dash
"Build anything, fast — no terminal required"
Tile ID 10970812
Time delay · 4 days
Advance on: dashboard_opened
Tile ID 10970832
Time delay · 4 days
Advance on: dashboard_opened
Tile ID 10970813
Email · M2 — First deploy
"Deploy it and drop the link in your portfolio"
Tile ID 10970833
Email · M2 — First deploy
"Get it live" — a real, shareable URL
Tile ID 10970814
Time delay · 4 days
Advance on: worker_deployed
Tile ID 10970834
Time delay · 4 days
Advance on: worker_deployed
Tile ID 10970815
Email · M3 — First Inference ★
KEYSTONE · "Run your first AI model — free"
Tile ID 10970835
Email · M3 — First Inference ★
KEYSTONE · "Add AI to your app in a few clicks"
Tile ID 10970816
Time delay · 4 days
Advance on: inference_run
Tile ID 10970836
Time delay · 4 days
Advance on: inference_run
Tile ID 10970817
Email · M4 — AI Gateway
"Now put a gateway in front of your AI"
Tile ID 10970837
Email · M4 — D1
"Make it more than a demo" — store signups
Tile ID 10970818
Time delay · 4 days
Advance on: product_added
Tile ID 10970838
Time delay · 4 days
Advance on: product_added
Tile ID 10970819
Email · M5 — Share
"Ship it loud" — X / README badge / Discord
Tile ID 10970839
Email · M5 — Share
"Take it further" — LinkedIn / CF for Students
Tile ID 10970820
List membership
Add to "Reactivated — Technical"
Tile ID 10970840
List membership
Add to "Reactivated — Non-technical"
Always-on
Exit Rules
Unsubscribe · hard bounce · spam · goal complete · 7-email cap reached
Delays skip on the event: if the milestone fires early the user jumps to the next email; if the window lapses with no event, one nudge sends (max 2 per user, counted toward the 7-cap), then the journey advances.

The Build

Six core components mapped to this journey

Everything below maps directly to the Iterable Studio component model so the team can build it tile-by-tile.

1 Entry Source

  • Type: List (dynamic), re-evaluated on a daily schedule. Dormancy is a state (lack of activity), not an event — so a list beats an event/API trigger here.
  • Two entry segments feed one journey: account_setup (set up account/zone, never returned) and worker_deployed (deployed one Worker, never returned).
  • Source list built from BI + ZoomInfo enrichment, synced to Iterable.

2 Conversion Goals

  • Primary goal: inference_run — first Workers AI inference (the keystone).
  • Secondary: worker_deployed (activation), product_added (expand).
  • Baseline KPIs: unique open rate, CTA click / click-to-open, conversion rate vs. a holdout control.

3 Audience & Eligibility

  • Entry rules: .edu + country = US + dormant = true (no login in 90d).
  • Entry limits: one active entry per user; 90-day re-entry guard so reactivated users aren't re-spammed.
  • Split immediately on persona; unknown → non-technical lane.

4 Workflow Tiles

  • Message: 5 milestone emails per lane (+ up to 2 nudges).
  • Delay: 4-day waits between milestones, with behavioral skip.
  • Filter: persona split, entry-segment split, "did event fire?" Yes/No routing.
  • User Update: stamp persona, increment emails_sent, set milestone flags.
  • Integration: Journey Webhook to sync conversions to Amplitude / CM360.

5 Exit Rules

  • Always-on ejection on: unsubscribe, hard bounce, spam complaint.
  • Goal complete: all milestones reached → exit (no irrelevant follow-ups).
  • 7-email cap: hard exit once emails_sent = 7 (5 milestones + ≤2 nudges).

6 Testing & Publishing

  • Test Mode: run test profiles for each combo — Technical/Non-tech × Segment A/B × unknown — through every tile.
  • Verify skip logic fires on each event and the 7-cap holds.
  • Optionally scaffold with Journey Assist, then refine tiles by hand.

The Copy

Milestone email matrix

Same 5-rung ladder, persona-tailored copy. The keystone row (M3) is highlighted.

MilestoneAdvance eventTechnical laneNon-technical lane
M1
Return to Dash
dashboard_opened "See what students like you are building with AI"
Peer Workers AI build + template. CTA: Open Workers & Pages · Start a template.
"Build anything, fast — no terminal required"
Describe-your-idea via Build. CTA: Open dashboard · Start a template.
M2
First deploy
worker_deployed "Deploy it and drop the link in your portfolio"
GitHub push or wrangler deploy. CTA: Open Dash · Build.
"Get it live"
Build publishes a real, shareable URL. CTA: Open Dash · Build.
M3 ★
First Inference
inference_run "Run your first AI model on the edge — free"
Llama/Mistral/Whisper, 10K neurons/day. CTA: Fork an AI template.
"Add AI to your app in a few clicks"
Add a chatbot/AI feature via template, no ML setup. CTA: Add AI.
M4
Adjacent product
product_added "Now put a gateway in front of your AI"
AI Gateway: caching = savings + traffic dashboard.
"Make it more than a demo"
D1: store real signups → prove demand.
M5
Share
build_shared "Ship it loud"
X / dev Twitter, GitHub README badge, Discord. UTM share link.
"Take it further"
LinkedIn / X + Cloudflare for Students. UTM share link.
Nudge rule: if a milestone event doesn't fire within its 4-day window, send one reminder, then advance after +3 days. Max 2 nudges per user. 5 milestones + 2 nudges = the hard 7-email cap.

The Copy — Full Drafts

Subject line, preheader & body for all 10 emails

Five milestones × two personas. Subject + preheader shown for each; {{firstName}} and {{featured_build_title}} are Iterable merge fields. Keystone milestone (M3) is the first-inference moment.

M1

Return to Dash

advance on: dashboard_opened
M2

First Worker deploy

advance on: worker_deployed
M3 ★

First Inference — KEYSTONE

advance on: inference_run
M4

Adjacent product

advance on: product_added
M5

Share the build

advance on: build_shared
Nudge emails reuse the milestone body with a lighter, shorter alt subject (e.g. M1 → "Your dashboard's still warm"; M3 → "Your free AI allocation is waiting"). Max 2 per user, counted toward the 7-email cap.

The Logic

Trigger logic & timing between sends

Every rung uses the same pattern: send → wait 4 days listening for the milestone event → advance on event (skip the wait) or send 1 nudge + 3 days → advance anyway, until a milestone completes, the cap is hit, or an exit rule fires.

Behavioral skip: fast movers who fire the event jump straight to the next milestone — they're never nagged.

Segment B (already deployed a Worker) skips M2 and enters near the keystone, so they're not told to do something they've already done.
Day 0
M1 — Return to Dash

Sends on entry.

Day 4or on event
M2 — First deploy

Sooner if dashboard_opened fires.

+ nudgeif stalled
Reminder

1× nudge, then +3 days.

Day 8–11or on event
M3 — First Inference ★

Keystone. Sooner if worker_deployed fires.

Day 15–18
M4 — Adjacent product

On inference_run or window expiry.

Day 19–22
M5 — Share

On product_added or window expiry → exit.

Measuring the keystone

How first inference is tracked & advances the journey

One event — inference_run — does two jobs: it measures conversion and it triggers the next email. It originates in the Cloudflare product, gets pushed into Iterable, and the delay tile listens for it.

1
Inference happens

Student makes their first Workers AI call (env.AI.run(...)). Usage is recorded in product data.

Workers AI binding
2
Detect "first"

BI / Amplitude watches for the account's first inference and dedupes (so only #1 counts).

Amplitude / BI
3
Push to Iterable

Fire the inference_run event + set first_inference_at on the profile.

/api/events/track
4
Journey advances

The M3 delay tile sees the event and routes the user to M4 immediately (skips the nudge).

Step 3 — the event you send to Iterable

A single Track API call stamps the event on the user. createdAt lets Iterable order it; dataFields are optional context.

// POST https://api.iterable.com/api/events/track { "email": "jordan@utexas.edu", "eventName": "inference_run", "createdAt": 1719772800, "dataFields": { "model": "@cf/meta/llama-3-8b-instruct", "account_id": "a1b2c3" } }

Step 4 — how the tile reacts

Iterable evaluates branch/exit criteria continuously, so the event pulls the user forward in near-real-time — no waiting out the full delay.

M3 step logic Send M3 email DELAY up to 4 days, listening… IF inference_run received advance to M4 (skip nudge) ELSE after 4 days send 1 nudge, wait 3d IF still none advance anyway Conversion Goal = inference_run // Iterable reports % of entrants who converted
Measure vs. trigger: the same inference_run event is set as the journey's Conversion Goal (so reporting shows first-inference conversion %, your primary KPI) and is what the delay tile listens for to advance. Dedupe upstream — gate on first_inference_at IS null so repeat inferences don't re-fire.

The Split

How we classify persona

Pull dormant .edu contacts from BI → enrich against ZoomInfo → classify technical vs. non-technical via keyword matching on job title, department, and field of study. Result is written to the persona profile field and drives the split at entry.

2Technical (sample)
4Non-technical (sample)
9Unknown → Non-tech
10Not students (excluded)

Counts from the proof-of-concept enrichment run 25_062926_PERSON_*.csv (25 contacts classified). Fields used: Job Title, Department, Persona, Classification_Reason.

Technical keywords

softwareengineerdevelopercomputer science dataITDevOpsMLbackend full-stackinformation systemsSWE

Non-technical keywords

founderbusinessmarketingproduct designcommunicationsfinanceliberal arts fine artsentrepreneur
Resolution order: ZoomInfo keyword hit → field-of-study/major keyword hit → unknown. Caveat: ZoomInfo coverage on current students is thin, so expect a sizable unknown bucket — worth A/B testing the unknown→non-technical default.

How it runs

Where the persona split actually happens

Iterable does not enrich or classify anyone. It only reads data fields on each user's profile. Persona is computed upstream (warehouse + ZoomInfo + the keyword classifier), written onto the Iterable profile as a field, and the Filter tile simply routes on that field. Same for entry segment, which comes from product data.

Outside Iterable — runs before the daily list sync

1
BI / Warehouse pull

Dormant .edu accounts (email + product signals: account created, Workers deployed, last login).

Internal Data MCP
2
ZoomInfo enrichment

Match each email to job title, department, and field-of-study signals.

ZoomInfo export
3
Keyword classifier

Score titles/majors against keyword lists → assign persona + entry_segment.

classify_students.py
4
Sync to Iterable

Write fields onto each profile via CSV import, Users API, or reverse-ETL (Hightouch/Census).

/api/users/bulkUpdate

Inside Iterable — at journey runtime

5
Entry list reads the fields

Dynamic list = .edu + country=US + dormant=true. Users already carry persona & entry_segment.

6
Filter tile · Persona

Criteria: persona = technical → Technical lane. Else → Non-technical lane (unknown defaults here).

7
Filter tile · Entry segment

Criteria: entry_segment = worker_deployed → skip M2, jump to keystone (M3).

Step 4 — the payload you push to Iterable

One call per user (or batched via bulkUpdate). The dataFields are what the Filter tiles read.

// POST https://api.iterable.com/api/users/update { "email": "jordan@utexas.edu", "dataFields": { "persona": "technical", // from classifier "entry_segment": "worker_deployed", "field_of_study": "Computer Science", "dormant": true, "last_dash_login": "2026-03-10" } }

Step 6 — the Filter tile in Studio

No code — you pick the field and value in the tile's criteria builder. It evaluates the stored profile field; it does not call ZoomInfo.

Filter tile criteria IF user.persona is "technical" Yes path (Technical lane) ELSE No path (Non-technical lane) // unknown / null also follows No path // = safe default to lower-friction lane
Timing rule: the classification job must run before the daily entry-list refresh, so persona is already on the profile when the user reaches the Filter tile. Iterable can't enrich mid-journey — it only reads what's there. (A Journey Webhook could call an external API live, but batch enrichment upstream is the right pattern here.)