| name | customerio-performance-tuning |
| description | Optimize Customer.io API performance.
Use when improving response times, reducing latency,
or optimizing high-volume integrations.
Trigger with phrases like "customer.io performance", "optimize customer.io",
"customer.io latency", "customer.io speed".
|
| allowed-tools | Read, Write, Edit, Bash(gh:*), Bash(curl:*) |
| version | 1.0.0 |
| license | MIT |
| author | Jeremy Longshore <jeremy@intentsolutions.io> |
Customer.io Performance Tuning
Overview
Optimize Customer.io API performance for high-volume and low-latency integrations.
Prerequisites
- Customer.io integration working
- Monitoring infrastructure
- Understanding of your traffic patterns
Instructions
Step 1: Connection Pooling
import { TrackClient, RegionUS } from '@customerio/track';
import { Agent } from 'http';
import { Agent as HttpsAgent } from 'https';
const httpsAgent = new HttpsAgent({
keepAlive: true,
keepAliveMsecs: 30000,
maxSockets: 100,
maxFreeSockets: 20,
timeout: 30000
});
export function createPooledClient(): TrackClient {
return new TrackClient(
process.env.CUSTOMERIO_SITE_ID!,
process.env.CUSTOMERIO_API_KEY!,
{
region: RegionUS,
httpAgent: httpsAgent
}
);
}
let clientInstance: TrackClient | null = null;
export function getClient(): TrackClient {
if (!clientInstance) {
clientInstance = createPooledClient();
}
return clientInstance;
}
Step 2: Batch Processing
import { TrackClient } from '@customerio/track';
interface BatchItem {
type: 'identify' | 'track';
userId: string;
data: Record<string, any>;
}
export class BatchProcessor {
private batch: BatchItem[] = [];
private batchSize: number;
private flushInterval: number;
private timer: NodeJS.Timer | null = null;
constructor(
private client: TrackClient,
options: { batchSize?: number; flushIntervalMs?: number } = {}
) {
this.batchSize = options.batchSize || 100;
this.flushInterval = options.flushIntervalMs || 1000;
this.startFlushTimer();
}
(: ): {
..(item);
(.. >= .) {
.();
}
}
(): <> {
(.. === ) ;
items = ..(, .);
concurrency = ;
( i = ; i < items.; i += concurrency) {
chunk = items.(i, i + concurrency);
.(chunk.( .(item)));
}
}
(: ): <> {
{
(item. === ) {
..(item., item.);
} {
..(item., {
: item..,
: item..
});
}
} (error) {
.(, error);
}
}
(): {
. = ( .(), .);
}
(): <> {
(.) {
(.);
}
.();
}
}
Step 3: Async Fire-and-Forget
import { TrackClient } from '@customerio/track';
class AsyncTracker {
private queue: Array<() => Promise<void>> = [];
private processing = false;
private concurrency = 5;
constructor(private client: TrackClient) {}
identifyAsync(userId: string, attributes: Record<string, any>): void {
this.enqueue(() => this.client.identify(userId, attributes));
}
trackAsync(userId: string, event: string, data?: Record<string, any>): void {
this.enqueue(() => this..(userId, { : event, data }));
}
(: <>): {
..(operation);
.();
}
(): <> {
(.) ;
. = ;
(.. > ) {
batch = ..(, .);
.(batch.( ()));
}
. = ;
}
}
asyncTracker = (());
Step 4: Caching for Deduplication
import { LRUCache } from 'lru-cache';
interface CacheEntry {
userId: string;
attributes: Record<string, any>;
timestamp: number;
}
const identifyCache = new LRUCache<string, CacheEntry>({
max: 10000,
ttl: 60000
});
export function shouldIdentify(
userId: string,
attributes: Record<string, any>
): boolean {
const cacheKey = `${userId}:${JSON.stringify(attributes)}`;
const cached = identifyCache.get(cacheKey);
if (cached) {
return false;
}
identifyCache.set(cacheKey, {
userId,
attributes,
timestamp: Date.now()
});
return ;
}
eventCache = <, >({
: ,
:
});
(): {
cacheKey = eventId || ;
(eventCache.(cacheKey)) {
;
}
eventCache.(cacheKey, .());
;
}
Step 5: Regional Optimization
import { TrackClient, RegionUS, RegionEU } from '@customerio/track';
interface RegionalConfig {
us: { siteId: string; apiKey: string };
eu: { siteId: string; apiKey: string };
}
class RegionalCustomerIO {
private clients: Map<string, TrackClient> = new Map();
constructor(config: RegionalConfig) {
this.clients.set('us', new TrackClient(
config.us.siteId,
config.us.apiKey,
{ region: RegionUS }
));
this.clients.set('eu', new TrackClient(
config.eu.siteId,
config.eu.,
{ : }
));
}
(: , ?: ): {
region = userRegion || .(userId);
..(region) || ..()!;
}
(: ): {
;
}
(
: ,
: <, >,
?:
): <> {
client = .(userId, region);
client.(userId, attributes);
}
}
Step 6: Performance Monitoring
import { metrics } from './metrics';
function wrapWithTiming<T>(
name: string,
operation: () => Promise<T>
): Promise<T> {
const start = Date.now();
return operation()
.then(result => {
metrics.histogram(`customerio.${name}.latency`, Date.now() - start);
metrics.increment(`customerio.${name}.success`);
return result;
})
.catch(error => {
metrics.histogram(`customerio.${name}.latency`, Date.now() - start);
metrics.increment(`customerio.${name}.error`);
throw error;
});
}
await wrapWithTiming('identify', () =>
client.identify(userId, attributes)
);
Performance Benchmarks
| Operation | Target Latency | Notes |
|---|
| Identify | < 100ms | With connection pooling |
| Track Event | < 100ms | With connection pooling |
| Batch (100 items) | < 500ms | Parallel processing |
| Webhook Processing | < 50ms | Excluding downstream ops |
Optimization Checklist
Error Handling
| Issue | Solution |
|---|
| High latency | Enable connection pooling |
| Timeout errors | Reduce payload size, increase timeout |
| Memory pressure | Limit cache and queue sizes |
Resources
Next Steps
After performance tuning, proceed to customerio-cost-tuning for cost optimization.