Create a minimal working Customer.io example.
Use when learning Customer.io basics, testing SDK setup,
or creating your first messaging integration.
Trigger with phrases like "customer.io hello world", "first customer.io message",
"test customer.io", "customer.io example".
Create a minimal working Customer.io integration: identify a user (create/update their profile), track an event, and send a transactional email. This covers the three fundamental Customer.io operations.
// hello-customerio.ts
import { TrackClient, RegionUS } from "customerio-node";
const cio = new TrackClient(
process.env.CUSTOMERIO_SITE_ID!,
process.env.CUSTOMERIO_TRACK_API_KEY!,
{ region: RegionUS }
);
// identify() creates the user if they don't exist, or updates if they do.
// The first argument is your internal user ID (immutable — use DB primary key).
await cio.identify("user-123", {
email: "[email protected]", // Required for email campaigns
first_name: "Jane",
last_name: "Doe",
plan: "pro",
created_at: Math.floor(Date.now() / 1000), // Unix seconds, NOT milliseconds
});
console.log("User identified in Customer.io");
Key rules:
id (first arg) should be your immutable database ID — never use email as ID
email attribute is required if you want to send email campaigns
created_at must be Unix timestamp in seconds (not ms) — Math.floor(Date.now() / 1000)
All custom attributes are stored on the user profile and usable in segments + Liquid templates
Step 2: Track an Event
// Track a custom event on the user's activity timeline.
// Events trigger campaigns — the event name must match exactly in the dashboard.
await cio.track("user-123", {
name: "signed_up", // snake_case, matches campaign trigger
data: {
signup_method: "google_oauth",
referral_source: "product_hunt",
timestamp: Math.floor(Date.now() / 1000),
},
});
console.log("Event tracked in Customer.io");
Key rules:
User must be identified before tracking events (call identify() first)
Event name is case-sensitive and must match your campaign trigger exactly
Use snake_case for event names — signed_up, not Signed Up or signedUp
data properties are accessible in Liquid templates as {{ event.property_name }}
Step 3: Track an Anonymous Event
// Track events before the user signs up — merge later on identification
await cio.trackAnonymous({
anonymous_id: "anon-abc-123", // Your anonymous tracking ID (cookie, device ID)
name: "page_viewed",
data: {
url: "/pricing",
referrer: "https://google.com",
},
});
console.log("Anonymous event tracked");
When the anonymous user signs up, include anonymous_id in the identify() call to merge their pre-signup activity: