From customerio-pack
Deploys Customer.io integrations to GCP Cloud Run, Vercel, AWS Lambda, and Kubernetes with secrets management, health checks, and GitHub Actions pipelines.
How this skill is triggered — by the user, by Claude, or both
Slash command
/customerio-pack:customerio-deploy-pipelineThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Deploy Customer.io integrations to production: GCP Cloud Run with Secret Manager, Vercel serverless functions, AWS Lambda with SSM, Kubernetes with external secrets, plus health check endpoints and blue-green deployment scripts.
Deploy Customer.io integrations to production: GCP Cloud Run with Secret Manager, Vercel serverless functions, AWS Lambda with SSM, Kubernetes with external secrets, plus health check endpoints and blue-green deployment scripts.
customerio-ci-integration)# .github/workflows/deploy-cloud-run.yml
name: Deploy to Cloud Run
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # Required for Workload Identity Federation
steps:
- uses: actions/checkout@v4
- id: auth
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ secrets.WIF_PROVIDER }}
service_account: ${{ secrets.WIF_SA }}
- uses: google-github-actions/setup-gcloud@v2
- name: Build and push
run: |
gcloud builds submit --tag gcr.io/${{ secrets.GCP_PROJECT }}/cio-service
- name: Deploy
run: |
gcloud run deploy cio-service \
--image gcr.io/${{ secrets.GCP_PROJECT }}/cio-service \
--region us-central1 \
--set-secrets "CUSTOMERIO_SITE_ID=cio-site-id:latest,\
CUSTOMERIO_TRACK_API_KEY=cio-track-key:latest,\
CUSTOMERIO_APP_API_KEY=cio-app-key:latest" \
--set-env-vars "CUSTOMERIO_REGION=us,NODE_ENV=production" \
--min-instances 1 \
--max-instances 10 \
--memory 512Mi \
--cpu 1 \
--allow-unauthenticated
// routes/health.ts
import { TrackClient, RegionUS } from "customerio-node";
import { Router } from "express";
const router = Router();
router.get("/health", async (_req, res) => {
const checks: Record<string, { status: string; latency_ms?: number }> = {};
// Check Track API
const cio = new TrackClient(
process.env.CUSTOMERIO_SITE_ID!,
process.env.CUSTOMERIO_TRACK_API_KEY!,
{ region: RegionUS }
);
const start = Date.now();
try {
await cio.identify("health-check", {
email: "[email protected]",
_health_check: true,
});
checks.track_api = { status: "ok", latency_ms: Date.now() - start };
} catch (err: any) {
checks.track_api = { status: `error: ${err.statusCode}` };
}
const allOk = Object.values(checks).every((c) => c.status === "ok");
res.status(allOk ? 200 : 503).json({
status: allOk ? "healthy" : "degraded",
checks,
version: process.env.npm_package_version ?? "unknown",
uptime_seconds: Math.floor(process.uptime()),
timestamp: new Date().toISOString(),
});
});
export default router;
// api/customerio/identify.ts (Vercel serverless function)
import type { VercelRequest, VercelResponse } from "@vercel/node";
import { TrackClient, RegionUS } from "customerio-node";
const cio = new TrackClient(
process.env.CUSTOMERIO_SITE_ID!,
process.env.CUSTOMERIO_TRACK_API_KEY!,
{ region: RegionUS }
);
export default async function handler(req: VercelRequest, res: VercelResponse) {
if (req.method !== "POST") {
return res.status(405).json({ error: "Method not allowed" });
}
const { userId, attributes } = req.body;
if (!userId || !attributes?.email) {
return res.status(400).json({ error: "userId and attributes.email required" });
}
try {
await cio.identify(userId, {
...attributes,
last_seen_at: Math.floor(Date.now() / 1000),
});
return res.status(200).json({ success: true });
} catch (err: any) {
return res.status(err.statusCode ?? 500).json({ error: err.message });
}
}
# k8s/customerio-service.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: customerio-service
spec:
replicas: 2
selector:
matchLabels:
app: customerio-service
template:
metadata:
labels:
app: customerio-service
spec:
containers:
- name: app
image: gcr.io/my-project/cio-service:latest
ports:
- containerPort: 3000
env:
- name: CUSTOMERIO_SITE_ID
valueFrom:
secretKeyRef:
name: customerio-secrets
key: site-id
- name: CUSTOMERIO_TRACK_API_KEY
valueFrom:
secretKeyRef:
name: customerio-secrets
key: track-api-key
- name: CUSTOMERIO_APP_API_KEY
valueFrom:
secretKeyRef:
name: customerio-secrets
key: app-api-key
- name: CUSTOMERIO_REGION
value: "us"
- name: NODE_ENV
value: "production"
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
readinessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 15
periodSeconds: 30
---
apiVersion: v1
kind: Service
metadata:
name: customerio-service
spec:
selector:
app: customerio-service
ports:
- port: 80
targetPort: 3000
#!/usr/bin/env bash
set -euo pipefail
# scripts/blue-green-deploy.sh
SERVICE="cio-service"
REGION="us-central1"
IMAGE="gcr.io/${GCP_PROJECT}/${SERVICE}:${COMMIT_SHA}"
echo "=== Blue-Green Deploy: ${SERVICE} ==="
# 1. Deploy with no traffic
gcloud run deploy "${SERVICE}" \
--image "${IMAGE}" \
--region "${REGION}" \
--no-traffic \
--tag "canary"
echo "Deployed canary. Running health check..."
# 2. Health check on canary
CANARY_URL=$(gcloud run services describe "${SERVICE}" \
--region "${REGION}" --format 'value(status.url)' \
| sed 's|https://|https://canary---|')
HEALTH=$(curl -s -o /dev/null -w "%{http_code}" "${CANARY_URL}/health")
if [ "${HEALTH}" != "200" ]; then
echo "FAIL: Health check returned ${HEALTH}. Aborting."
exit 1
fi
# 3. Shift traffic: 10% → 50% → 100%
for pct in 10 50 100; do
echo "Shifting ${pct}% traffic to canary..."
gcloud run services update-traffic "${SERVICE}" \
--region "${REGION}" \
--to-tags "canary=${pct}"
sleep 30
done
echo "Deploy complete. 100% traffic on new revision."
| Issue | Solution |
|---|---|
| Secret not found | Verify secret name in secrets manager |
| Health check timeout | Increase initialDelaySeconds, check CIO connectivity |
| Cold start latency | Set --min-instances 1 (Cloud Run) or keep-alive |
| Memory OOM | Increase memory limits, check for event queue buildup |
After deployment, proceed to customerio-webhooks-events for webhook handling.
7plugins reuse this skill
First indexed Jul 10, 2026
Showing the 6 earliest of 7 plugins
npx claudepluginhub luxdevnet/claude-plus-lux --plugin customerio-packDeploys Customer.io integrations to GCP Cloud Run, Vercel, AWS Lambda, and Kubernetes with secrets management, health checks, and GitHub Actions pipelines.
Deploy Klaviyo integrations to Vercel, Fly.io, and Cloud Run platforms. Use when deploying Klaviyo-powered applications to production, configuring platform-specific secrets, or setting up deployment pipelines. Trigger with phrases like "deploy klaviyo", "klaviyo Vercel", "klaviyo production deploy", "klaviyo Cloud Run", "klaviyo Fly.io".
Deploys Apollo.io integrations to production with configurations for Vercel, GCP Cloud Run, and Kubernetes, including health checks and secret management.