Customer Retention
Adaptive retention flows with engagement-driven escalation
Retain an insurance customer approaching renewal across multiple channels with slow-burn pacing and engagement-driven adjustment.
Intention
const retainIntention = await rodeo.intentions.create({
type: "retain",
description: "Retain policyholder approaching March 1 renewal",
success_condition: { renewed: true },
failure_conditions: [
{ cancelled: true },
{ noResponse: true, after: "14 days" },
],
alignment: {
audienceBenefit: "Rate lock, personalized coverage review, loyalty discount",
mutuality: "Customer keeps coverage at preferred rate, insurer retains premium revenue",
},
});Audience
const customer = await rodeo.audiences.create({
type: "individual",
context: {
name: "Pat",
accountId: "POL-2024-4821",
currentPremium: 1840,
yearsAsCustomer: 3,
claimsHistory: "none",
},
bounds: { maxTouchesPerDay: 1, maxTouchesPerWeek: 3, cooldownMinutes: 240 },
rhythm: { preferredTimes: ["09:00-11:00", "14:00-16:00"] },
});Scene
const scene = await rodeo.scenes
.build()
.intention(retainIntention.id)
.audience(customer.id)
.arc("slow_burn")
.constraints({ maxTouches: 6, maxDuration: "14d", budget: 30 })
.onDecline("terminate")
.touch({
sequence: 1,
channel_id: email.id,
content: {
subject: "Your coverage summary for 2025",
body: "Personalized coverage review with savings opportunities...",
},
tone: { warmth: "warm", urgency: "none", ask: "none" },
timing: { mode: "absolute", at: "2025-02-01T09:00:00Z" },
})
.touch({
sequence: 2,
channel_id: sms.id,
content: { body: "Quick heads up — your renewal is coming up March 1. We've locked in your current rate." },
tone: { warmth: "warm", urgency: "gentle", ask: "implicit" },
timing: { mode: "relative", after: "3d", anchor: "touch:1" },
})
.rule({
condition: { type: "engagement", metric: "opened", count: 0 },
action: "escalate",
params: { to: "phone" },
})
.rule({
condition: { type: "behavior", metric: "visited_competitors" },
action: "accelerate",
params: { factor: 2 },
})
.rule({
condition: { type: "conversion", metric: "renewed" },
action: "terminate",
})
.create();Ledger
const retentionResults = await rodeo.ledger.query({
intentionType: "retain",
since: "2025-01-01T00:00:00Z",
});
const successRate = retentionResults.entries.filter(
(e) => e.outcome === "succeeded"
).length / retentionResults.total;