
Screenshots with Selenium WebDriver BiDi in Java
Taking Screenshots with Selenium WebDriver BiDi in Java
BiDi Browsing Context Domainโ Screen Capture in Java


Browsing Context
Selenium WebDriver provides functionality to take screenshots within a browsing context, meaning the window, tab or frame where content is rendered. But before we can use this feature, we must enable WebDriver to create a bidirectional connection between our test script and the browser. This is done when instantiating our driver. So we can add a new option here, which is options.enableBiDi().
var options = new ChromeOptions();
options.enableBiDi();
WebDriver driver = new ChromeDriver(options);
Then we navigate to โ๐๐ฉ๐ฆ ๐๐ฏ๐ต๐ฆ๐ณ๐ฏ๐ฆ๐ตโ app, a test bed for aspiring automators developed by Dave Haeffner:
driver.get("https://the-internet.herokuapp.com/challenging_dom");
Next, we set the browsing context to the window that weโre on. So we type var BrowsingContext = new BrowsingContext() and pass in our driver instance and the context we want to set. In our case, letโs set the context to the current window and we can do so by typing driver.getWindowsHandle().
var browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
Full Page Screenshot

To capture a screenshot of the entire page, we type browsingContext.captureScreenshot(). This returns a Base64 encoded string of the binary image data. Letโs store this in a variable. Its type will be String and we can call this fullScreenshot.
String fullScreenshot = browsingContext.captureScreenshot();
To view the screenshot as an image, we need to decode the Base64 string into binary format. We can accomplish it with a custom saveScreenshot method.
private static void saveScreenshot(String screenshot, String filename) {
var decodedScreenshot = Base64.getDecoder().decode(screenshot);
try {
String path = "/Users/lanabegunova/eclipse-workspace/TakingScreenshotsBiDi/src/screenshots/";
Files.write(Paths.get(path + filename), decodedScreenshot);
} catch (IOException e) {
e.printStackTrace();
}
}
Line var decodedScreenshot = Base64.getDecoder().decode(screenshot) gives us the binary format of the image, which we can then save as an image file into a folder called โscreenshotsโ. And we can create that folder right under โsrcโ.

So within our main method, after we save the full-page screenshot, letโs call that method. We type saveScreenshot() and pass in our fullScreenshot and then a name of the file. Weโll call this one full_screenshot.png.
saveScreenshot(fullScreenshot, "full_screenshot.png")
When we run this, we should look in the Explorer under the โscreenshotsโ folder. Notice now we have a new file with the name that we provided. If we click on it, we see that it has taken a screenshot of the full page.

Element Screenshot

We can also scope our screenshot to a specific element. Letโs take a screenshot of this element, whose ๐ช๐ฅ is ๐๐๐ง๐ฏ๐๐ฌ. First, we find the element. Letโs type WebElement, call this object canvas, and assign to it the element located with driver.findElement(By.cssSelector(โ#canvasโ)).
WebElement canvas = driver.findElement(By.cssSelector("#canvas"));
Then we call the captureElementScreenshot() method from browsingContext. So we can type String elementScreenshot = browsingContext.captureElementScreenshot(). And this takes the internal ID of the element, not to be confused with the elementโs ID attribute. We need to cast the element to a remote web element for this.
String elementScreenshot = browsingContext.captureElementScreenshot();
Letโs see how thatโs done. We type String internalElementId =, then in parentheses we add RemoteWebElement, and then we put this entire thing in another set of parentheses. And next to the RemoteWebElement, weโll add the canvas. From here we can type getid().
String internalElementId = ((RemoteWebElement) canvas).getId();
We can pass this into the aforementioned captureElementScreenshot() method. So weโll type internalElementId.
String elementScreenshot = browsingContext.captureElementScreenshot(internalElementId);
Now letโs save the screenshot. We call saveScreenshot(), pass in the elementScreenshot and then give it a name. Letโs call this one element_screenshot.png.
saveScreenshot(elementScreenshot, "element_screenshot.png");
Letโs run this. If we check our โscreenshotsโ folder, notice we have a new screenshot that captured just the element.

Viewport Screenshot

WebDriver also allows us to capture a screenshot of a region of the page by specifying its coordinates. Letโs take a screenshot of this large column element whose ๐ค๐ญ๐ข๐ด๐ด๐๐ข๐ฎ๐ฆ is ๐ฅ๐๐ซ๐ ๐-2.
Letโs first find the column element. So we type var largeColumn = driver.findElement(), this time By.className, and its class name is large-2.
var largeColumn = driver.findElement(By.className("large-2"));
Once we find the element, we want to get its rectangle, which contains the data needed to screenshot it. So weโre going to type .getRect().
var largeColumn = driver.findElement(By.className("large-2")).getRect();
Now we can call captureBoxScreenshot(), which takes the X and Y coordinates as well as the width and height of the viewport to capture. To do so, weโre going to type String viewportScreenshot and set this equal to browsingContext.captureBoxScreenshot().
String viewportScreenshot = browsingContext.captureBoxScreenshot();
For the X coordinate, we can type largeColumn.getX(). For the Y coordinate - largeColumn.getY(). For the width - largeColumn.getWidth(). And for the height we can say largeColumn.getHeight().
String viewportScreenshot = browsingContext.captureBoxScreenshot(
largeColumn.getX(),
largeColumn.getY(),
largeColumn.getWidth(),
largeColumn.getHeight()
);
We can even add padding to the width and height if weโd like to capture a larger region surrounding the element. For example, if we wanted more width and height, we can just add extra pixels here. We can also subtract pixels from the X and Y coordinates to shift the top-left corner of the box/rectangle as desired.
String viewportScreenshot = browsingContext.captureBoxScreenshot(
largeColumn.getX() - 30,
largeColumn.getY() - 30,
largeColumn.getWidth() + 30,
largeColumn.getHeight() + 30
);
Finally, we want to save the screenshot. So we call saveScreenshot(), pass in our viewportScreenshot and then give it a name. Letโs call this one viewport_screenshot.png.
saveScreenshot(viewportScreenshot, "viewport_screenshot.png");
Letโs run this and check our โscreenshotsโ folder. We see that thereโs now a new screenshot for the viewport.

Full Code
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.RemoteWebElement;
import static io.github.bonigarcia.wdm.WebDriverManager.chromedriver;
public class Screenshots {
static protected WebDriver driver;
public static void main(String[] args) {
chromedriver().setup();
var options = new ChromeOptions();
options.enableBiDi();
WebDriver driver = new ChromeDriver(options);
driver.get("https://the-internet.herokuapp.com/challenging_dom");
var browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
// full page
String fullScreenshot = browsingContext.captureScreenshot();
saveScreenshot(fullScreenshot, "full_screenshot.png");
// element
WebElement canvas = driver.findElement(By.cssSelector("#canvas"));
String internalElementId = ((RemoteWebElement) canvas).getId();
String elementScreenshot = browsingContext.captureElementScreenshot(internalElementId);
saveScreenshot(elementScreenshot, "element_screenshot.png");
// viewport
var largeColumn = driver.findElement(By.className("large-2")).getRect();
String viewportScreenshot = browsingContext.captureBoxScreenshot(largeColumn.getX() - 30,
largeColumn.getY() - 30, largeColumn.getWidth() + 30, largeColumn.getHeight() + 30);
saveScreenshot(viewportScreenshot, "viewport_screenshot.png");
driver.quit();
}
private static void saveScreenshot(String screenshot, String filename) {
var decodedScreenshot = Base64.getDecoder().decode(screenshot);
try {
String path = "/Users/lanabegunova/eclipse-workspace/TakingScreenshotsBiDi/src/screenshots/";
Files.write(Paths.get(path + filename), decodedScreenshot);
} catch (IOException e) {
e.printStackTrace();
}
}
}

๐๐ถ๐ ๐ ๐ ๐๐ฎ๐๐๐พ๐๐ฐ ๐ถ๐๐น ๐น๐ฎ๐ท๐๐ฐ๐ฐ๐พ๐๐ฐ!
I welcome any comments and contributions to the subject. Connect with me on LinkedIn, X , GitHub, or Insta. Check out my website.
If you find this post useful, please consider buying me a coffee.