Catchpoint CI/CD Integration: Automated Performance Gates and Alerting

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:

  1. Developer ships a feature with a 300KB unoptimized image
  2. Synthetic monitors show LCP increased from 1.8s to 3.5s
  3. Alert fires 10 minutes after deploy
  4. Developer investigates, identifies the image, fixes it
  5. Second deploy 45 minutes later

With a performance gate in the pipeline:

  1. Developer ships a feature with a 300KB unoptimized image
  2. Post-deploy synthetic test detects LCP = 3.5s
  3. Pipeline fails; deploy does not proceed to production
  4. Developer fixes the image in the same PR
  5. 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 nodes

Authentication 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: production

Jenkins 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 resolved

Response Time Alert:

Trigger: Response time > 5000ms
Consecutive Failures: 2  
Nodes: Any 2 nodes simultaneously
Severity: High
Notify: Slack #performance-alerts
Recovery: Send notification when resolved

Escalation 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 call

Maintenance 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.99

Write 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_TOKEN

This sequencing ensures:

  1. Functional correctness is verified first
  2. Performance gates only run if the app is functionally correct
  3. 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.

Read more

Start now free