Welcome series
Greet on signup, resume the instant they activate, and nudge only the ones who don't.
waitForEvent is the activation detector: timedOut: false is the tips path, timedOut: true is the nudge path — a plain if statement.
Full write-upexport const welcomeSeries = defineJourney({
meta: {
id: "welcome-series",
name: "Onboarding — welcome series",
enabled: true,
trigger: { event: Events.USER_SIGNED_UP },
entryLimit: "once",
suppress: hours(12),
exitOn: [{ event: Events.USER_DELETED }],
},
run: async (user, ctx) => {
// Day 0 — welcome
await sendEmail({
to: user.email,
userId: user.id,
journeyStateId: user.stateId,
template: Templates.ONBOARDING_WELCOME,
subject: "Welcome — here's how to get set up",
journeyName: user.journeyName,
});
// Park on the first key action — resumes the instant it fires.
const activated = await ctx.waitForEvent({
event: Events.PROJECT_CREATED,
timeout: days(3),
lookback: minutes(30),
});
if (!(await ctx.guard.isSubscribed())) return;
if (!activated.timedOut) {
// They activated — deepen instead of nudging.
await sendEmail({
to: user.email,
userId: user.id,
journeyStateId: user.stateId,
template: Templates.ONBOARDING_TIPS,
subject: "Your first project is live — three things to try next",
journeyName: user.journeyName,
});
return;
}
// Three days, no project.
await sendEmail({
to: user.email,
userId: user.id,
journeyStateId: user.stateId,
template: Templates.ONBOARDING_NUDGE,
subject: "Your workspace is still empty",
journeyName: user.journeyName,
});
// Give the nudge two days to work before the last touch.
const second = await ctx.waitForEvent({
event: Events.PROJECT_CREATED,
timeout: days(2),
});
if (!second.timedOut) return; // the nudge worked — end quietly
// Final send: a day later, clamped into business hours, their timezone.
await ctx.sleepUntil(
ctx.when.window("09:00", "17:00").in(days(1)).at("10:00"),
);
if (!(await ctx.guard.isSubscribed())) return;
await sendEmail({
to: user.email,
userId: user.id,
journeyStateId: user.stateId,
template: Templates.ONBOARDING_RESOURCES,
subject: "Docs, examples, and a ten-minute setup guide",
journeyName: user.journeyName,
});
},
});