Catchpoint CI/CD Integration: Automated Performance Gates and Alerting
Catchpoint is most valuable when it's woven into your deployment process — not just running as a passive monitor. By integrating Catchpoint with your CI/CD pipeline, you can enforce performance budgets, trigger post-deploy validation, and automatically roll back when new code degrades user experience.
This guide covers the complete CI/CD integration pattern: webhook configuration, API-driven test execution, performance gate setup, and alerting best practices.
Why Performance Gates Matter
Without performance gates, performance regressions go undetected until users complain. The typical pattern:
- Developer ships a feature with a 300KB unoptimized image
- Synthetic monitors show LCP increased from 1.8s to 3.5s
- Alert fires 10 minutes after deploy
- Developer investigates, identifies the image, fixes it
- Second deploy 45 minutes later
With a performance gate in the pipeline:
- Developer ships a feature with a 300KB unoptimized image
- Post-deploy synthetic test detects LCP = 3.5s
- Pipeline fails; deploy does not proceed to production
- Developer fixes the image in the same PR
- Pipeline passes; single deploy with the fix included
Gates catch regressions at the cheapest moment to fix them.
Catchpoint API Overview
Catchpoint provides a REST API for programmatic test management. Key endpoints:
GET /api/v1/tests # List all tests
GET /api/v1/tests/{id}/results # Get test results
POST /api/v1/tests/{id}/run # Trigger an on-demand test run
GET /api/v1/tests/{id}/results/latest # Get most recent results
POST /api/v1/alerts # Create alert rules programmatically
GET /api/v1/nodes # List available nodesAuthentication uses OAuth 2.0. Generate a token via:
curl -X POST "https://io.catchpoint.com/api/v1/token" \
-d "grant_type=apikey&apiKey=YOUR_API_KEY"Store the token securely in your CI/CD secrets — never hardcode it in pipeline scripts.
GitHub Actions Integration
Basic Post-Deploy Synthetic Test
Create .github/workflows/performance-gate.yml:
name: Performance Gate
on:
deployment_status:
states: [success]
jobs:
check-performance:
if: github.event.deployment_status.environment == 'production'
runs-on: ubuntu-latest
steps:
- name: Get Catchpoint Token
id: auth
run: |
TOKEN=$(curl -s -X POST "https://io.catchpoint.com/api/v1/token" \
-d "grant_type=apikey&apiKey=${{ secrets.CATCHPOINT_API_KEY }}" \
| jq -r '.access_token')
echo "token=$TOKEN" >> $GITHUB_OUTPUT
- name: Trigger Synthetic Test
id: trigger
run: |
RUN_ID=$(curl -s -X POST \
"https://io.catchpoint.com/api/v1/tests/${{ vars.CATCHPOINT_TEST_ID }}/run" \
-H "Authorization: Bearer ${{ steps.auth.outputs.token }}" \
-H "Content-Type: application/json" \
| jq -r '.runId')
echo "run_id=$RUN_ID" >> $GITHUB_OUTPUT
- name: Wait for Results
run: sleep 120 # Wait 2 minutes for test to complete
- name: Evaluate Performance
run: |
RESULT=$(curl -s \
"https://io.catchpoint.com/api/v1/tests/${{ vars.CATCHPOINT_TEST_ID }}/results/latest" \
-H "Authorization: Bearer ${{ steps.auth.outputs.token }}")
LCP=$(echo $RESULT | jq '.metrics.lcp.p75')
echo "p75 LCP: ${LCP}ms"
# Fail if p75 LCP exceeds 2500ms
if (( $(echo "$LCP > 2500" | bc -l) )); then
echo "❌ Performance gate failed: p75 LCP ${LCP}ms exceeds 2500ms threshold"
exit 1
fi
echo "✅ Performance gate passed: p75 LCP ${LCP}ms"Tagging Deployments in Catchpoint
Catchpoint supports deployment markers that appear on your performance charts, making it easy to correlate performance changes with specific deploys.
- name: Tag Deploy in Catchpoint
run: |
curl -s -X POST \
"https://io.catchpoint.com/api/v1/annotations" \
-H "Authorization: Bearer ${{ steps.auth.outputs.token }}" \
-H "Content-Type: application/json" \
-d '{
"title": "Deploy: ${{ github.sha }}",
"description": "PR: ${{ github.event.pull_request.title }}",
"timestamp": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'",
"testIds": [${{ vars.CATCHPOINT_TEST_ID }}]
}'These annotations appear as vertical lines on your Catchpoint dashboards, making post-incident reviews much faster.
GitLab CI Integration
For GitLab pipelines, add a performance stage after your deploy stage:
stages:
- build
- test
- deploy
- performance-gate
variables:
CATCHPOINT_TEST_ID: "12345"
performance-check:
stage: performance-gate
image: alpine:latest
before_script:
- apk add --no-cache curl jq bc
script:
- |
# Authenticate
TOKEN=$(curl -s -X POST "https://io.catchpoint.com/api/v1/token" \
-d "grant_type=apikey&apiKey=$CATCHPOINT_API_KEY" \
| jq -r '.access_token')
# Trigger test
curl -s -X POST \
"https://io.catchpoint.com/api/v1/tests/${CATCHPOINT_TEST_ID}/run" \
-H "Authorization: Bearer $TOKEN"
# Wait for completion
sleep 180
# Fetch results
RESULT=$(curl -s \
"https://io.catchpoint.com/api/v1/tests/${CATCHPOINT_TEST_ID}/results/latest" \
-H "Authorization: Bearer $TOKEN")
AVAILABILITY=$(echo $RESULT | jq '.availability')
LCP=$(echo $RESULT | jq '.metrics.lcp.p75')
echo "Availability: $AVAILABILITY%"
echo "p75 LCP: ${LCP}ms"
[ $(echo "$AVAILABILITY < 99" | bc -l) -eq 1 ] && { echo "❌ Availability gate failed"; exit 1; }
[ $(echo "$LCP > 3000" | bc -l) -eq 1 ] && { echo "❌ LCP gate failed"; exit 1; }
echo "✅ All performance gates passed"
only:
- main
environment:
name: productionJenkins Integration
For Jenkins pipelines, use the Catchpoint API via shell steps:
pipeline {
agent any
environment {
CATCHPOINT_API_KEY = credentials('catchpoint-api-key')
CATCHPOINT_TEST_ID = '12345'
}
stages {
stage('Deploy') {
steps {
// Your existing deploy steps
sh './deploy.sh'
}
}
stage('Performance Gate') {
steps {
script {
// Get auth token
def token = sh(
script: """
curl -s -X POST "https://io.catchpoint.com/api/v1/token" \
-d "grant_type=apikey&apiKey=${CATCHPOINT_API_KEY}" \
| jq -r '.access_token'
""",
returnStdout: true
).trim()
// Trigger test
sh """
curl -s -X POST \
"https://io.catchpoint.com/api/v1/tests/${CATCHPOINT_TEST_ID}/run" \
-H "Authorization: Bearer ${token}"
"""
// Wait and evaluate
sleep(180)
def result = sh(
script: """
curl -s \
"https://io.catchpoint.com/api/v1/tests/${CATCHPOINT_TEST_ID}/results/latest" \
-H "Authorization: Bearer ${token}"
""",
returnStdout: true
).trim()
def lcp = sh(
script: "echo '${result}' | jq '.metrics.lcp.p75'",
returnStdout: true
).trim().toFloat()
if (lcp > 2500) {
error("Performance gate failed: p75 LCP ${lcp}ms exceeds 2500ms")
}
echo "Performance gate passed: p75 LCP ${lcp}ms"
}
}
}
}
}Alert Configuration
Alert Rule Architecture
Well-structured alerting requires three layers:
Layer 1: Immediate availability alerts (page the on-call engineer)
- Availability drops below 99% for 2+ consecutive checks from any node
- Response time exceeds 10 seconds for 2+ consecutive checks
Layer 2: Performance degradation alerts (notify the team in Slack)
- p75 response time increases more than 30% compared to previous hour baseline
- Error rate exceeds 0.5% of checks over 15 minutes
Layer 3: Trend alerts (weekly digest email)
- p75 LCP worsening more than 10% week-over-week
- Node-specific performance diverging more than 50% from median
Configuring Alerts in the Portal
Navigate to Alerts > Alert Rules > Add Alert Rule:
Availability Alert:
Trigger: Availability < 99%
Consecutive Failures: 2
Nodes: Any 1 node
Severity: Critical
Notify: PagerDuty + Slack #incidents
Recovery: Send notification when resolvedResponse Time Alert:
Trigger: Response time > 5000ms
Consecutive Failures: 2
Nodes: Any 2 nodes simultaneously
Severity: High
Notify: Slack #performance-alerts
Recovery: Send notification when resolvedEscalation Policies
Configure escalation so that unacknowledged alerts reach progressively more people:
T+0: Alert fires → Notify on-call engineer via PagerDuty
T+15m: No acknowledgment → Escalate to engineering lead
T+30m: No acknowledgment → Notify VP Engineering
T+60m: Ongoing → Create incident bridge callMaintenance Windows
When deploying, suppress alerts to avoid false positives from the deploy process itself:
# Create maintenance window via API
curl -X POST "https://io.catchpoint.com/api/v1/maintenance-windows" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Deploy maintenance window",
"startTime": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'",
"endTime": "'$(date -u -d "+30 minutes" +%Y-%m-%dT%H:%M:%SZ)'",
"testIds": [12345, 12346, 12347]
}'Add this to your deploy pipeline before the deploy step and delete the window after deploy completes.
Webhook-Driven Integrations
Receiving Catchpoint Webhooks
Catchpoint can send HTTP POST payloads to your endpoints on alert triggers. Set up a webhook receiver in your infrastructure:
// Express.js webhook receiver
const express = require('express');
const app = express();
app.use(express.json());
app.post('/webhooks/catchpoint', (req, res) => {
const alert = req.body;
console.log(`Alert: ${alert.TestName} - ${alert.AlertType}`);
console.log(`Severity: ${alert.AlertSeverity}`);
console.log(`Node: ${alert.NodeName} (${alert.NodeCity})`);
console.log(`Response time: ${alert.ResponseTime}ms`);
// Route to your incident management system
if (alert.AlertSeverity === 'CRITICAL') {
triggerPagerDuty(alert);
} else {
postToSlack(alert);
}
res.status(200).send('OK');
});Catchpoint webhook payload structure:
{
"TestId": 12345,
"TestName": "Homepage Performance Monitor",
"AlertType": "ResponseTime",
"AlertSeverity": "CRITICAL",
"Timestamp": "2026-06-05T14:30:00Z",
"NodeId": 456,
"NodeName": "New York - Backbone",
"NodeCity": "New York",
"ResponseTime": 8500,
"StatusCode": 200,
"AlertState": "OPEN"
}Sending Events TO Catchpoint
For deployment annotations and custom events, POST to the Catchpoint events API from your deployment tools:
# In your deploy script
deploy_app() {
# ... your deploy logic ...
# Annotate Catchpoint with the deploy
curl -s -X POST "https://io.catchpoint.com/api/v1/annotations" \
-H "Authorization: Bearer $CATCHPOINT_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"title\": \"Deployed v${VERSION}\",
\"description\": \"Commit: ${GIT_SHA}\",
\"timestamp\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"
}"
}Performance Budget Enforcement
Define performance budgets as code and enforce them in your pipeline:
# performance-budget.yml
budgets:
homepage:
test_id: 12345
thresholds:
lcp_p75_ms: 2500
ttfb_p75_ms: 800
availability_pct: 99.5
checkout:
test_id: 12346
thresholds:
lcp_p75_ms: 3000
ttfb_p75_ms: 1000
availability_pct: 99.9
api_health:
test_id: 12347
thresholds:
response_time_p75_ms: 200
availability_pct: 99.99Write a budget checker script that reads this file and queries the Catchpoint API:
#!/usr/bin/env python3
import yaml
import requests
import sys
def check_budgets(config_file, token):
with open(config_file) as f:
config = yaml.safe_load(f)
failures = []
for page, settings in config['budgets'].items():
test_id = settings['test_id']
thresholds = settings['thresholds']
# Fetch latest results
resp = requests.get(
f"https://io.catchpoint.com/api/v1/tests/{test_id}/results/latest",
headers={"Authorization": f"Bearer {token}"}
)
data = resp.json()
# Check each threshold
actual_lcp = data['metrics']['lcp']['p75']
if actual_lcp > thresholds.get('lcp_p75_ms', float('inf')):
failures.append(
f"{page}: LCP {actual_lcp}ms exceeds budget {thresholds['lcp_p75_ms']}ms"
)
return failures
if __name__ == '__main__':
token = sys.argv[1]
failures = check_budgets('performance-budget.yml', token)
if failures:
print("❌ Performance budget failures:")
for f in failures:
print(f" - {f}")
sys.exit(1)
print("✅ All performance budgets met")Combining Catchpoint with Functional Testing
Performance gates catch speed regressions. But a fast page that returns wrong results, broken checkout flows, or missing content is still a production failure.
Pair Catchpoint's performance gates with functional test gates in the same pipeline:
stages:
- deploy
- functional-tests # Did the deploy break any features?
- performance-gates # Did the deploy slow anything down?
- notify
functional-tests:
stage: functional-tests
script:
# Run plain-English functional tests via HelpMeTest
- helpmetest run --suite checkout-flow
- helpmetest run --suite user-auth
performance-gates:
stage: performance-gates
needs: [functional-tests] # Only run if functional tests pass
script:
- python3 check-budgets.py $CATCHPOINT_TOKENThis sequencing ensures:
- Functional correctness is verified first
- Performance gates only run if the app is functionally correct
- Both gates must pass before the deploy is considered successful
Conclusion
Integrating Catchpoint into your CI/CD pipeline transforms performance monitoring from a reactive to proactive capability. Deploy annotations tie performance data to code changes. Post-deploy tests validate new releases against defined budgets. Automated rollbacks prevent performance regressions from reaching users.
The investment pays off immediately: teams that gate deployments on performance catch regressions in minutes, not days, and fix them at the lowest possible cost.
Start with a single performance gate on your most critical user flow. Add budgets and gate coverage as your monitoring matures. Within a few sprints, your team will be catching performance regressions before they ever reach production.