Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

To capture Selenium screenshots in VSTS (now Azure DevOps), make Selenium save an image when a test fails, then attach or publish that file before the build agent is cleaned up. With Visual Studio Test results, register the path with TestContext.AddResultFile(fileName), publish the resulting TRX file with PublishTestResults@2, and open the individual test result’s Attachments area. NUnit 3.7 or later has a corresponding TestContext.AddTestAttachment() API. JUnit and xUnit results require a build artifact or the Azure DevOps attachment REST API instead.

What VSTS means here

Visual Studio Team Services (VSTS) was renamed Azure DevOps Services. The current Azure DevOps pipeline and Test Plans interfaces are therefore the right places to configure publishing, although older documentation and pipeline files may still use the VSTS name.

Azure DevOps does not take a browser image automatically merely because Selenium ran. Selenium creates the screenshot; your test framework or pipeline must register or upload the resulting file. Microsoft Learn notes that most UI-testing frameworks can capture screenshots and documents how to associate them with test results.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose where the screenshot should appear

Route Where you view it When to use it
Test-result attachment The specific automated test result’s Attachments area Use a result format and framework API that support attachments, such as VSTest/TRX or supported NUnit output.
Build artifact The build summary’s Artifacts page Use this for JUnit or xUnit output, or whenever you want a folder of all diagnostic images.
Attachment REST API An attachment associated through the Azure DevOps test system Use when you need result-level placement but your result format cannot carry attachments.

Test-result and run-level attachments are distinct in the Test Run Hub. Automated test-result retention normally follows the associated build’s retention settings.

Capture a screenshot in Selenium

Save only on failure

Capture on the failure path so successful runs do not generate unnecessary files. The directory must be inside the agent workspace and must exist before saving. Use a unique name containing the test name and a timestamp or execution identifier; parallel tests otherwise overwrite one another.

using OpenQA.Selenium;
using NUnit.Framework;
using System;
using System.IO;

[TestFixture]
public class CheckoutTests
{
    private IWebDriver driver;

    [TearDown]
    public void CaptureFailure()
    {
        if (TestContext.CurrentContext.Result.Outcome.Status == NUnit.Framework.Interfaces.TestStatus.Failed)
        {
            var directory = Path.Combine(TestContext.CurrentContext.WorkDirectory, "screenshots");
            Directory.CreateDirectory(directory);
            var safeName = TestContext.CurrentContext.Test.Name.Replace(" ", "_");
            var file = Path.Combine(directory, $"{safeName}_{DateTime.UtcNow:yyyyMMddHHmmssfff}.png");
            ((ITakesScreenshot)driver).GetScreenshot().SaveAsFile(file);
            TestContext.AddTestAttachment(file, "Browser screenshot");
        }
    }
}

The example uses NUnit’s attachment API, identified by Microsoft for NUnit 3.7 or later. Check the version used by your project and use its current method signature. If the driver is unavailable during teardown, guard the capture with a null/disposed check and record the original failure rather than replacing it with a teardown error.

Visual Studio Test (VSTest) and TRX

For Visual Studio Test, define TestContext on the test class and register the existing file:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
TestContext.AddResultFile(fileName);

Call it after Selenium has written the image and before the test process exits. The path must point to a file that exists on the agent at result-generation time. A typical failure handler is:

var path = Path.Combine(TestContext.TestResultsDirectory, "screenshots", "login-failure.png");
Directory.CreateDirectory(Path.GetDirectoryName(path));
((ITakesScreenshot)driver).GetScreenshot().SaveAsFile(path);
TestContext.AddResultFile(path);

Use the exact TestContext type and screenshot-save method supplied by your test framework and Selenium language binding. The important sequence is capture, verify the file exists, register the path, then let the runner emit its result file.

Publish TRX results in an Azure Pipeline

Configure the publish task for the format your runner actually creates. The task defaults to JUnit XML; a TRX run needs testRunner: VSTest and a TRX glob such as:

- task: PublishTestResults@2
  inputs:
    testRunner: VSTest
    testResultsFiles: '**/*.trx'

Make the glob match your real output location. If the test runner writes results under a custom directory, use that path rather than assuming the pattern above. Microsoft documents attachment support for VSTest/TRX and NUnit 3.0 result publishing; verify the task and framework versions used by your pipeline because labels and behavior can change.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Pipeline ordering

  1. Run Selenium tests and write screenshots into a workspace directory.
  2. Register each image with the framework’s result mechanism when the file is created.
  3. Publish the TRX or supported NUnit result with PublishTestResults@2.
  4. Only after publishing results, clean temporary files or end the job.

If cleanup runs first, Azure DevOps receives a result that points to a file the agent has already deleted.

JUnit and xUnit: publish screenshots another way

Microsoft states that the Publish Test Results route cannot publish result attachments for JUnit and xUnit because those formats do not formally define attachments in their result schemas. Saving a PNG beside the XML does not make it a test-result attachment.

Build artifacts

Copy the screenshot directory and publish it as a build artifact. This keeps the files with the build summary’s Artifacts page, separate from an individual test result. A simple YAML shape is:

- task: CopyFiles@2
  inputs:
    SourceFolder: '$(Agent.TempDirectory)/screenshots'
    Contents: '**/*'
    TargetFolder: '$(Build.ArtifactStagingDirectory)/screenshots'

- task: PublishBuildArtifacts@1
  inputs:
    PathtoPublish: '$(Build.ArtifactStagingDirectory)/screenshots'
    ArtifactName: 'selenium-screenshots'

Adjust the source directory to the location used by your tests. Artifact publishing is often the most portable option when several frameworks run in one job.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Attachment REST API

For result-level association, upload the file through Azure DevOps’ test attachment API. The request requires the organization, project, test run and result identifiers, the API version, and credentials with the required authorization scope. Microsoft documents the endpoint and payload in Create Test Iteration Result Attachment. Obtain the identifiers from the run your pipeline created; do not hard-code values between runs.

Find screenshots in Azure DevOps

  1. Open the Azure DevOps project and the pipeline run that executed the tests.
  2. Open the published test results or Test Plans test run.
  3. Select the failed automated test result, not only the overall run.
  4. Open its Attachments area and select the image. Supported image files can be previewed in the Test Run Hub.

Run-level attachments appear separately from result-specific attachments. If an image is missing, first confirm that the test runner registered it, the publish task found the result file, and the agent still had the image when publishing occurred.

Agent, browser and driver prerequisites

Microsoft’s Selenium pipeline guidance covers Microsoft-hosted and self-hosted agents. Hosted Visual Studio Windows images include Selenium WebDrivers intended to match their installed browser versions. Linux, Ubuntu and macOS hosted agents do not have those drivers preinstalled according to that guidance, so install and pin a compatible browser-driver pair yourself. Hosted images change over time; check the current image software list before diagnosing a new failure.

Self-hosted UI tests may need an interactive desktop session and, for some configurations, autologon. A headless browser can still capture images, but the viewport, fonts and rendering may differ from an interactive desktop. Record the browser, driver and agent image in your build logs so a visual difference is diagnosable.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshooting checklist

The file is never created

  • Confirm the failure hook runs for the framework’s actual failure status.
  • Ensure the screenshots directory is created and writable.
  • Check that the driver is still alive during teardown.
  • Log the absolute path and test whether the file exists and has a non-zero length.

The file exists but is not in the test result

  • For VSTest, call TestContext.AddResultFile with the absolute path after saving.
  • For NUnit, use the supported attachment API and version.
  • Verify PublishTestResults@2 uses the actual result format and glob.
  • Move cleanup steps after result publication.

The publish task reports no results

  • Inspect the agent workspace for the emitted TRX, NUnit, JUnit or xUnit file.
  • Change testResultsFiles to match its real name and directory.
  • Set testRunner explicitly instead of relying on the JUnit default.

Images are blank or inconsistent

  • Wait for a page condition, such as a key selector, before capturing.
  • Capture after scrolling or lazy-loaded content has rendered.
  • Check headless versus headed mode, viewport size, device scale and browser-driver compatibility.
  • Capture the page URL and relevant console or network errors alongside the image.

Results disappear later

Review the associated build’s retention policy. Automated test results normally follow that retention by default; an expired build can remove the evidence even when the original upload succeeded.

Or skip the browser setup

If you need a clean image of a URL rather than a browser session tied to a test assertion, ScreenshotNeo provides a website screenshot API and MCP server. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets. Only clean shots are billed: bot checks, CAPTCHAs, blank pages, timeouts, failed loads and cache hits cost nothing, and response headers report the page verdict and billing status.

Use the API documentation at https://screenshotneo.com/docs/. This cURL request returns a WebP image:

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

Python:

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)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo also offers an MCP server with take_screenshot, get_page_info and capture_pdf for Claude, Cursor and other MCP clients. Free accounts include 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Does Selenium attach a screenshot to Azure DevOps automatically?

No. Selenium writes the image, but your framework or pipeline must register or upload it before the agent workspace is removed.

Can I use a JUnit XML file for an Azure DevOps test attachment?

Not through the documented Publish Test Results attachment route. Publish the image as a build artifact or upload it with the Azure DevOps test attachment REST API.

Where are automated test screenshots retained?

They normally follow the retention policy of the associated build, so inspect build retention when older evidence is no longer available.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.