Customerio primary workflow
Skill jeremylongshore/claude-code-plugins-plus-skills/skills/.curated/customerio-primary-workflow
425 plugins, 2,810 skills, 200 agents for Claude Code. Open-source marketplace at tonsofskills.com with the ccpi CLI package manager.
npx -y skills add jeremylongshore/claude-code-plugins-plus-skills --skill customerio-primary-workflowAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
What its author says it does
Copied from the file, not written here
'Implement Customer.io primary messaging workflow.
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
8.5 KB, ~1.9k tokens by cl100k_base, as published. Nobody here has run it
Customer.io Primary Workflow
Overview
Implement Customer.io's core messaging workflow: identify users with segment-ready attributes, track lifecycle events that trigger campaigns, and set up the data layer for automated onboarding, nurture, and re-engagement sequences.
Prerequisites
customerio-nodeconfigured with Track API credentials- Campaigns created in Customer.io dashboard (triggered by events you define)
- Understanding of your user lifecycle stages
How Campaigns Work
Your App (SDK) Customer.io Dashboard User
───────────── ──────────────────── ────
cio.identify(user) → Profile created/updated
cio.track("signed_up") → Campaign trigger fires
Wait 1 day → Welcome email
Check: verified?
├─ No → Verification reminder
└─ Yes → Wait 3 days → Feature tips email
Events tracked via the SDK trigger campaigns you build in the dashboard. The SDK sends the data; the dashboard defines the workflow logic.
Instructions
Step 1: Define Your Event Taxonomy
// lib/customerio-events.ts
import { TrackClient, RegionUS } from "customerio-node";
// Central event definitions — every event your app tracks
export const CIO_EVENTS = {
// Onboarding
SIGNED_UP: "signed_up",
EMAIL_VERIFIED: "email_verified",
PROFILE_COMPLETED: "profile_completed",
FIRST_PROJECT_CREATED: "first_project_created",
// Engagement
FEATURE_USED: "feature_used",
INVITED_TEAMMATE: "invited_teammate",
UPGRADE_STARTED: "upgrade_started",
UPGRADE_COMPLETED: "upgrade_completed",
// Lifecycle
SUBSCRIPTION_RENEWED: "subscription_renewed",
SUBSCRIPTION_CANCELLED: "subscription_cancelled",
TRIAL_EXPIRING: "trial_expiring",
// Commerce
CHECKOUT_STARTED: "checkout_started",
CHECKOUT_COMPLETED: "checkout_completed",
REFUND_REQUESTED: "refund_requested",
} as const;
type EventName = (typeof CIO_EVENTS)[keyof typeof CIO_EVENTS];
Step 2: Build the Messaging Service
// services/customerio-messaging.ts
import { TrackClient, RegionUS } from "customerio-node";
import { CIO_EVENTS } from "../lib/customerio-events";
const cio = new TrackClient(
process.env.CUSTOMERIO_SITE_ID!,
process.env.CUSTOMERIO_TRACK_API_KEY!,
{ region: RegionUS }
);
interface UserProfile {
id: string;
email: string;
firstName: string;
lastName?: string;
plan: string;
companyName?: string;
}
export class MessagingService {
/** Call on user signup — creates profile and triggers onboarding campaign */
async onSignup(user: UserProfile, signupMethod: string): Promise<void> {
// 1. Identify with all attributes campaigns need
await cio.identify(user.id, {
email: user.email,
first_name: user.firstName,
last_name: user.lastName ?? "",
plan: user.plan,
company: user.companyName ?? "",
created_at: Math.floor(Date.now() / 1000),
onboarding_step: "signed_up",
});
// 2. Track the event that triggers the onboarding campaign
await cio.track(user.id, {
name: CIO_EVENTS.SIGNED_UP,
data: {
method: signupMethod, // "google", "email", "github"
plan: user.plan,
},
});
}
/** Call when user verifies email — updates profile + tracks event */
async onEmailVerified(userId: string): Promise<void> {
await cio.identify(userId, {
email_verified: true,
email_verified_at: Math.floor(Date.now() / 1000),
onboarding_step: "verified",
});
await cio.track(userId, {
name: CIO_EVENTS.EMAIL_VERIFIED,
});
}
/** Call on feature usage — drives engagement segments and campaigns */
async onFeatureUsed(
userId: string,
feature: string,
metadata?: Record<string, any>
): Promise<void> {
await cio.track(userId, {
name: CIO_EVENTS.FEATURE_USED,
data: { feature, ...metadata },
});
// Update engagement metrics on the profile for segmentation
await cio.identify(userId, {
last_active_at: Math.floor(Date.now() / 1000),
});
}
/** Call on plan upgrade — triggers upgrade confirmation campaign */
async onUpgrade(userId: string, from: string, to: string, mrr: number): Promise<void> {
await cio.identify(userId, {
plan: to,
mrr,
upgraded_at: Math.floor(Date.now() / 1000),
});
await cio.track(userId, {
name: CIO_EVENTS.UPGRADE_COMPLETED,
data: { from_plan: from, to_plan: to, mrr },
});
}
/** Call on cancellation — triggers win-back campaign */
async onCancellation(userId: string, reason: string): Promise<void> {
await cio.identify(userId, {
plan: "cancelled",
cancelled_at: Math.floor(Date.now() / 1000),
cancellation_reason: reason,
});
await cio.track(userId, {
name: CIO_EVENTS.SUBSCRIPTION_CANCELLED,
data: { reason },
});
}
}
Step 3: Integrate into Application Routes
// routes/auth.ts (Express example)
import { MessagingService } from "../services/customerio-messaging";
const messaging = new MessagingService();
router.post("/signup", async (req, res) => {
const user = await db.createUser(req.body);
// Fire-and-forget — don't block the signup response
messaging.onSignup(
{
id: user.id,
email: user.email,
firstName: user.firstName,
plan: user.plan,
},
req.body.signupMethod
).catch((err) => console.error("CIO signup tracking failed:", err));
res.json({ user });
});
router.post("/verify-email", async (req, res) => {
await db.verifyEmail(req.user.id);
messaging.onEmailVerified(req.user.id).catch(console.error);
res.json({ verified: true });
});
Step 4: Dashboard Campaign Configuration
In Customer.io dashboard, create campaigns triggered by these events:
Onboarding Campaign:
- Trigger: Event
signed_up - Wait 5 minutes
- Send welcome email (use
{{ customer.first_name }}and{{ event.method }}Liquid) - Wait 1 day
- Branch: Is
email_verifiedtrue?- No → Send verification reminder
- Yes → Continue
- Wait 3 days
- Send feature tips email
- Wait 7 days
- Branch: Has
first_project_createdevent?- No → Send activation nudge
- Yes → End (move to engagement campaign)
Cancellation Win-back Campaign:
- Trigger: Event
subscription_cancelled - Wait 3 days
- Send "We miss you" email with
{{ event.reason }}Liquid variable - Wait 7 days
- Send discount offer email
Liquid Template Variables
| Variable | Source | Example |
|---|---|---|
{{ customer.first_name }} | identify() attributes | "Jane" |
{{ customer.plan }} | identify() attributes | "pro" |
{{ event.method }} | track() event data | "google" |
{{ event.reason }} | track() event data | "too_expensive" |
Error Handling
| Error | Cause | Solution |
|---|---|---|
| Campaign not triggering | Event name mismatch | Event names are case-sensitive — verify exact match |
| User not receiving email | Missing email attribute | Always include email in identify() |
| Duplicate sends | Multiple event fires | Use fire-and-forget with deduplication |
Liquid rendering {{ }} | Missing data property | Ensure data object has all template variables |
Resources
Next Steps
After implementing primary workflow, proceed to customerio-core-feature for transactional messages, segments, and broadcasts.