Capture Full Page Screenshots Using WebDriver with HTML2Canvas.js

Capture Full Page Screenshots Using WebDriver with HTML2Canvas.js

In my WebDriver Series, I share lots of tips and tricks about browser automation. These days I was working on a new secret project of the company (stay tuned), and I got inspired. One of the things that I have found most problematic in WebDriver was that the screenshots made from most drivers contain only the visible part of the screen which makes them almost useless in troubleshooting tests’. Today I was reading JavaScript resources and got the idea to try to generate the screenshots through JavaScript. After a couple of hours of researching and writing code, I developed a solution that works on all new browsers and generates full page screenshots. Here I will share it with you.

Capture Screenshots Standard WebDriver API


public void TakingWebDriverScreenshot()
{
    using (var driver = new InternetExplorerDriver())
    {
        driver.Navigate().GoToUrl(@"https://automatetheplanet.com");
        var screenshot = ((ITakesScreenshot)driver).GetScreenshot();
        var tempFilePath = Path.GetTempFileName().Replace(".tmp", ".png");
        screenshot.SaveAsFile(tempFilePath, ScreenshotImageFormat.Png);
    }
}

The code for capturing a screenshot with WebDriver is short and concise. However, as mentioned earlier there is one big drawback. The images contain only the visible part of the screen. For the test I used the homepage of Automate The Planet which height is more than the standard screens.

ChromeDriver Screenshot Visible Part of the Screen

This is how looks like a screenshot made with ChromeDriver. The same happens in Firefox and Edge. A full page screenshot is generated only in Internet Explorer. Moreover, you need to manually maximize the browser if you want the image to look more accurate.

Capture Full Page Screenshots through HTML2Canvas.js and C#

HTML2Canvas.js

While I was reading about advanced JavaScript I read about a cool JS library called HTML2Canvas.js. Bellow you can find the official description:

Capture Screenshots Standard WebDriver API

Definition

The script allows you to take “screenshots” of webpages or parts of it, directly on the users browser. The screenshot is based on the DOM and as such may not be 100% accurate to the real representation as it does not make an actual screenshot, but builds the screenshot based on the information available on the page.

The library should work fine on the following browsers:

  • Firefox 3.5+
  • Chrome
  • Opera 12+
  • IE9+
  • Safari 6+

I have tested in on the latest versions of Chrome, Firefox, Edge and Internet Explorer and is working like a charm.

HTML2Canvas.js + WebDriver C#

However, to make it work together with WebDriver takes a little bit of “black magic”. Below you can find the working example.

Important Notes

Note: This method of capturing screenshots is slightly slower than the regular one. On average, slows down the test with 1 second.

Note: You need to make sure that the page is fully loaded before executing the JavaScript otherwise the screenshot may look a little bit strange.

While ago when we were working on the first version of the BELLATRIX test automation framework, I did this research while I was working on a similar feature for our solution.

Fully Working Code for Taking Full Page Screenshots


public void TakingHTML2CanvasFullPageScreenshot()
{
    using (var driver = new ChromeDriver())
    {
        driver.Manage().Timeouts().PageLoad = TimeSpan.FromSeconds(5);
        driver.Navigate().GoToUrl(@"https://automatetheplanet.com");
        IJavaScriptExecutor js = driver;
        var html2canvasJs = File.ReadAllText($"{GetAssemblyDirectory()}html2canvas.js");
        js.ExecuteScript(html2canvasJs);
        string generateScreenshotJS =
        @"function genScreenshot () {
var canvasImgContentDecoded;
html2canvas(document.body).then(function(canvas) {
window.canvasImgContentDecoded = canvas.toDataURL(""image/png"");
});
}
genScreenshot();";
        js.ExecuteScript(generateScreenshotJS);
        var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
        wait.IgnoreExceptionTypes(typeof(InvalidOperationException));
        wait.Until(
        wd =>
        {
            string response = (string)js.ExecuteScript
    ("return (typeof canvasImgContentDecoded === 'undefined' || canvasImgContentDecoded === null)");
            if (string.IsNullOrEmpty(response))
            {
                return false;
            }
            return bool.Parse(response);
        });
        wait.Until(wd => !string.IsNullOrEmpty((string)js.ExecuteScript("return canvasImgContentDecoded;")));
        var pngContent = (string)js.ExecuteScript("return canvasImgContentDecoded;");
        pngContent = pngContent.Replace("data:image/png;base64,", string.Empty);
        var tempFilePath = Path.GetTempFileName().Replace(".tmp", ".png");
        File.WriteAllBytes(tempFilePath, Convert.FromBase64String(pngContent));
    }
}
private string GetAssemblyDirectory()
{
    string codeBase = Assembly.GetExecutingAssembly().Location;
    var uri = new UriBuilder(codeBase);
    string path = Uri.UnescapeDataString(uri.Path);
    return Path.GetDirectoryName(path);
}

Solution Explanations

Let’s go though the most important parts of the code and explain the reasoning behind them.

First, you need to download the html2canvas.js file and add it to your project, make sure that the file is copied to the output folder.

IJavaScriptExecutor js = driver;
var html2canvasJs = File.ReadAllText($"{GetAssemblyDirectory()}html2canvas.js");
js.ExecuteScript(html2canvasJs);

Though these three lines we read the html2canvas.js from the output folder and execute it in the browser after we have navigated to the page.

Afterwards to use the power of html2canvas and save the result, we need to execute the following custom JavaScript.

function genScreenshot(){
    var canvasImgContentDecoded;
    html2canvas(document.body).then(function(canvas) {
        window.canvasImgContentDecoded = canvas.toDataURL(""image / png"");
    });
  }
  genScreenshot();

Here we create a function, and after that, we call it. A new canvas is generated based on the current DOM structure. We can get its image representation by calling canvas.toDataURL(“image/png”);. Through testing I found out that the standard ExecuteScript method of WebDriver was unable to retrieve the result immediately. I also tried to use ExecuteScriptAsync and playing with the associated timeouts but without success. Though the usage of window.canvasImgContentDecoded, we can access this variable in any subsequent calls of ExecuteScript.

var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.IgnoreExceptionTypes(typeof(InvalidOperationException));
wait.Until(
wd =>
{
    string response = (string)js.ExecuteScript
    ("return (typeof canvasImgContentDecoded === 'undefined' || canvasImgContentDecoded === null)");
    if (string.IsNullOrEmpty(response))
    {
        return false;
    }
    return bool.Parse(response);
});
wait.Until(wd => !string.IsNullOrEmpty((string)js.ExecuteScript("return canvasImgContentDecoded;")));
var pngContent = (string)js.ExecuteScript("return canvasImgContentDecoded;");

If you try to retrieve the mentioned variable immediately, its value will be null, or it will be undefined throwing InvalidException. So we use WebDriverWait to wait until the variable is not null and we setup the wait instance to ignore all InvalidException.

Unfortunately, we are still not ready. The returned content is a base64 encoded string. We need to decode it and save it to an image. You cannot set the download location through JavaScript because of security reasons. Because of that, I decided to do the job using C#.

If you try to decode the content immediately, you will found out that it is not a valid base64 string. First, you need to remove the following text “data:image/png;base64,” from the beginning of the content.

var pngContent = (string)js.ExecuteScript("return canvasImgContentDecoded;");

If you try to save the result in a file and change the file type to PNG, you will be surprised that you cannot open it afterwards. Below you can find the working code. We use MemoryStream and the Image type.

var pngContent = (string)js.ExecuteScript("return canvasImgContentDecoded;");

Below you can find the final result a full page screenshot of the Automate The Planet homepage.

Full Page Screenshot HTML2Canvas.js WebDriver C#

I hope that the information will be useful to you. If you find some issues or further improvements to the code, please share them in the comments.

Related Articles

VBNET, Web Automation

Selenium VB.NET MSTest Test Automating Angular, React, VueJS and 20 More

In the new article from the Web Automation Series, we will talk about creating a data-driven MSTest test automating all major web technologies such as React, An

Selenium VB.NET MSTest Test Automating Angular, React, VueJS and 20 More

Specflow, Web Automation

Getting Started with SpecFlow in 10 Minutes

I am happy to announce a new series of blog posts dedicated to Specflow. In the first article, I am going to introduce to you the Specflow framework. You will b

Getting Started with SpecFlow in 10 Minutes

Desktop Automation, Web Automation

Automate Windows Desktop Apps with WebDriver- WinAppDriver C#

In the Desktop Automation Series, you can find invaluable tips and tricks about desktop automation. I will dedicate the next couple of articles on the automatio

Automate Windows Desktop Apps with WebDriver- WinAppDriver C#

Web Automation

Automate Telerik Kendo Grid with WebDriver and JavaScript

Have you had this problem to try to automate custom-tuned web controls? Probably, your team has purchased these from some dedicated UI controls vendor. There ar

Automate Telerik Kendo Grid with WebDriver and JavaScript

Web Automation

10 Advanced WebDriver Tips and Tricks Part 2

As you probably know I am developing a series posts called- Pragmatic Automation with WebDriver. They consist of tons of practical information how to start writ

10 Advanced WebDriver Tips and Tricks Part 2

Specflow, Web Automation

Advanced SpecFlow: Using Hooks to Extend Test Execution Workflow

Last week I announced a new series of articles dedicated to Specflow (Behavior Driven Development for .NET). In my first publication, I showed you how to create

Advanced SpecFlow: Using Hooks to Extend Test Execution Workflow
Anton Angelov

About the author

Anton Angelov is Managing Director, Co-Founder, and Chief Test Automation Architect at Automate The Planet — a boutique consulting firm specializing in AI-augmented test automation strategy, implementation, and enablement. He is the creator of BELLATRIX, a cross-platform framework for web, mobile, desktop, and API testing, and the author of 8 bestselling books on test automation. A speaker at 60+ international conferences and researcher in AI-driven testing and LLM-based automation, he has been recognized as QA of the Decade and Webit Changemaker 2025.