smithery/jeremylongshore

customerio-primary-workflow

Implement Customer.io primary messaging workflow. Use when setting up campaign triggers, welcome sequences, onboarding flows, or event-driven email automation. "customer.io email automation", "customer.io messaging", "customer.io onboarding". '

Installation

$ npx skills add smithery/jeremylongshore --skill customerio-primary-workflow

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery/jeremylongshore · top by installs.

npx skills add smithery/jeremylongshore

Browse all from smithery/jeremylongshore

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Skill metadata

Parsed from SKILL.md frontmatter.

Version1.14.0
LicenseMIT
CompatibilityDesigned for Claude Code
Allowed toolsRead, Write, Edit, Bash(npm:*), Bash(npx:*), Glob, Grep
Declared agents claude-code

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 9,202 B
  • docs SUMMARY.md 318 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

Customer.io Primary Workflow

Output

  • A consent-aware workflow with explicit trigger, audience, data contract, message/template version, and owner.
  • A synthetic validation receipt and a scoped rollback/disable action for unexpected delivery behavior.

Examples

Build the workflow in development using one synthetic profile and a versioned event, confirm trigger conditions and suppression/consent rules, then promote through staging. Enable production through an approved canary audience; pause/disable the workflow if the audience or message behavior does not match the reviewed expectation.

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-node configured 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:

  1. Trigger: Event signed_up
  2. Wait 5 minutes
  3. Send welcome email (use {{ customer.first_name }} and {{ event.method }} Liquid)
  4. Wait 1 day
  5. Branch: Is email_verified true?

- No → Send verification reminder - Yes → Continue

  1. Wait 3 days
  2. Send feature tips email
  3. Wait 7 days
  4. Branch: Has firstprojectcreated event?

- No → Send activation nudge - Yes → End (move to engagement campaign)

Cancellation Win-back Campaign:

  1. Trigger: Event subscription_cancelled
  2. Wait 3 days
  3. Send "We miss you" email with {{ event.reason }} Liquid variable
  4. Wait 7 days
  5. 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.