Customer.io Production Checklist
Overview
Comprehensive go-live checklist for Customer.io integrations: credentials audit, integration quality review, email deliverability setup, monitoring configuration, smoke tests, and staged rollout plan.
Prerequisites
- Customer.io integration complete and tested in staging
- Production workspace credentials ready
- Sending domain configured and verified
Production Checklist
1. Credentials & Configuration
| Item |
Check |
How to Verify |
| Production Site ID |
Correct workspace |
Settings > API & Webhook Credentials |
| Production Track API Key |
Different from dev/staging |
Compare with staging .env |
| Production App API Key |
Set for transactional messages |
Test with curl bearer auth |
| Region setting |
Matches account region (US/EU) |
Settings > Workspace Settings |
| Secrets storage |
In secrets manager, not .env |
Check deployment config |
| Key rotation schedule |
Documented (90-day cycle) |
Calendar reminder set |
2. Integration Quality
// scripts/prod-audit.ts
import { TrackClient, RegionUS } from "customerio-node";
async function auditIntegration() {
const checks: { name: string; pass: boolean; detail: string }[] = [];
// Check 1: Credentials exist
const siteId = process.env.CUSTOMERIO_SITE_ID;
const trackKey = process.env.CUSTOMERIO_TRACK_API_KEY;
const appKey = process.env.CUSTOMERIO_APP_API_KEY;
checks.push({
name: "Track credentials",
pass: !!(siteId && trackKey),
detail: siteId ? `Site ID: ${siteId.substring(0, 4)}...` : "MISSING",
});
checks.push({
name: "App API credential",
pass: !!appKey,
detail: appKey ? "Set" : "MISSING (needed for transactional)",
});
// Check 2: API connectivity
if (siteId && trackKey) {
const cio = new TrackClient(siteId, trackKey, { region: RegionUS });
try {
await cio.identify("prod-audit-test", {
email: "prod-audit@example.com",
});
await cio.suppress("prod-audit-test");
checks.push({ name: "Track API", pass: true, detail: "Connected" });
} catch (err: any) {
checks.push({
name: "Track API",
pass: false,
detail: `${err.statusCode}: ${err.message}`,
});
}
}
// Report
console.log("\n=== Customer.io Production Audit ===\n");
for (const check of checks) {
const icon = check.pass ? "PASS" : "FAIL";
console.log(`[${icon}] ${check.name}: ${check.detail}`);
}
const passed = checks.filter((c) => c.pass).length;
console.log(`\nResult: ${passed}/${checks.length} passed`);
return checks.every((c) => c.pass);
}
auditIntegration().then((ok) => process.exit(ok ? 0 : 1));
3. Email Deliverability
| Item |
Status |
Dashboard Location |
| Sending domain verified |
Required |
Settings > Sending Domains |
| SPF record published |
Required |
DNS TXT record |
| DKIM record published |
Required |
DNS CNAME record |
| DMARC policy set |
Recommended |
DNS TXT record _dmarc.yourdomain.com |
| Return-Path configured |
Recommended |
Settings > Sending Domains |
| Unsubscribe link in all marketing emails |
Required (CAN-SPAM) |
Template editor |
| Physical address in marketing emails |
Required (CAN-SPAM) |
Template editor |
4. Campaign Readiness
5. Monitoring & Alerting
// Set up these alerts in your monitoring system:
const ALERT_THRESHOLDS = {
// API health
api_error_rate: 0.01, // Alert if > 1% of API calls fail
api_p99_latency_ms: 5000, // Alert if p99 > 5 seconds
// Delivery health
bounce_rate: 0.05, // Alert if > 5% bounce rate
complaint_rate: 0.001, // Alert if > 0.1% spam complaints
delivery_rate: 0.95, // Alert if < 95% delivery rate
// Operational health
queue_depth: 10000, // Alert if event queue > 10K pending
webhook_error_rate: 0.05, // Alert if > 5% webhook processing failures
};
6. Smoke Test Script
#!/usr/bin/env bash
set -euo pipefail
echo "=== Customer.io Production Smoke Test ==="
# Test 1: Track API connectivity
TRACK_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
-u "${CUSTOMERIO_SITE_ID}:${CUSTOMERIO_TRACK_API_KEY}" \
-X PUT "https://track.customer.io/api/v1/customers/smoke-test-$(date +%s)" \
-H "Content-Type: application/json" \
-d '{"email":"smoke@example.com","_smoke_test":true}')
if [ "$TRACK_STATUS" = "200" ]; then
echo "[PASS] Track API: HTTP 200"
else
echo "[FAIL] Track API: HTTP ${TRACK_STATUS}"
exit 1
fi
# Test 2: App API connectivity
APP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer ${CUSTOMERIO_APP_API_KEY}" \
"https://api.customer.io/v1/campaigns")
if [ "$APP_STATUS" = "200" ]; then
echo "[PASS] App API: HTTP 200"
else
echo "[FAIL] App API: HTTP ${APP_STATUS}"
exit 1
fi
echo ""
echo "All smoke tests passed"
7. Staged Rollout Plan
| Time |
Action |
Rollback Trigger |
| T-24h |
Final staging test pass |
Any test failure |
| T-12h |
Production smoke tests |
Smoke test failure |
| T-1h |
Enable for internal team (feature flag) |
Error reports |
| T-0 |
Enable for 10% of users |
Error rate > 1% |
| T+1h |
Increase to 50% |
Error rate > 1% or bounce rate > 5% |
| T+2h |
100% traffic |
Same thresholds |
| T+24h |
Post-launch review |
N/A |
// Feature flag integration for staged rollout
function shouldUseCio(userId: string, rolloutPercent: number): boolean {
// Deterministic — same user always gets same result
const hash = createHash("md5").update(userId).digest("hex");
const bucket = parseInt(hash.substring(0, 8), 16) % 100;
return bucket < rolloutPercent;
}
Rollback Procedure
- Set feature flag to 0% (immediate — no deploy needed)
- Pause all active campaigns in Customer.io dashboard
- Investigate logs and error reports
- Fix issue, test in staging
- Resume staged rollout from 10%
Error Handling
| Issue |
Solution |
| Smoke test fails in production |
Verify production credentials (different from staging) |
| High bounce rate post-launch |
Check sending domain verification, review bounce logs |
| Spam complaints spike |
Review email content, verify unsubscribe links work |
| Feature flag not working |
Check feature flag service connectivity |
Resources
Next Steps
After production launch, proceed to customerio-upgrade-migration for SDK maintenance.
1---2name: customerio-prod-checklist3description: |4 Execute Customer.io production deployment checklist.5 Use when preparing for production launch, auditing integration6 quality, or performing pre-launch validation.7 Trigger: "customer.io production", "customer.io checklist",8 "deploy customer.io", "customer.io go-live", "customer.io launch".9allowed-tools: Read, Write, Edit, Bash(curl:*), Bash(npx:*), Glob, Grep10version: 1.0.011license: MIT12author: Jeremy Longshore <jeremy@intentsolutions.io>13compatible-with: claude-code, codex, openclaw14tags: [saas, customer-io, deployment, production, audit]1516---1718# Customer.io Production Checklist1920## Overview2122Comprehensive go-live checklist for Customer.io integrations: credentials audit, integration quality review, email deliverability setup, monitoring configuration, smoke tests, and staged rollout plan.2324## Prerequisites2526- Customer.io integration complete and tested in staging27- Production workspace credentials ready28- Sending domain configured and verified2930## Production Checklist3132### 1. Credentials & Configuration3334| Item | Check | How to Verify |35|------|-------|---------------|36| Production Site ID | Correct workspace | Settings > API & Webhook Credentials |37| Production Track API Key | Different from dev/staging | Compare with staging `.env` |38| Production App API Key | Set for transactional messages | Test with `curl` bearer auth |39| Region setting | Matches account region (US/EU) | Settings > Workspace Settings |40| Secrets storage | In secrets manager, not `.env` | Check deployment config |41| Key rotation schedule | Documented (90-day cycle) | Calendar reminder set |4243### 2. Integration Quality4445```typescript46// scripts/prod-audit.ts47import { TrackClient, RegionUS } from "customerio-node";4849async function auditIntegration() {50 const checks: { name: string; pass: boolean; detail: string }[] = [];5152 // Check 1: Credentials exist53 const siteId = process.env.CUSTOMERIO_SITE_ID;54 const trackKey = process.env.CUSTOMERIO_TRACK_API_KEY;55 const appKey = process.env.CUSTOMERIO_APP_API_KEY;56 checks.push({57 name: "Track credentials",58 pass: !!(siteId && trackKey),59 detail: siteId ? `Site ID: ${siteId.substring(0, 4)}...` : "MISSING",60 });61 checks.push({62 name: "App API credential",63 pass: !!appKey,64 detail: appKey ? "Set" : "MISSING (needed for transactional)",65 });6667 // Check 2: API connectivity68 if (siteId && trackKey) {69 const cio = new TrackClient(siteId, trackKey, { region: RegionUS });70 try {71 await cio.identify("prod-audit-test", {72 email: "prod-audit@example.com",73 });74 await cio.suppress("prod-audit-test");75 checks.push({ name: "Track API", pass: true, detail: "Connected" });76 } catch (err: any) {77 checks.push({78 name: "Track API",79 pass: false,80 detail: `${err.statusCode}: ${err.message}`,81 });82 }83 }8485 // Report86 console.log("\n=== Customer.io Production Audit ===\n");87 for (const check of checks) {88 const icon = check.pass ? "PASS" : "FAIL";89 console.log(`[${icon}] ${check.name}: ${check.detail}`);90 }91 const passed = checks.filter((c) => c.pass).length;92 console.log(`\nResult: ${passed}/${checks.length} passed`);93 return checks.every((c) => c.pass);94}9596auditIntegration().then((ok) => process.exit(ok ? 0 : 1));97```9899### 3. Email Deliverability100101| Item | Status | Dashboard Location |102|------|--------|-------------------|103| Sending domain verified | Required | Settings > Sending Domains |104| SPF record published | Required | DNS TXT record |105| DKIM record published | Required | DNS CNAME record |106| DMARC policy set | Recommended | DNS TXT record `_dmarc.yourdomain.com` |107| Return-Path configured | Recommended | Settings > Sending Domains |108| Unsubscribe link in all marketing emails | Required (CAN-SPAM) | Template editor |109| Physical address in marketing emails | Required (CAN-SPAM) | Template editor |110111### 4. Campaign Readiness112113- [ ] All campaigns tested with test sends114- [ ] Liquid templates render correctly (preview with real data)115- [ ] Segment conditions verified with known test users116- [ ] Transactional templates have all required `message_data` fields117- [ ] Broadcast triggers tested end-to-end118- [ ] Unsubscribe flow tested (click unsubscribe link, verify suppression)119120### 5. Monitoring & Alerting121122```typescript123// Set up these alerts in your monitoring system:124const ALERT_THRESHOLDS = {125 // API health126 api_error_rate: 0.01, // Alert if > 1% of API calls fail127 api_p99_latency_ms: 5000, // Alert if p99 > 5 seconds128129 // Delivery health130 bounce_rate: 0.05, // Alert if > 5% bounce rate131 complaint_rate: 0.001, // Alert if > 0.1% spam complaints132 delivery_rate: 0.95, // Alert if < 95% delivery rate133134 // Operational health135 queue_depth: 10000, // Alert if event queue > 10K pending136 webhook_error_rate: 0.05, // Alert if > 5% webhook processing failures137};138```139140### 6. Smoke Test Script141142```bash143#!/usr/bin/env bash144set -euo pipefail145146echo "=== Customer.io Production Smoke Test ==="147148# Test 1: Track API connectivity149TRACK_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \150 -u "${CUSTOMERIO_SITE_ID}:${CUSTOMERIO_TRACK_API_KEY}" \151 -X PUT "https://track.customer.io/api/v1/customers/smoke-test-$(date +%s)" \152 -H "Content-Type: application/json" \153 -d '{"email":"smoke@example.com","_smoke_test":true}')154155if [ "$TRACK_STATUS" = "200" ]; then156 echo "[PASS] Track API: HTTP 200"157else158 echo "[FAIL] Track API: HTTP ${TRACK_STATUS}"159 exit 1160fi161162# Test 2: App API connectivity163APP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \164 -H "Authorization: Bearer ${CUSTOMERIO_APP_API_KEY}" \165 "https://api.customer.io/v1/campaigns")166167if [ "$APP_STATUS" = "200" ]; then168 echo "[PASS] App API: HTTP 200"169else170 echo "[FAIL] App API: HTTP ${APP_STATUS}"171 exit 1172fi173174echo ""175echo "All smoke tests passed"176```177178### 7. Staged Rollout Plan179180| Time | Action | Rollback Trigger |181|------|--------|-----------------|182| T-24h | Final staging test pass | Any test failure |183| T-12h | Production smoke tests | Smoke test failure |184| T-1h | Enable for internal team (feature flag) | Error reports |185| T-0 | Enable for 10% of users | Error rate > 1% |186| T+1h | Increase to 50% | Error rate > 1% or bounce rate > 5% |187| T+2h | 100% traffic | Same thresholds |188| T+24h | Post-launch review | N/A |189190```typescript191// Feature flag integration for staged rollout192function shouldUseCio(userId: string, rolloutPercent: number): boolean {193 // Deterministic — same user always gets same result194 const hash = createHash("md5").update(userId).digest("hex");195 const bucket = parseInt(hash.substring(0, 8), 16) % 100;196 return bucket < rolloutPercent;197}198```199200## Rollback Procedure2012021. Set feature flag to 0% (immediate — no deploy needed)2032. Pause all active campaigns in Customer.io dashboard2043. Investigate logs and error reports2054. Fix issue, test in staging2065. Resume staged rollout from 10%207208## Error Handling209210| Issue | Solution |211|-------|----------|212| Smoke test fails in production | Verify production credentials (different from staging) |213| High bounce rate post-launch | Check sending domain verification, review bounce logs |214| Spam complaints spike | Review email content, verify unsubscribe links work |215| Feature flag not working | Check feature flag service connectivity |216217## Resources218219- [Customer.io Email Deliverability](https://docs.customer.io/journeys/deliverability/)220- [Sending Domain Setup](https://docs.customer.io/accounts-and-workspaces/managing-credentials/)221- [Campaign Best Practices](https://docs.customer.io/journeys/campaigns-in-customerio/)222223## Next Steps224225After production launch, proceed to `customerio-upgrade-migration` for SDK maintenance.226