Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Collect Customer.io debug evidence for support tickets. Use when creating support requests, investigating delivery failures, or documenting integration issues. Trigger: "customer.io debug", "customer.io support ticket", "collect customer.io logs", "customer.io diagnostics".
.claude/skills/jeremylongshore-customerio-debug-bundle/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-24 | ✗→✓ | ▲ Improved | 69% | 0% |
| case-13 | ✗→✓ | ▲ Improved | 57% | 0% |
| case-01 | ✗→✓ | ▲ Improved | 14% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 122% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 111% | 0% |
!node --version 2>/dev/null || echo 'Node.js: not installed' !npm list customerio-node 2>/dev/null | grep customerio || echo 'customerio-node: not installed'
Collect a comprehensive debug bundle for Customer.io support tickets: API connectivity tests, user profile inspection, SDK version info, environment validation, and a structured support report.
curl available for API testsbash#!/usr/bin/env bash set -euo pipefail echo "=== Customer.io Debug Bundle ===" echo "Timestamp: $(date -u +%Y-%m-%dT%H:%M:%SZ)" echo "" # 1. Check Customer.io status echo "--- Platform Status ---" curl -s "https://status.customer.io/api/v2/status.json" \ | python3 -c "import sys,json; d=json.load(sys.stdin); print(f'Status: {d[\"status\"][\"description\"]}')" \ 2>/dev/null || echo "Could not reach status page" # 2. Test Track API authentication echo "" echo "--- Track API Auth ---" TRACK_RESULT=$(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/debug-test-$(date +%s)" \ -H "Content-Type: application/json" \ -d '{"email":"debug-test@example.com"}') echo "Track API: HTTP ${TRACK_RESULT}" # 3. Test App API authentication echo "" echo "--- App API Auth ---" APP_RESULT=$(curl -s -o /dev/null -w "%{http_code}" \ -H "Authorization: Bearer ${CUSTOMERIO_APP_API_KEY}" \ "https://api.customer.io/v1/campaigns") echo "App API: HTTP ${APP_RESULT}" # 4. DNS and latency echo "" echo "--- Network Diagnostics ---" for host in track.customer.io api.customer.io; do LATENCY=$(curl -s -o /dev/null -w "%{time_total}" "https://${host}") echo "${host}: ${LATENCY}s" done
typescript// scripts/debug-user.ts // Investigate a specific user's state in Customer.io import { TrackClient, APIClient, RegionUS } from "customerio-node"; async function investigateUser(userId: string) { const cio = new TrackClient( process.env.CUSTOMERIO_SITE_ID!, process.env.CUSTOMERIO_TRACK_API_KEY!, { region: RegionUS } ); console.log(`\n=== User Investigation: ${userId} ===\n`); // Test if we can identify (update) the user — confirms they exist try { await cio.identify(userId, { _debug_checked_at: Math.floor(Date.now() / 1000), }); console.log("Profile: EXISTS (identify succeeded)"); } catch (err: any) { console.log(`Profile: ERROR (${err.statusCode}: ${err.message})`); } // Test if we can track an event on the user try { await cio.track(userId, { name: "debug_check", data: { checked_at: new Date().toISOString() }, }); console.log("Event tracking: WORKING"); } catch (err: any) { console.log(`Event tracking: ERROR (${err.statusCode}: ${err.message})`); } // Check suppression status by trying to unsuppress // (If user is not suppressed, this is a no-op) console.log("\nNote: Check suppression status in Customer.io dashboard:"); console.log(` People > Search "${userId}" > check Suppressed badge`); console.log(" Also check Activity tab for bounce/complaint events"); } const userId = process.argv[2]; if (!userId) { console.error("Usage: npx tsx scripts/debug-user.ts <user-id>"); process.exit(1); } investigateUser(userId);
typescript// scripts/debug-env.ts import { readFileSync } from "fs"; function collectEnvInfo() { const report: Record<string, string> = {}; // Node.js version report["node_version"] = process.version; report["platform"] = `${process.platform} ${process.arch}`; // SDK version try { const pkg = JSON.parse( readFileSync("node_modules/customerio-node/package.json", "utf-8") ); report["customerio_node_version"] = pkg.version; } catch { report["customerio_node_version"] = "NOT INSTALLED"; } // Environment config (redacted) report["site_id_set"] = process.env.CUSTOMERIO_SITE_ID ? "YES" : "NO"; report["track_key_set"] = process.env.CUSTOMERIO_TRACK_API_KEY ? "YES" : "NO"; report["app_key_set"] = process.env.CUSTOMERIO_APP_API_KEY ? "YES" : "NO"; report["region"] = process.env.CUSTOMERIO_REGION ?? "us (default)"; // Redacted key prefix for identification const siteId = process.env.CUSTOMERIO_SITE_ID ?? ""; report["site_id_prefix"] = siteId.substring(0, 4) + "..."; console.log("\n=== Environment Debug Info ===\n"); for (const [key, value] of Object.entries(report)) { console.log(`${key}: ${value}`); } } collectEnvInfo();
typescript// scripts/generate-support-report.ts function generateReport(issue: { summary: string; userId?: string; deliveryId?: string; errorCode?: number; errorMessage?: string; reproducible: boolean; startedAt?: string; }) { const report = ` ## Customer.io Support Report Generated: ${new Date().toISOString()} ### Issue Summary ${issue.summary} ### Affected Resources - User ID: ${issue.userId ?? "N/A"} - Delivery ID: ${issue.deliveryId ?? "N/A"} - Error Code: ${issue.errorCode ?? "N/A"} - Error Message: ${issue.errorMessage ?? "N/A"} ### Reproduction - Reproducible: ${issue.reproducible ? "Yes" : "Intermittent"} - First observed: ${issue.startedAt ?? "Unknown"} ### Environment - Node.js: ${process.version} - Region: ${process.env.CUSTOMERIO_REGION ?? "us"} - Site ID prefix: ${(process.env.CUSTOMERIO_SITE_ID ?? "").substring(0, 4)}... ### Steps to Reproduce 1. [Describe the action taken] 2. [Describe the expected result] 3. [Describe the actual result] ### Attachments - [ ] Application logs (relevant time window) - [ ] API request/response captures - [ ] Screenshot of user profile in dashboard - [ ] Screenshot of campaign/broadcast configuration `.trim(); console.log(report); }
bash# Collect recent Customer.io related logs (adjust path for your setup) # Grep for CIO/customerio in your application logs grep -i "customer\\.io\\|customerio\\|cio_" /var/log/app/*.log \ | tail -100 \ > /tmp/cio-debug-logs.txt 2>/dev/null # Or from Docker docker logs your-app-container 2>&1 \ | grep -i "customer\\.io\\|customerio\\|cio_" \ | tail -100 \ > /tmp/cio-debug-logs.txt # Redact sensitive data before sharing sed -i 's/\(api_key\|apikey\|secret\)=[^&]*/\1=REDACTED/gi' /tmp/cio-debug-logs.txt
email attribute| Issue | Solution | |-------|----------| | Status page unreachable | Check your network; try from a different network | | Both APIs return 401 | Credentials are wrong — regenerate in dashboard | | Track OK but App 401 | Using Track API key for App API — they're separate keys | | Logs contain PII | Run redaction script before sharing with support |
After creating debug bundle, proceed to customerio-rate-limits to implement proper rate limiting.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-24 | fail→pass | 12,933 | 6,513 | -50% | 1 | 1 | 0% | 2,115 | 3,582 | +69% | 0 | 0 | — |
case-05 | pass→pass | 13,822 | 9,924 | -28% | 1 | 1 | 0% | 2,841 | 4,273 | +50% | 0 | 0 | — |
case-06 | pass→pass | 10,581 | 6,717 | -37% | 1 | 1 | 0% | 2,218 | 3,711 | +67% | 0 | 0 | — |
case-07 | pass→pass | 8,301 | 8,052 | -3% | 1 | 1 | 0% | 1,724 | 4,029 | +134% | 0 | 0 | — |
case-13 | fail→pass | 11,869 | 6,638 | -44% | 1 | 1 | 0% | 2,154 | 3,378 | +57% | 0 | 0 | — |
case-01 | fail→pass | 20,225 | 11,979 | -41% | 1 | 1 | 0% | 4,489 | 5,139 | +14% | 0 | 0 | — |
case-02 | fail→fail | 13,656 | 9,251 | -32% | 1 | 1 | 0% | 2,723 | 4,356 | +60% | 0 | 0 | — |
case-03 | fail→fail | 13,625 | 10,400 | -24% | 1 | 1 | 0% | 2,767 | 4,559 | +65% | 0 | 0 | — |
case-04 | pass→pass | 19,460 | 13,780 | -29% | 1 | 1 | 0% | 3,912 | 4,958 | +27% | 0 | 0 | — |
case-08 | fail→pass | 6,726 | 3,783 | -44% | 1 | 1 | 0% | 1,368 | 3,034 | +122% | 0 | 0 | — |
case-09 | pass→pass | 4,170 | 1,845 | -56% | 1 | 1 | 0% | 850 | 2,633 | +210% | 0 | 0 | — |
case-10 | pass→pass | 10,031 | 7,786 | -22% | 1 | 1 | 0% | 2,091 | 4,039 | +93% | 0 | 0 | — |
case-11 | fail→pass | 9,273 | 6,206 | -33% | 1 | 1 | 0% | 1,797 | 3,788 | +111% | 0 | 0 | — |
case-12 | fail→fail | 9,385 | 8,470 | -10% | 1 | 1 | 0% | 1,997 | 4,304 | +116% | 0 | 0 | — |
case-14 | fail→fail | 9,073 | 9,299 | +2% | 1 | 1 | 0% | 1,839 | 4,426 | +141% | 0 | 0 | — |
case-15 | pass→pass | 9,316 | 5,475 | -41% | 1 | 1 | 0% | 1,829 | 3,386 | +85% | 0 | 0 | — |
case-16 | pass→pass | 11,098 | 4,711 | -58% | 1 | 1 | 0% | 2,129 | 3,145 | +48% | 0 | 0 | — |
case-17 | fail→fail | 18,364 | 15,310 | -17% | 1 | 1 | 0% | 4,148 | 5,902 | +42% | 0 | 0 | — |
case-18 | fail→pass | 13,832 | 6,049 | -56% | 1 | 1 | 0% | 2,311 | 3,466 | +50% | 0 | 0 | — |
case-19 | fail→pass | 6,412 | 3,501 | -45% | 1 | 1 | 0% | 1,193 | 2,972 | +149% | 0 | 0 | — |
case-20 | fail→fail | 8,049 | 5,133 | -36% | 1 | 1 | 0% | 1,595 | 3,368 | +111% | 0 | 0 | — |
case-21 | pass→pass | 13,267 | 8,346 | -37% | 1 | 1 | 0% | 2,632 | 3,963 | +51% | 0 | 0 | — |
case-22 | pass→pass | 9,759 | 4,937 | -49% | 1 | 1 | 0% | 1,896 | 3,366 | +78% | 0 | 0 | — |
case-23 | fail→pass | 9,006 | 5,054 | -44% | 1 | 1 | 0% | 1,604 | 3,201 | +100% | 0 | 0 | — |
case-25 | pass→pass | 5,466 | 2,916 | -47% | 1 | 1 | 0% | 993 | 2,947 | +197% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 25 cases were attempted. The headline lift of +32 percentage points is the difference between those two pass rates over the 25 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.