Visual testing in GitLab CI/CD is the integration of an automated step for capturing and comparing screenshots within a pipeline defined in .gitlab-ci.yml, leveraging artifacts to store captures and environments to contextualize results, in order to detect any visual regression before a merge request is accepted.
GitLab CI/CD is the direct competitor to GitHub Actions. If you chose GitLab for your stack — and millions of teams have — you have a powerful native CI/CD system, deeply integrated with your code manager. And this system has features that make it particularly suited for visual testing.
Yet, how many .gitlab-ci.yml files include a visual verification step? Very few. The majority settle for building, functionally testing the code, and deploying. The application's appearance — what the user actually sees — is only verified manually, when it is verified at all.
Our position: GitLab CI is perfect for visual testing, thanks to its artifacts and environments. These two features, often underutilized, provide an ideal infrastructure for storing screenshots, comparing results between branches, and contextualizing regressions. If you use GitLab and are not doing visual testing, you are letting your pipeline's potential lie dormant.
What GitLab CI Offers Specifically for Visual Testing
GitLab CI has features that its competitors do not offer — or not as well. For visual testing, three of them are particularly valuable.
Artifacts: your screenshot library
Artifacts in GitLab CI allow you to save files produced by a job and make them accessible after pipeline execution. For visual testing, this is exactly what you need.
Each pipeline execution produces screenshots. These captures must be kept for two reasons. First, so the team can review them when a test fails. Second, to serve as references for future comparisons.
GitLab artifacts offer fine-grained retention management. You can keep screenshots from the last seven days, or thirty days for the main branch. You can download them directly from the GitLab interface, or browse them via the built-in artifact browser.
Environments: contextualizing your captures
GitLab environments allow you to associate a deployment with a named context (staging, production, review/feature-xyz). For visual testing, this means each capture is tied to a specific environment.
When you deploy a feature branch to a review environment, the captured screenshots are linked to that environment. You can compare captures from the review environment to those from the staging or production environment. This is a level of traceability that few CI/CD systems offer natively.
The built-in artifact browser
GitLab provides a file browser directly in the web interface for exploring artifacts. For visual testing, this means your team can view screenshots, visual diffs, and comparison reports without leaving GitLab. No third-party tool to open. No external link to follow. Everything is in the same ecosystem.
The Problem of Visually Blind Pipelines
Let us review the facts. A typical GitLab CI pipeline executes the following stages: lint, unit test, integration test, build, deploy. Five stages. Zero visual verification.
This pipeline can tell you if a function returns the wrong result. It cannot tell you if half your homepage is hidden by a mispositioned component.
Here is what happens in real life. A developer modifies a shared CSS file. The change is minimal: a margin adjustment on a component. The pipeline passes. The merge request is approved by a reviewer who read the diff without visualizing the rendering. The merge is done.
Three days later, a customer reports that the pricing page is unreadable on mobile. The modified margin propagated a cascading effect on a flexbox layout used by six other pages. Nobody saw it because nobody looked — neither the human nor the pipeline.
Automated visual testing is the systemic solution to this problem. Not a more attentive code review. Not a more rigorous manual QA. An automated test, in the pipeline, that compares before/after images and flags any difference.
Configuring Visual Testing in .gitlab-ci.yml
Configuring a visual testing pipeline in GitLab CI follows a well-defined step-by-step logic. Here is the conceptual structure of your .gitlab-ci.yml file.
The pipeline structure
Your pipeline must include the following stages, in this order.
The build stage. It compiles your application and makes it ready to serve. This is probably already in your pipeline.
The visual testing stage. This is the new stage. It starts a local server, captures screenshots, compares them to references, and produces a report. This stage must run after the build, and its results must be stored as artifacts.
The deploy stage. It only runs if all tests — including the visual test — have passed.
Dependencies of the visual testing job
The visual testing job requires a headless browser to capture screenshots. In GitLab CI, you have two options. Use a Docker image that already includes Chromium (such as the official Playwright images), or install Chromium in the job via before_script commands.
The Docker image is preferable. It is reproducible, fast (no installation on every run), and guarantees a fixed browser version.
Storing results
The visual testing job must produce several types of files as artifacts. The screenshots captured during this run. The visual diffs showing detected differences. An HTML or JSON report summarizing the results.
Configure an appropriate retention policy. Screenshots from the main branch should be kept longer (they serve as references). Screenshots from feature branches can be kept for just a few days.
The blocking condition
The visual testing job must be configured as a blocking job. If unapproved differences are detected, the pipeline must fail. No warning. No "continue on failure." A clear failure that prevents the merge.
Leveraging Artifacts for Screenshots
GitLab CI artifacts are the pillar of your visual testing strategy. Here is how to make the most of them.
Structuring artifacts in a readable way
Organize your screenshots in a clear tree structure within artifacts. Create a folder per tested page, containing the reference screenshot, the current screenshot, and the diff. An HTML report at the root allows navigation between results.
This structure makes it easy for reviewers. When a test fails, the reviewer opens the artifact browser, navigates to the affected page, and immediately sees the difference.
Using artifacts as references
The main branch artifacts can serve as references for feature branch comparisons. GitLab CI allows downloading artifacts from a specific job on a specific branch via the API.
Concretely, the visual testing job on your feature branch starts by downloading reference screenshots from the artifacts of the last successful pipeline on the main branch. It then captures screenshots of the feature branch. It compares the two sets of captures. It stores the results as artifacts of the current pipeline.
Managing retention intelligently
GitLab artifacts have a configurable retention duration. For visual testing, a two-tier policy works well. Main branch artifacts are kept for 30 days (or more). They serve as a stable reference. Feature branch artifacts are kept for 7 days, enough time for the merge request to be processed.
Environments as Comparison Context
GitLab environments add an additional dimension to your visual testing. They allow you to tie each set of screenshots to a deployment context.
Review apps as testing ground
If you use GitLab's review apps (a temporary deployment for each feature branch), you have a unique URL per branch. Visual testing can capture screenshots directly from this URL, offering a more faithful rendering than a local server in CI.
The advantage is twofold. The rendering is that of a real environment (not a development server). And the review app URL is accessible to the entire team, facilitating manual verification as a complement to automated testing.
Comparing between environments
Environments allow you to compare screenshots between contexts. You can compare a feature branch review app with the staging environment. Or compare staging with production to detect visual drift.
This inter-environment comparison capability is a major asset of GitLab CI for visual testing. It allows you to detect not only regressions introduced by a branch, but also drift accumulated between environments.
Integration with Merge Requests
Visual testing only has value if its results are visible and actionable. Integration with GitLab's merge requests is the ideal vector.
Merge request widgets
GitLab displays pipeline results directly on the merge request. The visual testing job status appears in the checks list. A click leads to the job logs and artifacts.
Automatic comments
Configure your pipeline to post an automatic comment on the merge request when visual differences are detected. This comment should include a summary (number of affected pages, severity of changes) and a link to the full report in the artifacts.
Approving expected changes
When a visual change is intentional (a redesign, a color change), there must be a mechanism to approve the change and update the references. In GitLab, this can be done via a manual job triggered by a button in the pipeline. The developer or QA views the diffs, confirms they are expected, and triggers the reference update.
No-Code Approach: Radically Simplifying Configuration
Everything described above works, but requires significant investment in configuration and maintenance. The no-code approach drastically reduces this complexity.
With a tool like Delta-QA, integration into GitLab CI comes down to adding a job that calls the tool with your project parameters. The tool handles the headless browser, capture, comparison, reference management, and reporting.
You do not have to manage Docker images with Chromium. You do not have to write capture scripts. You do not have to implement a comparison system. You do not have to build an HTML report.
The main advantage is not the initial simplicity — it is the long-term maintenance. A hand-crafted visual testing pipeline requires constant maintenance: browser updates, threshold adjustments, capture script fixes when the UI changes. A no-code tool absorbs this complexity.
Your .gitlab-ci.yml file stays clean. Your pipeline stays fast. And your team can focus on what matters: analyzing results and deciding whether changes are expected or not.
Common Pitfalls and Solutions
The large Docker image pitfall
Docker images containing a headless browser are heavy (often over one gigabyte). If you download them on every run, you add several minutes to your pipeline. Use a private Docker registry with caching, or pre-installed images on your shared runners.
The screen resolution pitfall
GitLab CI runners do not have a physical screen. The headless browser uses a virtual framebuffer. The resolution of this framebuffer must match your test viewports. If you capture at 1920x1080 but the framebuffer is configured at 1024x768, you will get truncated or resized screenshots.
The asynchronous content pitfall
Modern applications load content asynchronously. An API that takes 200 milliseconds to respond in development might take 2000 in CI (different network, shared resources). Wait for all network calls to complete and for content to be rendered before capturing.
The long-running branch reference pitfall
If a feature branch lasts several weeks, the main branch references may have evolved in the meantime. When you compare, you detect differences that come from main's evolution, not your branch. The solution is to regularly rebase your branch on main, or to download the most recent references on each run.
Frequently Asked Questions
Which Docker image should I use for visual testing in GitLab CI?
The official Playwright images (mcr.microsoft.com/playwright) are an excellent choice. They include Chromium, Firefox, and WebKit, with all necessary system dependencies. If you only use Chromium, lighter Alpine-based images with Puppeteer are available. For a no-code tool like Delta-QA, the Docker image is provided and optimized for this purpose.
How long should screenshot artifacts be retained?
For the main branch, keep artifacts for at least 30 days. They serve as references for all comparisons. For feature branches, 7 days is generally sufficient — enough time for the merge request to be processed and merged. Adjust based on your development pace. A team with longer cycles will need longer retention.
Does visual testing work with GitLab.com shared runners?
Yes, GitLab.com's shared runners (SaaS) support visual testing. They use virtual machines with Docker, capable of running a headless browser. However, performance may vary depending on shared runner load. If stability and speed are critical, dedicated or self-hosted runners offer better control.
How do I handle rendering differences between GitLab CI and my development machine?
Rendering differences between your local machine and CI runners are inevitable. Installed fonts, browser version, and framebuffer resolution differ. The rule is simple: never compare a local screenshot to a CI screenshot. References must always be generated in the same environment as the test captures. If your references are in CI, your comparisons happen in CI.
Can I parallelize screenshot captures in GitLab CI?
Absolutely, and it is recommended for projects with many pages to test. GitLab CI supports parallelization via the parallel keyword in your configuration. You can distribute pages across multiple jobs running simultaneously. Each job captures a subset of pages and stores its screenshots as artifacts. A final job aggregates the results. This approach divides capture time by the number of parallel jobs.
Does visual testing in GitLab CI work with monorepos?
Yes, but it requires specific configuration. In a monorepo, you probably have multiple frontend applications. Use GitLab CI rules to trigger visual testing only when files of the relevant application are modified. Each application can have its own set of references and its own visual testing job — a strategy detailed in our monorepo visual testing guide. Artifacts must be organized by application to avoid conflicts.
Conclusion
GitLab CI/CD possesses native features — artifacts, environments, review apps, artifact browser — that make it a remarkably well-suited platform for visual testing. This is not a calendar coincidence. It is an architectural convergence: visual testing needs to store files, compare contexts, and make results accessible. GitLab does all of this natively.
If you use GitLab and your pipeline does not check your application's appearance, you are underusing your tool. You have the infrastructure. All you are missing is the step.
Adding visual testing to your GitLab CI pipeline is not a digital transformation project. It is a stage in a .gitlab-ci.yml file, an initial set of references, and a process for approving changes. With a no-code tool like Delta-QA, it is even simpler: integration in minutes, and every merge request is automatically protected against visual regressions.
Your users see your application. Your pipeline should see it too.