---
version: "2026"
language: "en"
---
# Set Up Go Gates in CI/CD with Leapwork Go

This guide shows how to create threshold-based pass/fail gates for Leapwork Go in a CI/CD pipeline.

It assumes that your pipeline can already trigger a Leapwork Go run and poll for completion.

## What this guide covers

* How to define performance level thresholds in Leapwork Go.

* How to use those threshold values as release gates in CI/CD.

* How to fail a pipeline when run results exceed the limits you define.

## Before you start

* You need a timeline that already runs successfully in Leapwork Go.

* You need a Leapwork Go API key. An admin in your organization can generate this in the Admin Portal under `Profile > Integration API Keys`.

* Your CI/CD pipeline must already be able to submit a run and poll the terminal result.

* You should agree internally which metrics will block a release, for example `errors`, `average`, `p95`, or `p99`.

## How performance gates work

A performance gate in CI/CD has two parts:

1. You define acceptable response-time bands in Leapwork Go.

2. Your pipeline evaluates the returned run metrics against those same numeric limits.

Leapwork Go exposes the run outcome and step-level metrics through the CI/CD integration API. The terminal response includes fields such as:

* `status`

* `errors`

* `average`

* `median`

* `p95`

* `p99`

* `max`

Use these values to decide whether the pipeline should continue or fail.
> Leapwork Go stores and visualizes threshold bands in the product. In CI/CD, you enforce those thresholds by comparing the returned run metrics against the same numeric values in your pipeline logic.

## Step 1: Define threshold bands in Leapwork Go

1. Open the project that contains your timeline.

2. Open the timeline you want to use as a release gate.

3. Select the sequence on the timeline.

4. In the right-side editor, locate `Go level thresholds`.

5. Set the response-time limits for the sequence.

6. Save the timeline.

Each sequence on a timeline has three performance bands:

* `Satisfactory`: response times from `0` up to the satisfactory upper limit.

* `Tolerable`: response times from the satisfactory limit up to the tolerable upper limit.

* `Frustrating`: response times above the tolerable limit.

Default thresholds for a new timeline sequence are:  

|      Band      |     Default range     |
|----------------|-----------------------|
| `Satisfactory` | `0` to `250 ms`       |
| `Tolerable`    | `250 ms` to `1000 ms` |
| `Frustrating`  | `1000 ms` and above   |

A practical example:  

|        Sequence type         | Satisfactory | Tolerable | Frustrating |
|------------------------------|--------------|-----------|-------------|
| Internal API                 | `300 ms`     | `800 ms`  | `> 800 ms`  |
| Customer-facing checkout API | `500 ms`     | `1500 ms` | `> 1500 ms` |
| Long-running partner API     | `1000 ms`    | `3000 ms` | `> 3000 ms` |

## Step 2: Decide what should fail the pipeline

Leapwork Go returns several metrics. Not all of them need to be hard gates.

A good starting policy is:  

|  Metric   | Recommended gate type  |                           Example rule                           |
|-----------|------------------------|------------------------------------------------------------------|
| `errors`  | Hard fail              | Fail if any step returns more than `0` errors                    |
| `p95`     | Hard fail              | Fail if `p95` is above the `Tolerable` limit                     |
| `average` | Soft fail or warning   | Investigate if `average` leaves the `Satisfactory` band          |
| `p99`     | Optional hard fail     | Use for strict gates on critical APIs                            |
| `max`     | Optional review signal | Useful for investigation, but often too noisy for a release gate |

For most teams, the safest first production gate is:

* Fail if the run status is not `Finished`.

* Fail if any step reports `errors > 0`.

* Fail if any critical step has `p95` above the `Tolerable` limit.

## Step 3: Run the test from CI/CD

Use the CI/CD integration API to:

1. Submit a run.

2. Poll for completion.

3. Evaluate the terminal response.

The terminal poll response includes a `metadata` array grouped by track item. Each step contains the values you need for gating.

Example terminal fields used for gates:  

|   Field   |                    Meaning                    |
|-----------|-----------------------------------------------|
| `title`   | Step name or request label                    |
| `errors`  | Number of failed requests                     |
| `average` | Average response time in milliseconds         |
| `median`  | Median response time in milliseconds          |
| `p95`     | 95th percentile response time in milliseconds |
| `p99`     | 99th percentile response time in milliseconds |
| `max`     | Maximum response time in milliseconds         |

## Step 4: Add a gate evaluation step to your pipeline

The reference integration scripts already stop the pipeline if the run status is not `Finished`.

To turn the run into a threshold-based release gate, add one more step after polling completes. That step should:

1. Fetch the terminal run response from `pollResultUrl`.

2. Loop through the returned step metrics.

3. Compare the metrics to your threshold values.

4. Exit with a non-zero code when a rule is violated.

### PowerShell example

Use this example in Azure DevOps, Jenkins on Windows, or any PowerShell-based runner.

    param(
        [Parameter(Mandatory = $true)][string]$ApiKey,
        [Parameter(Mandatory = $true)][string]$PollResultUrl,
        [int]$SatisfactoryMs = 250,
        [int]$TolerableMs = 1000
    )
    $headers = @{ Authorization = "X-API-KEY $ApiKey" }
    $result = Invoke-RestMethod -Uri $PollResultUrl -Headers $headers -Method Get
    if ($result.status -ne 'Finished') {
        throw "Run did not finish successfully. Status: $($result.status)"
    }
    $failures = New-Object System.Collections.Generic.List[string]
    $warnings = New-Object System.Collections.Generic.List[string]
    foreach ($track in $result.metadata) {
        foreach ($step in $track.metadata) {
            $name = if ($step.title) { $step.title } else { $step.stepId }
            if (($step.errors | ForEach-Object { [int]$_ }) -gt 0) {
                $failures.Add("$name: errors=$($step.errors)")
            }
            if (($step.p95 | ForEach-Object { [int]$_ }) -gt $TolerableMs) {
                $failures.Add("$name: p95=$($step.p95) ms exceeded tolerable limit $TolerableMs ms")
            }
            if (($step.average | ForEach-Object { [int]$_ }) -gt $SatisfactoryMs) {
                $warnings.Add("$name: average=$($step.average) ms is above satisfactory limit $SatisfactoryMs ms")
            }
        }
    }
    if ($warnings.Count -gt 0) {
        Write-Host "Warnings:"
        $warnings | ForEach-Object { Write-Host "  $_" }
    }
    if ($failures.Count -gt 0) {
        Write-Host "Go gate failed:"
        $failures | ForEach-Object { Write-Host "  $_" }
        exit 1
    }
    Write-Host "Go gate passed."

### Bash example

Use this example in Jenkins on Linux, GitHub Actions, or any Bash-based runner with `jq` installed.

    #!/usr/bin/env bash
    set -euo pipefail
    : "${API_KEY:?API_KEY is required}"
    : "${POLL_RESULT_URL:?POLL_RESULT_URL is required}"
    SATISFACTORY_MS="${SATISFACTORY_MS:-250}"
    TOLERABLE_MS="${TOLERABLE_MS:-1000}"
    response="$(curl -sS -H "Authorization: X-API-KEY ${API_KEY}" "${POLL_RESULT_URL}")"
    status="$(echo "$response" | jq -r '.status')"
    if [ "$status" != "Finished" ]; then
      echo "Run did not finish successfully. Status: $status"
      exit 1
    fi
    warnings="$(echo "$response" | jq -r --argjson satisfactory "$SATISFACTORY_MS" '
      [
        .metadata[]?.metadata[]? as $step
        | ($step.title // $step.stepId) as $name
        | select(($step.average // 0) > $satisfactory)
        | "\($name): average=\($step.average) ms is above satisfactory limit \($satisfactory) ms"
      ] | .[]')"
    failures="$(echo "$response" | jq -r --argjson tolerable "$TOLERABLE_MS" '
      [
        .metadata[]?.metadata[]? as $step
        | ($step.title // $step.stepId) as $name
        | if ($step.errors // 0) > 0 then
            "\($name): errors=\($step.errors)"
          elif ($step.p95 // 0) > $tolerable then
            "\($name): p95=\($step.p95) ms exceeded tolerable limit \($tolerable) ms"
          else empty end
      ] | .[]')"
    if [ -n "$warnings" ]; then
      echo "Warnings:"
      printf '  %s
    ' "$warnings"
    fi
    if [ -n "$failures" ]; then
      echo "Go gate failed:"
      printf '  %s
    ' "$failures"
      exit 1
    fi
    echo "Go gate passed."

## Recommended implementation pattern

For a maintainable setup, store your threshold values as pipeline variables and keep them aligned with the values configured in Leapwork Go.

Example:  

|     Variable      | Example value |       Purpose       |
|-------------------|---------------|---------------------|
| `SATISFACTORY_MS` | `500`         | Warning threshold   |
| `TOLERABLE_MS`    | `1500`        | Hard fail threshold |

This gives you a predictable gate model:

* `Satisfactory` helps you detect early drift.

* `Tolerable` acts as the release gate.

* `Frustrating` remains visible in the product for analysis and reporting.

## Example release policy

A typical release policy for a customer-facing API might be:

* Pass only if the run finishes successfully.

* Pass only if all steps have `errors = 0`.

* Fail if any critical step has `p95 > 1500 ms`.

* Warn if average response time for any critical step is above `500 ms`.

This gives teams a clear, automated release signal without overreacting to a single outlier.

## Troubleshooting

* If the pipeline fails before gate evaluation, confirm that the run reached a terminal `Finished` status.

* If the gate fails unexpectedly, inspect the returned `metadata` fields for the affected step and compare them with your configured threshold values.

* If the pipeline uses different threshold values from the timeline, update the pipeline variables so they match the values defined in Leapwork Go.

* If you want to gate only specific APIs, filter the evaluation script to a list of critical step names instead of checking every step.

## Next step

If you have not yet connected Leapwork Go to your pipeline, start with the CI/CD integration reference. After that is in place, add a gate evaluation step using the examples above