ScreenshotNeo

BlogHow-to

How to Run Happo Screenshot Tests in GitLab CI

Connect Happo to GitLab CI for visual regression checks on merge requests. Configure credentials and a pipeline job, then verify baselines, status checks, and common setup issues.

By the ScreenshotNeo team4 October 20267 min read

Happo announced GitLab support on September 10, 2026. Its experimental integration can post merge request status checks, find baselines by walking commit history, and cancel superseded jobs. A practical setup has two parts: connect the GitLab project through Happo’s integration flow, then add a CI job that installs your project and runs the Happo CLI after the pages you want to capture are ready. Happo has not published a complete GitLab YAML recipe on its accessible general CI page, so use the current setup flow for provider-specific connection details rather than guessing token scopes or special command-line flags.

This guide shows a safe pipeline shape and the checks to make before relying on it. For the latest provider-specific instructions, use Happo’s CI documentation and GitLab connection flow.

1. Check the integration fits your GitLab setup

Happo labels GitLab support experimental. The vendor says the integration supports GitLab.com and self-managed GitLab, although a self-managed instance may need network allowlisting. Its announcement calls out unusual branch names, forks, retargeted merge requests, self-managed network setups, and CI concurrency as areas that need real-world validation. Confirm that your repository and runner setup can reach the services involved before making the check a required merge gate. Happo’s GitLab announcement

The GitLab connection form asks for a project ID, access token, instance URL, and webhook signing token. The announcement does not specify access-token scopes. Follow the current form or its linked instructions for the minimum required permissions; do not infer a scope from this example.

2. Install Happo and configure capture targets

Install the happo package as a development dependency using the package manager already used by your project:

# npm
npm install --save-dev happo

# pnpm
pnpm add --save-dev happo

# yarn
yarn add --dev happo

Create a Happo configuration file in the repository root. The repository documents config filenames including happo.config.js, .mjs, .cjs, .ts, .mts, and .cts. A representative configuration using environment-provided credentials and browser targets is:

// happo.config.js
module.exports = {
  apiKey: process.env.HAPPO_API_KEY,
  apiSecret: process.env.HAPPO_API_SECRET,
  targets: {
    chrome: {
      viewport: '1024x768',
    },
    firefox: {
      viewport: '1024x768',
    },
    'ios-safari': {
      viewport: '375x667',
    },
  },
};

Use the exact configuration schema and target names supported by the version of Happo you install; treat the snippet as a starting shape, not a substitute for the package’s current README. The official repository documents installation and configuration examples: Happo repository.

3. Store credentials as GitLab CI/CD variables

  1. Open the project’s CI/CD variable settings in GitLab.
  2. Add HAPPO_API_KEY and HAPPO_API_SECRET for the CLI configuration.
  3. Complete the Happo GitLab connection flow with its requested project ID, access token, GitLab instance URL, and webhook signing token.
  4. Mark secrets as masked and restrict their availability to protected branches where that matches your pipeline policy.
  5. Do not commit credentials in the config file, YAML, or repository history.

Fork pipelines may not receive protected variables, and this can affect whether Happo can publish results for a fork-based merge request. Test that flow explicitly and follow Happo’s current integration guidance for credentials and permissions.

4. Add a GitLab CI job

GitLab defines pipeline jobs in .gitlab-ci.yml. The following is an illustrative pipeline shape, not an official Happo GitLab recipe. It assumes your project’s test command makes the pages or Storybook available to Happo before capture. Replace the app startup and capture commands with the ones your repository requires.

stages:
  - test

happo:
  stage: test
  image: node:22
  script:
    - npm ci
    # Start your app or Storybook here if the capture setup requires it.
    # For example, use your project's documented CI server command.
    - npx happo
  rules:
    - if: '$CI_COMMIT_BRANCH'
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'

The general Happo CI documentation describes --beforeSha, --afterSha, and --link for generic CI. Do not add these arguments blindly to the GitLab job: check whether the current GitLab integration supplies commit context and merge request links automatically. If the project’s actual setup requires generic-CI arguments, use the documented values for the base commit, current commit, and relevant GitLab link.

Run the job on the default branch as well as merge request changes so Happo has a usable baseline. Verify exact default-branch and baseline behavior in your connected project, since the GitLab integration is experimental and may behave differently from Happo’s established provider workflows. Use GitLab’s CI Lint to validate the YAML before debugging application behavior.

5. Confirm merge request reporting and baselines

Open a merge request and check that the job runs, Happo receives the expected commit, a baseline is found, and the status check appears on the merge request. The integration is intended to find baselines by walking commit history, but repository history, branch conventions, forks, and retargeted merge requests can affect real projects. Validate each case that matters to your workflow.

Also test overlapping pipelines. Happo says it can cancel superseded jobs, but concurrent GitLab pipelines and runner behavior should be checked in your project before depending on cancellation to control load or report ordering.

6. Keep GitLab JUnit reports distinct from Happo diffs

GitLab can display JUnit test reports and optional screenshot attachments in test details. Those attachments are test diagnostics; they are not Happo’s visual comparisons. A JUnit report also does not make a job fail by itself: the script must exit nonzero when a test failure should fail the pipeline. Use JUnit alongside Happo only when you need GitLab-native test output in addition to visual diffs. GitLab unit test reports

7. Troubleshoot common failures

Symptom Likely cause What to check
Happo reports missing credentials or authentication fails Variables are absent, named differently, unavailable to this pipeline, or contain invalid values. Check variable names, project/group scope, protected-variable rules, and whether the pipeline is from a fork. Keep secrets out of job logs.
The Happo job succeeds but no merge request status appears The project connection is incomplete, webhook details are wrong, or commit/MR context is not reaching the integration. Revisit the Happo GitLab connection form and its current instructions. Confirm the project ID, instance URL, token, webhook signing token, and the merge request pipeline type.
No baseline is found The default branch has not produced a Happo capture, history is shallow, or the branch/commit relationship is unusual. Run a capture on the default branch. Check whether the checkout includes the history the integration needs, and validate branch and merge request retargeting behavior.
Capture fails because the page cannot load The app or Storybook is not running yet, the target URL is wrong, or the runner cannot reach it. Start the capture target before npx happo, verify its readiness from the job, and check runner networking and any self-managed allowlisting.
Fork merge request has no result Protected credentials may not be exposed to fork pipelines, or the integration’s fork behavior needs setup. Test with a real fork merge request and consult current Happo guidance. Do not expose project secrets to untrusted code as a workaround.
Old or duplicate results appear during rapid pushes Multiple pipelines may overlap, or cancellation and result ordering may differ from expectations. Inspect GitLab pipeline concurrency and Happo’s superseded-job behavior on representative pushes before making the status a required gate.
Pipeline YAML is rejected Invalid YAML, unsupported keywords, or incorrect quoting/indentation. Validate with GitLab CI Lint, then confirm the job’s rules and variables in the project’s GitLab version.

8. Performance, reliability, and cost considerations

Happo runtime in CI depends on the number of captures and browser targets, app startup, dependency installation, and runner resources. Keep the capture job after the target app is ready, and use your project’s existing package cache and CI dependency strategy where appropriate. Avoid assuming a fixed runtime or speedup; the available research provides no benchmark.

For reliability, establish a default-branch baseline, retain sufficient commit history for baseline lookup, and test merge request, fork, retargeted, self-managed, and overlapping-pipeline cases that apply to your project. Since the GitLab integration is experimental, begin with a non-blocking status check until the cases important to your team behave as expected.

Happo is a hosted visual regression service, so check its current plan and usage terms in Happo’s own product information before estimating spend. No pricing figure is established in the sources used for this guide.

Or skip the browser setup

If the goal is to capture pages from code or an AI agent workflow rather than run Happo’s visual comparison integration, ScreenshotNeo is a website screenshot API and MCP server for developers. A single GET request returns a PNG, JPEG, WebP, or PDF. See the ScreenshotNeo API documentation.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);

ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents use screenshot tools. The free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000 screenshots. Sign up for 1,000 free screenshots a month, with no card.

FAQ

Is Happo’s GitLab integration generally available?

Happo’s announcement labels it experimental. Confirm its current status in the live setup flow before making it a required merge gate.

Does Happo’s GitLab integration replace GitLab’s JUnit reports?

No. Happo provides visual comparisons and merge request status integration; JUnit reports provide test results in GitLab’s test interface.

Can I use it with self-managed GitLab?

Happo says self-managed GitLab is supported, and notes that network allowlisting may be necessary. Validate reachability from the actual environment.

Does the example YAML include every required integration setting?

No. It shows a basic CLI job shape. The current Happo GitLab connection flow and linked instructions are authoritative for provider-specific fields, token permissions, and any required CI details.

Sources