How to render screenshots with Playwright

Sharing working Playwright examples based on the experience of building one the best screenshot APIs.

Written by

Dmytro Krasun

Published on

How to render screenshots with Playwright

Making screenshots of the websites with Playwright is straightforward and powerful. And I write that as somebody who has been working with Playwright for years.

Let’s play with Playwright on a set of screenshotting problems and see how it can solve them.

I am sharing a set of working Playwright examples. You can just copy them and adjust for your needs.

Meet Playwright

It is a Node library that interacts with multiple browsers including Chromium, Firefox, and WebKit. Playwright provides a unified API to work with all these browsers, making it a versatile choice for web automation and screenshotting.

The library was developed by Microsoft and is maintained by the same team that previously worked on Puppeteer. It offers several advantages:

  1. Cross-browser support out of the box
  2. Modern and intuitive API
  3. Built-in auto-waiting mechanisms
  4. Excellent documentation and community support
  5. And of course, powerful screenshot capabilities

Generating screenshots with Playwright is the main focus of the post.

Practical Examples of using Playwright to take screenshots

Before starting to work with Playwright, let’s install it using npm:

npm i playwright

Simple screenshots with Playwright

To take a simple screenshot with Playwright and save it into the file, you can use the following code:

"use strict";
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
try {
const page = await browser.newPage();
await page.goto("https://github.com");
await page.screenshot({ path: "github.png" });
} catch (e) {
console.log(e);
} finally {
await browser.close();
}
})();

The result is a screenshot of the GitHub website:

GitHub screenshot

You use the parameter path in Playwright to save the screenshot. And always close the browser to avoid resource leaking!

You can use our reliable and scalable screenshot API with myriad options to avoid the burden of setting up and managing Playwright.

High-resolution and Retina Displays

To avoid blurred images on a high-resolution display like Retina Display you can change the viewport properties width, height and deviceScaleFactor:

"use strict";
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
try {
const page = await browser.newPage();
await page.setViewportSize({
width: 2880, // default: 800
height: 1800, // default: 600
deviceScaleFactor: 2, // default: 1
});
await page.goto("https://apple.com");
await page.screenshot({ path: "apple.com.png" });
} catch (e) {
console.log(e);
} finally {
await browser.close();
}
})();

That’s called pixel-perfect screenshots.

Full-page screenshots

Playwright knows how to make screenshot of the scrollable page. Use fullPage option:

"use strict";
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
try {
const page = await browser.newPage();
await page.goto("https://apple.com");
await page.screenshot({ path: "apple.com.png", fullPage: true });
} catch (e) {
console.log(e);
} finally {
await browser.close();
}
})();

But it won’t work good with lazy-loaded images. I wrote a brief guide on how to take full page screenshots with Playwright right.

Wait until the page is completely loaded

It is a good practice to wait until the page is completely loaded to make screenshot:

"use strict";
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({});
try {
const page = await browser.newPage();
await page.goto("https://apple.com/", {
waitUntil: "networkidle",
});
await page.screenshot({ path: "apple.com.png" });
} catch (e) {
console.log(e);
} finally {
await browser.close();
}
})();

It is a little bit of magic, but networkidle event is heuristic to determine page load state. It works quite well for many real-world use cases.

But if you need to wait until some element is rendered and visible, you need to add page.waitForSelector():

"use strict";
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({});
try {
const page = await browser.newPage();
await page.goto("https://example.com/", {
waitUntil: "networkidle",
});
const selector = "div";
await page.waitForSelector(selector, {
state: "visible",
});
await page.screenshot({ path: "example.com.png" });
} catch (e) {
console.log(e);
} finally {
await browser.close();
}
})();

You can also wait:

  • for selector or function or timeout
  • for file chooser
  • for frame
  • for function
  • for navigation
  • for network idle
  • for request
  • for response
  • for selector
  • for timeout
  • and for XPath

How to take a screenshot of the page area

To take the screenshot of the page area, use the clip option:

"use strict";
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
try {
const page = await browser.newPage();
await page.goto("https://apple.com");
await page.screenshot({
path: "apple.com.png",
clip: {
x: 100,
y: 100,
width: 800,
height: 800,
},
});
} catch (e) {
console.log(e);
} finally {
await browser.close();
}
})();

But if you need to take a screenshot of the element, there is a better approach.

A screenshot of the specific element

Playwright allows to take the screenshot of any element on the web page:

"use strict";
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
try {
const page = await browser.newPage();
await page.goto("https://example.com");
const selector = "body > div:first-child";
await page.waitForSelector(selector);
const element = await page.$(selector);
await element.screenshot({
path: "example.com.png",
});
} catch (e) {
console.log(e);
} finally {
await browser.close();
}
})();

As you see, it is essential to make sure that the element is ready.

In ScreenshotOne screenshot API, you can take the screenshot of the element by specifying the selector parameter.

Screenshots with transparent background

Playwright provides a useful option to omit the background of the site. Just set omitBackground to true:

"use strict";
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
try {
const page = await browser.newPage();
await page.goto("https://example.com");
await page.screenshot({
path: "example.com.png",
omitBackground: true,
});
} catch (e) {
console.log(e);
} finally {
await browser.close();
}
})();

Have you run the code? If yes, you spotted that the screenshot does not have a transparent background. It happens because omitting background works only for elements with transparent background.

So if your target site does not have a transparent background and you want to force it, you can use JavaScript to accomplish the task. Change the background of the body in the evaluate function:

"use strict";
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
try {
const page = await browser.newPage();
await page.goto("https://example.com");
await page.evaluate(() => {
document.body.style.background = "transparent";
});
await page.screenshot({
path: "example.com.png",
omitBackground: true,
});
} catch (e) {
console.log(e);
} finally {
await browser.close();
}
})();

Screenshot as Base64

You build Playwright as a service and do not want to store screenshot files. You can choose to return the screenshot in Base64 encoding format:

"use strict";
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({});
try {
const page = await browser.newPage();
await page.goto("https://example.com/");
const base64 = await page.screenshot({ encoding: "base64" });
console.log(base64);
} catch (e) {
console.log(e);
} finally {
await browser.close();
}
})();

You will receive a string that you can share with another service or even store somewhere.

Generate JPEG or WebP instead of PNG

It is super easy to generate JPEG or WebP instead of PNG:

"use strict";
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
try {
const page = await browser.newPage();
await page.goto("https://example.com");
await page.screenshot({
path: "example.jpg",
type: "jpeg",
quality: 100,
});
} catch (e) {
console.log(e);
} finally {
await browser.close();
}
})();

When you generate JPEG or WebP, you can specify the quality of the screenshot.

If JPEG, WebP or PNG is not enough for you, you can render URL or HTML in GIF, JP2, TIFF, AVIF or HEIF format with Playwright.

Blocking ads and trackers when using Playwright

In our screenshot API, you can block ads by setting blockAds=true.

I do not use any ad blocking extension because life is tough, and everybody needs some way to earn money. If I can help sites sustain and survive by non-blocking the ads, I will do it.

But when you test your site or your customer site, you might need to block the ads. There are 2 ways to do it:

  1. Intercept and block request that load ad into the site.
  2. Use an extension that is optimized exactly to solve this problem.

The first one is tricky and highly depends on the site you are taking screenshots of. But using an extension is a highly-scalable approach that works out of the box.

Install playwright-extra and playwright-extra-plugin-adblocker in addition to playwright package:

npm i playwright-extra playwright-extra-plugin-adblocker

And then use it:

"use strict";
const { chromium } = require('playwright-extra');
const AdblockerPlugin = require('playwright-extra-plugin-adblocker');
chromium.use(AdblockerPlugin());
(async () => {
const browser = await chromium.launch();
try {
const page = await browser.newPage(); // ads are blocked automatically
await page.goto("https://www.example.com");
await page.screenshot({
path: "example.com.png",
fullPage: true,
});
} catch (e) {
console.log(e);
} finally {
await browser.close();
}
})();

Most pages include ads and trackers, which consume a lot of bandwidth and take a long time to load. Because fewer requests are made, and less JavaScript is performed when advertisements and trackers are blocked, pages load substantially quicker.

To take screenshots faster you might block trackers. It will help to speed up rendering. The ad blocking plugin can help us with this issue.

Just set blockTrackers to true when initializing the plugin:

chromium.use(
AdblockerPlugin({
blockTrackers: true, // default: false
})
);

If you need to block only trackers, but do not block ads, just use request interceptor.

Preventing Playwright detection

Some sites might block your Playwright script because of the user agent, and it is easy to fix:

"use strict";
const { chromium } = require('playwright');
(async () => {
const options = {
args: [
'--user-agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"',
],
headless: true,
};
const browser = await chromium.launch(options);
try {
const page = await browser.newPage();
await page.goto("https://www.example.com");
await page.screenshot({
path: "example.com.png",
fullPage: true,
});
} catch (e) {
console.log(e);
} finally {
await browser.close();
}
})();

There are also many other hacks to ensure that Playwright is not detected, but you can save time by using the ready playwright-extra-plugin-stealth plugin for the stealth mode. Install it in addition to playwright package:

npm i playwright-extra playwright-extra-plugin-stealth

And then use:

"use strict";
const { chromium } = require('playwright-extra');
const StealthPlugin = require('playwright-extra-plugin-stealth');
chromium.use(StealthPlugin());
(async () => {
const browser = await chromium.launch();
try {
const page = await browser.newPage();
await page.evaluateOnNewDocument(() => {
const newProto = navigator.__proto__;
delete newProto.webdriver;
navigator.__proto__ = newProto;
});
await page.goto("https://bot.sannysoft.com");
await page.waitForTimeout(5000);
await page.screenshot({ path: "stealth.png", fullPage: true });
} catch (e) {
console.log(e);
} finally {
await browser.close();
}
})();

Important! As you see, I remove the webdriver property since the stealth plugin misses this hack and by using webdriver property usage of the Playwright can be detected.

Using basic access authentication with Playwright

If your page is protected by HTTP basic access authentication, the only thing you need to do is to specify username and password before loading and taking the screenshot of the page:

"use strict";
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
try {
const page = await browser.newPage();
await page.setExtraHTTPHeaders({
'Authorization': 'Basic ' + Buffer.from('YOUR_BASIC_AUTH_USERNAME:YOUR_BASIC_AUTH_PASSWORD').toString('base64')
});
await page.goto("https://example.com");
await page.screenshot({ path: "example.png" });
} catch (e) {
console.log(e);
} finally {
await browser.close();
}
})();

Support of emojis, Japanese, Chinese and other non-Latin languages in Playwright

Our screenshot API supports emojis out of the box.

If you run Playwright in OS without emojis support, you need to install OS-wide fonts to support emojis. The same can happen with non-English characters like Chinese, Japanese, Korean, Arabic, Hebrew, etc.

To get Playwright to render emojis, you can use Noto Fonts published under SIL Open Font License (OFL) v1.1.

You need to search and how to install fonts for your host OS.

Playwright Alternatives

There are a lot more, but the most popular two are:

  1. The oldest alternative to make screenshots is using the Selenium WebDriver protocol.
  2. The second one is taking screenshots with Puppeteer, which is a good and high-quality alternative but with fewer browsers. If you plan to write tests, Puppeteer is worse at that than playwright.
  3. If you consider only rendering screenshots, ScreenshotOne is the best Playwright alternative.

Puppeteer and Playwright have compatible API, but Playwright supports more browsers. So, if you must take screenshots in different browsers, prefer to use Playwright. By the way, top contributors of the Puppeteer work on Playwright, making it a more modern and feature-rich choice.

Conclusion

I posted a lot of Playwright examples, and I hope I helped you solve your screenshot problems with Playwright.

As you see you can go really far with Playwright. But if only need to take screenshots, consider using one of the best Playwright alternatives—our screenshot API.

Thank you for reading! And have a nice day 👋

Read more Playwright guides

Interviews, tips, guides, industry best practices, and news.

View all posts

Automate website screenshots

Exhaustive documentation, ready SDKs, no-code tools, and other automation to help you render website screenshots and outsource all the boring work related to that to us.