Skip to content
customerio-cost-tuning logo

Customer.io Cost Tuning

customerio-cost-tuning

Optimize Customer.io costs and usage efficiency.

SKILL.md

Full skill instructions

Customer.io Cost Tuning

Overview

Optimize Customer.io costs by managing profile count (the primary billing driver), suppressing/​deleting inactive users, deduplicating events, reducing unnecessary API calls, and monitoring usage trends.

How Customer.io Pricing Works

Customer.io bills based on profile count (number of identified people in your workspace) and email/​SMS volume. Key cost drivers:

FactorImpactOptimization Strategy
Total profilesPrimary cost driverDelete inactive profiles
Email sendsPer-email cost above tierSuppress unengaged users
SMS sendsPer-SMS costOnly send to opt-in users
OveridentificationCreates unnecessary profilesDon't identify users who'll never receive messages
Event volumeCan increase processing costsDeduplicate and sample

Instructions

Step 1: Profile Audit

// scripts/​cio-profile-audit.ts
// Audit your Customer.io integration for cost optimization opportunities

import { TrackClient, RegionUS } from "customerio-node";

const cio = new TrackClient(
  process.env.CUSTOMERIO_SITE_ID!,
  process.env.CUSTOMERIO_TRACK_API_KEY!,
  { region: RegionUS }
);

// Check: Are you identifying users who'll never receive messages?
const AUDIT_RULES = {
  // Users without email can't receive email campaigns
  noEmail: "Don't identify users without email unless using push/​SMS",

  // Test users should be cleaned up
  testUsers: "Suppress and delete test-*, ci-*, dev-* prefixed users",

  // Anonymous users that never convert inflate profile count
  staleAnonymous: "Delete anonymous profiles older than 90 days without conversion",

  // Inactive users who haven't opened email in 6+ months
  unengaged: "Suppress users with no email opens in 180+ days",
};

console.log("=== Customer.io Cost Audit Rules ===\n");
for (const [rule, action] of Object.entries(AUDIT_RULES)) {
  console.log(`${rule}: ${action}`);
}
console.log("\nRun these checks in Customer.io dashboard:");
console.log("1. People > Segments > Create 'Inactive 90 days' segment");
console.log("2. People > Segments > Create 'No email attribute' segment");
console.log("3. People > Filter by created_at < 90 days ago AND email_opened = 0");

Step 2: Suppress and Delete Inactive Users

// scripts/​cio-cleanup-inactive.ts
import { TrackClient, RegionUS } from "customerio-node";

const cio = new TrackClient(
  process.env.CUSTOMERIO_SITE_ID!,
  process.env.CUSTOMERIO_TRACK_API_KEY!,
  { region: RegionUS }
);

interface CleanupTarget {
  userId: string;
  reason: string;
}

async function cleanupInactiveUsers(
  targets: CleanupTarget[],
  dryRun: boolean = true
): Promise<void> {
  let suppressed = 0;
  let deleted = 0;
  let errors = 0;

  for (const target of targets) {
    if (dryRun) {
      console.log(`[DRY RUN] Would suppress+delete: ${target.userId} (${target.reason})`);
      continue;
    }

    try {
      // Step 1: Suppress — stops all messaging immediately
      await cio.suppress(target.userId);
      suppressed++;

      // Step 2: Destroy — removes from billing
      await cio.destroy(target.userId);
      deleted++;

      // Rate limit to 50/​sec for bulk operations
      await new Promise((r) => setTimeout(r, 20));
    } catch (err: any) {
      errors++;
      console.error(`Failed ${target.userId}: ${err.message}`);
    }

    if ((suppressed + errors) % 100 === 0) {
      console.log(`Progress: ${suppressed} deleted, ${errors} errors`);
    }
  }

  console.log(`\nResult: ${suppressed} suppressed, ${deleted} deleted, ${errors} errors`);
}

// Usage: Build target list from your database
// const inactiveUsers = await db.query(`
//   SELECT id FROM users
//   WHERE last_login_at < NOW() - INTERVAL '180 days'
//   AND email_verified = false
// `);

Step 3: Event Deduplication

// lib/​customerio-dedup-events.ts
// Prevent sending duplicate events that inflate volume

import { createHash } from "crypto";
import { TrackClient, RegionUS } from "customerio-node";

const cio = new TrackClient(
  process.env.CUSTOMERIO_SITE_ID!,
  process.env.CUSTOMERIO_TRACK_API_KEY!,
  { region: RegionUS }
);

// Simple LRU dedup (use Redis in production)
const recentEvents = new Map<string, number>();
const MAX_CACHE = 50_000;
const DEDUP_WINDOW_MS = 60 * 1000;  // 1 minute window

function isDuplicate(userId: string, eventName: string, data?: any): boolean {
  const hash = createHash("sha256")
    .update(`${userId}:${eventName}:${JSON.stringify(data ?? {})}`)
    .digest("hex")
    .substring(0, 12);

  const last = recentEvents.get(hash);
  if (last && Date.now() - last < DEDUP_WINDOW_MS) {
    return true;
  }

  recentEvents.set(hash, Date.now());

  // Prevent unbounded growth
  if (recentEvents.size > MAX_CACHE) {
    const cutoff = Date.now() - DEDUP_WINDOW_MS;
    for (const [key, time] of recentEvents) {
      if (time < cutoff) recentEvents.delete(key);
    }
  }

  return false;
}

export async function trackDeduped(
  userId: string,
  name: string,
  data?: Record<string, any>
): Promise<void> {
  if (isDuplicate(userId, name, data)) {
    return; // Skip duplicate
  }
  await cio.track(userId, { name, data });
}

Step 4: Event Sampling for High-Volume Events

// lib/​customerio-sampling.ts
// Sample high-volume events to reduce API calls

const EVENT_SAMPLE_RATES: Record<string, number> = {
  page_viewed: 0.1,          // Sample 10% of page views
  button_clicked: 0.25,      // Sample 25% of clicks
  search_performed: 0.5,     // Sample 50% of searches
  signed_up: 1.0,            // Always track signups
  checkout_completed: 1.0,   // Always track purchases
  subscription_cancelled: 1.0, // Always track cancellations
};

export function shouldTrack(eventName: string): boolean {
  const rate = EVENT_SAMPLE_RATES[eventName] ?? 1.0;
  return Math.random() < rate;
}

// Usage
if (shouldTrack("page_viewed")) {
  await cio.track(userId, {
    name: "page_viewed",
    data: { url: "/​pricing", sampled: true },
  });
}

Step 5: Usage Monitoring

// scripts/​cio-usage-monitor.ts
// Track your Customer.io usage trends

interface UsageMetrics {
  identifyCalls: number;
  trackCalls: number;
  transactionalSends: number;
  broadcastTriggers: number;
  webhooksReceived: number;
}

class UsageMonitor {
  private metrics: UsageMetrics = {
    identifyCalls: 0,
    trackCalls: 0,
    transactionalSends: 0,
    broadcastTriggers: 0,
    webhooksReceived: 0,
  };

  increment(metric: keyof UsageMetrics): void {
    this.metrics[metric]++;
  }

  report(): void {
    console.log("\n=== Customer.io Usage Report ===");
    console.log(`Period: ${new Date().toISOString()}`);
    for (const [key, value] of Object.entries(this.metrics)) {
      console.log(`  ${key}: ${value.toLocaleString()}`);
    }
    const total = Object.values(this.metrics).reduce((a, b) => a + b, 0);
    console.log(`  TOTAL API calls: ${total.toLocaleString()}`);
  }

  reset(): void {
    for (const key of Object.keys(this.metrics)) {
      this.metrics[key as keyof UsageMetrics] = 0;
    }
  }
}

export const usageMonitor = new UsageMonitor();

Cost Savings Estimates

OptimizationTypical SavingsImplementation Effort
Delete inactive profiles (180+ days)15-30% profile costLow
Event deduplication5-15% event volumeLow
Event sampling (analytics events)50-80% event volume for sampled eventsLow
Suppress bounced emails2-5% email costLow
Don't identify email-less users5-20% profile costMedium
Annual billing10-20% total costNone

Monthly Cost Review Checklist

  • Review profile count trend (People > Overview)
  • Identify and delete stale test profiles
  • Review segment for users with no email attribute
  • Check bounce rate and suppress chronic bouncers
  • Review event volume by type (optimize high-volume/​low-value events)
  • Compare plan tier vs actual usage

Resources

Next Steps

After cost optimization, proceed to customerio-reference-architecture for enterprise patterns.

More skills from jeremylongshore

openrouter-compliance-review logo
jeremylongshore/claude-code-plugins-plus-skills

openrouter-compliance-review

Review OpenRouter integration for regulatory compliance (SOC2, GDPR,

2.8K 0
View
maintainx-data-handling logo
jeremylongshore/claude-code-plugins-plus-skills

maintainx-data-handling

Data synchronization, ETL patterns, and data management for MaintainX.

2.8K 0
View
groq-core-workflow-a logo
jeremylongshore/claude-code-plugins-plus-skills

groq-core-workflow-a

Execute Groq primary workflow: chat completions with tool use and JSON

2.8K 0
View
validating-csrf-protection logo
jeremylongshore/claude-code-plugins-plus-skills

validating-csrf-protection

Validate CSRF protection implementations for security gaps. Use when

2.8K 0
View
api-contract logo
jeremylongshore/claude-code-plugins-plus-skills

api-contract

Configure this skill should be used when the user asks about "API contract",

2.8K 0
View
ideogram-incident-runbook logo
jeremylongshore/claude-code-plugins-plus-skills

ideogram-incident-runbook

Execute Ideogram incident response with triage, mitigation, and postmortem.

2.8K 0
View
gamma-sdk-patterns logo
jeremylongshore/claude-code-plugins-plus-skills

gamma-sdk-patterns

Reusable patterns for the Gamma REST API (no SDK exists).

2.8K 0
View
deepgram-sdk-patterns logo
jeremylongshore/claude-code-plugins-plus-skills

deepgram-sdk-patterns

Apply production-ready Deepgram SDK patterns for TypeScript and Python.

2.8K 0
View
openrouter-upgrade-migration logo
jeremylongshore/claude-code-plugins-plus-skills

openrouter-upgrade-migration

Migrate to OpenRouter from direct provider APIs or upgrade between SDK/model

2.8K 0
View
openrouter-common-errors logo
jeremylongshore/claude-code-plugins-plus-skills

openrouter-common-errors

Diagnose and fix common OpenRouter API errors. Use when encountering

2.8K 0
View
linear-cost-tuning logo
jeremylongshore/claude-code-plugins-plus-skills

linear-cost-tuning

Optimize Linear API usage, reduce unnecessary calls, and maximize

2.8K 0
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View