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 by adding them to your project file or using the Package Manager Console:

Using Package Manager Console:

Install-Package Selenium.WebDriver -Version 4.16.2
Install-Package Selenium.WebDriver.ChromeDriver -Version 120.0.6099.7100

Alternatively, include the following in your project file:

<PackageReference Include="Selenium.WebDriver" Version="4.16.2" />
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="120.0.6099.7100" />

Here's a basic example of capturing a webpage screenshot:

using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;

public class ScreenshotCapture
{
    public static void CaptureWebpage(string url, string outputPath)
    {
        var options = new ChromeOptions();
        options.AddArgument("--headless"); // Run in headless mode

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

            // Wait for the page to load completely
            var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
            wait.Until(d => ((IJavaScriptExecutor)d).ExecuteScript("return document.readyState").Equals("complete"));

            // Capture the screenshot
            var screenshot = ((ITakesScreenshot)driver).GetScreenshot();
            screenshot.SaveAsFile(outputPath, ScreenshotImageFormat.Png);
        }
    }
}

Capturing local HTML files

To capture screenshots of local HTML files, use the file:// protocol:

using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;

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

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

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

        // Wait for the page to load completely
        var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
        wait.Until(d => ((IJavaScriptExecutor)d).ExecuteScript("return document.readyState").Equals("complete"));

        var screenshot = ((ITakesScreenshot)driver).GetScreenshot();
        screenshot.SaveAsFile(outputPath, ScreenshotImageFormat.Png);
    }
}

Handling dynamic content

Modern web applications often include dynamic content that requires additional time to load. To handle such cases:

using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;

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

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

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

        // Set viewport size for consistent screenshots
        driver.Manage().Window.Size = new System.Drawing.Size(1920, 1080);

        var screenshot = ((ITakesScreenshot)driver).GetScreenshot();
        screenshot.SaveAsFile(outputPath, ScreenshotImageFormat.Png);
    }
}

Ensure that the By.Id("content-loaded") matches an element in your webpage that indicates loading is complete.

Capturing full-page screenshots

To capture the entire webpage, including content below the fold:

using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;

public static void CaptureFullPage(string url, string outputPath)
{
    var options = new ChromeOptions();
    options.AddArgument("--headless");
    options.AddArgument("--start-maximized");

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

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

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

        var screenshot = ((ITakesScreenshot)driver).GetScreenshot();
        screenshot.SaveAsFile(outputPath, ScreenshotImageFormat.Png);
    }
}

Note that setting the window size to match the page height allows the entire page to be captured.

Managing screenshot storage

To keep your screenshots organized, implement a simple storage manager:

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 OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using System.IO;

public static void CaptureResponsiveScreenshots(string url, string outputDirectory)
{
    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");

    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);

            // Allow time for the layout to adjust
            var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(2));
            wait.Until(d => ((IJavaScriptExecutor)d).ExecuteScript("return document.readyState").Equals("complete"));

            var screenshot = ((ITakesScreenshot)driver).GetScreenshot();
            var outputPath = Path.Combine(outputDirectory, $"{viewport.Name}_{DateTime.Now:yyyyMMdd_HHmmss}.png");
            screenshot.SaveAsFile(outputPath, ScreenshotImageFormat.Png);
        }
    }
}

This approach helps ensure that your webpage renders correctly across different devices.

Alternative tools for webpage rendering

In addition to Selenium WebDriver, other open-source tools like Puppeteer Sharp and Playwright can capture webpage screenshots in .NET. These tools provide advanced features and can handle complex web applications effectively.

Conclusion

Capturing screenshots programmatically in .NET provides valuable capabilities for testing, documentation, and monitoring. The examples above demonstrate various approaches to handle different scenarios, from simple static pages to dynamic content and responsive designs.

If you need to process, convert, or manipulate these screenshots as part of your workflow, consider using Transloadit's Document Processing service for automated image processing at scale.