Capturing screenshots of webpages programmatically is a valuable capability for automated testing, documentation, and monitoring. In this guide, we will explore how to capture screenshots of webpages and HTML files using .NET (C#).

Prerequisites

To follow along with this tutorial, you will need:

  • .NET 6.0 or later
  • Visual Studio 2022 or Visual Studio Code
  • NuGet Package Manager

Using Selenium WebDriver

Selenium WebDriver is a powerful tool for browser automation that includes screenshot capabilities. First, install the required NuGet packages:

Install-Package Selenium.WebDriver -Version 4.28.0
Install-Package WebDriverManager -Version 2.17.1

Below is an updated example demonstrating how to capture a full-page screenshot with proper error handling using the Selenium 4 TakeScreenshot() extension method:

using System;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
using OpenQA.Selenium.Support.Extensions;
using WebDriverManager;
using WebDriverManager.DriverConfigs.Impl;

public class ScreenshotCapture
{
    public static void CaptureWebpage(string url, string outputPath)
    {
        try
        {
            new DriverManager().SetUpDriver(new ChromeConfig());
            var options = new ChromeOptions();
            options.AddArgument("--headless=new");

            using (var driver = new ChromeDriver(options))
            {
                driver.Navigate().GoToUrl(url);

                // Wait until the page is fully loaded
                var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
                wait.Until(d => ((IJavaScriptExecutor)d)
                    .ExecuteScript("return document.readyState").Equals("complete"));

                // Adjust the window size to capture the full page height
                var totalHeight = (long)((IJavaScriptExecutor)driver)
                    .ExecuteScript("return Math.max(document.body.scrollHeight, document.documentElement.scrollHeight);");
                driver.Manage().Window.Size = new System.Drawing.Size(1920, (int)totalHeight);

                var screenshot = driver.TakeScreenshot();
                screenshot.SaveAsFile(outputPath, ScreenshotImageFormat.Png);
            }
        }
        catch (WebDriverException ex)
        {
            throw new Exception($"Failed to capture screenshot: {ex.Message}", ex);
        }
    }
}

Browser compatibility

The code examples in this guide are compatible with:

  • Chrome: Version 115+
  • Firefox: Version 115+
  • Edge: Version 115+

Note: For Chrome version 115 and above, the ChromeDriver installation process is handled automatically by WebDriverManager.

Capturing local HTML files

To capture screenshots of local HTML files, use the file:// protocol with proper error handling:

using System;
using System.IO;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
using OpenQA.Selenium.Support.Extensions;
using WebDriverManager;
using WebDriverManager.DriverConfigs.Impl;

public static void CaptureLocalHtml(string htmlFilePath, string outputPath)
{
    try
    {
        var absolutePath = Path.GetFullPath(htmlFilePath);
        var fileUri = new Uri(absolutePath).AbsoluteUri;

        new DriverManager().SetUpDriver(new ChromeConfig());
        var options = new ChromeOptions();
        options.AddArgument("--headless=new");

        using (var driver = new ChromeDriver(options))
        {
            driver.Navigate().GoToUrl(fileUri);

            var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
            wait.Until(d => ((IJavaScriptExecutor)d)
                .ExecuteScript("return document.readyState").Equals("complete"));

            var screenshot = driver.TakeScreenshot();
            screenshot.SaveAsFile(outputPath, ScreenshotImageFormat.Png);
        }
    }
    catch (Exception ex)
    {
        throw new Exception($"Failed to capture local HTML: {ex.Message}", ex);
    }
}

Handling dynamic content

Modern web applications often include dynamic content that requires additional time to load:

using System;
using System.Threading;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
using OpenQA.Selenium.Support.Extensions;
using WebDriverManager;
using WebDriverManager.DriverConfigs.Impl;

public static void CaptureDynamicWebpage(string url, string outputPath)
{
    try
    {
        new DriverManager().SetUpDriver(new ChromeConfig());
        var options = new ChromeOptions();
        options.AddArgument("--headless=new");

        using (var driver = new ChromeDriver(options))
        {
            driver.Navigate().GoToUrl(url);

            var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
            // Wait for a specific element to ensure dynamic content is loaded
            wait.Until(d => d.FindElement(By.Id("content-loaded")));

            // Additional wait for any animations
            Thread.Sleep(1000);

            driver.Manage().Window.Size = new System.Drawing.Size(1920, 1080);

            var screenshot = driver.TakeScreenshot();
            screenshot.SaveAsFile(outputPath, ScreenshotImageFormat.Png);
        }
    }
    catch (WebDriverTimeoutException ex)
    {
        throw new Exception("Timeout waiting for dynamic content to load", ex);
    }
}

Managing screenshot storage

To keep your screenshots organized and manage storage efficiently:

using System;
using System.IO;

public class ScreenshotManager
{
    private readonly string _baseDirectory;

    public ScreenshotManager(string baseDirectory)
    {
        _baseDirectory = baseDirectory;
        Directory.CreateDirectory(_baseDirectory);
    }

    public string SaveScreenshot(byte[] screenshotBytes, string prefix = "")
    {
        var fileName = $"{prefix}screenshot_{DateTime.Now:yyyyMMdd_HHmmss}.png";
        var filePath = Path.Combine(_baseDirectory, fileName);
        File.WriteAllBytes(filePath, screenshotBytes);
        return filePath;
    }

    public void CleanupOldScreenshots(int daysToKeep = 7)
    {
        var cutoffDate = DateTime.Now.AddDays(-daysToKeep);
        var files = Directory.GetFiles(_baseDirectory, "*.png");
        foreach (var file in files)
        {
            if (File.GetCreationTime(file) < cutoffDate)
            {
                File.Delete(file);
            }
        }
    }
}

Handling different screen sizes

For responsive design testing, capture screenshots at various viewport sizes:

using System;
using System.IO;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
using OpenQA.Selenium.Support.Extensions;
using WebDriverManager;
using WebDriverManager.DriverConfigs.Impl;

public static void CaptureResponsiveScreenshots(string url, string outputDirectory)
{
    try
    {
        new DriverManager().SetUpDriver(new ChromeConfig());
        var viewports = new[]
        {
            new { Width = 375, Height = 667, Name = "mobile" },
            new { Width = 768, Height = 1024, Name = "tablet" },
            new { Width = 1920, Height = 1080, Name = "desktop" }
        };

        var options = new ChromeOptions();
        options.AddArgument("--headless=new");

        using (var driver = new ChromeDriver(options))
        {
            foreach (var viewport in viewports)
            {
                driver.Manage().Window.Size = new System.Drawing.Size(viewport.Width, viewport.Height);
                driver.Navigate().GoToUrl(url);

                var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(2));
                wait.Until(d => ((IJavaScriptExecutor)d)
                    .ExecuteScript("return document.readyState").Equals("complete"));

                var screenshot = driver.TakeScreenshot();
                var outputPath = Path.Combine(outputDirectory,
                    $"{viewport.Name}_{DateTime.Now:yyyyMMdd_HHmmss}.png");
                screenshot.SaveAsFile(outputPath, ScreenshotImageFormat.Png);
            }
        }
    }
    catch (Exception ex)
    {
        throw new Exception($"Failed to capture responsive screenshots: {ex.Message}", ex);
    }
}

Conclusion

This guide demonstrates various approaches to capturing webpage screenshots programmatically in .NET, from static pages to dynamic content and responsive designs. The examples include detailed error handling, browser compatibility considerations, and best practices for managing screenshot storage.