----
url: https://screenshotone.com/docs/no-code/zapier
----

[Skip to content](#_top)

How to automate website screenshots with Zapier

===============================================

Copy page

Zapier is a powerful automation platform that lets you connect your apps and automate workflows without writing any code. These automated workflows, called “Zaps”, can connect thousands of apps to help you save time and reduce manual work.

With ScreenshotOne’s Zapier integration, you can easily incorporate website screenshot generation into your automated workflows, making it simple to capture and process screenshots as part of your business processes.

You can use Zapier to automatically trigger screenshot captures and send them to your favorite apps like Google Drive, Slack, or any of the thousands of apps Zapier supports.

Integrations

------------

Check out [ScreenshotOne integrations on Zapier](https://zapier.com/apps/screenshotone/integrations) and [a help guide provided by Zapier](https://help.zapier.com/hc/en-us/articles/16307799273613-How-to-get-started-with-ScreenshotOne-on-Zapier).

Tutorials

---------

### Screenshots to Google Drive with Zapier

A guide by [Toolfolio](https://toolfolio.io/) on [how to automate website screenshots upload to Google Drive with Zapier](https://toolfolio.io/productive-value/automate-website-screenshots-with-zapier-screenshotone).

### Troubleshooting

#### Timeouts

Zapier has [a timeout limit of 30 seconds for executing a Zap](https://docs.zapier.com/platform/build/troubleshoot-action-timeouts). If you encounter timeouts, you can try the following:

1.  If it is [a full-page screenshot, try to optimize it](/docs/guides/performance/). E.g. disable full page scrolling.

2.  Or use [webhooks instead and asynchronous requests](/docs/async-and-webhooks/).

Support

-------

If you have any questions, don’t hesitate to reach out to our support at [support@screenshotone.com](mailto:support@screenshotone.com).

----
url: https://screenshotone.com/docs/errors/network-error
----

[Skip to content](#_top)

Network Error

=============

Copy page

It is an API error returned when the API cannot connect to the target host.

    1{2    "is_successful": false,3    "error_code": "network_error",4    "error_message": "The error happens when the API can't connect to the provided URL. It might mean that the site blocks the API or is temporarily unavailable. Generally, you can safely retry to take a screenshot.",5    "documentation_url": "https://screenshotone.com/docs/errors/network-error/"6}

Reasons and how to fix

----------------------

### Proxy issues

If you use an external [proxy](/docs/guides/how-to-use-proxies/), make sure that it has access to the target host.

Also, often when you use proxy providers, you might not notice that you don’t have sufficient credits to keep using proxy.

We noticed that for some providers, you sometimes need to recreate your proxy user/account to make it work again.

Also, many providers might block ScreenshotOne API IP addresses. In that case, consider adding [our IP ranges](/docs/ip-ranges/) to the proxy provider’s allow list.

### The API is under heavy load

Rarely but under heavy load, ScreenshotOne API might fail to connect to target hosts. In that case, retry requests.

Reach out to support

--------------------

If nothing helps you, please, reach out to `support@screenshotone.com` and we will try to help you as fast as possible.

----
url: https://screenshotone.com/contributors/barnabs-rmssy
----

Barnabs Rmssy

-------------

View all Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [Taking care of WordPress Sites with ScreenshotOne](/blog/kinsta/)

How Kinsta uses ScreenshotOne to deliver reliable automatic updates.

Written by

[Roger Williams](/contributors/roger-williams/), [Barnabás Ürmössy](/contributors/barnabs-rmssy/)

Published on

Apr 29, 2025

•

2 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/screenshot-url
----

[Skip to content](#_top)

Screenshot URL

==============

Copy page

Danger

The URL is temporary and will be available for a limited time—**4 hours maximum**. Do not rely on it for long-term storage of screenshots.

Except, when you use [caching](/docs/caching/), and the cache TTL is set to more than 4 hours.

Note

For long-term screenshot or video archival, consider [uploading them to any compatible S3-storage](/docs/guides/upload-to-s3/).

When you set `response_type=json` for both [animated/scrolling screenshots](/docs/animated-screenshots/) or [regular screenshots](/docs/options/), you will get a screenshot URL in the response:

    1{2    "screenshot_url": "..."3}

The URL is always a fresh URL where the screenshot is stored, it is not a cached URL unless you use [caching](/docs/caching/).

Also, when [using webhooks](/docs/async-and-webhooks/) and if you do not upload the screenshot to any S3-compatible storage, you will get the URL in the webhook request body,too.

----
url: https://screenshotone.com/docs/no-code/make
----

[Skip to content](#_top)

How to render website screenshots with Make

===========================================

Copy page

Make (formerly Integromat) is a powerful visual platform for creating automated workflows (often called “scenarios” or “blueprints”) between different apps and services—without needing to write code.

It helps to save time, reduce manual work, and connect various tools in an organized, automated way.

And with ScreenshotOne you can integrate website screenshot rendering into your Make workflows.

There is no official integration for Make yet, but there is a lot of ways you can use ScreenshotOne to render website screenshots in your Make workflows.

Community Integrations

----------------------

There are integrations that are not officially made by ScreenshotOne, but you can use any of [the community-supported integrations](https://www.make.com/en/integrations/screenshotone-community).

Tutorials

---------

### How to Automate ScreenshotOne with Make by Synergetic

A tutorial by [Synergetic](https://www.go-synergetic.com/apps/screenshotone) on how to automate ScreenshotOne with Make:

[Play](https://youtube.com/watch?v=lzKhO9VRzgM)

### How to generate Scrolling Screenshots ScreenshotOne with Make by Synergetic

In his guide on [how to multiply your leads tenfold using text-to-video AI automation](https://www.youtube.com/watch?v=Fild563M2Qo), Jack Roberts uses ScreenshotOne to generate scrolling screenshots:

[Play](https://youtube.com/watch?v=Fild563M2Qo)

The same method can be applied to regular and full-page screenshots as well.

Support

-------

If you have any questions, don’t hesitate to reach out to our support at [support@screenshotone.com](mailto:support@screenshotone.com).

----
url: https://screenshotone.com/blog/how-to-create-a-site-thumbnail-with-puppeteer
----

How to create a site thumbnail with Puppeteer

=============================================

We can consider the screenshot of URL or HTML as a thumbnail, but I write about the thumbnail of a screenshot. How do you take a screenshot within the defined viewport but with different image width and height? Resize!

[Blog post](/blog/) 3 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jul 17, 2022

#### Tags

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

Puppeteer only supports setting viewport width and height. And you can’t generate a small image (preview) of the site within a viewport of 1028x1024 pixels. But there is always a workaround! So, let’s play with [the sharp library](https://sharp.pixelplumbing.com/) and resize the screenshot after taking it.

Resizing a website screenshot with sharp and Puppeteer

------------------------------------------------------

Please, install the sharp library first:

    1npm i sharp

And then let’s take a screenshot and resize it:

    1const puppeteer = require('puppeteer');2const sharp = require('sharp');3

    4(async () => {5    const browser = await puppeteer.launch({ headless: true });6    try {7        const page = await browser.newPage();8

    9        await page.goto('https://screenshotone.com/');10        await page.setViewport({ width: 1280, height: 1024 });11

    12        const binaryScreenshot = await await page.screenshot({ type: 'png', encoding: 'binary' });13

    14        await sharp(binaryScreenshot).15            resize(700, 200, { fit: sharp.fit.inside }).16            toFile('screenshotone.com_1280x1024px_in_700x200px.png');17    } catch (e) {18        console.log(e)19    } finally {20        await browser.close();21    }22})();

The result is:

I specified both the width and the height of the image and the sharp library, but since the screenshot doesn’t fit perfectly, I must set the fit parameter as inside. Why does it matter, and what other options can you use?

First, you can specify only the width, and then you don’t need to use fit. Height will be computed automatically and vice versa.

But when both a width and height are provided, the possible methods by which the image should **fit** these are: `cover`, `contain`, `fill`, `inside`, `outside`.

Use `cover` fit (default) to preserve the aspect ratio, and ensure the image covers both provided dimensions by cropping/clipping to fit. An example of `cover` fit:

Use `contain` fit to preserve the aspect ratio, and contain within both provided dimensions using “letterboxing” where necessary. An example of `contain` fit:

Use `fill` fit to ignore the input aspect ratio and stretch to both provided dimensions. An example of `fill` fit:

Use `inside` fit to preserve the aspect ratio, and resize the image to be as large as possible while ensuring its dimensions are less than or equal to those specified. An example of `inside` fit:

Use `outside` to preserve the aspect ratio, and resize the image to be as small as possible while ensuring its dimensions are greater than or equal to both those specified. An example of `outside` fit:

Cloudflare Image Resizing

-------------------------

Another beautiful way to generate screenshots or render HTML in a different format is to use Cloudflare as a proxy that converts images on the go and can transform and resize them.

[Cloudflare Image Resizing](https://developers.cloudflare.com/images/) allows using Cloudflare’s edge platform to convert images to WebP or AVIF format on the fly, independently of where they are stored.

API as a service

----------------

Suppose you don’t want to ding with Puppeteer, write code, test it and make sure it is scalable. In that case, you can use a well-established solution — [ScreenshotOne.com API](/) that already supports different formats, resizing, and many more — [get started for free](https://dash.screenshotone.com/sign-up).

To render screenshots of URL or HTML in a specific format. You will only need to specify two options, URL or HTML, and desired [image width](/docs/options/#image_width) and [height](/docs/options/#image_height). Can it be more straightforward than:

    1https://api.screenshotone.com/take?image_width=100&url=https://apple.com&access_key=<your access key>

Summary

-------

If you have time and have already installed Puppeteer, you can easily use the sharp library for image resizing. But if you don’t want to deal with Puppeteer, you can use [ScreenshotOne.com API](/) to save time.

Have a nice day 👋 and you also might find helpful:

*   [the complete guide on how to take a screenshot with Puppeteer](/blog/how-take-a-screenshot-with-puppeteer)

Read more Puppeteer guides

--------------------------

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

[View all posts](/blog/tags/puppeteer-guides/)

#### [How to Take Bulk Screenshots with Playwright in Python](/blog/bulk-screenshots-playwright-python/)

Learn how to automate bulk website screenshots with Playwright in Python. Master async batch processing, concurrent screenshots, rate limiting, and error handling for large-scale screenshot automation.

Read more

#### [How to take bulk screenshots with Puppeteer](/blog/bulk-screenshots-with-puppeteer/)

Learn how to take screenshots of multiple URLs with Puppeteer, including concurrency management, error handling, retries, and proxy support.

Read more

#### [How to take website screenshots with C# (.NET)](/blog/how-to-take-website-screenshots-with-csharp-dotnet/)

The article examines how you can take screenshots of any URL with C# (.NET) by using PuppeteerSharp, or screenshot API as a service.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/improved-full-page-rendering
----

Improved full-page screenshot rendering

=======================================

Fixed a few issues related to full-page screenshots rendering.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Aug 26, 2025

Scrolling websites with wrapped content containers

--------------------------------------------------

A few cases were reported where API timed out when rendering websites with wrapped content containers. That usually means that the page has viewport adjust max height and the content inside is scrolled.

We improved the API to detect and handle a subset of such cases. Now, you will see better success rate for full-page screenshots in such cases.

Content visibility

------------------

For specific subset of elements caused by a well-known plugin for a well-known CMS, we update and force CSS styles to make the content visible always, not only when lazy loaded.

Your feedback is always appreciated

-----------------------------------

We are constantly working on improving the quality of full-page screenshots rendering. But if you notice more issues with full-page screenshots rendering, please let us know at `hey@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Added an Above-the-Fold Checker Tool](/changelog/above-the-fold-checker/)

A new ScreenshotOne tool to capture what users see before the first scroll.

Read more →

1 min read

#### [ScreenshotOne integration with Dirstarter](/changelog/dirstarter-integration/)

Build a directory with Dirstarter and add website screenshots automatically with ScreenshotOne.

Read more →

1 min read

#### [Improved errors](/changelog/improved-errors/)

Now, errors will have relevant documentation links. It will be also possible to see why some requests failed in the dashboard and get recommendations on how to address the issue.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/improved-playground
----

Use cases in the ScreenshotOne playground

=========================================

Having documentation and code examples is great, but not enough to allow developers to quickly integrate the API and assess all available features of the ScreenshotOne API.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Apr 8, 2024

That’s why ScreenshotOne’s playground was upgraded to support the most often used product use cases.

You can render static, scrolling screenshots, videos, and PDFs right from the playground from today and just copy and paste working code examples.

There are many more use cases. But let’s start with these ones and add more on the go.

Enjoy!

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Screenshot URLs are now available in the response](/changelog/screenshot-url/)

You can now get a screenshot URL in the response of the API call.

Read more →

1 min read

#### [Improved webhooks documentation and playground](/changelog/improved-webhooks-documentation-and-playground/)

We improved the webhooks documentation and playground.

Read more →

1 min read

#### [Trigger screenshot download](/changelog/attachment-name/)

Now you can set attachment filename to trigger screenshot download in the browser.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/best-screenshot-apis
----

3 best screenshot APIs in 2026

==============================

The truth is, that there is no single best screenshot API that fits everyone. But some APIs stand out and shine when compared to others. Also, it depends on your use case and needs which must be included in considering what API to use.

[Blog post](/blog/) 7 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Jan 6, 2026

#### Tags

[Screenshot rendering](/blog/tags/screenshot-rendering/)

Only the 3 best screenshot APIs

-------------------------------

If I listed [all the possible screenshot APIs as I did in the past](/the-best-screenshot-api/), it would only make your purchasing decision more complicated, so I simplified the process for you.

I [searched on Google for the “screenshot API” keyword](https://www.google.com/search?q=screenshot+api) and evaluated only the top 3 results, assuming that Google already ranks the products people are most likely to consider the best.

[](https://www.google.com/search?q=screenshot+api)

I encourage you to check them for yourself, because results might be a bit different for you.

At the moment of writing, the best screenshot APIs according to Google:

1.  [ScreenshotOne.com—the screenshot API for developers](#ScreenshotOne)

2.  [ScreenshotAPI.net—programmatic screenshots in seconds](#ScreenshotAPI)

3.  [Screenshot Machine—reliable screenshot API](#ScreenshotMachine)

While I try to keep the post as objective as possible, you need to be aware that I have an interest to promote ScreenshotOne and make it the best API possible. However, I reached out to the founders and developers of these APIs and shared the post with them and asked if they wanted to add or edit something.

If you run or know a screenshot API that isn’t included in the guide but it is a good candidate, please, reach out to `support@screenshotone.com` and I will consider adding an update. The goal is to reduce decision friction, not list all possible screenshot APIs.

But do you really need a screenshot API?

----------------------------------------

Don’t forget that while you have landed on the article to read about the best screenshot APIs, it might be that you don’t need a screenshot API at all.

Most of the time, you can start quickly rendering screenshots with [Puppeteer](/blog/how-to-take-a-screenshot-with-puppeteer/) or a similar solution for your language of choice ([Python](/blog/how-to-take-website-screenshots-in-python/), [Java](/blog/how-to-take-website-screenshots-with-java/), [Ruby](/blog/how-to-take-website-screenshots-in-ruby/), [Haskell](/blog/how-to-take-a-screenshot-of-a-webpage-in-haskell/), [JavaScript or TypeScript](/blog/how-to-take-website-screenshots-with-javascript-or-typescript-nodejs/), [PHP](/blog/how-to-take-website-screenshots-with-php/)).

It is the cheapest option, except you often need proper servers to render websites with headless browsers. You can check out [our guide on how to build a screenshot API yourself](/blog/building-screenshot-api/).

But once you need to render screenshots at scale and you want to remove cookie banners, and glitches, and solve hundreds of other issues related to websites, you better go with any screenshot API and outsource that boring and often annoying work to the service that can do it for you at some fee.

I promised to keep this guide simple and help you make a quick decision. However, if you have time and want to explore the various reasons and considerations for choosing a screenshot API, check out [why and how to choose a screenshot API](/blog/why-and-how-to-choose-a-screenshot-api/).

The best screenshot APIs

------------------------

### 1\. ScreenshotOne.com—the screenshot API for developers

[](/)

ScreenshotOne is one of the best solutions in the market, recently grew past 1000 active developers using it, rendering 1,000,000+ screenshots monthly and with high uptime for real screenshot renders.

I must be open in advance that I am a founder of [ScreenshotOne](https://screenshotone.com/), one of the best screenshot APIs [according to my customers](https://screenshotone.com/customers/), and we do whatever we can to deliver an excellent screenshot automation experience. But no matter how much we would want everybody to become my customer, we understand that it is impossible and our API is not for everybody.

Of course, I am not objective when describing ScreenshotOne, but I can prove to you, that it is one of the best certainly.

While ScreenshotOne supports [Zapier and other no-code automation tools (and not only)](/integrations/), my sole focus is developers and my goal is to offload them from the boring job of dealing with all headless browser and screenshotting issues.

[](/integrations/)

We want to free developers’ time for more interesting tasks and tasks related to their business core.

As a software engineer with 15+ years of experience, I understand developers’ needs well and try to close any issues or problems as fast as possible.

Think of using ScreenshotOne as hiring a skilled developer for [only $20+ a month (depending on your needs)](https://screenshotone.com/pricing/) to close all the boring tasks and issues related to screenshot automation.

[](https://screenshotone.com/pricing/)

We have plans and strategies to grow the API further and proved that [for the last 2 years](/roadmap/). We carefully listen to our customer demands and try to solve all current and future problems that arise for them.

[](/blog/rivalflowai-by-spyfu/)

By the way, you also can try our API for free and see if it fits you.

What you get if you go with ScreenshotOne:

1.  Clean screenshots. We block cookie banners and other annoying pop-ups for you. You just get crisp screenshots that delight your customers.

2.  Full-page screenshots. Lazy loading images, different glitches, whatever—we got you covered.

3.  Videos with predefined scenarios like scrolling screenshots.

4.  GPU rendering if needed.

5.  Responsive support

6.  Native SDK for your language of choice.

7.  Caching on Cloudflare CDN for free, for up to 30 days!

8.  Upload screenshots to any S3-compatible storage.

9.  Proxies.

10.  Choose the IP location. Geolocation coordinates, and whatever.

11.  And more, I can continue forever.

And that’s only the small subset of benefits you can get if you go with ScreenshotOne.

A quick example of code for Node.js of you can render screenshots with ScreenshotOne:

    1// npm install screenshotone-api-sdk --save2

    3import * as fs from "fs";4import * as screenshotone from "screenshotone-api-sdk";5

    6// create API client7const client = new screenshotone.Client("<access key>", "<secret key>");8

    9// set up options10const options = screenshotone.TakeOptions.url("https://example.com").delay(3).blockAds(true);11

    12// generate URL13const url = client.generateTakeURL(options);14console.log(url);15// expected output: https://api.screenshotone.com/take?url=...16

    17// or download the screenshot18const imageBlob = await client.take(options);19const buffer = Buffer.from(await imageBlob.arrayBuffer());20fs.writeFileSync("example.png", buffer);21

    22// the screenshot is stored in the example.png file

There are [many more ways on how you can integrate with ScreenshotOne](/integrations/).

If you have any questions or concerns, we would be happy to answer them. Please, feel free to reach out at `support@screenshotone.com` or just [schedule a demo call](/book-a-call/).

### 2\. ScreenshotAPI.net—programmatic screenshots in seconds

For a long time, this API was in the first position of Google and it fully deserves it still, but we don’t have control over Google and they decide what to rank due to the ranking factors.

[](https://screenshotapi.net)

[ScreenshotAPI.net](https://screenshotapi.net) was a part of the [XO Capital company](https://notes.xo.capital/). According to their blog, they bought the product a few years ago and did a great job of improving and growing it, then they sold it again. Running screenshot APIs is not easy. And now it again has a new founder behind it.

I just checked out their product and they keep improving it. They added the scrolling screenshots feature recently, for example. While [ScreenshotOne had scrolling screenshots](/scrolling-screenshots/) for a few years.

It seems to be much more feature rich than [Screenshot Machine](#ScreenshotMachine), but a bit pricier. But still their cheapest plan is only $9 monthly and if that is really important for you, it might be the best option to start:

[](https://www.screenshotapi.net/pricing)

The main difference between ScreenshotOne and ScreenshotAPI.net is that the former is focused on building only the API, but the new owners of ScreenshotAPI.net dedicate their time to other products, too.

The screenshot API is not a product that must be constantly developed with new features, but when choosing the API I want to rely on, I would consider that factor, too—whether the owners of the API are focused and dedicate their full attention or not.

ScreenshotAPI.net doesn’t have an official SDK, but they support the HTTP protocol, so it is easy:

    1// npm install node-fetch2

    3import fetch from "node-fetch";4import { writeFile } from "fs/promises";5

    6async function captureScreenshot(token, url, options = "") {7    const response = await fetch(8        `https://shot.screenshotapi.net/screenshot?token=${token}&url=${url}&${options}`9    );10    const buffer = await response.buffer();11    await writeFile("screenshot.png", buffer);12}13

    14const TOKEN = "YOUR_TOKEN_HERE";15const URL = "https://example.com";16

    17captureScreenshot(TOKEN, URL);

All in all, it is a good product, and I would give it a try.

### 3\. Screenshot Machine—reliable screenshot API

[Screenshot Machine](https://www.screenshotmachine.com/) is a screenshot API that is founded in 2012. However, it is hard to find reviews of it on the Internet. It seems to have a simple API and is focused on the screenshot and PDF rendering only.

[](https://www.screenshotmachine.com/)

With [a few only options according to their documentation](https://www.screenshotmachine.com/website-screenshot-api.php), you can consider it as simple and affordable solution for your screenshot needs:

[](https://www.screenshotmachine.com/pricing.php)

They only charge around $9 per month for 2,000+ screenshots, compared to about $20 for [ScreenshotOne](#ScreenshotOne) or [ScreenshotAPI](#ScreenshotAPI), which provide 1,000 screenshots for $9 per month.

Summary

-------

Today, [ScreenshotOne](https://screenshotone.com/) and [ScreenshotAPI](https://www.screenshotapi.net/) are the best solutions in the market for screenshot automation both striving for excellence and keeping up daily with rising customer demands.

If you are a developer or small to medium and more focused on marketing tasks and want to generate different animated videos for outreach or engaging content, I would give you a chance to ScreenshotOne since it has more capabilities in this niche.

Otherwise, consider ScreenshotOne and ScreenshotAPI equal but different in the pricing structure. Choose whatever suits you best.

[Screenshot Machine](https://www.screenshotmachine.com/) is also a good choice if you need it. It is much cheaper to start with, has [good reviews](https://www.screenshotmachine.com/), and is almost on par with the best solutions by features in the screenshot API niche.

Frequently Asked Questions

--------------------------

If you read the article, but still have questions. Please, check the most frequently asked. And if you still have questions, feel free reach out at [support@screenshotone.com](mailto:support@screenshotone.com).

### When and why use a screenshot API?

There are many use cases for screenshot APIs. You can use them for website archivation for historical reference, or for automating personalized videos at scale, among other purposes.

### Who can benefit from screenshot APIs?

Screenshot APIs are designed for developers who want to automate taking screenshots, as well as website owners who need to track user interactions or add screenshot capabilities to their apps.

### Which screenshot API is the best?

The best screenshot API depends on your needs for functionality and budget. The list above is a helpful starting point. Consider ScreenshotOne as a potential option.

Read more Screenshot rendering

------------------------------

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

[View all posts](/blog/tags/screenshot-rendering/)

#### [Why and how to choose a screenshot API](/blog/why-and-how-to-choose-a-screenshot-api/)

You don't need a screenshot API if it is a one-off task for you and you can use some library for screenshotting.

Read more

#### [How to Take Screenshots with pyppeteer in Python](/blog/pyppeteer-python-screenshots/)

Guide to taking screenshots with pyppeteer in Python. Learn the basics, full page captures, and why you should migrate to Playwright.

Read more

#### [How to Take Full Page Screenshots with Playwright in Python](/blog/playwright-python-full-page-website-screenshots/)

Learn how to capture full page screenshots with Playwright in Python. Master the full\_page parameter, handle infinite scroll pages, lazy-loaded images, and maximum size limits.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/tags/puppeteer-guides
----

Puppeteer Guides

----------------

How-to posts and troubleshooting guides for Puppeteer-based automation.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [page.waitForTimeout is not a function in Puppeteer](/blog/page-waitfortimeout-is-not-a-function-in-puppeteer/)

Puppeteer removed page.waitForTimeout(). Learn why the error happens and which modern alternatives to use instead.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 13, 2026

•

2 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take bulk screenshots with Puppeteer](/blog/bulk-screenshots-with-puppeteer/)

Learn how to take screenshots of multiple URLs with Puppeteer, including concurrency management, error handling, retries, and proxy support.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Dec 16, 2025

•

8 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [How to render screenshots with different emoji styles in Puppeteer](/blog/emojis/)

Learn how to render screenshots with different emoji styles in Puppeteer using emoji-js in a few lines of code.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Apr 4, 2025

•

2 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Playwright guides](/blog/tags/playwright-guides/)

#### [Puppeteer versus Playwright](/blog/puppeteer-versus-playwright/)

When to use Playwright and when to use Puppeteer.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

May 6, 2024

•

2 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [What is Puppeteer](/blog/puppeteer/)

What is Puppeteer and what you can use it for.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

May 6, 2024

•

4 min read

[PDF rendering](/blog/tags/pdf-rendering/) [Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [How to generate PDFs with Puppeteer](/blog/how-to-generate-pdf-with-puppeteer/)

A practical and working guide on how to generate PDFs with Puppeteer.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

May 2, 2025

•

2 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [Comparing Puppeteer versus Selenium for rendering website screenshots](/blog/comparing-puppeteer-versus-selenium-for-rendering-website-screenshots/)

When comparing Puppeteer, Selenium, and ScreenshotOne for rendering screenshots, it's crucial to understand the distinct capabilities and use cases of each tool.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Oct 5, 2023

•

2 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [Puppeteer Performance Monitoring with Inspector](/blog/puppeteer-performance-monitoring-with-inspector/)

In this article I'll show you how to monitor performance and errors of a browser automation script written with Puppeteer.

Written by

[Valerio Barbera](/contributors/valerio-barbera/)

Published on

Jun 13, 2023

•

5 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/3
----

Changes and updates

-------------------

Stay updated with the latest information about new features, bug fixes, and optimizations at ScreenshotOne

### Product updates in the last 12 months

Oct 27, 2025

#### [ScreenshotOne Dashboard performance has been improved](/changelog/upgraded-dashboard-underlying-framework/)

ScreenshotOne Dashboard has been upgraded to Next.js 16

Read more →

1 min read

Oct 26, 2025

#### [Improved webhooks documentation and playground](/changelog/improved-webhooks-documentation-and-playground/)

We improved the webhooks documentation and playground.

Read more →

1 min read

Oct 25, 2025

#### [Updated the official Go SDK](/changelog/updated-gosdk/)

We updated the Go SDK to support the latest API features.

Read more →

1 min read

Oct 20, 2025

#### [Fixed a validation issue in the playground](/changelog/fixed-a-playground-issue/)

We fixed a validation issue in the ScreenshotOne playground caused by selector scroll into view.

Read more →

1 min read

Oct 16, 2025

#### [Improved full page screenshot algorithm](/changelog/fixed-a-corner-case-for-full-page-screenshots/)

We fixed issues with full page screenshots when the viewport was overridden together with the device option.

Read more →

1 min read

Sep 29, 2025

#### [Proxy option in the ScreenshotOne Playground](/changelog/proxy-option-in-playground/)

You can now take screenshots with a proxy in the ScreenshotOne Playground.

Read more →

1 min read

Sep 23, 2025

#### [Improved Supabase Storage integration](/changelog/better-supabase-storage-support/)

Improved Supabase storage integration.

Read more →

1 min read

Sep 23, 2025

#### [Improved guards for full-page screenshots by sections](/changelog/guards-for-full-page-screenshots-by-sections/)

Improved guards for full-page screenshots by sections.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/competitive-product-analysis
----

Automate Website Screenshots

1 min read

Competitive Product Analysis

============================

Automate the capture of competitor product listings for market analysis and strategy planning.

The ScreenshotOne API allows companies to conduct competitive analysis by automating the capture of competitor product listings, content blogs, and other publicly available assets. This helps in assessing market position and planning strategic product developments or adjustments.

Why ScreenshotOne API?

----------------------

Using the ScreenshotOne API for competitive analysis streamlines the process of collecting and reviewing competitor product information. It offers an efficient way to monitor changes in competitors’ offerings, pricing strategies, and feature enhancements over time.

Value Proposition

-----------------

A screenshot API provides a clear advantage in time and resource savings over developing in-house screenshot automation solutions. It ensures that businesses can quickly adapt to market changes and maintain a competitive edge by focusing on their core competencies rather than spending time on automating website screenshots.

RivalFlowAI as an example

-------------------------

[RivalFlowAI](https://www.rivalflow.com/) is a new product by SpyFu, launched in 2023. The product helps to improve existing content with AI by finding the missing pieces your page needs to rank.

ScreenshotOne processes a really high volume of screenshots with a high success rate. Taking all the boring and scaling work and allowing RivalFlowAI to focus on its core business.

If you are curious, you can read more about [how RivalFlowAI uses ScreenshotOne for competitive analysis](/blog/rivalflowai-by-spyfu)

ScreenshotOne is the best product on the market - and that's before you take into account how responsive and easy Dmytro is to work with.

Any time we've found a rare edge case, it's been resolved in hours.

Great company, great founder - can't say enough!

Mike Roberts

Founder, [SpyFu](https://www.spyfu.com/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/code-examples
----

[Skip to content](#_top)

SDK and Code Examples

=====================

Copy page

If you have any questions, please, reach out at `support@screenshotone.com`.

Postman

-------

You can run ScreenshotOne API requests in [Postman](https://www.postman.com/) using the following collection:

[](https://god.gw.postman.com/run-collection/50121564-7b48803f-b44f-4f5b-892b-f624c9d124b8?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D50121564-7b48803f-b44f-4f5b-892b-f624c9d124b8%26entityType%3Dcollection%26workspaceId%3D192aa74a-dd79-4388-8bdd-10d7cbaa8435)

SDKs and Code Examples

----------------------

There is a set of native SDKs you can use:

*   [Go](/docs/code-examples/go/)

*   [Java](/docs/code-examples/java/)

*   [PHP](/docs/code-examples/php/)

*   [Ruby](/docs/code-examples/ruby/)

*   [Python](/docs/code-examples/python/)

*   [C# (.NET)](/docs/code-examples/c-net/)

*   [JavaScript and TypeScript (Node.js)](/docs/code-examples/c-net/)

If your language is not supported, please, reach out to [support@screenshotone.com](mailto:support@screenshotone.com) and we will try to close it quickly. Otherwise, you can always use any HTTP client.

----
url: https://screenshotone.com/blog/how-to-take-a-screenshot-of-the-element-with-puppeteer
----

How to take a screenshot of the element with Puppeteer

======================================================

Puppeteer allows you to automate everything you can do in the browser manually and even more. You can take screenshots of the entire page and the specific elements.

[Blog post](/blog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Jun 18, 2022

Puppeteer allows you to automate everything you can do in the browser manually and even more. You can take screenshots of the entire page and the specific elements.

Make sure you installed [the puppeteer library](https://www.npmjs.com/package/puppeteer) first:

Terminal window

    1npm i puppeteer

Then you can import the library and take a screenshot of any desired element:

    1'use strict';2

    3const puppeteer = require('puppeteer');4

    5(async () => {6       const browser = await puppeteer.launch();7

    8       try {9           const page = await browser.newPage();10           await page.goto('https://example.com');11

    12           const selector = 'body > div:first-child';13           await page.waitForSelector(selector);14           const element = await page.$(selector);15

    16           await element.screenshot({17               path: 'example.com.png',18           });19       } catch (e) {20           console.log(e)21       } finally {22           await browser.close();23       }24})();

It is essential to wait until the selector is ready and rendered. Otherwise, you can miss it and take a screenshot of nothing. After the element is ready, you need to find it (select it) and then call the `screenshot()` method.

In our [screenshot API](/), you can take the screenshot of the element by specifying [the selector parameter](/docs/options/#selector).

If you want to check out [the complete guide on how to take screenshots with Puppeteer](/blog/how-to-take-a-screenshot-with-puppeteer/), you are welcome.

Read more posts

---------------

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

[View all posts](/blog/)

#### [Monitoring website changes](/blog/monitoring-website-changes/)

I tried many ways to monitor and detect website changes. But I was always disappointed by the results. I want to share a few tips that might help you to get better results, if you plan to do the same.

Read more

#### [What is OpenClaw and how can it help?](/blog/openclaw/)

A short practical introduction to OpenClaw, what it is good at, and why it is useful if you want a proactive AI assistant that lives in your chat apps.

Read more

#### [Using Clobbr to quickly load test the ScreenshotOne API](/blog/using-clobbr-to-quickly-load-test-the-screenshotone-api/)

Google Cloud gives $300 in credits for 3 months for experimenting. And I decided to give it a try, but not because of the free credits.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/nextjs-screenshots
----

How to screenshot websites in Next.js

=====================================

There 3 simple ways to render website screenshots in Next.js—using Puppeteer, Cloudflare Browser Rendering, and a screenshot API like ScreenshotOne or similar.

[Blog post](/blog/) 5 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

May 7, 2024

#### Tags

[Screenshot rendering](/blog/tags/screenshot-rendering/)

[Next.js](https://nextjs.org/) is a full-stack framework based on React and its ecosystem.

[](https://nextjs.org/)

All the mentioned code is stored in [the Next.js screenshots example GitHub repository](https://github.com/screenshotone/next.js-screenshots-example).

Your runtime matters

--------------------

There are many ways to deploy and run Next.js, starting from a standalone application with Node.js runtime and ending with serverless on Vercel, Cloudflare, or similar platforms.

That means, for example, that you can not use [Puppeteer](/blog/puppeteer/) easily on serverless platforms, because it will launch headless Chrome/Chromium, and highly likely it will miss dependencies and won’t just work.

Let’s quickly consider a few ways how to render website screenshots with Next.js depending on how you deploy it and run, it and your requirements.

An example application

----------------------

I have built [a simple Next.js application](https://github.com/screenshotone/next.js-screenshots-example) that demonstrates and compares approaches. It is just a simple form that asks for the URL of a website and then returns backs a screenshot.

    1"use client";2

    3import { FormEvent, useState } from "react";4

    5export default function Home() {6    const [screenshotUrl, setScreenshotUrl] = useState<string | null>(null);7

    8    async function onSubmit(event: FormEvent<HTMLFormElement>) {9        // ... render screenshots10    }11

    12    return (13        <main className="flex min-h-screen flex-col items-center gap-24 p-24">14            <h1 className="text-7xl font-semibold tracking-tighter">15                Render Screenshots16            </h1>17            <div>18                <form onSubmit={onSubmit}>19                    <div className="flex gap-2">20                        <input21                            type="url"22                            name="url"23                            placeholder="https://example.com"24                            className="ring-1 text-lg rounded-md p-4 w-96"25                        />26                        <button27                            type="submit"28                            className="bg-red-500 text-white inline-flex items-center justify-center whitespace-nowrap rounded-md text-lg font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 p-4"29                        >30                            Render31                        </button>32                    </div>33                </form>34            </div>35            <div>{screenshotUrl && <img src={screenshotUrl} />}</div>36        </main>37    );38}

The form submit handler:

    1export default function Home() {2    const [screenshotUrl, setScreenshotUrl] = useState<string | null>(null);3

    4    async function onSubmit(event: FormEvent<HTMLFormElement>) {5        event.preventDefault();6

    7        const formData = new FormData(event.currentTarget);8        const response = await fetch("/api/screenshot", {9            method: "POST",10            body: JSON.stringify({ url: formData.get("url")?.toString() }),11        });12

    13        if (response.ok) {14            const encoded = Buffer.from(await response.arrayBuffer()).toString(15                "base64"16            );17            setScreenshotUrl(`data:image/jpeg;base64,${encoded}`);18        }19    }20

    21    return <main>// ...</main>;22}

The resulting application looks like:

Now, let’s try different approaches to rendering screenshots in Next.js and see what fits the best.

Puppeteer

---------

[Puppeteer](/blog/puppeteer/) is the most popular library in the Node.js ecosystem working with headless browsers. Another alternative can be [Playwright](/blog/playwright/), but [Playwright is more about testing than a standalone browser automation library](https://screenshotone.com/blog/puppeteer-versus-playwright/).

### Next.js, Node.js and headless browsers

If you plan to deploy your Next.js application on a VPS with Linux or containerize with Docker and can run headless browsers, then it is pretty straightforward to implement.

Let’s install `Puppeteer` first:

Terminal window

    1npm i puppeteer

Now, let’s write a simple function to render screenshots with the `Puppeteer` library. We will create an HTTP POST route handler in the `app/api/screenshot/route.ts` file:

    1import { renderScreenshotWithPuppeteer } from "@/app/lib/puppeteer";2import { unstable_noStore } from "next/cache";3

    4export default async function POST(request: Request) {5    // do not cache6    unstable_noStore();7

    8    // parse request and get the website URL to render9    const data = (await request.json()) as { url: string };10

    11    // get the screenshot12    const screenshot = await renderScreenshotWithPuppeteer(data.url);13

    14    // return the image15    return new Response(screenshot, {16        headers: { "content-type": "image/jpeg" },17    });18}

And then we will implement the Puppeteer rendering function in the `lib/puppeteer.ts` file:

    1import puppeteer from "puppeteer";2

    3export async function renderScreenshotWithPuppeteer(url: string) {4    const browser = await puppeteer.launch();5

    6    const page = await browser.newPage();7    await page.goto(url);8    const screenshot = await page.screenshot({9        encoding: "binary",10        type: "jpeg",11    });12

    13    await browser.close();14

    15    return screenshot;16}

That’s it!

And don’t forget to add [all the necessary Puppeteer dependencies](https://pptr.dev/guides/docker) to your Docker image.

The real problem arises when you want to run that on serverless, be it Cloudflare Workers or Vercel Edge functions. Then you can’t run Chrome/Chromium headless. [You might solve some of the problems, but then you will memory limits and there is no end to that](https://github.com/orgs/vercel/discussions/124). But there is a way out—hosting and running headless browsers outside of your application or using a screenshot API.

### Next.js, serverless and browsers in the cloud

In case you host Next.js on Vercel, or Cloudflare Workers or similar platform, there is a better solution. Either you can run headless browsers on a separate VPS and connect to them or you can use services like [Browserless](/blog/browserless/) which run browsers for you.

The idea is simple. Since you can run headless browsers remotely either by yourself or using Browserless, you can connect to them via a simple WebSockets endpoint, and that’s the only thing you need to change in the code, except using the `puppeteer-code` instead of `puppeteer`, since you don’t need to download browsers anymore.

    1const browserWSEndpoint = "...";2const browser = await puppeteer.connect({ browserWSEndpoint });

Cloudflare, by the way, has their own solution which you can use—[Browser Rendering](/blog/cloudflare-browser-rendering/).

Using a screenshot API

----------------------

But you don’t need to work with Puppeteer, headless browsers, and be worried about your runtime at all if… you choose to use a screenshot API.

The problem of rendering screenshots at scale while covering all the potential issues was solved a long time ago by screenshot APIs. As an example, I will use ScreenshotOne, but you can consider any other of [the best screenshot APIs](/blog/best-screenshot-apis-2024/) that also might fit you.

Let’s first integrate the API (`lib/api.ts`):

    1if (!process.env.SCREENSHOTONE_ACCESS_KEY) {2    throw new Error("SCREENSHOTONE_ACCESS_KEY is required");3}4

    5const accessKey = process.env.SCREENSHOTONE_ACCESS_KEY;6

    7export async function renderScreenshotWithScreenshotAPI(url: string) {8    const params = new URLSearchParams({9        access_key: accessKey,10        url: url,11    });12

    13    const response = await fetch(14        "https://api.screenshotone.com/take?" + params.toString()15    );16    if (response.ok) {17        return await response.arrayBuffer();18    }19

    20    throw new Error(21        `Failed to render screenshot: response status code is ${response.status}`22    );23}

Then update the route handler (`app/api/screenshot/route.ts`):

    1import { renderScreenshotWithScreenshotAPI } from "@/app/lib/api";2import { unstable_noStore } from "next/cache";3

    4export async function POST(request: Request) {5    unstable_noStore();6

    7    const data = (await request.json()) as { url: string };8

    9    const screenshot = await renderScreenshotWithScreenshotAPI(data.url);10

    11    return new Response(screenshot, {12        headers: { "content-type": "image/jpeg" },13    });14}

That’s how simple it is when all that complexity is outsourced to an external application that cares of it for you.

The result is:

It is a bit different from the Puppeteer integration since ScreenshotOne uses the most popular viewport size `1920x1080` compared to the Puppeteer defaults.

By the way, a few bonuses you get when you use screenshot APIs instead of building your own solution:

1.  Blocking of cookie banners, ads, and other pop-ups.

2.  Custom fixes for different websites.

3.  Predictable pricing, not based on CPU and memory usage.

4.  Usually, screenshot APIs have support teams available for you and fix any issues you encounter.

5.  [GPU rendering](/blog/screenshotone-api-supports-gpu-rendering/), videos if needed, lazy loading images for full pages, and many other features.

If you are curious, check out [ScreenshotOne](https://screenshotone.com).

Summary

-------

Choose whatever method suits you best. If you deploy Next.js with Node.js runtime, can run headless browsers, and don’t need to render a lot of screenshots, consider using classic Puppeteer.

But if you encounter issues, plan to scale, or don’t want to spend time on boring screenshot automation, you can go with [a screenshot API like ScreenshotOne](https://screenshotone.com) or choose one from [the best screenshot APIs](/blog/best-screenshot-apis-2024/).

Read more Screenshot rendering

------------------------------

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

[View all posts](/blog/tags/screenshot-rendering/)

#### [How to Take Full Page Screenshots with Playwright in Python](/blog/playwright-python-full-page-website-screenshots/)

Learn how to capture full page screenshots with Playwright in Python. Master the full\_page parameter, handle infinite scroll pages, lazy-loaded images, and maximum size limits.

Read more

#### [How to Take Website Screenshots with Playwright in Python](/blog/playwright-python-screenshots/)

A complete guide to taking website screenshots with Playwright in Python. Learn page.screenshot() parameters, async patterns, element screenshots, dark mode, and device emulation.

Read more

#### [How to add custom scripts to a page in Puppeteer](/blog/how-to-add-custom-scripts-to-a-page-in-puppeteer/)

How to add custom scripts to a page in Puppeteer. Let's discover how it works quickly."

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/errors
----

[Skip to content](#_top)

Errors

======

Copy page

There is [a detailed guide](/docs/guides/how-to-handle-api-errors/) on how to handle the ScreenshotOne API errors.

The request might return an error due to an internal error, invalid options or when the limit is reached. Our screenshot API follows the HTTP status code semantic and returns JSON in case of an error:

    1GET https://api.screenshotone.com/?[options]2

    3Content-Type: application/json4{5    "is_successful": false,6    "error_code": "an_error_code",7    "error_message": "An error message",8    "documentation_url": "..."9}

The API will always return a human-readable error message, error code as a string key, and suitable HTTP status code.

Codes with explanations

-----------------------

Error Code

HTTP Status

Explanation

[access\_key\_required](/docs/errors/access-key-required/)

400

The “access\_key” parameter is required. Please, check out [the access page](https://dash.screenshotone.com/access) to get the access key.

[access\_key\_invalid](/docs/errors/access-key-invalid/)

400

The “access\_key” parameter is given, but it is not correct. Please, check out [the access page](https://dash.screenshotone.com/access) to check the access key.

[signature\_is\_required](/docs/errors/signature-is-required/)

400

The “signature” parameter is required. Because signing requests is required in [the access page](https://dash.screenshotone.com/access). Make sure you use [the correct signing algorithm](/docs/signed-requests/).

[signature\_is\_not\_valid](/docs/errors/signature-is-invalid/)

400

You provided the “signature” parameter, but it is not valid. Make sure you use [the correct signing algorithm](/docs/signed-requests/).

[screenshots\_limit\_reached](/docs/errors/usage-quota-exceeded/)

400

The usage quota has been exceeded. Please, either upgrade to a plan with more quota or change the maximum allowed limit (if possible) in the ScreenshotOne dashboard. If it is a mistake, please, reach out at `support@screenshotone.com.`

[concurrency\_limit\_reached](/docs/errors/concurrency-limit-reached/)

400

You reached the request concurrency limit, retry after a while. Or feel free to [upgrade you current plan](https://dash.screenshotone.com/subscription).

[request\_not\_valid](/docs/errors/request-invalid/)

400

The request parameters are not valid. You can look at the `error_details` response field to get the details.

[selector\_not\_found](/docs/errors/selector-not-found/)

400

If [selector](/docs/options#selector) is specified and `error_on_selector_not_found=true`, the error will be returned if the element by selector is not visible or it took more than `timeout` seconds to render it, but not more than 30 seconds.

[name\_not\_resolved](/docs/errors/name-not-resolved/)

400

Usually, the error happens when the domain name of the requested URL is not resolved. If you are trying to take a screenshot of the new site, please, wait a bit until the DNS records are refreshed.

[network\_error](/docs/errors/network-error/)

500

The error happens when the API can’t connect to the provided URL. It might mean that the site blocks the API or is temporarily unavailable. Generally, you can safely retry to take a screenshot.

[invalid\_storage\_configuration](/docs/errors/invalid-storage-configuration/)

400

If you haven’t created the bucket in the `us-east-1` AWS region, please, specify your bucket region through an endpoint in a format like `https://s3.<your-region>.amazonaws.com`.

[script\_triggers\_redirect](/docs/errors/script-triggers-redirect/)

400

The specified “scripts” option might trigger a redirect, please, specify the “scripts\_wait\_until” option. If you think it is a mistake, please, reach out at `support@screenshotone.com`.

[host\_returned\_error](/docs/errors/host-returned-error/)

500

If the host doesn’t respond successfully within the range of 200-299 status codes, the API won’t take a screenshot. You can force the API to take a screenshot of the error page by specifying [ignore\_host\_errors=true](/docs/options#ignore_host_errors). You can get the returned status code from the site by reading the `returned_status_code` field.

[timeout\_error](/docs/errors/timeout/)

500

The screenshot couldn’t be taken within the specified timeout. Either the site doesn’t respond quickly, or rendering takes longer than expected. Play with the `timeout` or the `navigation_timeout` options or reach the support for the investigation.

[internal\_application\_error](/docs/errors/internal-application-error/)

500

The API failed to serve your request. You can safely replay the request. We are notified about it instantly and will try to fix it as soon as possible. If the error is repeated for a long time, feel free to reach out at [support@screenshotone.com](mailto:support@screenshotone.com).

[storage\_access\_denied](/docs/errors/storage-access-denied/)

400

Failed to upload the screenshot to the storage since access was denied. Check the API keys you specify when using the storage integration.

[storage\_returned\_transient\_error](/docs/errors/storage-returned-transient-error/)

500

The storage returned an HTTP status code between 500 and 599 and we exhausted retries. You can likely retry the request again.

[request\_aborted](/docs/errors/request-aborted/)

500

The request was aborted either by the user or the intermediate proxies and can’t be fulfilled. If the error persists, please, reach out to [support@screenshotone.com](mailto:support@screenshotone.com).

[content\_contains\_specified\_string](/docs/errors/content-contains-specified-string/)

500

The page content contains the specified string by the [fail\_if\_content\_contains](/docs/options#fail_if_content_contains) option. If it seems to be a mistake or not what you expected, please, reach out to \`[support@screenshotone.com](mailto:support@screenshotone.com)\` as quickly as possible, and will assist and try to resolve your problem.

[temporary\_unavailable](/docs/errors/temporary-unavailable/)

503

The API is temporarily unavailable due to an error or overload. Please wait a bit and then safely retry your request.

[invalid\_cookie\_parameter](/docs/errors/invalid-cookie-parameter/)

400

The `cookies` parameters you provided are invalid. Please, consider providing different values and adhere to the format specified in the ScreenshotOne documentation.

[resulting\_image\_too\_large](/docs/errors/resulting-image-too-large/)

400

The resulting image is too large for the specified format. Please, consider providing different values and adhere to the format specified in the ScreenshotOne documentation.

[matched\_failed\_request](/docs/errors/matched-failed-request/)

500

The request matched by the specified pattern by the [fail\_if\_request\_failed](/docs/options#fail_if_request_failed) option has been failed. If it seems to be a mistake or not what you expected, please, reach out to \`[support@screenshotone.com](mailto:support@screenshotone.com)\` as quickly as possible, and will assist and try to resolve your problem.

[invalid\_header\_parameter](/docs/errors/invalid-header-parameter/)

400

The `headers` parameters you provided are invalid. Please, consider providing different values and adhere to the format specified in the ScreenshotOne documentation.

[request\_body\_too\_large](/docs/errors/request-body-too-large/)

413

The request body is too large. Please, reduce the size of the request body or reach out to \`[support@screenshotone.com](mailto:support@screenshotone.com)\` for assistance.

List of all errors

------------------

1.  [Timeout error](/docs/errors/timeout/).

2.  [Storage Access Denied](/docs/errors/storage-access-denied/).

3.  [Script Trigger Redirect](/docs/errors/script-triggers-redirect/).

4.  [Internal Application Error](/docs/errors/internal-application-error/).

5.  [Usage Quota Exceeded](/docs/errors/usage-quota-exceeded/).

6.  [Request Aborted](/docs/errors/request-aborted/).

7.  [Access Key Required](/docs/errors/access-key-required/).

8.  [Access Key Invalid](/docs/errors/access-key-invalid/).

9.  [Signature Is Required](/docs/errors/signature-is-required/).

10.  [Signature Is Not Valid](/docs/errors/signature-is-invalid/).

11.  [Screenshots Limit Reached](/docs/errors/usage-quota-exceeded/).

12.  [Concurrency Limit Reached](/docs/errors/concurrency-limit-reached/).

13.  [Request Not Valid](/docs/errors/request-invalid/).

14.  [Selector Not Found](/docs/errors/selector-not-found/).

15.  [Name Not Resolved](/docs/errors/name-not-resolved/).

16.  [Network Error](/docs/errors/network-error/).

17.  [Invalid Storage Configuration](/docs/errors/invalid-storage-configuration/).

18.  [Host Returned Error](/docs/errors/host-returned-error/).

19.  [Storage Returned Transient Error](/docs/errors/storage-returned-transient-error/).

20.  [Content Contains Specified String](/docs/errors/content-contains-specified-string/).

21.  [Temporary Unavailable](/docs/errors/temporary-unavailable/).

22.  [Invalid Cookie Parameter](/docs/errors/invalid-cookie-parameter/).

23.  [Resulting Image Too Large](/docs/errors/resulting-image-too-large/).

24.  [Matched Failed Request](/docs/errors/matched-failed-request/).

25.  [Invalid Header Parameter](/docs/errors/invalid-header-parameter/).

26.  [Request Body Too Large](/docs/errors/request-body-too-large/).

----
url: https://screenshotone.com/changelog/screenshot-url-in-webhooks
----

Screenshot URL in webhooks

==========================

Now, you can get the screenshot URL in the webhook response.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Aug 27, 2025

Screenshot URL in webhooks

--------------------------

Due to historical reasons, the screenshot URL was not returned in the webhook response with JSON format. Since today, you can get it.

The URL is available if you don’t store the screenshot in any S3 storage. And the URL is temporary, do not rely on it. Read more in [our documentation on how it works](/docs/screenshot-url/).

Your feedback is always appreciated

-----------------------------------

Any more ideas and what we should build and improve? Feel free to reach out and share at `hey@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Support for multiple API keys](/changelog/multiple-api-keys/)

You can now use multiple API keys to the access ScreenshotOne API.

Read more →

1 min read

#### [Added support of Slack notifications](/changelog/slack-notifications/)

We added support of Slack notifications to ScreenshotOne. Now you can set up and get Slack notifications when you reach your quota limits.

Read more →

1 min read

#### [Trigger screenshot download](/changelog/attachment-name/)

Now you can set attachment filename to trigger screenshot download in the browser.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/new-organization-role
----

New organization role

=====================

Allow other members to manage your organization without transferring ownership.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jan 28, 2026

We have added a new **Admin** role to [organizations](/docs/organizations/).

Admins can manage members (invite, remove, change roles), access billing and invoices, and edit organization settings. Only owners can transfer ownership or delete the organization.

You can now promote developers to admin or choose a role when inviting new members. All members can view the organization members list.

No migration is required. Existing users keep their current roles.

Read more about [how organizations and roles work in ScreenshotOne](/docs/organizations/).

If you have any questions or need any assistance, please, reach out at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Update your company information in the dashboard](/changelog/company-information-management/)

Starting today, you can update your company information in the dashboard. It includes updating the address, tax number, company number, and company name.

Read more →

1 min read

#### [Added an Above-the-Fold Checker Tool](/changelog/above-the-fold-checker/)

A new ScreenshotOne tool to capture what users see before the first scroll.

Read more →

1 min read

#### [Fail rendering if the content is missing a string](/changelog/fail-if-content-missing/)

There is a set of use cases when you want to fail screenshot rendering and retry it if the content of the page is missing a string.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/brand-consistency-font-checks
----

Automate Website Screenshots

1 min read

Brand Consistency Font Checks

=============================

Use ScreenshotOne font detection API to automatically verify font consistency across web pages to maintain brand integrity.

Automated **brand consistency font checks** with [ScreenshotOne font detection API](/font-detection-api/) in content management systems or your platform of choice to automatically check and ensure font consistency across web pages, which is a vital part of maintaining brand integrity.

Why Font Consistency Matters

----------------------------

Brand guidelines often specify exact typography requirements, but ensuring these standards are followed across hundreds or thousands of web pages can be challenging. Manual checking is time-consuming and error-prone, especially for large websites with multiple content contributors.

Automated Brand Compliance

--------------------------

With ScreenshotOne’s font detection API, CMS platforms can automatically scan pages and verify that the correct fonts are being used according to brand guidelines. This automation ensures that brand standards are consistently maintained without requiring manual audits.

Check out [our guide on how to detect website fonts](/docs/guides/how-to-detect-website-fonts/) for more details.

Time Savings and Risk Reduction

-------------------------------

By integrating this API, companies save countless hours of manual font checking and reduce the risk of brand inconsistencies that could damage their professional image. The API provides instant feedback, allowing content teams to identify and fix typography issues before they go live.

ScreenshotOne is one of those rare tools that just does its job perfectly. It's simple to integrate, consistently delivers great results, and the support is excellent.

We tested a few alternatives and ScreenshotOne was the clear winner for both quality and ease of use. We'd love to see the option to capture different screen formats too, like tablet and mobile, to support a more complete analysis.

William Prud'homme

Founder, [Forge IQ](https://screenshotone.com/blog/forge-iq/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

### Educational Font Detection Tool

Use our font detection API to enable students to explore and learn from typography used in real-world web applications.

[Read more →](/use-cases/educational-font-detection/)

### Font Legal Compliance Check

Ensure fonts used on websites are legally compliant to avoid copyright issues.

[Read more →](/use-cases/font-legal-compliance/)

### Design Tools Font Detection

Use our font detection API to help designers identify and analyze typography on any website.

[Read more →](/use-cases/design-apps-font-detection/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/integrations/flowmattic
----

Integrations

1 min read

FlowMattic

==========

Use ScreenshotOne with FlowMattic, a WordPress automation platform, to automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

No-Code Automation WordPress

Resources

---------

*   [ScreenshotOne on FlowMattic](https://flowmattic.com/integration/screenshotone/)

ScreenshotOne is a terrific Screenshot API. We're taking screenshots at scale at landing.gallery and ScreenshotOne is handling it like an absolute champ.

The founder is incredibly responsive and the docs are outstanding and get you going within minutes.

Chris Jayden

Maker, [Landing Gallery](https://screenshotone.com/blog/landing-gallery/)

Check more Integrations

-----------------------

No-code tools, AI, code libraries, and more.

[Check more Integrations](/integrations/)

No-Code Automation

### Clay

Generate website screenshots inside Clay to qualify leads, assess content, and enrich rows with visual context automatically.

[Read more →](/integrations/clay/)

No-Code Automation

### Zapier

Automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos in Zapier.

[Read more →](/integrations/zapier/)

Code API

### SDK and Code Examples

Use the SDKs and code examples to take screenshots in your own code.

[Read more →](/integrations/code/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/puppeteer-performance-monitoring-with-inspector
----

Puppeteer Performance Monitoring with Inspector

===============================================

In this article I'll show you how to monitor performance and errors of a browser automation script written with Puppeteer.

[Blog post](/blog/) 5 min read

#### Written by

[Valerio Barbera](/contributors/valerio-barbera/)

#### Published on

Jun 13, 2023

#### Tags

[Puppeteer guides](/blog/tags/puppeteer-guides/)

Most things that you can do manually in the browser can be done programmatically using [Puppeteer](https://pptr.dev/)! But implementing browser automations in a server-side script makes it difficult to understand the resource consumption and performance implications of any step of the automation.

I’m Valerio, software engineer and CTO at [Inspector](https://inspector.dev/), a tool that helps you find bugs and bottlenecks in your applications automatically. Before your customers stumble onto the problem.

One of the most useful things when it comes to monitoring is the ability to monitor not only the general execution performance, but build the timeline of all the individual tasks that make up the automation script.

Step 1: Create the project

--------------------------

To configure a new project create a new directory and run the init command inside it:

Terminal window

    1mkdir puppeteer-performance & cd puppeteer-performance & npm init

It will prompt you for input for a few aspects of the project, just press enter if you want to use the default values.

After completing the init process a `package.json` file will be generated and placed in the current directory.

Step 2: Install Puppeteer

-------------------------

Run the command below to install Puppeteer in your project:

Terminal window

    1npm install puppeteer

During the installation process Puppeteer also automatically downloads a recent version of Chromium that will be used behind the scene to execute browser commands.

Step 3: Create the script

-------------------------

Now we can create the **index.js** file in the project directory. This is where we put the code to make screenshots with Puppeteer.

    1// Include Puppeteer2const puppeteer = require("puppeteer");3

    4(async () => {5  // Create a browser instance6  const browser = await puppeteer.launch();7

    8  // Create a new page9  const page = await browser.newPage();10

    11  // Set viewport width and height12  await page.setViewport({ width: 1280, height: 720 });13

    14  // Open a URL15  await page.goto("https://screenshotone.com", { waitUntil: "networkidle0" });16

    17  // Capture screenshot18  await page.screenshot({ path: "screenshot.jpg" });19

    20  // Close the browser instance21  await browser.close();22})();

Execute the code by running **node index.js** in your terminal and you should see the new file “screenshot.jpg” appearing in the project directory.

We are ready to integrate performance monitoring.

Step 4: Install Inspector for Nodejs

------------------------------------

Run the command below to install the Inspector nodejs module:

Terminal window

    1npm install @inspector-apm/inspector-nodejs

As recommended in the [official documentation](https://docs.inspector.dev/guides/pure-nodejs), you should initialize the module at the beginning of the script. Before requiring any other module.

To get an Ingestion Key you have to [register an account](https://app.inspector.dev/register) on Inspector and create a new project.

Other than the initializing the module I start the transaction at line 15. This line tell Inspector to start monitoring.

    1/*2 * -------------------------------------------3 * Initialize Inspector with the Ingestion Key.4 * -------------------------------------------5 */6const inspector = require("@inspector-apm/inspector-nodejs")({7  ingestionKey: "9cd5715238227ada16ed0f0e2e5323434ce1437b",8});9

    10// Include Puppeteer11const puppeteer = require("puppeteer");12

    13(async () => {14  // Start a transaction15  let transaction = inspector.startTransaction("puppeteer");16

    17  // Create a browser instance18  const browser = await puppeteer.launch();19

    20  // Create a new page21  const page = await browser.newPage();22

    23  // Set viewport width and height24  await page.setViewport({ width: 1280, height: 720 });25

    26  // Open a URL27  await page.goto("https://inspector.dev", { waitUntil: "networkidle0" });28

    29  // Capture screenshot30  await page.screenshot({ path: "screenshot.jpg" });31

    32  // Close the browser instance33  await browser.close();34

    35  transaction.setResult("success");36})();

After running the script you should see the new transaction coming in your dashboard:

Now we are aware that the execution of the script takes 4.5 seconds and uses 18MB of memory. But… What is the impact of each statement inside the script?

Step 5: Enrich your timeline

----------------------------

The inspector library has a really simple API to add custom segments during a transaction. You can wrap any line of codes you write into the `addSegment()` method to monitor the impact they have within the execution flow.

Here is the script with segments:

    1/*2 * -------------------------------------------3 * Initialize Inspector with the Ingestion Key.4 * -------------------------------------------5 */6const inspector = require('@inspector-apm/inspector-nodejs')({7    ingestionKey: 'xxxxxxxxxxxxxxxxxxx'8});9

    10// Include Puppeteer11const puppeteer = require('puppeteer');12

    13(async () => {14    // Start a transaction15    let transaction = inspector.startTransaction("puppeteer");16

    17    // Create a browser instance18    const browser = await inspector.addSegment(segment => {19        return puppeteer.launch();20    }, 'launch');21

    22    // Create a new page23    const page = await inspector.addSegment(async segment => {24        console.log('Create a new page');25        return await browser.newPage();26    }, 'new-page');27

    28    // Set viewport width and height29    await page.setViewport({width: 1280, height: 720});30

    31    // Open a URL32    await inspector.addSegment(async segment => {33        await page.goto('https://screenshotone.dev', {waitUntil: 'networkidle0'});34    }, 'goto', 'https://screenshotone.com35

    36    // Capture screenshot37    await inspector.addSegment(async segment => {38        await page.screenshot({path: 'screenshot.jpg'});39    }, 'screenshot', true);40

    41    // Close the browser instance42    await browser.close();43

    44    transaction.setResult('success');45})();

Execute the script again running the command **node index.js** in your terminal.

Now you can explore the execution details of each task in the script. And you will immediately see that the most impactful task is the opening of the URL.

Step 6: Detect Errors

---------------------

It would be even more useful to receive alerts in case an exception is thrown at runtime and execution fails. The tool and the library should allow you to catch these events.

Inspector detects unhandled errors by default. You can try adding a `throw` statement to simulate an error making the screenshot.

    1/*2 * -------------------------------------------3 * Initialize Inspector with the Ingestion Key.4 * -------------------------------------------5 */6const inspector = require('@inspector-apm/inspector-nodejs')({7    ingestionKey: '9cd5715238227ada16ed0f0e2e5323434ce1437b'8});9

    10// Include Puppeteer11const puppeteer = require('puppeteer');12

    13(async () => {14    // Start a transaction15    let transaction = inspector.startTransaction("puppeteer");16

    17    // Create a browser instance18    {...}19

    20    // Create a new page21    {...}22

    23    // Set viewport width and height24    {...}25

    26    // Open a URL27    {...}28

    29    // Capture screenshot (Throw Error)30    throw new Error('Unable to write file.');31

    32    {...}33})();

You will immediately receive an alert via email and a complete report will be available in project dashboard.

Conclusion

----------

I hope the code snippets have been helpful for you to better understand what performance monitoring is in practical terms.

You can use this script to compare the performance of different headless browsers for example (like, [Puppeteer](https://pptr.dev/) or [Selenium](https://www.selenium.dev/)) and make a better decision about which one to use in your scripts.

If you want learn more about Inspector, visit the official website—[inspector.dev](https://inspector.dev).

Read more Puppeteer guides

--------------------------

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

[View all posts](/blog/tags/puppeteer-guides/)

#### [How to generate PDFs with Puppeteer](/blog/how-to-generate-pdf-with-puppeteer/)

A practical and working guide on how to generate PDFs with Puppeteer.

Read more

#### [How to hide cookie banners when taking a screenshot with Puppeteer](/blog/how-to-hide-cookie-banners-when-taking-a-screenshot-with-puppeteer/)

When taking a screenshot, you want to ensure that you take a clean screenshot without cookie banners or cookie consent forms. And in this article, I will share with you how you can do it when using Puppeteer.

Read more

#### [Puppeteer waitUntil: how to wait for page load](/blog/puppeteer-wait-until-the-page-is-ready/)

Join me in exploring how to find the ideal wait time or event of when to take the page screenshot with Puppeteer.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/a-friendly-guide-on-how-to-render-html-or-site-screenshots-in-google-sheets-in-less-than-10-minutes
----

A friendly guide on how to render HTML or site screenshots in Google Sheets in less than 10 minutes

===================================================================================================

It is not the first time that one of the ScreenshotOne users asked how to render screenshots in Google Sheets. I wrote a simple but complete tutorial once and for all.

[Blog post](/blog/) 3 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Mar 5, 2023

You can do it in 3 simple steps:

1.  Sign up to ScreenshotOne and get an access key to a website screenshot API.

2.  Prepare a screenshot URL template.

3.  Render site screenshots in Google Sheets.

That will be our final result:

You can copy and modify [the sheet](https://docs.google.com/spreadsheets/d/198RLj7ooateEIPxDMdoYaPD6yjHyLGsFO_ir8xdS_jA/edit?usp=sharing) for you needs.

Let’s quickly go through each step and its nuances in achieving the result.

Get an access key to the website screenshot API

-----------------------------------------------

To render screenshots, you need to get an access key to [the ScreenshotOne API](https://screenshotone.com/).

The API is free to start with 100 monthly screenshots to ensure you are satisfied with the quality before subscribing and paying.

You also might consider using other [screenshot APIs](/the-best-screenshot-api/). It is up to you. Most of the APIs have more or less the same format so that you can apply the tutorial for them too.

Once you have an access key, we can move to the next step and prepare a website screenshot URL template that we will use to fetch images.

Prepare a screenshot URL template

---------------------------------

Before rendering screenshots, we need to set up an API URL template for requests. Without any advanced options, it might look like this:

    1https://api.screenshotone.com/take?access_key=<your access key>&url=

It is important the URL is the last one and is empty because we are going to set it for each cell. If you need more parameters, add them in between, like:

    1https://api.screenshotone.com/take?access_key=<your access key>&delay=5&full_page=true&url=

Put the template in a separate cell or page—choose what works best for you.

And let’s render screenshots.

Render website screenshots

--------------------------

If you plan to share or expose links of the screenshots, use [signed links](/docs/signed-requests/) to don’t allow using your API key even if exposed. And require singing for every request (in the “dashboard” app).

For example I created 3 columns table with a readable name of the site, site URL, and screenshot:

Let’s use the CONCAT and [the IMAGE](https://support.google.com/docs/answer/3093333?hl=en) functions to render screenshots.

The CONCAT function concatenates strings, so by joining the URL template and the site URL, we will receive the actual URL of the screenshot, and by applying the IMAGE function, we can render it. You can copy the formula:

    1=IMAGE(CONCAT(B1, B4))

Applying the formula to each row will result in what we wanted to achieve:

Google Sheets don’t render screenshots immediately. It might take some time until you see them.

You can copy and modify [the sheet](https://docs.google.com/spreadsheets/d/198RLj7ooateEIPxDMdoYaPD6yjHyLGsFO_ir8xdS_jA/edit?usp=sharing) for you needs.

Signed Links

------------

We need to make a few changes to use signed links instead of regular links. Let’s add the function allowing us to sign the query string for every request and return the signed screenshot URL.

Open the “Apps Script” editor:

Copy and paste the following function:

    1function SIGNED_REQUEST_URL(siteUrl, queryString, accessKey, secretKey) {2    const forSigning =`url=${siteUrl}&${queryString}&access_key=${accessKey}`;3

    4    const hash = Utilities.computeHmacSha256Signature(forSigning, secretKey);5    let signature = '';6    for (j = 0; j <hash.length; j++) {7        let byte = hash[j];8        if (byte < 0) {9            byte += 256;10        }11        if (byte.toString(16).length == 1) {12            signature += "0";13        }14

    15        signature += byte.toString(16);16    }17

    18    return `https://api.screenshotone.com/take?${forSigning}&signature=${signature}`;19}

Then save it:

Once the function is saved, let’s edit the formula:

And now we have rendered “signed “screenshots:

Feel free to reach the support

------------------------------

That’s it. That’s how simple it was. If you have any questions and decide to go with ScreenshotOne, feel free to ask any questions related to the topic at `support@screenshotone.com`.

Read more posts

---------------

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

[View all posts](/blog/)

#### [How to build a Programmatic SEO site with automated website screenshots using ScreenshotOne, Airtable, and Launchman](/blog/how-to-build-a-programmatic-seo-site-with-automated-website-screenshots-using-screenshotone-airtable-and-launchman/)

Programmatic SEO is a great growth hacking strategy where you create a large number of content pages that rank for long-tailed keywords on Google.

Read more

#### [OpenClaw with Playwright or Puppeteer: how to install browser support](/blog/openclaw-playwright-puppeteer/)

A practical guide to OpenClaw browser automation, why Playwright is the documented path, where Puppeteer fits, how to make screenshots, and when ScreenshotOne is the better choice for screenshot-only flows.

Read more

#### [Alexander Schnebel about how he uses ScreenshotOne in Productglowup](/blog/alexander-schnebel-about-how-he-uses-screenshotone-in-productglowup/)

I had a great chat with Alexander Schnebel, the fullstack software engineer behind Productglowup.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/optimize-for-speed-when-rendering-screenshots-in-puppeteer-and-chrome-devtools-protocol
----

Optimize for speed when rendering screenshots in Puppeteer and Chrome DevTools Protocol

=======================================================================================

Let's talk about the optimizeForSpeed parameter introduced in Chrome DevTools Protocol which will soon be supported by Puppeteer or even supported now at the time when you are reading the post.

[Blog post](/blog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jan 4, 2023

The `optimizeForSpeed` option is introduced in [an update for Chromium](https://github.com/chromium/chromium/commit/c67febd82ae3e18ac8db1397f4ccfa87b0da2ffc#diff-7cf5fa0a4f160d1d4c658c1de7fbf5c19fa3268f1e30bb56a198b189769cb124), allows to use of faster encoding for images, and might increase the performance of taking screenshots by a lot.

Internally, the browser will use faster encoding for PNG, JPEG and WebP formats by restricting compression to `zlib q1`, which is `rle` encoding.

Try the option yourself to see if it improves performance and doesn’t change the quality of your screenshots.

By the way, there is a few related articles you might be interested in:

1.  [Capture beyond viewport in Puppeteer and Chrome DevTools Protocol](/blog/capture-beyond-viewport-in-puppeteer-and-chrome-devtools-protocol).

2.  [Take a screenshot “from the surface” in Puppeteer and Chrome DevTools Protocol](/blog/take-a-screenshot-from-the-surface-in-puppeteer-and-chrome-devtools-protocol).

3.  [A complete guide on how to take full page screenshots with Puppeteer, Playwright or Selenium](/blog/puppeteer-full-page-screenshot).

Read more posts

---------------

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

[View all posts](/blog/)

#### [Unveil the Power of Automation with ScreenshotOne and Zapier](/blog/unveil-the-power-of-automation-with-screenshotone-and-zapier/)

I am thrilled to announce an exciting update for the ScreenshotOne users – the much-anticipated integration of ScreenshotOne with Zapier. This powerful combination is here to enhance your automation journey and expand your workflow capabilities to new heights.

Read more

#### [ScreenshotOne is featured in the Cloudflare "Built With" series](/blog/screenshotone-and-cloudflare/)

The Cloudflare platform is at the core of ScreenshotOne—it is used for caching, API gateway, storage for screenshots, and many other functions. It was an opportunity to learn about the company from a closer distance.

Read more

#### [OpenClaw with Playwright or Puppeteer: how to install browser support](/blog/openclaw-playwright-puppeteer/)

A practical guide to OpenClaw browser automation, why Playwright is the documented path, where Puppeteer fits, how to make screenshots, and when ScreenshotOne is the better choice for screenshot-only flows.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/competitor-price-tracking
----

Automate Website Screenshots

1 min read

Competitor Price Tracking

=========================

Automate the capture of competitor pricing data for analysis.

For businesses in the e-commerce and retail sectors, keeping an eye on competitors’ pricing is crucial for competitive pricing strategies. A screenshot API provides an automated way to capture and archive competitors’ pricing strategies directly from their websites.

Why ScreenshotOne API?

----------------------

ScreenshotOne API allows developers to automate the process of taking screenshots at specified intervals, ensuring that businesses have up-to-date information on competitors’ pricing. This method is far more efficient and less prone to errors than manual tracking, offering a comprehensive view of the market landscape without the need for constant manual oversight.

Value and Time Savings

----------------------

Integrating ScreenshotOne API for competitor price tracking not only saves time but also ensures accuracy and reliability in capturing data. It eliminates the need for manual price monitoring, freeing up resources to focus on analysis and strategic decision-making. Moreover, compared to developing an in-house solution, using ScreenshotOne API is a cost-effective approach that provides immediate benefits without the lengthy development time.

Screenshotone is a game changer. The product works well and is a huge time saver. Most importantly Dmytro has been an amazing support throughout the process and always went the extra mile. Highly recommend.

Ben Machek

CEO, [Aybee](https://www.getaybee.com/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/screenshotone-and-viasocket-integration
----

ScreenshotOne and viaSocket integration

=======================================

Use viaSocket with ScreenshotOne to build workflows that include website screenshot automation.

[Blog post](/blog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Feb 25, 2026

[viaSocket](https://viasocket.com/) is a simple way to turn [ScreenshotOne API](/) calls into reliable no-code or low-code workflows that include website screenshots.

ScreenshotOne for rendering screenshots

---------------------------------------

[ScreenshotOne](/) handles the hard rendering part:

*   loading and rendering modern complex websites;

*   blocks cookie banners, ads and other elements that are not part of the website;

*   waiting for JavaScript;

*   and giving you controls like delay, element blocking, and custom CSS for stable captures.

viaSocket for workflow orchestrations

-------------------------------------

[viaSocket with 2000+ integrations](https://viasocket.com/) handles orchestration around that API call: triggers, authenticated HTTP requests, retries, error branches, and logs. Instead of writing and maintaining your own scheduler and failure handling, you configure the flow visually and keep moving.

An example of how a viaSocket workflow looks like visually:

[](https://viasocket.com/automations/automate-zoho-crm-lead-capture-create-only-if-not-found/b9c8e4cb1221f960ee7521bb1176493672b5ebdec3b296b94ff17e63a59d0b88)

In practice, this combination works well for:

*   scheduled monitoring of key pages;

*   post-deploy visual checks;

*   and [many more screenshot automation use cases](/use-cases/).

Read the [viaSocket launch blog post](https://viasocket.com/blog/automated-website-screenshot-monitoring-using-screenshotone-and-viasocket/) for more details.

[viaSocket also offers a library of ready-to-use automations](https://viasocket.com/automations) that you can use as a foundation for your own workflows.

A good starting point is to test one URL in ScreenshotOne first, find the delay that produces a stable render, and then build a viaSocket workflow around it with explicit error routing.

If your team needs screenshot automation but does not want to run browser infrastructure, viaSocket plus ScreenshotOne is a fast and maintainable setup for no-code or low-code workflows.

Read more posts

---------------

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

[View all posts](/blog/)

#### [ScreenshotOne August 2025 updates](/blog/screenshotone-august-2025-updates/)

Playground presets, screenshot URL in webhooks, improved full‑page rendering, and ownership change for subscribed orgs.

Read more

#### [OpenAI 4o image generation and marketing opportunities](/blog/openai-4o-marketing-opportunities/)

OpenAI 4o image generation is a really good model that can change the way you automate marketing

Read more

#### [Unveil the Power of Automation with ScreenshotOne and Zapier](/blog/unveil-the-power-of-automation-with-screenshotone-and-zapier/)

I am thrilled to announce an exciting update for the ScreenshotOne users – the much-anticipated integration of ScreenshotOne with Zapier. This powerful combination is here to enhance your automation journey and expand your workflow capabilities to new heights.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/llms-full.txt
----

\# ScreenshotOne.com Full Documentation

\# Animated Screenshots

import Alert from "@/components/Alert.astro";
import Video from "@/components/Video.astro";

 In case you need a custom scenario or have propositions, feel free to reach
 out at \`support@screenshotone.com\`.

You can rely on ScreenshotOne API to generate animated screenshots and handle image and video streaming infrastructure.

ScreenshotOne supports animated (including scrollable) screenshots of different types, caching based on the world’s fastest and most potent CDN (Cloudflare), blocking ads, cookie banners, and chats.

In just one API request, you can quickly generate animated screenshots. And if you need more, various scenarios with many options are covered.

Grasp how simple it is:

\`\`\`
https://api.screenshotone.com/animate?url=https://tailwindcss.com&scenario=scroll&access\_key=
\`\`\`

The result might differ a bit in case default options are changed, but as for now, it is similar to what I have shown in the video:

Don't forget that you can use \[signed links to share videos and GIF images publicly\](https://screenshotone.com/docs/signed-requests/), \[caching\](https://screenshotone.com/docs/options/#caching), \[block ads\](/docs/options/#block\_ads), \[block cookie banners\](/docs/options/#block\_cookie\_banners), and \[many other options\](#all-supported-options).

\## Scenarios

Select a basic scenario of how you want to animate screenshots or render ed HTML. Specify additional options and tune the scenario for your use case. And you are good to go.

\### Default (stand still)

Use the \`scenario=default\` parameter, or don't specify \`scenario\` at all when sending a request to \`/animate\`.

The default scenario is to record animation after loading the site without additional animations.

The use case is when you generate animated screenshots of sites that have animations and you want to showcase it.

Look at \[the Handwrytten site\](https://www.handwrytten.com/) as an example. It has a default animation when loaded. So, we won't scroll it or add any other activities.

We will record the site as is after load:

\`\`\`
https://api.screenshotone.com/animate?url=https://www.handwrytten.com/&access\_key=
\`\`\`

The result:

\### Scrollable (scrolling) screenshot

Use the \`scenario=scroll\` parameter, or don't specify \`scenario\` at all when sending a request to \`/animate\`.

There is an example for scrolling \[Senja\](https://senja.io):

\`\`\`
https://api.screenshotone.com/animate?url=https://senja.io&scenario=scroll&access\_key=
\`\`\`

The result is:

These are supported options for scrolling screenshot animation:

\- \`scroll\_delay\`—delay in milliseconds between scrolls. The default value is \`500\`.
\- \`scroll\_duration\`—duration in milliseconds of one scroll. The default value is \`1500\`. The scroll duration is not the duration of the video or animated GIF. Please, use the \`duration\` parameter to specify the length of the video or animated GIF.
\- \`scroll\_by\`—by how many pixes scroll. The default value is \`1000\`.
\- \`scroll\_start\_immediately\`—scroll immediately or wait for the \`scroll\_delay\` milliseconds before scrolling. The default value is \`true\`.
\- \`scroll\_start\_delay\`—wait time (in milliseconds) till starting scrolling. The default value is \`0\`\`.
\- \`scroll\_back\`—scroll back or not. The default value is \`true\`.
\- \`scroll\_back\_algorithm\`—\`once\` is by default and means that it will scroll back immediately once with the easing you have defined. But if you set \`repeat\`, it will repeat the same algorithm the API used to scroll to the bottom of the page.
\- \`scroll\_back\_after\_duration\`—scroll back after the specified duration in milliseconds.
\- \`scroll\_complete\`—stop recording animation when full scrolling is completed. The option \`true\` by default.
\- \`scroll\_stop\_after\_duration\`—stop scrolling after the specified duration in milliseconds. Use \`scroll\_complete=false\` and \`scroll\_back=false\`, to stop and just stand still after the specified duration.
\- \`scroll\_easing\`—use it to define the scrolling easing effect. The default value is \`ease\_in\_out\_quint\`. There is a list of all available options:
 \- \`linear\`–no easing, no acceleration;
 \- \`ease\_in\_quad\`–accelerating from zero velocity;
 \- \`ease\_out\_quad\`–decelerating to zero velocity;
 \- \`ease\_in\_out\_quad\`–acceleration until halfway, then deceleration;
 \- \`ease\_in\_cubic\`–accelerating from zero velocity;
 \- \`ease\_out\_cubic\`–decelerating to zero velocity;
 \- \`ease\_in\_out\_cubic\`–acceleration until halfway, then deceleration;
 \- \`ease\_in\_quart\`–accelerating from zero velocity;
 \- \`ease\_out\_quart\`–decelerating to zero velocity;
 \- \`ease\_in\_out\_quart\`–acceleration until halfway, then deceleration;
 \- \`ease\_in\_quint\`–accelerating from zero velocity;
 \- \`ease\_out\_quint\`–decelerating to zero velocity;
 \- \`ease\_in\_out\_quint\`–acceleration until halfway, then deceleration.
\- \`scroll\_try\_navigate\`—navigate while scrolling and record the new opened page.
\- \`scroll\_navigate\_after\`—navigate after duration in milliseconds, by default it is half of the duration.
\- \`scroll\_navigate\_to\_url\`—to what URL navigate;
\- \`scroll\_navigate\_link\_hints\`—if the URL is not specified, the hints of what links to use, by default \`'pricing', 'about', 'customers'\`. E.g. "pricing" means to open any internal link which has the "pricing" keyword in its text;
\- \`scroll\_till\_selector\`—scroll till the selector is visible;
\- \`scroll\_till\_selector\_adjust\_top\`—adjust the top position of the selector in the viewport;
\- \`scroll\_to\_end\_after\`—scroll to the end after the specified duration in milliseconds with the specified easing in one scroll.

There is an example of applying custom options for scrolling \[Senja\](https://senja.io):

\`\`\`
https://api.screenshotone.com/animate?url=https://senja.io&scenario=scroll&scroll\_delay=400&scroll\_by=400&access\_key=
\`\`\`

The result is:

\### Navigation

You can record a page navigation when recording scrolling screenshot video. It allows render less boring and more engaging videos.

It is rendered with a simple request like:

\`\`\`
https://api.screenshotone.com/animate?url=https://screenshotone.com/&scenario=scroll&duration=10&scroll\_try\_navigate=true&scroll\_navigate\_link\_hints=pricing&access\_key=
\`\`\`

You need to specify either the "scroll\_navigate\_to\_url" or the "scroll\_navigate\_link\_hints" options.
If neither is specified, any first random visible internal link will be used for navigation if available.

The \`scroll\_navigate\_link\_hints\` option can be used as an array:

\`\`\`
scroll\_navigate\_link\_hints\[\]=pricing&scroll\_navigate\_link\_hints\[\]=about
\`\`\`

The API will attempt to find any internal links that match the hints.

\## All supported options

\### Animation specific

\#### format

Available response formats:

\- \`mp4\`
\- \`mov\`
\- \`avi\`
\- \`webm\`
\- \`gif\`

Default value is \`mp4\`.

\#### duration

 If you need a longer animation, please, reach out at
 \`support@screenshotone.com\` and describe your use case.

The default value is \`5\` seconds (\`duration=5\`).

The minimum value is \`1\` and the maximum is \`30\`.

Suppose \`scroll\_complete\` is set to \`true\`, which is by default, and \[the scrolling scenario\](/docs/animated-screenshots/#scrollable-scrolling-screenshot)) is completed earlier than the specified \`duration\`. In that case, the recording will be stopped, and the resulting animation will be short.

Since GIFs are not videos, but images, the duration might not be mapped exactly to the number of frames and represent the duration as is for the video. It is better to consider it as a duration of recording of the video, and then frames glued together into a GIF.

\#### width

You must specify both the \`width\` and \[height\](#height) parameters. You can't specify only one. By default, the width and the height parameters are the same as \[viewport width\](/docs/options/#viewport\_width) and \[viewport height\](/docs/options/#viewport\_height) parameters.

\[The device scale factor\](/docs/options/#device\_scale\_factor) is taken into consideration. If you set the viewport width and height to \`1000x500\`, with \`device\_scale\_factor=1\`, the resulting resolution of the video will be \`1000x500\`, but with \`device\_scale\_factor=2\`, it will be \`2000x1000\`.

If \[aspect ratio\](#aspect\_ratio) is specified, \`width\` and \`height\` are not used. And API will try to fit the video of the viewport size into the specified aspect ratio.

\#### height

You must specify both the \[width\](#width) and \`height\` parameters. You can't specify only one. By default, the width and the height parameters are the same as \[viewport width\](/docs/options/#viewport\_width) and \[viewport height\](/docs/options/#viewport\_height) parameters.

\[The device scale factor\](/docs/options/#device\_scale\_factor) is taken into consideration. If you set the viewport width and height to \`1000x500\`, with \`device\_scale\_factor=1\`, the resulting resolution of the video will be \`1000x500\`, but with \`device\_scale\_factor=2\`, it will be \`2000x1000\`.

If \[aspect ratio\](#aspect\_ratio) is specified, \`width\` and \`height\` are not used. And API will try to fit the video of the viewport size into the specified aspect ratio.

\#### aspect ratio

If \[aspect ratio\](#aspect\_ratio) is specified, \`width\` and \`height\` are not used. And API will try to fit the video of the viewport size into the specified aspect ratio.

\#### scenario

Available scenarios formats:

\- not specified or \`default\` is for \[the default animation scenario\](#default-stand-still).
\- \`scroll\` is for \[the scrolling screenshots\](#scrollable-scrolling-screenshot).

The default value is \`default\`.

\#### clip

You can clip part of the video. But currently, it is only available when the format is \`gif\`.

Use \`clip\_width\`, \`clip\_height, \`clip\_x\`and\`clip\_y\` to specify the clip size and coordinates.

\### Regular

Animated screenshots also support most options supported by regular image screenshots. There is a list of supported options:

\- \`omit\_background\` but only for the \`mov\` format;
\- \[credentials\](/docs/options/#credentials);
\- \[essentials\](/docs/options/#essentials), except \`selector\` and with different values for \[format\](#format);
\- \[viewport\](/docs/options/#viewport);
\- \[emulations\](/docs/options/#emulations);
\- \[customization\](/docs/options/#customization);
\- \[blocking\](/docs/options/#blocking);
\- \[geolocation\](/docs/options/#geolocation);
\- \[request\](/docs/options/#request);
\- \[wait\](/docs/options/#wait);
\- \[caching\](/docs/options/#caching);
\- \[storing\](/docs/options/#storing).

\# Async and Webhooks

import Alert from "@/components/Alert.astro";

ScreenshotOne supports asynchronous screenshot rendering and webhooks. The document describes both of them in one
place since usually they are used together.

The main current supported use case is to render screenshots asynchronously, \[upload them to S3\](/docs/upload-to-s3/) and return the file location to the specified webhook. That's what customers asked to implement first.

\## Async

You can literally execute any request asynchronously by setting the \`async\` option to \`true.\` But not every request makes sense to execute asynchronously.

Once you set \`async=true,\` the API checks your access key and limits and returns the response immediately but continues to execute the request.

One of the top use cases for which it was requested is uploading files to S3 asynchronously without waiting for screenshots to be rendered.

An example of such a request could be:

\`\`\`
https://api.screenshotone.com/take?access\_key=0MpjJxw8Vk7ZAw&url=https://example.com&store=true&storage\_path=example.com&response\_type=json&async=true
\`\`\`

You request rendering but don't wait for the response. What if you want to get the result of uploading? You can do it by using webhooks.

\## Webhooks

Using webhooks with ScreenshotOne allows you to deliver the results of the request execution to your URL as a POST body.

 Currently, caching is not supported for webhooks since it doesn't make much
 sense. If you need its support for other use cases, please, send a chat
 message or email to \`support@screenshotone.com\`.

You can use webhooks with both synchronous and asynchronous requests. But usually, it is used in combination with asynchronous requests.

An example of an asynchronous request that uploads rendered screenshot to S3 and sends a webhook might look like this:

\`\`\`
https://api.screenshotone.com/take?access\_key=
 &url=https://example.com
 &store=true
 &storage\_path=example.com
 &response\_type=json
 &async=true
 &webhook\_url=
 &storage\_return\_location=true
\`\`\`

Not that, to get the location, you must specify the \`storage\_return\_location\` parameter as \`true\`.

An example of the webhook request body you will receive:

\`\`\`
{
 "screenshot\_url": "...",
 // ...
 "store": {
 // ...
 "location": "..."
 },
}
\`\`\`

You also receive the \`X-ScreenshotOne-Signature\` (\`x-screenshotone-signature\`) header that you should use to validate the webhook request body and make sure that ScreenshotOne sent the request.

If you do not upload the screenshot to any S3-compatible storage, you will receive \[the \`screenshot\_url\`\](/docs/screenshot-url/) in the response body if you set \`response\_type=json\`:

\`\`\`json
{
 // ...
 "screenshot\_url": "..."
}
\`\`\`

If you don't specify the \`response\_type\` parameter as \`json\`, you will receive the screenshot in the binary format in the response body.

\`\`\`

\`\`\`

\### Verifying Signature

To ensure that ScreenshotOne sent the request, you should get the signature from the \`X-ScreenshotOne-Signature\` header and verify it with your secret key from \[the access page\](https://dash.screenshotone.com/access) by applying the HMAC SHA-256 algorithm.

 Never share your secret key with any party. In case it is leaked, you can
 quickly regenerate it on \[the access\
 page\](https://dash.screenshotone.com/access).

A pseudo-code on TypeScript (Node.js) of how you can do it:

\`\`\`javascript
import \* as crypto from "crypto";

const receivedSignature = request.headers.get("x-screenshotone-signature");
const requestBody = await request.rawText();

const calculatedSignature = crypto
 .createHmac("sha256", yourSecretKey)
 .update(requestBody, "utf-8")
 .digest("hex");

if (calculatedSignature !== receivedSignature) {
 // the signature is not valid
 // you should not process this request and reject it immediately
 throw new Error("...");
}

// it is safe to process the request
// you can do something with the webhook request body
\`\`\`

\### Disable Signing

Singing webhook request body takes time. If you are sure that your webhooks are unique and secret, you might want to disable signing to improve performance by using \`webhook\_sign=false\`.

\### Debugging and support headers

There are a few headers that are not part of the body and are not participating in the signing. They must not be used for any logic; it is just for debugging and support purposes:

\- \`x-screenshotone-rendering-seconds\`—screenshot rendering time in seconds with fractions, e.g. \`2.56\`;
\- \`x-screenshotone-size-bytes\`—screenshot size if available (not streaming), e.g. \`30033\`;
\- \`x-screenshotone-trace-id\`—unique request trace id when reaching out to the ScreenshotOne support;
\- \`x-screenshotone-reference\`—screenshot or video id (if available) that can be seen in the history or used when reaching out to the ScreenshotOne support.

\### External identifier

You can set \`external\_identifier\` parameter to any alphanumeric value. It will be included in the webhook request headers:

\- \`x-screenshotone-external-identifier\`—external identifier. It is helpful for error tracking and successful request tracking.

\### Webhook errors

We currently don't support a separate endpoint to send webhook errors. But you can still get them in the webhook request body or headers.

By default, errors are not sent to the webhook URL, at all. But if you want to get them, you can set \`webhook\_errors=true\` parameter.

And you will get error details in the webhook request body if the JSON response type is used:

\`\`\`javascript
{
 // ...
 "error\_code": "...",
 "error\_message": "...",
 "documentation\_url": "..."
}
\`\`\`

Or always in the headers:

\- \`x-screenshotone-error-code\`—error code;
\- \`x-screenshotone-error-message\`—error message;
\- \`x-screenshotone-documentation-url\`—documentation URL about the error.

Check out all possible error codes in the \[API error reference\](/docs/errors/).

\### Testing webhook errors

You can test it with an URL like this \`https://example.com/404\`. It will trigger an error.

In general, it is enough to check for the error code presence or absence of the screenshot URL/binary data to determine if the request was successful or not.

In the worst case scenario, you might assume if you haven't been notified about any errors or successful requests, likely the request has been failed.

\## Summary

That's it. In case you have any questions or problems, feel free to write to \`support@screenshotone.com\`.

\# Bulk Screenshots

import Alert from "@/components/Alert.astro";

:::tip
Our bulk screenshots API endpoint is a simple wrapper endpoint around the regular screenshot API endpoints like (\`/take\`, \`/animate\`, and similar). But since it is a simple wrapper, you might find it much better to implement your own bulk screenshot solution. Check out our guide on \[how to take screenshots of multiple URLs\](/docs/guides/bulk-screenshots/) with ScreenshotOne API.
:::

\## Request

You can use a bulk screenshot-taking feature to take many screenshots in one request.
Send a simple POST HTTP request to \`/bulk\` path with the list of URLs (HTML or Markdown):

\`\`\`
POST https://api.screenshotone.com/bulk

{
 "access\_key": ""
 "execute": false,
 "optimize": false,
 "options": {"url": "https://example.com", "viewport\_width": 1280, "viewport\_height": 1024, "block\_ads": true},
    "requests": \[\
 {"viewport\_width": 360, "viewport\_height": 640}, // a screenshot of example.com with a different viewport\
        {"url": "https://example.com"},\
        {"url": "https://finance.yahoo.com", "block\_cookie\_banners": true},\
        {"html": "\
\
# Hello, world!\
\
", "block\_ads": false},\
        {"markdown": "\*\*Yes!\*\*"}\
    \]
}
\`\`\`

The options property contains default options that will be applied to every request. And for every request, you can specify options to override the default values. You can specify all \[the regular options you use to take a single screenshot\](/docs/options).

You can specify the access key as a query parameter \`access\_key=\`, an HTTP header \`X-Access-Key: \`, or in the request's body.

\## Response

The response contains an array of screenshot URLs you can use to download the screenshots:

\`\`\`json
{
 "responses": \[\
 {"url": "https://api.screenshotone.com/take?url=http://example.com&viewport\_width=1280&viewport\_height=1024&block\_ads=true"},\
 {"url": "https://api.screenshotone.com/take?url=https://finance.yahoo.com&viewport\_width=1280&viewport\_height=1024&block\_ads=true&block\_cookie\_banners=true"},\
 {"url": "https://api.screenshotone.com/take?html=\
\
# Hello, world!\
\
&viewport\_width=1280&viewport\_height=1024&block\_ads=false&block\_cookie\_banners=true"}\
 \]
}
\`\`\`

But if you requested to \[execute requests\](#execute-requests), the result will also contain a summary execution response for each request:

\`\`\`
\[\
 {\
 "url": "https://api.screenshotone.com/take?url=http://example.com&viewport\_width=1280&viewport\_height=1024&block\_ads=true",\
 "response": {\
 "is\_successful": true,\
 "status": 200,\
 "statusText": "OK"\
 }\
 },\
 {\
 "url": "https://api.screenshotone.com/take?url=https://finance.yahoo.com&viewport\_width=1280&viewport\_height=1024&block\_ads=true&block\_cookie\_banners=true",\
 "response": {\
 "is\_successful": true,\
 "status": 200,\
 "statusText": "OK"\
 }\
 },\
 {\
 "url": "https://api.screenshotone.com/take?html=\
\
# Hello, world!\
\
&viewport\_width=1280&viewport\_height=1024&block\_ads=false&block\_cookie\_banners=true",\
 "response": {\
 "is\_successful": true,\
 "status": 200,\
 "statusText": "OK"\
 }\
 },\
 {\
 "url": "https://api.screenshotone.com/take?markdown=\*\*Yes!\*\*&viewport\_width=1280&viewport\_height=1024&block\_ads=false&block\_cookie\_banners=true",\
 "response": {\
 "is\_successful": true,\
 "status": 200,\
 "statusText": "OK"\
 }\
 }\
\]
\`\`\`

As you noticed, images are not returned, but in case of an error, the \`is\_successful\` property will be \`false\`, and you can expect the \`body\` property to explore the error:

\`\`\`
\[\
 {\
 "url": "https://api.screenshotone.com/take?url=http://example.com&viewport\_width=1280&viewport\_height=1024&block\_ads=true",\
 "response": {\
 "is\_successful": false,\
 "status": 400,\
 "statusText": "Bad request",\
 body: {\
 "error\_code": "concurrency\_limit\_reached"\
 "error\_message": "Concurrency limit is reached"\
 }\
 }\
 }\
\]
\`\`\`

\## Execute requests

Bulk screenshots are implemented in a lazy loading way. It means that the screenshot is literally taken when you tried to download it, not when you sent a bulk request. If you want to execute each request before you get a response, set the parameter \`execute\` to \`true\`:
\`\`\`
POST https://api.screenshotone.com/bulk

{
 "access\_key": ""
 "execute": true,
 // ...
}
\`\`\`

But make sure to wait enough time until all the screenshots are done.

\## Optimizations

To take bulk screenshots faster, you can use the optimization feature if you want to take bulk screenshots for the same URLs (HTML or Markdown) but with a different set of parameters:

\`\`\`
POST https://api.screenshotone.com/bulk

{
 "access\_key": ""
 "execute": true,
 "optimize": true,
 "options": {"url": "https://example.com", "viewport\_width": 1280, "viewport\_height": 1024},
    "requests": \[\
 {"viewport\_width": 360, "viewport\_height": 640}, // a screenshot of example.com with a different viewport\
 {"viewport\_width": 736, "viewport\_height": 414}\
    \]
}
\`\`\`

The feature only works when \`execute\` is set to \`true\`.

The optimization is not guaranteed since many sites can reload and take the same time to render in case the viewport is changed. And some options, like blocking and not blocking ads, do require a page reload, which takes the same time as not using optimization at all.

The best approach is to test if it works for your use case.

\## Use cases

\### Upload bulk screenshots to S3-compatible storage

In the example, I want to take screenshots for one site but for different devices and upload them to \[S3-compatible storage\](https://screenshotone.com/docs/options/#storing):

\`\`\`
POST https://api.screenshotone.com/bulk

{
 "access\_key": ""
 "execute": true,
 "options": {"url": "https://example.com", "store": true, "response\_type": "empty"},
    "requests": \[\
 {"viewport\_device": "pixel\_4a\_5g\_landscape", "storage\_path": "pixel\_4a\_5g\_landscape"},\
 {"viewport\_device": "iphone\_13\_pro", "storage\_path": "iphone\_13\_pro"},\
 {"viewport\_device": "iphone\_13", "storage\_path": "iphone\_13"}\
    \]
}
\`\`\`

In this example, I upload screenshots taken from different devices and save the files with the names of the devices.

\## Limitations

Currently, only up to 20 requests are supported in the one bulk request.

\# Errors

import Alert from "@/components/Alert.astro";

 There is \[a detailed guide\](/docs/guides/how-to-handle-api-errors/) on how
 to handle the ScreenshotOne API errors.

The request might return an error due to an internal error, invalid options or when the limit is reached. Our screenshot API follows the HTTP status code semantic and returns JSON in case of an error:

\`\`\`
GET https://api.screenshotone.com/?\[options\]

Content-Type: application/json
{
 "is\_successful": false,
 "error\_code": "an\_error\_code",
 "error\_message": "An error message",
 "documentation\_url": "..."
}
\`\`\`

The API will always return a human-readable error message, error code as a string key, and suitable HTTP status code.

\## Codes with explanations

\| Error Code \| HTTP Status \| Explanation \|
\| \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- \| \-\-\-\-\-\-\-\-\-\-\- \| \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- \|
\| \[access\_key\_required\](/docs/errors/access-key-required/) \| 400 \| The "access\_key" parameter is required. Please, check out \[the access page\](https://dash.screenshotone.com/access) to get the access key. \|
\| \[access\_key\_invalid\](/docs/errors/access-key-invalid/) \| 400 \| The "access\_key" parameter is given, but it is not correct. Please, check out \[the access page\](https://dash.screenshotone.com/access) to check the access key. \|
\| \[signature\_is\_required\](/docs/errors/signature-is-required/) \| 400 \| The "signature" parameter is required. Because signing requests is required in \[the access page\](https://dash.screenshotone.com/access). Make sure you use \[the correct signing algorithm\](/docs/signed-requests/). \|
\| \[signature\_is\_not\_valid\](/docs/errors/signature-is-invalid/) \| 400 \| You provided the "signature" parameter, but it is not valid. Make sure you use \[the correct signing algorithm\](/docs/signed-requests/). \|
\| \[screenshots\_limit\_reached\](/docs/errors/usage-quota-exceeded/) \| 400 \| The usage quota has been exceeded. Please, either upgrade to a plan with more quota or change the maximum allowed limit (if possible) in the ScreenshotOne dashboard. If it is a mistake, please, reach out at \`support@screenshotone.com.\` \|
\| \[concurrency\_limit\_reached\](/docs/errors/concurrency-limit-reached/) \| 400 \| You reached the request concurrency limit, retry after a while. Or feel free to \[upgrade you current plan\](https://dash.screenshotone.com/subscription). \|
\| \[request\_not\_valid\](/docs/errors/request-invalid/) \| 400 \| The request parameters are not valid. You can look at the \`error\_details\` response field to get the details. \|
\| \[selector\_not\_found\](/docs/errors/selector-not-found/) \| 400 \| If \[selector\](/docs/options#selector) is specified and \`error\_on\_selector\_not\_found=true\`, the error will be returned if the element by selector is not visible or it took more than \`timeout\` seconds to render it, but not more than 30 seconds. \|
\| \[name\_not\_resolved\](/docs/errors/name-not-resolved/) \| 400 \| Usually, the error happens when the domain name of the requested URL is not resolved. If you are trying to take a screenshot of the new site, please, wait a bit until the DNS records are refreshed. \|
\| \[network\_error\](/docs/errors/network-error/) \| 500 \| The error happens when the API can't connect to the provided URL. It might mean that the site blocks the API or is temporarily unavailable. Generally, you can safely retry to take a screenshot. \|
\| \[invalid\_storage\_configuration\](/docs/errors/invalid-storage-configuration/) \| 400 \| If you haven't created the bucket in the \`us-east-1\` AWS region, please, specify your bucket region through an endpoint in a format like \`https://s3..amazonaws.com\`. \|
\| \[script\_triggers\_redirect\](/docs/errors/script-triggers-redirect/) \| 400 \| The specified "scripts" option might trigger a redirect, please, specify the "scripts\_wait\_until" option. If you think it is a mistake, please, reach out at \`support@screenshotone.com\`. \|
\| \[host\_returned\_error\](/docs/errors/host-returned-error/) \| 500 \| If the host doesn't respond successfully within the range of 200-299 status codes, the API won't take a screenshot. You can force the API to take a screenshot of the error page by specifying \[ignore\_host\_errors=true\](/docs/options#ignore\_host\_errors). You can get the returned status code from the site by reading the \`returned\_status\_code\` field. \|
\| \[timeout\_error\](/docs/errors/timeout/) \| 500 \| The screenshot couldn't be taken within the specified timeout. Either the site doesn't respond quickly, or rendering takes longer than expected. Play with the \`timeout\` or the \`navigation\_timeout\` options or reach the support for the investigation. \|
\| \[internal\_application\_error\](/docs/errors/internal-application-error/) \| 500 \| The API failed to serve your request. You can safely replay the request. We are notified about it instantly and will try to fix it as soon as possible. If the error is repeated for a long time, feel free to reach out at support@screenshotone.com. \|
\| \[storage\_access\_denied\](/docs/errors/storage-access-denied/) \| 400 \| Failed to upload the screenshot to the storage since access was denied. Check the API keys you specify when using the storage integration. \|
\| \[storage\_returned\_transient\_error\](/docs/errors/storage-returned-transient-error/) \| 500 \| The storage returned an HTTP status code between 500 and 599 and we exhausted retries. You can likely retry the request again. \|
\| \[request\_aborted\](/docs/errors/request-aborted/) \| 500 \| The request was aborted either by the user or the intermediate proxies and can't be fulfilled. If the error persists, please, reach out to support@screenshotone.com. \|
\| \[content\_contains\_specified\_string\](/docs/errors/content-contains-specified-string/) \| 500 \| The page content contains the specified string by the \[fail\_if\_content\_contains\](/docs/options#fail\_if\_content\_contains) option. If it seems to be a mistake or not what you expected, please, reach out to \\\`support@screenshotone.com\\\` as quickly as possible, and will assist and try to resolve your problem. \|
\| \[temporary\_unavailable\](/docs/errors/temporary-unavailable/) \| 503 \| The API is temporarily unavailable due to an error or overload. Please wait a bit and then safely retry your request. \|
\| \[invalid\_cookie\_parameter\](/docs/errors/invalid-cookie-parameter/) \| 400 \| The \`cookies\` parameters you provided are invalid. Please, consider providing different values and adhere to the format specified in the ScreenshotOne documentation. \|
\| \[resulting\_image\_too\_large\](/docs/errors/resulting-image-too-large/) \| 400 \| The resulting image is too large for the specified format. Please, consider providing different values and adhere to the format specified in the ScreenshotOne documentation. \|
\| \[matched\_failed\_request\](/docs/errors/matched-failed-request/) \| 500 \| The request matched by the specified pattern by the \[fail\_if\_request\_failed\](/docs/options#fail\_if\_request\_failed) option has been failed. If it seems to be a mistake or not what you expected, please, reach out to \\\`support@screenshotone.com\\\` as quickly as possible, and will assist and try to resolve your problem. \|
\| \[invalid\_header\_parameter\](/docs/errors/invalid-header-parameter/) \| 400 \| The \`headers\` parameters you provided are invalid. Please, consider providing different values and adhere to the format specified in the ScreenshotOne documentation. \|
\| \[request\_body\_too\_large\](/docs/errors/request-body-too-large/) \| 413 \| The request body is too large. Please, reduce the size of the request body or reach out to \\\`support@screenshotone.com\\\` for assistance. \|

\## List of all errors

1\. \[Timeout error\](/docs/errors/timeout/).
2\. \[Storage Access Denied\](/docs/errors/storage-access-denied/).
3\. \[Script Trigger Redirect\](/docs/errors/script-triggers-redirect/).
4\. \[Internal Application Error\](/docs/errors/internal-application-error/).
5\. \[Usage Quota Exceeded\](/docs/errors/usage-quota-exceeded/).
6\. \[Request Aborted\](/docs/errors/request-aborted/).
7\. \[Access Key Required\](/docs/errors/access-key-required/).
8\. \[Access Key Invalid\](/docs/errors/access-key-invalid/).
9\. \[Signature Is Required\](/docs/errors/signature-is-required/).
10\. \[Signature Is Not Valid\](/docs/errors/signature-is-invalid/).
11\. \[Screenshots Limit Reached\](/docs/errors/usage-quota-exceeded/).
12\. \[Concurrency Limit Reached\](/docs/errors/concurrency-limit-reached/).
13\. \[Request Not Valid\](/docs/errors/request-invalid/).
14\. \[Selector Not Found\](/docs/errors/selector-not-found/).
15\. \[Name Not Resolved\](/docs/errors/name-not-resolved/).
16\. \[Network Error\](/docs/errors/network-error/).
17\. \[Invalid Storage Configuration\](/docs/errors/invalid-storage-configuration/).
18\. \[Host Returned Error\](/docs/errors/host-returned-error/).
19\. \[Storage Returned Transient Error\](/docs/errors/storage-returned-transient-error/).
20\. \[Content Contains Specified String\](/docs/errors/content-contains-specified-string/).
21\. \[Temporary Unavailable\](/docs/errors/temporary-unavailable/).
22\. \[Invalid Cookie Parameter\](/docs/errors/invalid-cookie-parameter/).
23\. \[Resulting Image Too Large\](/docs/errors/resulting-image-too-large/).
24\. \[Matched Failed Request\](/docs/errors/matched-failed-request/).
25\. \[Invalid Header Parameter\](/docs/errors/invalid-header-parameter/).
26\. \[Request Body Too Large\](/docs/errors/request-body-too-large/).

\# How credits work in ScreenshotOne

:::note
Currently, everything costs 1 credit, be it a full-page screenshot, a scrolling screenshot, a PDF, or a video.

It is done that way to keep the pricing simple and predictable.
:::

Every plan on ScreenshotOne comes with a monthly credit allowance. Credits reset at the start of each billing cycle—regardless of whether you’re on a monthly or annual plan.

\- \*\*Monthly plans\*\*: Credits refresh on the same day you subscribed each month.
\- \*\*Annual plans\*\*: You pay once per year, but your credits still refresh monthly, giving you a predictable reset cadence.
\- \*\*No rollover\*\*: Unused credits expire at the end of the cycle.
\- \*\*Overages\*\*: If you go over your limit and \[extra charging is enabled, extra screenshots are billed automatically based on your plan’s per-credit rate\](https://screenshotone.com/docs/charging-extra/).

This keeps your usage simple and helps you forecast your monthly screenshot volume, even if you prefer paying annually.

\## Cancellation

When you cancel a plan, you keep your current billing cycle until it ends. Your credit behavior depends on that cycle:

\### You keep your credits until the cycle ends

All remaining credits stay available and usable until the end of your current billing period. Nothing is removed immediately.

\### No new credits after cancellation

When your cycle ends, your plan won’t renew and you won’t receive the next month’s credit reset. You will be downgraded to the free plan or if the free plan is not available, you will lose access to the service.

\### No refunds for unused credits

Because credits are issued monthly and expire at the end of each cycle, any unused credits at the moment your billing period ends simply expire.

\### Annual subscribers

If you’re on an annual plan:

\- You continue to receive monthly credit resets until the end of your paid annual term.
\- Once the annual term ends, no new credits are issued.
\- Any remaining credits at that moment expire.

\## Support

If you have any questions or need help, please contact our support team at \[support@screenshotone.com\](mailto:support@screenshotone.com).

\# ScreenshotOne IP Ranges

In case you need to allow access from the ScreenshotOne API to your servers or your proxy provider allow list, you can configure your firewall to allow the following IP addresses:

1\. IPs for the \`east-4\` region \[from public Google Cloud IP ranges\](https://www.gstatic.com/ipranges/cloud.json).
2\. Hetzner GPU rendering IP (if applicable for your use case)—\`95.216.67.59\`.
3\. IP range for New York from \[DigitalOcean Public IPs\](https://digitalocean.com/geo/google.csv).

If that doesn't work for you, please, reach out at \`support@screenshotone.com\` with any questions you have and we will try to get back to you as soon as possible.

\# Organizations and Roles

Organizations are the core unit for managing your ScreenshotOne account. Every user belongs to one organization, and all billing, API access, and resources are scoped to the organization level.

\## Roles

There are three roles in an organization:

\### Owner

The owner has full control over the organization:

\- Full access to billing, invoices, and subscription management
\- Can invite and remove members
\- Can change member roles
\- Can transfer ownership to another member
\- Can delete the organization
\- Can configure notifications

Every organization has exactly one owner. When you sign up, you automatically become the owner of your organization.

\### Admin

Admins are trusted team members who can help manage the organization:

\- Can view and manage billing information
\- Can invite and remove members
\- Can change member roles (promote/demote between admin and developer)
\- Can edit organization settings
\- Can configure notifications
\- \*\*Cannot\*\* transfer ownership
\- \*\*Cannot\*\* delete the organization

Use the admin role for team leads, managers, or anyone who needs to manage the team without having full control.

\### Developer

Developers have access to everything needed to integrate with ScreenshotOne:

\- Can view and manage API keys
\- Can view request logs and screenshot history
\- Can access the playground
\- Can configure S3 storage
\- Can view organization members (read-only)
\- \*\*Cannot\*\* manage members or invites
\- \*\*Cannot\*\* view billing or payment information
\- \*\*Cannot\*\* change organization settings

Use the developer role for engineers and team members who need to work with the API but don't need administrative access.

\## Managing Your Team

\### Inviting Members

1\. Go to the \*\*Organization\*\* page
2\. Click \*\*Invite new member\*\*
3\. Enter the email address
4\. Select a role (Developer or Admin)
5\. Click \*\*Invite\*\*

The invited user will receive an email with instructions to join. They can sign in (or sign up if new to ScreenshotOne) to accept the invitation.

\*\*Note:\*\* You cannot invite users who already have an active subscription or are owners of another organization with members.

\### Changing Roles

1\. Go to the \*\*Organization\*\* page
2\. Find the member in the list
3\. Click \*\*Change role\*\*
4\. Select the new role (Developer or Admin)
5\. Click \*\*Change Role\*\*

Only owners and admins can change roles. You cannot change the owner's role or your own role.

\### Removing Members

1\. Go to the \*\*Organization\*\* page
2\. Find the member in the list
3\. Click \*\*Remove member\*\*
4\. Confirm the removal

When a member is removed, they are moved to their own organization with fresh API keys. \*\*Important:\*\* They may still have copies of your API keys. Consider regenerating your keys after removing a member.

\### Transferring Ownership

If you need to transfer ownership to another member:

1\. Go to the \*\*Organization\*\* page
2\. Find the member who will become the new owner
3\. Click \*\*Transfer ownership\*\*
4\. Confirm the transfer

After transfer, you will become a developer in the organization. Only the owner can transfer ownership, and only if no members have active legacy subscriptions.

\## Common Use Cases

\### Small Team

\- \*\*Owner\*\*: Founder or team lead (handles billing)
\- \*\*Developers\*\*: Engineers working on the integration

\### Medium Team

\- \*\*Owner\*\*: Finance or operations (manages billing)
\- \*\*Admins\*\*: Team leads (manage their developers)
\- \*\*Developers\*\*: Engineers

\### Enterprise

\- \*\*Owner\*\*: Account administrator
\- \*\*Admins\*\*: Department heads or project managers
\- \*\*Developers\*\*: Development teams

\## FAQ

\*\*Can I have multiple owners?\*\*
No, each organization has exactly one owner. Use the admin role for additional people who need management access.

\*\*What happens to removed members?\*\*
They get their own organization with a free plan and new API keys. They lose access to your organization's resources immediately.

\*\*Can developers see billing information?\*\*
No, only owners and admins can view billing, invoices, and subscription details.

\*\*Can admins change the subscription?\*\*
Yes, admins have full access to billing and can change plans, update payment methods, and manage the subscription.

\*\*What if I need help?\*\*
Contact us at support@screenshotone.com or use the support chat. We're happy to help with any organization-related questions.

\# Signed Links

import Alert from "@/components/Alert.astro";

When you share links to the screenshots with your access key in public, there is a problem that everybody can take your API access key and reuse it to take screenshots on their own and exhaust your screenshot quota.

To prevent others from using your API key, you need to:
1\. \[Sign every request\](https://screenshotone.com/docs/signed-requests/#signing-requests) you are going to share publicly.
2\. \[Require signing\](https://screenshotone.com/docs/signed-requests/#require-signing) for every request.

Then even if the potential unscrupulous person sees or steals your access key, they can't reuse it until they also steal your secret key (signing key).

You generally don't need to sign requests if you will not share screenshot links publicly and will use screenshot API only on the server-side.

\## Signing requests

Singed links do not work with HTTP "POST" requests. The feature is intended to be used for sharing links in public.

To sign the request, like \`https://api.screenshotone.com/take?access\_key=0Ij4LFMtFnGUrA&url=https://apple.com\`, you need to follow the simple algorithm:

1\. Use your secret to hash the query string \`access\_key=0Ij4LFMtFnGUrA&url=https://apple.com\` with the HMAC SHA256 algorithm.

2\. \*\*Append\*\* the signature parameter with the hash: \`https://api.screenshotone.com/?access\_key=0Ij4LFMtFnGUrA&url=https://apple.com&signature=70bea3e52efc43834129ecbea236f38bf9bb4a7cd7c2e1951017435defd4dbaf\`.

\*\*Do not sort the parameters. Or if you sort them, send them sorted, too.\*\*

To hash the query string with your secret key and HMAC SHA256 algorithm in the CLI, you can run the following command:

\`\`\`bash
$ echo -n "access\_key=0Ij4LFMtFnGUrA&url=https://apple.com" \| openssl sha256 -hmac "m9ajW9br9hTw2A" 130 ↵

70bea3e52efc43834129ecbea236f38bf9bb4a7cd7c2e1951017435defd4dbaf
\`\`\`

\## Code examples

You can need to apply the same algorithm in the language of your choice.

\### Python

For example, in Python:

\`\`\`python
import urllib.parse
import hmac
import hashlib

def generate\_signature(params: dict, secret\_key: str) -> str:
 """
 Generate a signature for the given parameters using HMAC-SHA256.

 Args:
 params (dict): Dictionary of parameters to sign
 secret\_key (str): Secret key used for signing

 Returns:
 str: The hexadecimal signature
 """
 # convert parameters to URL-encoded query string
 query\_string = urllib.parse.urlencode(params, doseq=True)

 signature = hmac.new(
 bytes(secret\_key, "utf-8"),
 msg=bytes(query\_string, "utf-8"),
 digestmod=hashlib.sha256,
 ).hexdigest()

 return signature

\# Example usage
if \_\_name\_\_ == "\_\_main\_\_":
 # options
 params = {
 "access\_key": "your\_access\_key",
 "url": "https://example.com",
 "format": "jpeg",
 "viewport\_width": 1920,
 "viewport\_height": 1080
 }

 secret\_key = "your\_secret\_key"

 # generate signature
 signature = generate\_signature(params, secret\_key)

 print("Parameters:", params)
 print("Query string:", urllib.parse.urlencode(params, doseq=True))
 print("Signature:", signature)

 query\_string = urllib.parse.urlencode(params, doseq=True)
 final\_url = f"https://api.screenshotone.com/take?{query\_string}&signature={signature}"
 print("\\nAPI URL:", final\_url)
\`\`\`

\### JavaScript

Or in JavaScript:

\`\`\`javascript
// npm install @peculiar/webcrypto
import { Crypto } from "@peculiar/webcrypto";

const encoder = new TextEncoder();

export async function signQueryString(queryString: string, secretKey: string) {
 const webCrypto =
 typeof globalThis.crypto !== "undefined"
 ? globalThis.crypto
 : new Crypto();

 let algorithm = { name: "HMAC", hash: "SHA-256" };
 let key = await webCrypto.subtle.importKey(
 "raw",
 encoder.encode(secretKey),
 algorithm,
 false,
 \["sign", "verify"\]
 );
 const digest = await webCrypto.subtle.sign(
 algorithm.name,
 key,
 encoder.encode(queryString)
 );

 const signature = Array.from(new Uint8Array(digest))
 .map((b) => b.toString(16).padStart(2, "0"))
 .join("");

 return signature;
}

// example usage
const query = new URLSearchParams({
 access\_key: "your\_access\_key",
 url: "https://example.com"
});
let queryString = query.toString();

const signature = await signQueryString(queryString, "your\_secret\_key");
queryString += "&signature=" + signature;

console.log(queryString);
\`\`\`

\## Require signing

After you start signing requests and make sure that the API accepts your requests, you can require signing every request.
Go to \[the access configuration page\](https://dash.screenshotone.com/access) and enforce signing every request.
The change will be applied immediately, but cached screenshots might not be impacted.
That's it. After this step, unsigned requests with your API access key are not accepted.

\## Animated screenshots

\[Animated screenshots\](/docs/animated-screenshots/) also support signed links. There is no difference in the underlying mechanism besides that the URL prefix should be \`/animate\`.

\# Charging Extra

You can set the hard limit for screenshots higher than the limit in your current plan. And by doing this, you are enabling charging for extra screenshots. The option is available only for paying customers who are organization owners.

!\[Changing the hard limit\](charge-extra.png)

Once the charging extra is enabled (at \[your subscription page\](https://dash.screenshotone.com/subscription)), you will be charged for successful not cached requests that go over your plan limitation.

\## Examples

:::note
\*\*Your price per extra screenshot depends on the plan you have\*\*. You can see all prices at the \[ScreenshotOne Pricing page\](https://screenshotone.com/pricing) or check out your price at \[your subscription page\](https://dash.screenshotone.com/billing).
:::

Let's look at different examples of an artificial subscription plan. Imagine you have a limit of 10000 screenshots monthly, and let's assume the price of one extra screenshot is $0.004 (this is an example price, not a real price):

1\. The plan limit is 10000, the hard limit is 15000, and you rendered 12000 screenshots. You will be charged for 2000 extra screenshots. $0.004 x 2000 = $8.
2\. The plan limit is 10000, the hard limit is 15000, and you rendered 12500 screenshots. You will be charged for 3000 extra screenshots. $0.004 x 3000 = $12.

Why for 3000 extra screenshots?

\*\*It is because extra charges are rounded to the close upper bound of a thousand screenshots.\*\*

If you render only one extra screenshot, you pay for 1000 screenshots. If you render 1001, you pay for 2000, and so on. If you render 999, you pay for 1000, and so on.

\## Upgrading subscription

Once you upgrade your subscription, your hard limit is reset. And you need to set it up again.

\## Cancelling or downgrading subscription

Before you cancel your subscription, ScreenshotOne will try to charge you for extra screenshots and only then cancel it.

For downgrading, charging happens only when downgrading to a free plan. Otherwise, there is no need.

\## When you are charged

ScreenshotOne charges you periodically over the extra usage if needed, usually once per 1000 screenshots.

Or you also might be charged in one "batch" for the extra usage. It depends on the internal logic of the service.

\## Maximum hard limit

Every new customer has a maximum hard limit of 100,000 screenshots. If you need to upgrade it and make it higher, feel free to write to \`support@screenshotone.com\`. Please, describe your use case.

ScreenshotOne is a scalable and highly performant API that has paying customers who make render more than 100,000 screenshots monthly. Still, there is a need to make sure that there is no service abuse and that high-quality service can be delivered. That's why the maximum hard limit for new customers is applied.

\# Devices

import Alert from "@/components/Alert.astro";
import devices from "screenshotone-devices";

Instead of manually specifying viewport parameters like width and height, you can specify a device to use for emulation. In addition, other parameters of the viewport, including the user agent, will be set automatically.

The \[viewport\_device\](/docs/options/#viewport\_device) option sets the next options for you: \[viewport\_width\](/docs/options/#viewport\_width), \[viewport\_height\](/docs/options/#viewport\_height), \[device\_scale\_factor\](/docs/options/#device\_scale\_factor), \[viewport\_mobile\](/docs/options/#viewport\_mobile), \[viewport\_has\_touch\](/docs/options/#viewport\_has\_touch), \[viewport\_landscape\](/docs/options/#viewport\_landscape). You can change these options and override the ones set by the \`viewport\_device\` option.

API does not use an actual device to take a screenshot. It is emulation that works in most cases.

Use the \`id\` property of the device as the \[viewport\_device\](/docs/options/#viewport\_device) option, e.g. \`viewport\_device=galaxy\_s9+\_landscape\`.

You can get the list of supported devices by:

\`\`\`
GET https://api.screenshotone.com/devices?access\_key=\`

\[\
 {\
 "id": "iphone\_13\_pro\_max\_landscape",\
 "name": "iPhone 13 Pro Max landscape",\
 "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15\_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Mobile/15E148 Safari/604.1",\
 "viewport": {\
 "width": 926,\
 "height": 428,\
 "deviceScaleFactor": 3,\
 "isMobile": true,\
 "hasTouch": true,\
 "isLandscape": true\
 }\
 },\
 // ... many devices ...\
 {\
 "id": "galaxy\_s9+",\
 "name": "Galaxy S9+",\
 "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36",\
 "viewport": {\
 "width": 320,\
 "height": 658,\
 "deviceScaleFactor": 4.5,\
 "isMobile": true,\
 "hasTouch": true,\
 "isLandscape": false\
 }\
 },\
 {\
 "id": "galaxy\_s9+\_landscape",\
 "name": "Galaxy S9+ landscape",\
 "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36",\
 "viewport": {\
 "width": 658,\
 "height": 320,\
 "deviceScaleFactor": 4.5,\
 "isMobile": true,\
 "hasTouch": true,\
 "isLandscape": true\
 }\
 },\
 // ... many devices ...\
\]
\`\`\`

\## Devices

The list of devices returned by API is dynamic and continuously updated. But there is a snapshot of all supported devices if you want to take a quick look (\*\*don't rely on it solely, use the API method\*\* \`GET /devices\` \*\*instead\*\*):

 {Object.entries(devices.default.devices).map((\[id, device\]) => (
 <>


 ))}

| Device (id) | Viewport (scale) | Mobile | Touch | Landscape |
| --- | --- | --- | --- | --- |
| User Agent |
| --- |
| {device.name} ({id}) | {device.viewport.width}x{device.viewport.height} ({device.viewport.deviceScaleFactor}) | {device.viewport.isMobile ? "Yes" : "No"} | {device.viewport.hasTouch ? "Yes" : "No"} | {device.viewport.isLandscape ? "Yes" : "No"} |
| {device.userAgent} |

\# Screenshot URL

:::danger
The URL is temporary and will be available for a limited time—\*\*4 hours maximum\*\*. Do not rely on it for long-term storage of screenshots.

Except, when you use \[caching\](/docs/caching/), and the cache TTL is set to more than 4 hours.
:::

:::note
For long-term screenshot or video archival, consider \[uploading them to any compatible S3-storage\](/docs/guides/upload-to-s3/).
:::

When you set \`response\_type=json\` for both \[animated/scrolling screenshots\](/docs/animated-screenshots/) or \[regular screenshots\](/docs/options/), you will get a screenshot URL in the response:

\`\`\`json
{
 "screenshot\_url": "..."
}
\`\`\`

The URL is always a fresh URL where the screenshot is stored, it is not a cached URL unless you use \[caching\](/docs/caching/).

Also, when \[using webhooks\](/docs/async-and-webhooks/) and if you do not upload the screenshot to any S3-compatible storage, you will get the URL in the webhook request body,too.

\# Get Usage

You can get your current plan usage by:

\`\`\`
GET https://api.screenshotone.com/usage?access\_key=\`

{
 "total": 10000,
 "available: 950,
 "used": 9050,
 "concurrency": {
 "limit":20,
 "remaining":20,
 "reset":1681646947775437264
 }
}
\`\`\`

A bit of clarification:

\- \`total\` is the total number of requests allowed in the current billing plan period;
\- \`available\` is the number of available requests until the end of the current period;
\- \`used\` is the number of successfully executed requests.
\- \`concurrency.limit\` is the total number of concurrent requests allowed per interval;
\- \`concurrency.remaining\` is the number of available concurrent requests allowed per interval;
\- \`concurrency.reset\` is the time when the limitation will be reset, in UNIX timestamp format in nanoseconds.

\# Access Key Invalid

It is an API error returned when the provided access key is invalid or incorrect.

\`\`\`json
{
 "is\_successful": false,
 "error\_code": "access\_key\_invalid",
 "error\_message": "The \`access\_key\` parameter is set, but it is not correct. Please, check out the access dashboard page to get the access key—https://dash.screenshotone.com/access.",
 "documentation\_url": "https://screenshotone.com/docs/errors/access-key-invalid/"
}
\`\`\`

\## Reasons and how to fix

\### Incorrect Access Key

One common reason for the "access\_key\_invalid" error is using an incorrect access key. This can happen if the key is copied incorrectly or if an old key is being used.

To fix this, ensure you are using the correct access key by visiting the \[access dashboard page\](https://dash.screenshotone.com/access) and copying the key directly from there.

\### Typographical Errors

Typos in the access key parameter can also lead to this error. This includes extra spaces, missing characters, or incorrect case sensitivity.

To fix this, carefully check and re-enter the access key, ensuring there are no typographical errors. Copy-pasting the key directly from the dashboard is recommended.

\### Misconfigured Environment

In some cases, the environment where the API request is being made might be misconfigured, leading to the wrong access key being used.

To fix this, review your environment configuration settings to ensure the correct access key is being used in the appropriate environment (e.g., development, staging, production).

\## Reach out to support

If you continue to face issues, please reach out to \`support@screenshotone.com\`, and we will assist you as soon as possible.

\# Access Key Required

It is an API error returned when the access key parameter is missing in the request.

\`\`\`json
{
 "is\_successful": false,
 "error\_code": "access\_key\_required",
 "error\_message": "The \`access\_key\` parameter is required. Please, check out the access dashboard page to get the access key—https://dash.screenshotone.com/access.",
 "documentation\_url": "https://screenshotone.com/docs/errors/access-key-required/"
}
\`\`\`

\## Reasons and how to fix

\### Missing Access Key Parameter

The most common reason for the "access\_key\_required" error is that the \`access\_key\` parameter is not included in the request. This is mandatory for authenticating and authorizing the API request.

To fix this, ensure that you include the \`access\_key\` parameter in your API request. You can obtain your access key from the \[access dashboard page\](https://dash.screenshotone.com/access).

\### Misconfigured Request

Sometimes, a request might be misconfigured, leading to the \`access\_key\` parameter being omitted.

To fix this, review the configuration of your API client or the code that constructs the request to ensure that the \`access\_key\` parameter is always included.

\### Typographical Errors

A typo or incorrect parameter name might lead to the \`access\_key\` not being recognized by the API.

To fix this, double-check the parameter name in your request to ensure it is spelled correctly as \`access\_key\`.

\### Programmatic Issues

If you are dynamically generating requests (e.g., through a script or application), there might be a bug causing the \`access\_key\` to be omitted.

To fix this, debug your script or application to ensure the \`access\_key\` is being properly set and included in every API request.

\## Reach out to support

If you continue to face issues, please reach out to \`support@screenshotone.com\`, and we will assist you as soon as possible.

\# Concurrency Limit Reached

It is an API error returned when the request concurrency limit has been reached.

\`\`\`json
{
 "is\_successful": false,
 "error\_code": "concurrency\_limit\_reached",
 "error\_message": "You reached the request concurrency limit, retry after a while. Or feel free to upgrade your current plan—https://dash.screenshotone.com/subscription.",
 "documentation\_url": "https://screenshotone.com/docs/errors/concurrency-limit-reached/"
}
\`\`\`

\## Reasons and how to fix

\### Exceeded Concurrency Limit

The most common reason for the "concurrency\_limit\_reached" error is that you have reached the maximum number of concurrent requests allowed by your current subscription plan.

To fix this, you can:

1\. \*\*Wait and retry\*\*: Wait for some of the current requests to complete and then retry your request.
2\. \*\*Upgrade your plan\*\*: Visit the \[subscription page\](https://dash.screenshotone.com/subscription) to upgrade your plan, which will increase your concurrency limit.

\### High Traffic Periods

During high traffic periods, you might hit the concurrency limit more frequently if multiple requests are being made simultaneously.

To fix this, consider:

1\. \*\*Load balancing\*\*: Implementing load balancing strategies to distribute requests more evenly over time.
2\. \*\*Queueing requests\*\*: Queueing requests and processing them in batches to avoid hitting the concurrency limit.

\### Inefficient Request Handling

If your application is not handling requests efficiently, it might lead to a buildup of concurrent requests, hitting the limit.

To fix this, review your application’s request handling logic to ensure that requests are being processed and completed as efficiently as possible.

\## Reach out to support

If you continue to face issues, please reach out to \`support@screenshotone.com\`, and we will assist you as soon as possible.

\# Content Contains Specified String

It is an API error returned when the page content contains a specified string that triggers a failure condition.

\`\`\`json
{
 "is\_successful": false,
 "error\_code": "content\_contains\_specified\_string",
 "error\_message": "The page content contains the specified string by the \`fail\_if\_content\_contains\` option. If it seems to be a mistake or not what you expected, please, reach out to \`support@screenshotone.com\` as quickly as possible, and we will assist and try to resolve your problem.",
 "documentation\_url": "https://screenshotone.com/docs/errors/content-contains-specified-string/"
}
\`\`\`

The page content contains the specified string by the \`fail\_if\_content\_contains\` option. If it seems to be a mistake or not what you expected, please, reach out to \`support@screenshotone.com\` as quickly as possible, and we will assist and try to resolve your problem.

\# Content Missing Specified String

It is an API error returned when the page content is missing a specified string that triggers a failure condition.

\`\`\`json
{
 "is\_successful": false,
 "error\_code": "content\_missing\_specified\_string",
 "error\_message": "The page content is missing the specified string by the \`fail\_if\_content\_missing\` option. If it seems to be a mistake or not what you expected, please, reach out to \`support@screenshotone.com\` as quickly as possible, and we will assist and try to resolve your problem.",
 "documentation\_url": "https://screenshotone.com/docs/errors/content-missing-specified-string/"
}
\`\`\`

The page content is missing the specified string by the \`fail\_if\_content\_missing\` option. If it seems to be a mistake or not what you expected, please, reach out to \`support@screenshotone.com\` as quickly as possible, and we will assist and try to resolve your problem.

\# Internal Application Error

It is an API error returned when the API fails to serve the request due to internal reasons:

\`\`\`json
{
 "is\_successful": false,
 "error\_message": "The API failed to serve your request. You can try replay the request. If the error is repeated after a few retries, please, reach out at \`support@screenshotone.com.\`",
 "error\_code": "internal\_application\_error",
 "documentation\_url": "https://screenshotone.com/docs/errors/internal-application-error/"
}
\`\`\`

\## Retry

On rare occasions it can be caused by the website you try to screenshot. So, you can retry the request. It is free, ScreenshotOne doesn't charge you for retries and cached requests.

\## Reach out to support

Most of the time, the error is triggered because of some issues in the API or even because of some bugs.

If nothing helps you, please, reach out to \`support@screenshotone.com\` and we will try to help you as fast as possible.

\# Caching

:::note
When you don't use caching (\`cache=true\`), storage (\`store=true\`) or similar options, screenshots are rendered on-demand and returned directly to you without being stored anywhere on ScreenshotOne infrastructure. This ensures maximum privacy for your rendered content. Except if you use \`response\_type=json\`, in which case the screenshot is temporarily stored on ScreenshotOne servers to serve the screenshot URL for you.

\*\*During processing\*\*, rendered content may be temporarily stored to pass through internal system components (such as queues, message brokers, or temporary buffers).

Caching is free and available for all plans. However, it is not intended to be used in CDN-like scenarios. It is for you to save costs on rendering.
:::

To use cache, the only option you need to set is \`cache=true\`:

\`\`\`
https://api.screenshotone.com/screenshot?url=https://example.com&cache=true
\`\`\`

\[Check out more cache options\](/docs/options/#caching).

And the screenshot will be cached for 4 hours by default or if you specify the \`cache\_ttl\` option in seconds, you can prolong the cache time up to one month.

Caching is available for all rendering methods.

\## When to use cache

The best usage of cache is to make rendering less expensive and faster, in case if you plan to render a lot of similar websites.

\## Cache key

Screenshots are cached by the combination of all specified request options. And the \[cache\_key\](/docs/options/#cache\_key) option allows having different cached versions of the same screenshot.

\## Impact on rendering quota

Cached screenshots are not counted by quota and are not logged anywhere. They are served directly from the cache. Screenshots are cached in a combination of Cloudflare CDN and R2 storage (like Amazon S3).

However, rarely but cache misses might happen and screenshots might be rendered again and counted towards your quota.

\## Cache URL

:::note
Fetching the cache URL doesn't trigger the rendering process. It is a direct link to the cached screenshot.

If you want to regenerate the cache, you need to make a new API request with the same parameters and if the cache is expired, it will be rendered again.
:::

There is a header \`x-screenshotone-cache-url\` that provides a direct link to the cached image, PDF or video. The file exist as long as it was defined in the \[cache\_ttl\](/docs/options/#cache\_key) parameter when API request was performed with \`cache=true\`.

And if the \`response\_type\` option is specified as \`json\`, you can find a cache URL in the JSON response too:

\`\`\`json
{
 "cache\_url": "https://cache.screenshotone.com/..."
}
\`\`\`

What is the benefits of using the cache URL?

1\. You don't share API keys and don't complicate your code with \[signed links\](/docs/signed-requests/).
2\. You have full control over when the cache is refreshed—only you can trigger cache regeneration by making a new API request with the same parameters. If you share just the cache URL, others can only access the cached screenshot and cannot cause it to be regenerated after it expires. In contrast, sharing an API request link would allow anyone to trigger a new rendering once the cache expires. \*\*Important!\*\* The link will be unavailable after the cache is expired.

\[The screenshot URL\](/docs/screenshot-url/) might be different from the cache URL, but it will be likely the same as the cache URL.

\## Cache TTL

:::note
For long-term screenshot or video archival, consider \[uploading them to any compatible S3-storage\](/docs/guides/upload-to-s3/).
:::

The cache TTL is 4 hours by default. You can change it by specifying the \`cache\_ttl\` option in seconds up to one month.

Once the cache TTL is reached, the cached screenshot is deleted and the next request will be rendered again and counted towards your quota.

Cache URL will not be accessible after the cache TTL is reached. It is recommended to avoid using it and always render screenshots and videos with the rendering API request. It will rely on the cache anyway (if specified).

\## Support

In case if you have any issues with caching or any ideas on how to improve it and make it better, please contact us at \[support@screenshotone.com\](mailto:support@screenshotone.com).

\# Host Returned Error

It is an API error returned when the host server does not respond with a successful status code within the range of 200-299.

\`\`\`json
{
 "is\_successful": false,
 "error\_code": "host\_returned\_error",
 "error\_message": "If the host doesn't respond successfully within the range of 200-299 status codes, the API won't take a screenshot. You can force the API to take a screenshot of the error page by specifying \`ignore\_host\_errors\`=true. You can get the returned status code from the site by reading the \`returned\_status\_code\` field.",
 "documentation\_url": "https://screenshotone.com/docs/errors/host-returned-error/"
}
\`\`\`

\## Reasons and how to fix

\### Host Returned Non-Success Status Code

The most common reason for the "host\_returned\_error" error is that the host server returned a status code outside the 200-299 range, indicating an unsuccessful response.

To fix this, you can:

1\. \*\*Check host server status\*\*: Ensure the host server is operational and capable of returning a successful status code.
2\. \*\*Review site response\*\*: Investigate the response from the host server to understand why it is not returning a successful status code.

\### Forcing Screenshot of Error Pages

If you want the API to take a screenshot of the error page even when the host returns an error, you can use the \`ignore\_host\_errors\` option.

To fix this, set \`ignore\_host\_errors\` to \`true\` in your API request:

\`\`\`json
{
 "ignore\_host\_errors": true
}
\`\`\`

\## Retrieving the Returned Status Code

You can get the status code returned by the host server by reading the \`returned\_status\_code\` field in the response. This will help in diagnosing and understanding the nature of the error.

\## Reach out to support

If you continue to face issues or need further assistance, please reach out to \`support@screenshotone.com\`, and we will assist you as soon as possible.

\# Invalid Storage Configuration

It is an API error returned when the storage configuration for S3 is invalid.

\`\`\`json
{
 "is\_successful": false,
 "error\_code": "invalid\_storage\_configuration",
 "error\_message": "If you haven't created the bucket in the \`us-east-1\` AWS region, please, specify your bucket region through an endpoint in a format like https://s3..amazonaws.com.",
 "documentation\_url": "https://screenshotone.com/docs/errors/invalid-storage-configuration/"
}
\`\`\`

\## Reasons and how to fix

\### Incorrect AWS S3 Bucket Region

One common reason for the "invalid\_storage\_configuration" error is that the S3 bucket is not created in the \`us-east-1\` region and the bucket region is not specified correctly.

To fix this, you can:

1\. \*\*Specify the bucket Region\*\*: Ensure you specify your bucket region in the endpoint format like \`https://s3..amazonaws.com\`. Replace \`\` with the actual AWS region where your bucket is located.

\### Missing or misconfigured Bucket

If the S3 bucket does not exist or is misconfigured, this can lead to the "invalid\_storage\_configuration" error.

To fix this, consider:

1\. \*\*Verify bucket existence\*\*: Check that the S3 bucket exists in your AWS account and is accessible.
2\. \*\*Correct bucket configuration\*\*: Ensure the bucket is configured correctly, including permissions and policies.

\### Incorrect Endpoint URL

The endpoint URL might be incorrectly formatted, causing the API to fail in accessing the specified S3 bucket.

To fix this, ensure the endpoint URL is correctly formatted as \`https://s3..amazonaws.com\`, with the correct region specified.

\### AWS IAM Permissions

Inadequate permissions set in the AWS IAM policies might prevent the API from accessing the S3 bucket, leading to this error.

To fix this, ensure that the IAM roles and policies associated with your bucket have the necessary permissions to allow access from the API.

\## Reach out to support

If you continue to face issues or need further assistance, please reach out to \`support@screenshotone.com\`, and we will assist you as soon as possible.

\# Name Not Resolved

It is an API error returned when the domain name of the requested URL cannot be resolved.

\`\`\`json
{
 "is\_successful": false,
 "error\_code": "name\_not\_resolved",
 "error\_message": "Usually, the error happens when the domain name of the requested URL is not resolved. If you are trying to take a screenshot of a new site, please, wait a bit until the DNS records are refreshed.",
 "documentation\_url": "https://screenshotone.com/docs/errors/name-not-resolved/"
}
\`\`\`

\## Reasons and how to fix

\### Unresolved Domain Name

The most common reason for the "name\_not\_resolved" error is that the domain name of the requested URL cannot be resolved to an IP address. This often occurs with new domains or recently updated DNS records.

To fix this, you can:

1\. \*\*Wait for the DNS propagation if it is your website\*\*: If you are trying to take a screenshot of a new site, wait for the DNS records to propagate fully. This can take anywhere from a few minutes to 48 hours.
2\. \*\*Or check DNS configuration\*\*: Ensure that the DNS configuration for the domain is correct and that the records are properly set up.

\### Temporary DNS Issues

Temporary DNS issues can also cause the "name\_not\_resolved" error. These can be due to network problems, DNS server issues, or other transient conditions.

To fix this, consider simply retrying the request after a short wait

\### Incorrect Domain Name

If the domain name is incorrectly typed or does not exist, the API will not be able to resolve it.

To fix this, verify that the domain name in the request is correct and exists.

\## Reach out to support

If you continue to face issues or need further assistance, please reach out to \`support@screenshotone.com\`, and we will assist you as soon as possible.

\# Request Aborted

It is an API error returned when the request was aborted either by the user or the intermediate proxies and can't be fulfilled.

\`\`\`json
{
 "is\_successful": false,
 "error\_code": "request\_aborted",
 "error\_message": "The request was aborted either by the user or the intermediate proxies and can't be fulfilled. If the error persists, please, reach out to \`support@screenshotone.com\`.",
 "documentation\_url": "https://screenshotone.com/docs/request-aborted/"
}
\`\`\`

\## Reasons and how to fix

\### HTTP Client Timeouts

One common reason for the "request\_aborted" error is HTTP client timeouts. This occurs when the client (e.g., a web browser or a server making a request) has a timeout setting that is shorter than the time it takes for the request to be processed.

To fix this, you can increase the timeout setting in your HTTP client configuration.

\### Local Development Live Reloading

During local development, live reloading tools (such as those used in web development environments) may cause requests to be aborted if the server restarts or if the code is recompiled. This can lead to the "request\_aborted" error.

To avoid this, ensure that you have a stable development environment and minimize the frequency of live reloads while making API requests.

\### Edge Function Timeouts

If you are using edge functions or serverless functions (e.g., AWS Lambda, Vercel Edge Functions), they might have their own timeout settings. When these timeouts are exceeded, the request will be aborted, resulting in the "request\_aborted" error.

To fix this, you should increase the timeout settings for your edge functions.

\## Reach out to support

If nothing helps you, please, reach out to \`support@screenshotone.com\` and we will try to help you as fast as possible.

\# Network Error

It is an API error returned when the API cannot connect to the target host.

\`\`\`json
{
 "is\_successful": false,
 "error\_code": "network\_error",
 "error\_message": "The error happens when the API can't connect to the provided URL. It might mean that the site blocks the API or is temporarily unavailable. Generally, you can safely retry to take a screenshot.",
 "documentation\_url": "https://screenshotone.com/docs/errors/network-error/"
}
\`\`\`

\## Reasons and how to fix

\### Proxy issues

If you use an external \[proxy\](/docs/guides/how-to-use-proxies/), make sure that it has access to the target host.

Also, often when you use proxy providers, you might not notice that you don't have sufficient credits to keep using proxy.

We noticed that for some providers, you sometimes need to recreate your proxy user/account to make it work again.

Also, many providers might block ScreenshotOne API IP addresses. In that case, consider adding \[our IP ranges\](/docs/ip-ranges/) to the proxy provider's allow list.

\### The API is under heavy load

Rarely but under heavy load, ScreenshotOne API might fail to connect to target hosts. In that case, retry requests.

\## Reach out to support

If nothing helps you, please, reach out to \`support@screenshotone.com\` and we will try to help you as fast as possible.

\# Request Body Too Large

It is an API error returned when the API fails to serve the request due to internal reasons:

\`\`\`json
{
 "is\_successful": false,
 "error\_message": "The request body is too large. Please, reduce the size of the request body or reach out to \`support@screenshotone.com\` for assistance.",
 "error\_code": "request\_body\_too\_large",
 "documentation\_url": "https://screenshotone.com/docs/errors/request-body-too-large/"
}
\`\`\`

\## How to fix

Reduce the size of the request body. It should be no more than 50MB.

\## Reach out to support

If nothing helps you, please, reach out to \`support@screenshotone.com\` and we will try to help you as fast as possible.

\# Resulting Image Too Large

It is an API error returned when the resulting image is too large for the specified format.

\`\`\`json
{
 "is\_successful": false,
 "error\_message": "The resulting image is too large for the specified format.",
 "error\_code": "resulting\_image\_too\_large",
 "documentation\_url": "https://screenshotone.com/docs/errors/resulting-image-too-large/"
}
\`\`\`

\## Reasons and how to fix

\### Using image formats with size limits for full-page screenshots

The JPEG format has a height limit of 65,535 pixels, WebP format has a height limit of 16,383 pixels.

Full-page screenshots that don't fit the size limits will trigger the error \`resulting\_image\_too\_large\`.

A solution would be is to choose the format that fits your use case better. E.g. if you use WebP, try to use JPEG. Or maybe try PNG.

\### Limiting the height of the full-page screenshot

If it happens for full-page screenshots, you can set the \`full\_page\_max\_height\` option to make sure the height of the resulting image always fits the specified format, e.g. set it to 16000 for WebP format or 60000 for JPEG format.

\### Reducing the device scale factor

If the issue is with the size of the page, you can try to reduce the device scale factor by setting the \`device\_scale\_factor\` option to a lower value, e.g. \`1\` instead of \`2\`.

\## Combining the options

You can try to combine all the options above to find the best solution for your use case.

Or you can even send API requests as-is, but when you encounter the error, just perform a retry with the limited full page height or lower device scale factor, or even a different format.

\## Reach out to support

If you continue to face issues, please reach out to \`support@screenshotone.com\`, and we will assist you as soon as possible.

\# Request Invalid

It is an API error returned when the API fails to serve the request due to internal reasons:

\`\`\`json
{
 "is\_successful": false,
 "error\_message": "The request parameters are not valid. You can look at the \`error\_details\` response field to get more details.",
 "error\_details": {
 // ... validation errors ...
 },
 "error\_code": "request\_invalid",
 "documentation\_url": "https://screenshotone.com/docs/errors/request-invalid/"
}
\`\`\`

\## Reasons and how to fix

\### Invalid Request Parameters

The most common reason for the "request\_not\_valid" error is that one or more of the request parameters are invalid or missing.

To fix this, you can:

1\. \*\*Check \`error\_details\` property\*\*: Review the \`error\_details\` field in the response to get specific information about which parameters are invalid.
2\. \*\*Correct request parameters\*\*: Ensure that all required parameters are included in the request and that they are correctly formatted and valid.

\### Missing Required Parameters

If required parameters are missing from the request, this will trigger the "request\_not\_valid" error.

To fix this, ensure that all mandatory parameters are provided in the request. Refer to the API documentation for a list of required parameters.

\### Incorrect Data Types

Providing parameters with incorrect data types (e.g., a string instead of an integer) can lead to this error.

To fix this, verify that the data types of all parameters match the expected types as specified in the API documentation.

\### Parameter Value Constraints

Some parameters may have constraints on their values (e.g., minimum or maximum length, specific formats). Violating these constraints will result in this error.

To fix this, check the constraints for each parameter in the API documentation and ensure that the provided values comply with these constraints.

\### Syntax Errors

Syntax errors in the request, such as missing commas or brackets in JSON, can make the request invalid.

To fix this, carefully review the syntax of your request and correct any errors. Using a JSON validator can help identify syntax issues.

\## Reach out to support

If you continue to face issues or need further assistance, please reach out to \`support@screenshotone.com\`, and we will assist you as soon as possible.

\# Invalid Cookie Parameter

It is an API error returned when the \`cookies\` parameter is invalid.

\`\`\`json
{
 "is\_successful": false,
 "error\_message": "The \`cookies\` parameters you provided are invalid. Please, consider providing different values and adhere to the format specified in the ScreenshotOne documentation.",
 "error\_code": "invalid\_cookie\_parameter",
 "documentation\_url": "https://screenshotone.com/docs/errors/invalid-cookie-parameter/"
}
\`\`\`

\## Reasons and how to fix

\### The format of the parameter is invalid

Make sure you adhere to the format specified in the \[ScreenshotOne options documentation\](https://screenshotone.com/docs/options/#cookies):

\`\`\`
cookies=name1=val1; Domain=example.com; Secure; HttpOnly
\`\`\`

It is not for demonstration purposes, but the string must be URL-encoded.

If you need to specify multiple cookies, you can do it like this:

\`\`\`
cookies=name1=val1; Domain=example.com; Secure; HttpOnly&cookies=name2=val2; Domain=example.com; Secure; HttpOnly
\`\`\`

\## Reach out to support

If you continue to face issues, please reach out to \`support@screenshotone.com\`, and we will assist you as soon as possible.

\# Matched Failed Request

This API error is returned when a request matched by the specified pattern in the \`fail\_if\_request\_failed\` option has been failed:

\`\`\`json
{
 "is\_successful": false,
 "error\_code": "matched\_failed\_request",
 "error\_message": "A request matched by the specified pattern by the \`fail\_if\_request\_failed\` option has been failed. If it seems to be a mistake or not what you expected, please, reach out to \`support@screenshotone.com\` as quickly as possible, and we will assist and try to resolve your problem.",
 "documentation\_url": "https://screenshotone.com/docs/errors/matched-failed-request/"
}
\`\`\`

\## Reasons and how to fix

The reason you get this error message is because you specified the \[fail\_if\_request\_failed\](/docs/options/#fail\_if\_request\_failed) option.

If you want to disable this behavior, you simply need to remove the parameter from your request. If you have a request like:

\`\`\`
https://api.screenshotone.com/take?access\_key=&url=https://example.com&fail\_if\_request\_failed=\*\*example.com\*\*
\`\`\`

Make it like this:

\`\`\`
https://api.screenshotone.com/take?access\_key=&url=https://example.com
\`\`\`

In case, if the error persists, please immediately reach out to \`support@screenshotone.com\`, and we will try to fix that as soon as possible.

\## Reach out to support

Also, if you encounter any issues or bugs, please reach out to \`support@screenshotone.com\`, and we will assist you as soon as possible.

\# Invalid Header Parameter

It is an API error returned when the \`headers\` parameter is invalid.

\`\`\`json
{
 "is\_successful": false,
 "error\_message": "The \`headers\` parameters you provided are invalid. Please, consider providing different values and adhere to the format specified in the ScreenshotOne documentation.",
 "error\_code": "invalid\_header\_parameter",
 "documentation\_url": "https://screenshotone.com/docs/errors/invalid-header-parameter/"
}
\`\`\`

\## Reasons and how to fix

\### The format of the parameter is invalid

Make sure you adhere to the format specified in the \[ScreenshotOne options documentation\](https://screenshotone.com/docs/options/#headers). If you sent a GET request, your headers must be in the query string as:

\`\`\`
headers=name1:val1&headers=name2:val2
\`\`\`

If you sent a POST request, your headers must be in the request body as:

\`\`\`json
{
 // ...
 "headers": \["name1:val1", "name2:val2"\]
 // ...
}
\`\`\`

\## Reach out to support

If you continue to face issues, please reach out to \`support@screenshotone.com\`, and we will assist you as soon as possible.

\# Script Trigger Redirect

It is an API error returned when the API detects that the script will trigger a redirect and screenshots won't be rendered successfully.

\`\`\`json
{
 "is\_successful": false,
 "error\_code": "script\_triggers\_redirect",
 "error\_message": "The specified \\"scripts\\" option might trigger a redirect, please, specify the \\"scripts\_wait\_until\\" option. If you think it is a mistake, please, reach out at \`support@screenshotone.com\`.",
 "documentation\_url": "https://screenshotone.com/docs/script-triggers-redirect/"
}
\`\`\`

\## Reasons and how to fix

Let's quickly consider possible reasons and possible solutions.

\### Add some wait options

Since the custom script you add with the "scripts" options triggers a redirect, you must also set \[the "scripts\_wait\_until" option\](/docs/options/#scripts\_wait\_until), too.

And to force the API to wait until the new page is loaded.

\## Reach out to support

If nothing helps you, please, reach out to \`support@screenshotone.com\` and we will try to help you as fast as possible.

\# Signature Invalid

It is an API error returned when the provided signature parameter is not valid.

\`\`\`json
{
 "is\_successful": false,
 "error\_code": "signature\_is\_not\_valid",
 "error\_message": "You provided the \`signature\` parameter, but it is not valid. Make sure you use the correct signing algorithm—https://screenshotone.com/docs/signed-requests/.",
 "documentation\_url": "https://screenshotone.com/docs/errors/signature-is-invalid/"
}
\`\`\`

\## Reasons and how to fix

\### Incorrect Signing Algorithm

The most common reason for the "signature\_is\_not\_valid" error is using an incorrect signing algorithm to generate the signature.

To fix this, you can:

1\. \*\*Verify signing algorithm\*\*: Ensure you are using the correct signing algorithm as specified in the \[signed requests documentation\](https://screenshotone.com/docs/signed-requests/).
2\. \*\*Check signature generation code\*\*: Review your code that generates the signature to ensure it follows the correct algorithm and procedure.

\### Mismatched Signature

The signature provided in the request might not match the expected signature due to data mismatches or incorrect key usage.

To fix this, consider:

1\. \*\*Verify request data\*\*: Ensure that all data used to generate the signature matches the data sent in the request.
2\. \*\*Use correct secret key\*\*: Ensure that the correct secret key is used to generate the signature.

\### Signature Formatting Issues

Formatting issues, such as encoding problems or extra characters, can lead to an invalid signature.

To fix this, verify that the signature is correctly formatted and encoded as required by the API.

\### Debugging Signature Issues

If you are still encountering issues, you can use debugging tools or logging to trace the signature generation process and identify where it might be going wrong.

\## Reach out to support

If you continue to face issues or need further assistance, please reach out to \`support@screenshotone.com\`, and we will assist you as soon as possible.

\# Signature Required

It is an API error returned when the signature parameter is missing in the request.

\`\`\`json
{
 "is\_successful": false,
 "error\_code": "signature\_is\_required",
 "error\_message": "The \`signature\` parameter is required. Because signing requests is required in the access page—https://dash.screenshotone.com/access. Make sure you use the correct signing algorithm—https://screenshotone.com/docs/signed-requests/.",
 "documentation\_url": "https://screenshotone.com/docs/errors/signature-is-required/"
}
\`\`\`

\## Reasons and how to fix

\### Missing Signature Parameter

The most common reason for the "signature\_is\_required" error is that the \`signature\` parameter is not included in the request. This parameter is mandatory for authenticating and authorizing the API request if on the \[access dashboard page\](https://dash.screenshotone.com/access) forcing signing requests is activated.

To fix this, ensure that you include the \`signature\` parameter in your API request.

\### Programmatic Issues

If you are dynamically generating requests (e.g., through a script or application), there might be a bug causing the \`signature\` to be omitted.

To fix this, debug your script or application to ensure the \`signature\` is being properly set and included in every API request.

\### Request Validation

To ensure your request is valid, double-check all parameters and the generated signature before sending the request to the API.

\## Reach out to support

If you continue to face issues or need further assistance, please reach out to \`support@screenshotone.com\`, and we will assist you as soon as possible.

\# Storage Returned Transient Error

It is an API error returned when the storage server returns a transient error and retries have been exhausted.

\`\`\`json
{
 "is\_successful": false,
 "error\_code": "storage\_returned\_transient\_error",
 "error\_message": "The storage returned an HTTP status code between 500 and 599 and we exhausted retries. You can likely retry the request again.",
 "documentation\_url": "https://screenshotone.com/docs/errors/storage-returned-transient-error/"
}
\`\`\`

\## Reasons and how to fix

\### Transient Storage Server Error

The most common reason for the "storage\_returned\_transient\_error" is that the S3 storage returned an HTTP status code between 500 and 599, indicating a transient error.

To fix this, you can:

1\. \*\*Retry the request\*\*: Since the error is transient, retrying the request after a short wait is often effective.
2\. \*\*Check storage service status\*\*: Verify the status of the storage service you are using to see if there are any ongoing issues or maintenance that might be causing the error.

\### Exhausted Retries

The API has attempted to retry the request multiple times but has exhausted its retry limit.

To fix this, consider implementing additional retries on your end, with exponential backoff to avoid overwhelming the storage server.

\### Temporary Network Issues

Temporary network issues can also cause transient errors from the storage server.

To fix this, ensure that your network connection is stable and retry the request.

\## Reach out to support

If you continue to face issues or need further assistance, please reach out to \`support@screenshotone.com\`, and we will assist you as soon as possible.

\# Selector Not Found

It is an API error returned when the specified selector is not found or not visible within the given timeout period.

\`\`\`json
{
 "is\_successful": false,
 "error\_code": "selector\_not\_found",
 "error\_message": "If \`selector\` is specified and \`error\_on\_selector\_not\_found\`=true, or \`click\` is specified and \`error\_on\_click\_selector\_not\_found\`=true, the error will be returned if the element by selector is not visible or it took more than timeout seconds to render it, but not more than 30 seconds.",
 "documentation\_url": "https://screenshotone.com/docs/errors/selector-not-found/"
}
\`\`\`

\## Reasons and how to fix

\### Selector Not Visible

The most common reason for the "selector\_not\_found" error is that the element specified by the selector is not visible on the page within the given timeout period.

To fix this, you can:

1\. \*\*Check the selector\*\*: Ensure that the selector you are using is correct and matches an element on the page.
2\. \*\*Increase timeout\*\*: If the element takes longer to load, increase the timeout value to give the element more time to become visible.

\### Element is visible but has zero height

If there is an empty element on the page, the API will not be able to take a screenshot of it. In that case you will still get the "selector\_not\_found" error.

One of the ways to still get a screenshot is to make sure that \[\`error\_on\_selector\_not\_found\`\](https://screenshotone.com/docs/options/#error\_on\_selector\_not\_found) is set to \`false\` (and it is \`false\` by default).

You will get then the screenshot of the page instead of the error.

\### Incorrect Selector

An incorrect or invalid selector can lead to this error, as the API cannot find the element on the page.

To fix this, verify that the selector is correctly specified and matches the element you want to target.

\### Element Not Rendered

If the element is not rendered within the timeout period (not more than 30 seconds), the error will be triggered.

To fix this, ensure that the element is being rendered properly and within the expected time frame. You might need to investigate any delays in rendering the element.

\### Conditional Visibility

If the element's visibility is conditional (e.g., depends on user interaction or specific page states), it might not be visible when the API checks for it.

To fix this, ensure that the conditions for the element's visibility are met before making the API request.

\### Page Load Issues

Page load issues or JavaScript errors on the page can prevent the element from becoming visible.

To fix this, check for any page load issues or JavaScript errors that might be interfering with the rendering of the element.

\## Reach out to support

If you continue to face issues or need further assistance, please reach out to \`support@screenshotone.com\`, and we will assist you as soon as possible.

\# Temporary Unavailable

It is an API error returned when the API is temporarily unavailable due to an error or overload.

\`\`\`json
{
 "is\_successful": false,
 "error\_code": "temporary\_unavailable",
 "error\_message": "The API is temporarily unavailable due to an error or overload. Please wait a bit and then safely retry your request.",
 "documentation\_url": "https://screenshotone.com/docs/errors/temporary-unavailable/"
}
\`\`\`

\## Reasons and how to fix

\### API Overload

One common reason for the "temporary\_unavailable" error is that the API is overloaded with requests, causing temporary unavailability.

To fix this, you can:

1\. \*\*Wait and retry\*\*: Wait for a short period and then retry your request. The API should become available once the load decreases.
2\. \*\*Rate limiting\*\*: Implement rate limiting on your end to avoid overwhelming the API with too many requests in a short period.

\### Temporary Errors

Temporary errors or issues within the API infrastructure can also cause this error.

To fix this, consider:

1\. \*\*Retry the request\*\*: Since the issue is temporary, retrying the request after a brief wait is often effective.
2\. \*\*Monitor status page\*\*: Check \[the API status page\](https://status.screenshotone.com/) to see if there are any ongoing issues.

\### Scheduled Maintenance

The API might be undergoing scheduled maintenance, leading to temporary unavailability.

\### Network Issues

Network issues between your system and the API server can also result in this error.

To fix this, ensure your network connection is stable and retry the request.

\## Implementing Retry Logic

Implementing retry logic in your application can help handle temporary unavailability gracefully. Use exponential backoff strategy for retries to avoid overwhelming the API further.

\## Reach out to support

If you continue to face issues or need further assistance, please reach out to \`support@screenshotone.com\`, and we will assist you as soon as possible.

\# Timeout Error

It is an API error returned when the API can't render screenshots or video within the specified timeout:

\`\`\`json
{
 "is\_successful": false,
 "error\_code": "timeout\_error",
 "error\_message": "The screenshot couldn't be taken within the specified timeout. Either the site doesn't respond quickly, or rendering takes longer than expected. Play with the \`timeout\` or the \`navigation\_timeout\` options or reach the support for the investigation.",
 "documentation\_url": "https://screenshotone.com/docs/errors/"
}
\`\`\`

\## Reasons and how to fix

Let's quickly consider possible reasons and possible solutions.

\### Timeout is too small

By default, the timeout is about 60 seconds. You must fit your rendering request within that timeout.

You can:

Either use asynchronous requests and webhooks to get the results. And set the timeout up to 300 seconds.
Or you can try to increase the timeout up to 90 seconds.

\### Delay is too big

Make sure that your delay is not too big, e.g. if you set it to 30 seconds, and it takes the website to load for 30 seconds, it is better to decrease the delay.

\### A website is not loading properly

Some sites just take too much time to load or they don't emit DOMContentLoaded events.

Try to play with different values of \[the wait\_until option\]() and see if it helps.

\### Long duration of the video

Often when you record a video of a long duration, the API must not respond in time. Since it takes to both record a video and stream it.

Try to decrease the video duration you are recording, it might help.

\## Reach out to support

If nothing helps you, please, reach out to \`support@screenshotone.com\` and we will try to help you as fast as possible.

\# Usage Quota Exceeded

It is an API error returned when the monthly usage quota has been exceeded:

\`\`\`json
{
 "is\_successful": false,
 "error\_code": "screenshots\_limit\_reached",
 "error\_message": "The usage quota has been exceeded. Please, either upgrade to a plan with more quota or change the maximum allowed limit (if possible) in the ScreenshotOne dashboard. If it is a mistake, please, reach out at \`support@screenshotone.com.\`",
 "documentation\_url": "https://screenshotone.com/docs/usage-quota-exceeded/"
}
\`\`\`

\## Reasons and how to fix

There is a few ways on how to fix the error:

1\. If you use a free plan, you need to upgrade to a paid plan. You can do that at \[the Dashboard Billing page\](https://dash.screenshotone.com/billing).
2\. If you are already a paying customer, please, consider upgrade to a higher plan.
3\. Or you can \[request extra quota\](/docs/charging-extra/).

\## Reach out to support

If nothing helps you, please, reach out to \`support@screenshotone.com\` and we will try to help you as fast as possible.

\# Getting Started

You can use the API to generate invoices in PDF format for any given URL or HTML. Or make hundreds of screenshots of your site with different options to check that the site looks as expected.

Whatever use case you have, I get you covered. If there is a feature missing, please, contact me, and I will try to help you as fast as possible.

\## First Touch

ScreenshotOne API is straightforward to use. There is an example of an actual request to an API:

\`\`\`
GET https://api.screenshotone.com/take?url=https://apple.com&access\_key=
\`\`\`

The result is:
!\[A screenshot of the Apple site\](apple-screenshot.png)

\[Sign up\](https://dash.screenshotone.com/sign-up) to get the access key and start taking screenshots.

\## Requests

ScreenshotOne API supports both GET and POST HTTP requests.

All requests are sent over HTTPS. HTTPS is a non-negotiable requirement to protect your privacy.

To take a screenshot of the site with GET HTTP request, send a request to:

\`\`\`
https://api.screenshotone.com/take?\[options\]
\`\`\`

Takes and returns a screenshot of the given site with specified \[options\](/docs/options).

If you send a POST HTTP request to take a screenshot, you should specify options as JSON in the body of the request:

\`\`\`
POST https://api.screenshotone.com/take
Content-Type: application/json
{
 ...\[options\]
}
\`\`\`

\### Access key

You can specify the access key as part of \`GET\` parameters, \`POST\` \`JSON\` body, or as a header \`X-Access-Key\`.

\## Responses

The response format depends on the given options. You might request API to return an image of PNG type or raw HTML instead of rendering it.

API returns the \`Content-Type\` header set according to the relevant MIME type for the requested format in options.

Since API returns binary in the data, you can safely put the request URL to ScreenshotOne API directly into the  and tags:

\`\`\`
![A screenshot of apple.com](https://api.screenshotone.com/take?url=apple.com&access_key=%3Cyour%20access%20key%3E)
\`\`\`

\## Errors

The request might return an error due to an internal error, invalid options or when the limit is reached. ScreenshotOne API follows the HTTP status code semantic and returns JSON in case of an error:

\`\`\`
GET https://api.screenshotone.com/?\[options\]

Content-Type: application/json
{
 "error": {
     "code": "an\_error\_code",
        "message": "An error message"
    }
}
\`\`\`

The API will always return \[a human-readable error message, error code, and suitable HTTP status code\](/docs/errors).

\# No-code Integrations

All available no-code integrations for ScreenshotOne:

\- \[Zapier\](/docs/no-code/zapier/);
\- \[Make\](/docs/no-code/make/);
\- \[n8n\](/docs/no-code/n8n/);
\- \[Bubble\](/docs/no-code/bubble/).
\- \[Clay\](/docs/no-code/clay/).

Please, reach out to us at \[support@screenshotone.com\](mailto:support@screenshotone.com) if you have any questions, need any assistance or want to request a new integration.

\# Guides

Check out our collection of guides to help you get the most out of ScreenshotOne:

\- \[How to handle API errors\](/docs/guides/how-to-handle-api-errors/)
\- \[How to use proxies\](/docs/guides/how-to-use-proxies/)
\- \[How to optimize for performance\](/docs/guides/performance/)
\- \[How to screenshot authenticated pages\](/docs/guides/authenticated-pages/)
\- \[How to take full-page screenshots\](/docs/guides/full-page-screenshots/)
\- \[How to bypass CAPTCHAs\](/docs/guides/how-to-bypass-captchas/)
\- \[Upload to any S3 storage\](/docs/guides/upload-to-s3/)
\- \[How to screenshot an area of a site\](/docs/guides/how-to-screenshot-an-area-of-a-site/)
\- \[Translate and screenshot a website\](/docs/guides/how-to-translate-and-render-a-website-as-a-screenshot/)
\- \[How to customize websites\](/docs/guides/how-to-customize-any-website-before-screenshotting/)
\- \[Fail rendering if the content contains a string\](/docs/guides/fail-if-content-contains/)
\- \[Render Google Slides as scrolling screenshots\](/docs/guides/google-slides-as-scrolling-screenshots/)
\- \[Screenshot Google Documents\](/docs/guides/screenshot-google-docs/)
\- \[Emojis\](/docs/guides/emojis/)
\- \[How to detect website fonts\](/docs/guides/how-to-detect-website-fonts/)
\- \[How to take screenshots of multiple URLs\](/docs/guides/bulk-screenshots/)

\# Screenshot Options

import Alert from "@/components/Alert.astro";
import Details from "@/components/docs/Details.astro";

This document lists all available request options to take screenshots of websites, render HTML, or Markdown.

\## Credentials

\### access\_key

Each request must have an access key to authenticate the API user. You can find it on the \[access page\](https://dash.screenshotone.com/access).

An example of the request URL with \`access\_key\`:

\`\`\`
https://api.screenshotone.com/take?url=https://apple.com&access\_key=
\`\`\`

 !\[A screenshot of the Apple site taken by screenshot\
 API\](./default\_example.png)

\### signature

A signature is optional. It is used for \[the signed requests\](/docs/signed-requests).

 Do not use the secret (signing) key as a signature. A signature is a complex
 parameter that is \[a hash of all screenshot parameters with a signing\
 key\](/docs/signed-requests).

You can force signing all requests \[access page\](https://dash.screenshotone.com/access).

\## Essentials

\### url

URL of the site to take a screenshot of. One of the \[Markdown\](#markdown), \[HTML\](#html) or \[URL\](#url) parameters is required.

An example of the request URL with \`url=https://www.youtube.com/feed/explore\`:

\`\`\`
https://api.screenshotone.com/take?url=https://www.youtube.com/feed/explore&access\_key=
\`\`\`

 !\[A screenshot of the Youtube site taken by screenshot\
 API\](./youtube\_example.png)

\### html

HTML you want to render. One of the \[Markdown\](#markdown), \[HTML\](#html) or \[URL\](#url) parameters is required.

An example of the request URL with \`html=

# Hello, world!

\`:

\`\`\`
https://api.screenshotone.com/take?html=

# Hello,%20world!

&access\_key=
\`\`\`

 !\[A screenshot of the custom HTML taken by screenshot\
 API\](./html\_example.png)

\### markdown

Markdown you want to render. One of the \[Markdown\](#markdown), \[HTML\](#html) or \[URL\](#url) parameters is required.

An example of the request URL with \`markdown=# Hello, world!\` (encoded to \`markdown=%23%20Hello%2C%20world!\`):

\`\`\`
https://api.screenshotone.com/take?html=%23%20Hello%2C%20world!&access\_key=
\`\`\`

 !\[A screenshot of the custom Markdown taken by screenshot\
 API\](./markdown.jpeg)

\### format

 You can get the HTML content of the page and image in one request by using
 the \[metadata\_content\](#metadata\_content) parameter.

Available response formats:

\- \`png\`
\- \`jpeg\` or \`jpg\`
\- \`webp\`
\- \`gif\`
\- \`jp2\`
\- \`tiff\`
\- \`avif\`
\- \`heif\`
\- \`pdf\` (see \[PDF options\](#pdf-rendering))
\- \`html\` (text representation)
\- \`markdown\` (text representation)

Default value is \`jpg\`.

An example of the request URL with \`format=jpeg\` (an alias for \`format=jpg\`):

\`\`\`
https://api.screenshotone.com/take?format=jpeg&url=https://apple.com&access\_key=
\`\`\`

 !\[A screenshot of the Apple site taken by screenshot\
 API\](./format\_jpeg\_example.jpeg)

For the HTML format (\`format=html\`), consider including the shadow DOM elements with the \[\`include\_shadow\_dom\`\](#include\_shadow\_dom) option.

\### response\_type

Available response types:

\- \`by\_format\` — return exactly the response defined in the \[format option\](#format). If \`format=png\`, the response will be the binary representation of the \`png\` with the content type header \`image/png\`. \*\*With this option (default), screenshots are not stored on ScreenshotOne servers\*\* unless you explicitly enable \[caching\](#caching), \[storage\](#storing) options or similar.
\- \`empty\` — return only status or error. It is suitable when you want to \[upload the screenshot to storage\](#storing) and don't care about the results. It also speeds up the response since there are no networking costs involved.
\- \`json\` — A method returns the response in the JSON format, but it is only suitable if you use options that are effective for JSON. By default, the JSON response will be empty. But for example, when you use \[caching\](#caching), the JSON will be populated with additional data. (This option might temporarily store the rendered content on ScreenshotOne servers to serve the screenshot or other content URLs for you.)

ScreenshotOne API doesn't support the \`base64\` encoding format. But you can get the screenshot in the binary format and convert it to the \`base64\` encoding with your language of choice.

The default value is \`by\_format\`.

An example of the request URL:

\`\`\`
https://api.screenshotone.com/take?response\_type=empty&url=https://example.com&access\_key=
\`\`\`

\### selector

A CSS-like selector of the element to take a screenshot of. It is optional.

If the selector is specified and \`error\_on\_selector\_not\_found=true\`, the error will be returned if the element by selector is not visible or it took more than \`timeout\` seconds to render it, but not more than 30 seconds.

For HTML or Markdown formats, the selector returns the outer rendered HTML of the provided input.

Supports \`shadow/\` selectors which will traverse the shadow DOM elements. It will be slower, and if many elements have the same selectors, the first one will be chosen.

An example of the request URL with \`selector=.content\`:

\`\`\`
https://api.screenshotone.com/take?selector=.content&url=https://scalabledeveloper.com/posts/context-in-go/&access\_key=
\`\`\`

 !\[A screenshot of the content part of the Scalable Developer site taken by\
 screenshot API\](./scalable\_developer\_content\_example.png)

The same page without selector:

\`\`\`
https://api.screenshotone.com/take?url=https://scalabledeveloper.com/posts/context-in-go/&access\_key=
\`\`\`

 !\[A screenshot of the Scalable Developer site taken by screenshot\
 API\](./scalable\_developer\_example\_without\_selector.png)

Setting the \[selector\](#selector) option changes the behavior of the \[capture\_beyond\_viewport\](#capture\_beyond\_viewport) option, and sets it to \`true\` by default.

\### selector\_algorithm

The default algorithm is \`default\` which means to use the browser tools to screenshot the element by selector. But the new algorithm \`clip\` allows more flexibility and better results for some cases.

E.g. if you need to screenshot the element by selector and the element is not fully visible, or it requires scrolling to screenshot the element, the \`clip\` algorithm will be more suitable.

An example of the API request URL with \`selector\_algorithm=clip\`:

\`\`\`
https://api.screenshotone.com/take?selector\_algorithm=clip&selector=h1&url=https://example.com&access\_key=
\`\`\`

\### selector\_scroll\_into\_view

When you take a screenshot of an element by \[selector\](#selector), there is a rare case where the page or the part of the element might not be visible on the viewport or
the element might contain lazy loaded images or elements that are not visible on the viewport.

With the \`selector\_scroll\_into\_view\` option, you control if you want to scroll the page to the element or not and to trigger lazy loaded images and elements.

The option is set to \`true\` by default.

\### capture\_beyond\_viewport

When you take \[a full page screenshot\](#full\_page) or a screenshot of an element by \[selector\](#selector), there is a rare case where the page or the part of the element might not be visible on the viewport.

With the \`capture\_beyond\_viewport\` option, you control if you want to take the screenshot of the full page or the element (\`capture\_beyond\_viewport=true\`) or if you are OK with taking a screenshot of the part of the page or the element (\`capture\_beyond\_viewport=false\`).

When you take \[full page screenshot\](#full\_page) or you take screenshot of an element by \[selector\](#selector).

The option is set to \`true\` by default for the full-page screenshots, when \[full\_page\](#full\_page) is \`true\`.

You might find it useful to check out \[the examples of how the captureBeyondViewport option works\](/blog/capture-beyond-viewport-in-puppeteer-and-chrome-devtools-protocol) "examples of how the captureBeyondViewport option works").

The option is \`true\` by default for the screenshots by the \[selector\](#selector), too.

\### scroll\_into\_view

It scrolls the page if needed and ensures that the given selector is present in the view when taking a screenshot.

If more than one element matches the selector, the first visible element in DOM is selected.

The element will be positioned at the top of the viewport. To adjust the position a bit before taking a screenshot,
use the \[scroll\_into\_view\_adjust\_top\](#scroll\_into\_view\_adjust\_top) option.

In case, if the selector is not found, it will render the viewport at the top of the page. To change this behavior, use the \[error\_on\_selector\_not\_found\](#error\_on\_selector\_not\_found) option, set it to \`true\` to return an error if the selector is not found.

An example of the request URL:

\`\`\`
https://api.screenshotone.com/take?scroll\_into\_view=%23faq&url=https://screenshotone.com&access\_key=
\`\`\`

\### scroll\_into\_view\_adjust\_top

After the given element appears in the viewport and its top coordinate is aligned with the viewport's top, you can adjust the position a bit before taking a screenshot by specifying the \`scroll\_into\_view\_adjust\_top\` parameter.

By default, it is \`0\`. But you can use negative and positive integers.

An example of the request URL:

\`\`\`
https://api.screenshotone.com/take?scroll\_into\_view\_adjust\_top=-100&scroll\_into\_view=%23faq&url=https://screenshotone.com&access\_key=
\`\`\`

\### request\_gpu\_rendering

By default is disabled and currently available only for the top-tier paid plans.

Setting \`request\_gpu\_rendering\` to \`true\` hints API to route requests to servers with supported hardware rendering acceleration.

It is not 100% guaranteed to satisfied and software acceleration might be used as a fallaback, but most of the time the ScreenshotOne API will do its best to render screenshots with GPU support if the option is set to \`true\`.

However, you can use the \`fail\_if\_gpu\_rendering\_fails\` option to force the request to fail if GPU rendering fails.

\### include\_shadow\_dom

By default is disabled and equals to \`false\`.

Setting \`include\_shadow\_dom\` to \`true\` will use a different method of content extraction for requests that has \`format=html\`
or request \`metadata\_content=true\`. The API will try to include all open and closed shadow DOM roots in the content. By default, they are not included.

\### attachment\_name

The option allows you to specify the name of the attachment. The format will be added as a suffix to the name.

\`\`\`
https://api.screenshotone.com/take?attachment\_name=screenshot&url=https://example.com&access\_key=&format=jpg
\`\`\`

It will trigger the browser to download the screenshot with the name \`screenshot.jpg\`

\### external\_identifier

You can set \`external\_identifier\` parameter to any alphanumeric value. It will be included in the webhook request headers:

\- \`x-screenshotone-external-identifier\`—external identifier. It is helpful for error and successful request tracking.

\## PDF Rendering

If you want resulting PDF reflects a full page screenshot as close as possible, use the combination of next options:

\`\`\`
format=pdf&media\_type=screen&pdf\_print\_background=true&pdf\_fit\_one\_page=true
\`\`\`

\### pdf\_print\_background

Set to \`true\` to print background graphics. The default value is \`false\`.

\### pdf\_fit\_one\_page

The default value is \`false\`.

When the option is set to \`true\`\`, the API will try to fit the website on one page. It is the closest equivalent to a full-page screenshot as a PDF without splitting into pages.

\### pdf\_landscape

Set to \`true\` to set PDF orientation to landscape. It is \`false\` by default.

\### pdf\_paper\_format

Specifies the paper format for the PDF output. Available options are:

\- "a0": ISO A0 paper size (841 x 1189 mm)
\- "a1": ISO A1 paper size (594 x 841 mm)
\- "a2": ISO A2 paper size (420 x 594 mm)
\- "a3": ISO A3 paper size (297 x 420 mm)
\- "a4": ISO A4 paper size (210 x 297 mm)
\- "a5": ISO A5 paper size (148 x 210 mm)
\- "a6": ISO A6 paper size (105 x 148 mm)
\- "legal": Legal paper size (8.5 x 14 inches)
\- \*\*"letter": Letter paper size (8.5 x 11 inches)—default.\*\*
\- "tabloid": Tabloid paper size (11 x 17 inches)

If not specified, the default paper format is "a4".

\### pdf\_margin

Specifies the margin for the PDF file. By default, the margin is \`0\`.

But you can set it to any value in string format, e.g. \`pdf\_margin=20px\` or other supported units.

You can then override the margin for each side separately:

\`\`\`
pdf\_margin=20px&pdf\_margin\_top=0px
\`\`\`

This will set the margin for all sides to \`20px\` except the top, which will be \`0px\`.

\### pdf\_margin\_top

The top margin for the resulting PDF.

\### pdf\_margin\_right

The top margin for the resulting PDF.

\### pdf\_margin\_bottom

The top margin for the resulting PDF.

\### pdf\_margin\_left

The top margin for the resulting PDF.

\## OpenAI Vision Integration

ScreenshotOne supports direct integration with \[OpenAI vision\](https://platform.openai.com/docs/guides/vision), so you can get a screenshot and generate vision prompt completion in one simple API call with no additional cost.

You will get the result either as a \`X-ScreenshotOne-Vision-Completion\` header in the reponse or as:

\`\`\`json
{

 "vision": {
 "completion": "..."
 }
}
\`\`\`

If you use \`response\_type=json\`.

\### openai\_api\_key

Use your OpenAI API key to send requests to the OpenAI API key. It is not stored in the ScreenshotOne database.

\### vision\_prompt

Specify the prompt you want to use along with the screenshot of the site.

\### vision\_max\_tokens

Specify how many tokens at max the GPT vision must return as a response.

\## Clip

There is a guide on \[how to screenshot an area of a site\](/docs/guides/how-to-screenshot-an-area-of-a-site/) with examples of how to use clip options.

\### clip\_x

You can use clip options (\[clip\_x\](#clip\_x), \[clip\_y\](#clip\_y), \[clip\_width\](#clip\_width), \[clip\_height\](#clip\_height)) to clip only the part of the screen.

The \`clip\_x\` option specifies only the top coordinate (x) of the area to clip.

\### clip\_y

You can use clip options (\[clip\_x\](#clip\_x), \[clip\_y\](#clip\_y), \[clip\_width\](#clip\_width), \[clip\_height\](#clip\_height)) to clip only the part of the screen.

The \`clip\_y\` option specifies only the left coordinate (y) of the area to clip.

\### clip\_width

You can use clip options (\[clip\_x\](#clip\_x), \[clip\_y\](#clip\_y), \[clip\_width\](#clip\_width), \[clip\_height\](#clip\_height)) to clip only the part of the screen.

The \`clip\_width\` option specifies only the width of the area to clip.

\### clip\_height

You can use clip options (\[clip\_x\](#clip\_x), \[clip\_y\](#clip\_y), \[clip\_width\](#clip\_width), \[clip\_height\](#clip\_height)) to clip only the part of the screen.

The \`clip\_height\` option specifies only the width of the area to clip.

\## Full page

Read more suggestions on \[how to take better full-page screenshots\](/docs/guides/full-page-screenshots/).

\### full\_page

To take the screenshot of the full page, set \`full\_page=true\`.

Default value is \`false\`.

When \`full\_page\` is set to \`true\`, \[full\_page\_scroll\](#full\_page\_scroll) is automatically set to \`true\`, until you override it. It is done to make sure that all lazy loaded images are requested and rendered.

An example of the request URL:

\`\`\`
https://api.screenshotone.com/take?full\_page=true&url=https://netflix.com&access\_key=
\`\`\`

 !\[A full page screenshot of the Apple site taken by screenshot\
 API\](./full\_page\_example.png)

\### full\_page\_scroll

If set to \`true\`, scrolls to the bottom of the page and back to the top. Default value is \`false\`.

When \`full\_page\` is set to \`true\`, \`full\_page\_scroll\` is automatically set to \`true\`, until you override it. It is done to make sure that all lazy loaded images are requested and rendered.

An example of the request URL:

\`\`\`
https://api.screenshotone.com/take?full\_page\_scroll=true&full\_page=true&url=https://netflix.com&access\_key=
\`\`\`

\### full\_page\_scroll\_delay

The default value is \`400\` microseconds. Use it to specify how fast you want to scroll the page to the bottom.

Some sites require larger values than \`400\` microseconds to trigger the loading of lazy-load images.

Use it in combination with \[full\_page\_scroll\_delay\](#full\_page\_scroll\_by) to find optimal solution.

An example of the request URL:

\`\`\`
https://api.screenshotone.com/take?full\_page\_scroll\_delay=1000&full\_page\_scroll=true&full\_page=true&url=https://netflix.com&access\_key=
\`\`\`

\### full\_page\_scroll\_by

The default value is the height of the viewport. Use it to specify how fast you want to scroll the page to the bottom.

Some sites require values less than viewport height to trigger the loading of lazy-load images. Try to play with values between \`100\` and \`500\`. However, don't hesitate to try out any value that might work for you.

Use it in combination with \[full\_page\_scroll\_delay\](#full\_page\_scroll\_delay) to find optimal solution.

An example of the request URL:

\`\`\`
https://api.screenshotone.com/take?full\_page\_scroll\_by=400&full\_page\_scroll=true&full\_page=true&url=https://netflix.com&access\_key=
\`\`\`

\### full\_page\_max\_height

The default value is not set. Use it to limit the height of the full page screenshot. Also allows to handle
and fix problems related to infinite scrolling.

An example of the request URL:

\`\`\`
https://api.screenshotone.com/take?full\_page\_max\_height=10000&full\_page\_scroll=true&full\_page=true&url=https://netflix.com&access\_key=
\`\`\`

\### full\_page\_algorithm

The default value is \`default\`.

The \`default\` algorithm is the same as the one used in the Chrome DevTools Protocol, with some tuning and for some websites with different optimizations.

But if you set \`full\_page\_algorithm=by\_sections\`, the API will take a screenshot section by section and then combine them into one image.
It allows more complex pages with animations to be rendered correctly.

The \`by\_sections\` will scroll the website automatically regardless of the \[full\_page\_scroll\](#full\_page\_scroll) option value.

\## Viewport

When rendering a full-page screenshot, the viewport dimensions play an important role and affect the quality of the screenshot, please, check out \[the guide on how to take better full-page screenshots\](/docs/guides/full-page-screenshots/) for more details.

\### viewport\_device

\*\*The default value is not set.\*\*

Instead of manually specifying viewport parameters like width and height, you can specify a device to use for emulation. In addition, other parameters of the viewport, including the user agent, will be set automatically.

The \`viewport\_device\` option sets the next options for you: \[viewport\_width\](#viewport\_width), \[viewport\_height\](#viewport\_height), \[device\_scale\_factor\](#device\_scale\_factor), \[viewport\_mobile\](#viewport\_mobile), \[viewport\_has\_touch\](#viewport\_has\_touch), \[viewport\_landscape\](#viewport\_landscape). You can change these options and override the ones set by the \`viewport\_device\` option.

Use \[the list of devices\](/docs/viewport-devices/) for available values. Use the \`id\` property of the device as \`viewport\_device\`, e.g. \`viewport\_device=galaxy\_s9+\_landscape\`.

 API does not use an actual device to take a screenshot. It is emulation that
 works in most cases.

An example of the request URL with \`viewport\_device=iphone\_13\_pro\_max\_landscape\`:

\`\`\`
https://api.screenshotone.com/take?viewport\_device=iphone\_13\_pro\_max\_landscape&url=https://tailwindcss.com&access\_key=
\`\`\`

 !\[A screenshot of the Apple site taken by screenshot API for the specified\
 device\](./viewport\_device\_example.jpeg)

\### viewport\_width

 If the \[viewport\_device\](#viewport\_device) option is set, the parameter
 overrides it!

The width of the browser viewport (pixels).

The browser's viewport is the window area where you can see the web content.

Default value is \`1280\`.

An example of the request URL with \`viewport\_width=1920\` and \`viewport\_height=1080\`:

\`\`\`
https://api.screenshotone.com/take?viewport\_width=1920&viewport\_height=1080&url=https://apple.com&access\_key=
\`\`\`

 !\[A full page screenshot of the Apple site taken by screenshot\
 API\](./viewport\_width\_and\_height\_example.png)

\### viewport\_height

 If the \[viewport\_device\](#viewport\_device) option is set, the parameter
 overrides it!

The height of the browser viewport (pixels).

The browser's viewport is the window area where you can see the web content.

Default value is \`1024\`.

An example of the request URL with \`viewport\_width=1920\` and \`viewport\_height=1080\`:

\`\`\`
https://api.screenshotone.com/take?viewport\_width=1920&viewport\_height=1080&url=https://apple.com&access\_key=
\`\`\`

 !\[A full page screenshot of the Apple site taken by screenshot\
 API\](./viewport\_width\_and\_height\_example.png)

\### device\_scale\_factor

 If the \[viewport\_device\](#viewport\_device) option is set, the parameter
 overrides it!

Set the device scale factor, think of it as DPR (Device Pixel Ratio). The acceptable value is between the range of 1 and 5, including real numbers, like 2.25.

Set 2 if you need to render a screenshot with a higher pixel density like Apple's Retina Display.

The parameter can override the value set by \[viewport\_device\](#viewport\_device) option.

An example of the request URL with \`device\_scale\_factor=1\`:

\`\`\`
https://api.screenshotone.com/take?device\_scale\_factor=1&url=https://apple.com&access\_key=
\`\`\`

 !\[A full page screenshot of the Apple site taken by screenshot\
 API\](./device\_scale\_factor\_1\_example.png)

An example of the request URL with \`device\_scale\_factor=2\`:

\`\`\`
https://api.screenshotone.com/take?device\_scale\_factor=2&url=https://apple.com&access\_key=
\`\`\`

 !\[A full page screenshot of the Apple site taken by screenshot\
 API\](./device\_scale\_factor\_2\_example.png)

\### viewport\_mobile

 If the \[viewport\_device\](#viewport\_device) option is set, the parameter
 overrides it!

Whether the \[meta viewport\](https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport\_meta\_tag) tag is taken into account. Defaults to \`false\`.

An example of the request URL with \`viewport\_mobile=true\`:

\`\`\`
https://api.screenshotone.com/take?viewport\_mobile=true&url=https://example.com&access\_key=
\`\`\`

\### viewport\_has\_touch

 If the \[viewport\_device\](#viewport\_device) option is set, the parameter
 overrides it!

The default value is \`false\`. Set to \`true\` if the viewport supports touch events.

The parameter can override the value set by \[viewport\_device\](#viewport\_device) option.

An example of the request URL with \`viewport\_has\_touch=true\`:

\`\`\`
https://api.screenshotone.com/take?viewport\_has\_touch=true&url=https://example.com&access\_key=
\`\`\`

\### viewport\_landscape

 If the \[viewport\_device\](#viewport\_device) option is set, the parameter
 overrides it!

The default value is \`false\`. Set to \`true\` if the viewport is in landscape mode.

The parameter can override the value set by \[viewport\_device\](#viewport\_device) option.

An example of the request URL with \`viewport\_landscape=true\`:

\`\`\`
https://api.screenshotone.com/take?viewport\_landscape=true&url=https://example.com&access\_key=
\`\`\`

\## Image

\### image\_quality

Render image with specified quality. Available for the next formats:

\- \`jpeg\` (\`jpg\`)
\- \`webp\`
\- \`png\`
\- \`tiff\`
\- \`jp2\`
\- \`avif\`
\- \`hei\`

Allowed range is between 0 and 100. Default value is \`80\`.

An example of the request URL with \`image\_quality=10\`:

\`\`\`
https://api.screenshotone.com/take?format=webp&image\_quality=10&url=https://apple.com&access\_key=
\`\`\`

 !\[A screenshot of the Apple site taken by screenshot\
 API\](./format\_jpeg\_low\_quality\_example.jpeg)

\### image\_width

The \`image\_width\` and \`image\_height\` parameters allow you to create a thumbnail of the screenshot.

By default \`image\_width\` = \[viewport\_width\](#viewport\_width) and \`image\_height\` = \[viewport\_height\](#viewport\_height).

If you specify image width and height parameters, the API will resize a screenshot, preserving the aspect ratio. The image will be resized to be as large as possible while ensuring its dimensions are less than or equal to the image width and height specified.

If you omit one of the parameters, the other is computed automatically, preserving the aspect ratio.

An example of the request with \`image\_width=500\`:

\`\`\`
https://api.screenshotone.com/take?image\_width=500&url=https://example.com/&access\_key=
\`\`\`

\### image\_height

The \`image\_width\` and \`image\_height\` parameters allow you to create a thumbnail of the screenshot.

By default \`image\_width\` = \[viewport\_width\](#viewport\_width) and \`image\_height\` = \[viewport\_height\](#viewport\_height).

If you specify image width and height parameters, the API will resize a screenshot, preserving the aspect ratio. The image will be resized to be as large as possible while ensuring its dimensions are less than or equal to the image width and height specified.

If you omit one of the parameters, the other is computed automatically, preserving the aspect ratio.

An example of the request with \`image\_width=500&image\_height=400\`:

\`\`\`
https://api.screenshotone.com/take?image\_width=500&image\_height=400&url=https://example.com/&access\_key=
\`\`\`

\### omit\_background

Render a transparent background for the image. Works only if the site has not defined background color. Available for the following response formats:

\- \`png\`
\- \`webp\`

Default value is \`false.

Set \`omit\_background=true\` to take a screenshot with the transparent background.

\## Emulations

\### dark\_mode

The default value is not set.

Set \`true\` to request site rendering, if supported, in the dark mode. Set \`false\` to request site rendering in the light mode if supported. If you don't set the parameter. The site is rendered in the default mode.

An example of the request URL with \`dark\_mode=true\`:

\`\`\`
https://api.screenshotone.com/take?dark\_mode=true&url=https://tailwindcss.com/&access\_key=
\`\`\`

 !\[A screenshot of the tailwindcss.com site taken by screenshot API in the\
 dark mode\](./tailwindcss.com\_dark\_mode.png)

\### reduced\_motion

When \`reduced\_motion\` set to \`true\`, the API will request the site to minimize the amount of non-essential motion it uses. When the site supports it, it should use animations as least as possible.

An example of the request URL with \`reduced\_motion=true\`:

\`\`\`
https://api.screenshotone.com/take?reduced\_motion=true&url=https://tailwindcss.com/&access\_key=
\`\`\`

\### media\_type

If you want to request the page and it is supported to be rendered for printers, specify \`print\`. If the page is by default rendered for printers and you want it to be rendered for screens, use \`screen\`.

An example of the request URL with \`media\_type=print\`:

\`\`\`
https://api.screenshotone.com/take?media\_type=print&url=https://example.com/&access\_key=
\`\`\`

\## Customization

\### hide\_selectors

The \`hide\_selectors\` option allows hiding elements before taking a screenshot. You can specify as many selectors as you wish. \*\*All\*\* elements that match each selector will be hidden by setting the \`display\` style property to \`none !important\`.

An example of the request URL with \`hide\_selectors=.a&hide\_selectors=.b\`:

\`\`\`
https://api.screenshotone.com/take?hide\_selectors=.a&hide\_selectors=.b&url=https://example.com/&access\_key=
\`\`\`

\### scripts

\`scripts\` parameter allows to inject custom JavaScript and customize the page behavior.

An example of the request URL with \`scripts=document.body.innerHTML="Hello, world!"\`:

If the script might trigger a redirect by using window.location functions or something similar, it is required
to set \[the "scripts\_wait\_until" option\](#scripts\_wait\_until).

\`\`\`
https://api.screenshotone.com/take?scripts=document.body.innerHTML="Hello,%20world!"&url=https://example.com/&access\_key=
\`\`\`

 !\[A screenshot of the example.com site taken by screenshot\
 API\](./scripts\_example.png)

\### scripts\_wait\_until

The default value of \`scripts\_wait\_until\` is \`\[\]\` — nothing, no wait at all.

The \`scripts\_wait\_until\` option allows you to wait until a given set of events after the \[scripts\](#scripts) were executed. You need to use in case, if your script might trigger page reloading, like:

\`\`\`javascript
window.location = "https://example.com";
\`\`\`

It accepts the same values as \[wait\_until\](#wait\_until) and can have multiple values:

\- \`load\`: the navigation is successful when the load even is fired;
\- \`domcontentloaded\`: the navigation is finished when the DOMContentLoaded even is fired;
\- \`networkidle0\`: the navigation is finished when there are no more than 0 network connections for at least 500 ms;
\- \`networkidle2\`: consider navigation to be finished when there are no more than 2 network connections for at least 500 ms.

The parameter accepts many values. It means that screenshots will be taken after all events occur altogether.

An example of the request with \`scripts\_wait\_until=networkidle2&scripts\_wait\_until=domcontentloaded\`:

\`\`\`
https://api.screenshotone.com/take?scripts\_wait\_until=networkidle2&scripts\_wait\_until=domcontentloaded&url=https://example.com/&access\_key=
\`\`\`

\### styles

\`styles\` parameter allows to inject custom styles and customize the page. It might help generate beautiful images for the Open Graph protocol.

An example of the request URL with \`styles=h1{color: red;}\`:

\`\`\`
https://api.screenshotone.com/take?styles=h1{color:%20red;}&url=https://example.com/&access\_key=
\`\`\`

 !\[A screenshot of the example.com site taken by screenshot\
 API\](./example\_styles.png)

A screenshot without styles for comparison:

 !\[A screenshot of the example.com site taken by screenshot\
 API\](./example\_without\_styles.png)

\### click

Specify the CSS selector of an element to click on before taking the screenshot. It could be anything, including a button, link, or even a regular \`div\` element.

Supports \`shadow/\` selectors which will traverse the shadow DOM elements. It will be slower, and if many elements have the same selectors, the first one will be chosen.

An example of the request URL with \`click=.a-some-button-class-selector\`:

\`\`\`
https://api.screenshotone.com/take?click=.a-some-button-class-selector&url=https://example.com&access\_key=
\`\`\`

\### hover

Specify the CSS selector of an element to hover on before taking the screenshot. It could be anything, including a button, link, or even a regular \`div\` element.

Supports \`shadow/\` selectors which will traverse the shadow DOM elements. It will be slower, and if many elements have the same selectors, the first one will be chosen.

An example of the request URL with \`hover=.a-some-button-class-selector\`:

\`\`\`
https://api.screenshotone.com/take?hover=.a-some-button-class-selector&url=https://example.com&access\_key=
\`\`\`

\### error\_on\_click\_selector\_not\_found

If the element by selector to click is not visible or it took more than timeout seconds to render it, the error will be returned. Default value is \`true\`.

Set \`error\_on\_click\_selector\_not\_found=false\` to do not throw an error if the element by selector is not found.

\### error\_on\_hover\_selector\_not\_found

If the element by selector to hover is not visible or it took more than timeout seconds to render it, the error will be returned. Default value is \`true\`.

Set \`error\_on\_hover\_selector\_not\_found=false\` to do not throw an error if the element by selector is not found.

\## Blocking

\### block\_cookie\_banners

Blocks cookie banners, GDPR overlay windows, and other privacy-related notices. Default value is \`false\` when the \`url\` option is set.

It is useful when you want to take "clean" screenshots.

An example of the request URL with \`block\_cookie\_banners=true\`:

\`\`\`
https://api.screenshotone.com/take?block\_cookie\_banners=true&url=https://stackoverflow.com&access\_key=
\`\`\`

 !\[A screenshot of the StackOverflow site taken by screenshot\
 API\](./stackoverflow.com\_without\_cookie\_banner.png)

An example of the request URL with \`block\_cookie\_banners=false\`:

\`\`\`
https://api.screenshotone.com/take?block\_ads=false&url=https://stackoverflow.com&access\_key=
\`\`\`

 !\[A screenshot of the StackOverflow site taken by screenshot\
 API\](./stackoverflow.com\_with\_cookie\_banner.png)

\### block\_banners\_by\_heuristics

 The option might be helpful if the regular
 \[block\_cookie\_banners\](#block\_cookie\_banners) option doesn't work. This
 parameter uses a different set of techniques and heuristics to block
 banners. But use it at your own risk. The site screenshot might not be
 precise with it.

Blocks cookie banners, GDPR overlay windows, and other privacy-related notices. Default value is \`false\`.

It is useful when you want to take "clean" screenshots, but the \[block\_cookie\_banners\](#block\_cookie\_banners) option doesn't work.

An example of the request URL with \`block\_banners\_by\_heuristics=true\`:

\`\`\`
https://api.screenshotone.com/take?block\_banners\_by\_heuristics=true&url=https://example.com&access\_key=
\`\`\`

\### block\_chats

Blocks chats like Crisp, Facebook Messenger, Intercom, Drift, Tawk, User.com, Zoho SalesIQ and many others. Default value is \`false\` when the \`url\` option is set..

It is useful when you want to take "clean" screenshots.

An example of the request URL with \`block\_chats=true\`:

\`\`\`
https://api.screenshotone.com/take?block\_chats=true&url=https://screenshotone.com&access\_key=
\`\`\`

 !\[A screenshot of the ScreenshotOne site taken by screenshot\
 API\](./without\_chat\_widget.png)

An example of the request URL with \`block\_chats=false\`:

\`\`\`
https://api.screenshotone.com/take?block\_chats=false&url=https://screenshotone.com&access\_key=
\`\`\`

 !\[A screenshot of the ScreenshotOne site taken by screenshot\
 API\](./with\_chat\_widget.png)

\### block\_ads

Blocks ads. Default value is \`false\` when the \`url\` option is set..

It is useful when you want to take "clean" screenshots or don't want to generate a loss for advertisers.

An example of the request URL with \`block\_ads=true\`:

\`\`\`
https://api.screenshotone.com/take?block\_ads=true&url=https://scalabledeveloper.com/posts/linux-kernel-coding-style/&access\_key=
\`\`\`

 !\[A screenshot of the Scalable Developer site taken by screenshot\
 API\](./without\_ads\_example.png)

An example of the request URL with \`block\_ads=false\`:

\`\`\`
https://api.screenshotone.com/take?block\_ads=false&url=https://scalabledeveloper.com/posts/linux-kernel-coding-style/&access\_key=
\`\`\`

 !\[A screenshot of the Scalable Developer site taken by screenshot\
 API\](./with\_ads\_example.png)

\### block\_trackers

Block trackers. Default value is \`false\` when the \`url\` option is set.

It is useful when you don't want to count screenshots as client visits in your analytics app.

Set \`block\_trackers=true\` to disable all trackers.

\### block\_requests

Block requests by specifying URL, domain, or even a simple pattern like \`block\_requests=\*.example.com/\*\`. You can specify the parameter multiple times like \`block\_requests=example.com&block\_requests=http://\*\`.

Blocking requests by URL or domain can be used to test how the site responds when resources are not available. Or it might be used to speed up page loading.

Or, as an example, another way of blocking ads and trackers with \`block\_requests=\*.carbonads.com&block\_requests=\*.google-analytics.com\`:

\`\`\`
https://api.screenshotone.com/take?block\_requests=\*.carbonads.com&url=https://scalabledeveloper.com/posts/linux-kernel-coding-style/&access\_key=
\`\`\`

 !\[A screenshot of the Scalable Developer site taken by screenshot\
 API\](./without\_ads\_example.png)

\### block\_resources

Blocks loading resources by type. Available resource types are:

\- \`document\`
\- \`stylesheet\`
\- \`image\`
\- \`media\`
\- \`font\`
\- \`script\`
\- \`texttrack\`
\- \`xhr\`
\- \`fetch\`
\- \`eventsource\`
\- \`websocket\`
\- \`manifest\`
\- \`other\`

Blocking resources might be helpful when you need to optimize page loading speed before taking a screenshot.

You can specify multiple values as \`block\_resources=stylesheet&block\_resources=image\`:

\`\`\`
https://api.screenshotone.com/take?block\_resources=stylesheet&block\_resources=image&url=https://screenshotone.com&access\_key=
\`\`\`

 !\[A screenshot of the ScreenshotOne landing page site taken by screenshot\
 API\](./without\_styles\_and\_images.png)

\## Geolocation

\### geolocation\_latitude

Set geolocation latitude for the request. Both latitude and longitude are required if one of them is set.

Take a screenshot from Eiffel Tower with accuracy in 50 meters \`geolocation\_latitude=48.858184&geolocation\_longitude=2.294720&geolocation\_accuracy=50\`:

\`\`\`
https://api.screenshotone.com/take?geolocation\_latitude=48.858184&geolocation\_longitude=2.294720&geolocation\_accuracy=50&url=https://www.infobyip.com/browsergeolocation.php&access\_key=
\`\`\`

 !\[A screenshot from Eiffel Tower with accuracy in 50 meters taken by\
 screenshot API\](./eiffel\_tower.png)

\### geolocation\_longitude

Set geolocation longitude for the request. Both latitude and longitude are required if one of them is set.

Take a screenshot from Eiffel Tower with accuracy in 50 meters \`geolocation\_latitude=48.858184&geolocation\_longitude=2.294720&geolocation\_accuracy=50\`:

\`\`\`
https://api.screenshotone.com/take?geolocation\_latitude=48.858184&geolocation\_longitude=2.294720&geolocation\_accuracy=50&url=https://www.infobyip.com/browsergeolocation.php&access\_key=
\`\`\`

 !\[A screenshot from Eiffel Tower with accuracy in 50 meters taken by\
 screenshot API\](./eiffel\_tower.png)

\### geolocation\_accuracy

Set the geolocation accuracy in meters.

Take a screenshot from Eiffel Tower with accuracy in 50 meters \`geolocation\_latitude=48.858184&geolocation\_longitude=2.294720&geolocation\_accuracy=50\`:

\`\`\`
https://api.screenshotone.com/take?geolocation\_latitude=48.858184&geolocation\_longitude=2.294720&geolocation\_accuracy=50&url=https://www.infobyip.com/browsergeolocation.php&access\_key=
\`\`\`

 !\[A screenshot from Eiffel Tower with accuracy in 50 meters taken by\
 screenshot API\](./eiffel\_tower.png)

\## Request

\### ip\_country\_code

If \`proxy\` is set, it overrides the \`ip\_country\_code\` option.

You can use data center proxies provided by ScreenshotOne to take screenshots from different countries. Set parameter \`ip\_country\_code\`to the desired country, and you are ready to go, e.g., \`ip\_country\_code=gb\`.

The parameter is not supposed to be used for stealth screenshots. These are not residential proxies. If you have such a case, please, feel free to send the request to support@screenshotone.com.

While ScreenshotOne uses premium, highly available data center proxies, routing requests through them is slower than without a proxy. Try to avoid using the feature if you don't need it.

The list of supported countries:

\- \`us\` (United States) \*\*default\*\*
\- \`gb\` (Great Britain)
\- \`de\` (Germany)
\- \`it\` (Italy)
\- \`fr\` (France)
\- \`cn\` (China)
\- \`ca\` (Canada)
\- \`es\` (Spain)
\- \`jp\` (Japan)
\- \`kr\` (South Korea)
\- \`in\` (India)
\- \`au\` (Australia)
\- \`br\` (Brazil)
\- \`mx\` (Mexico)
\- \`nz\` (New Zealand)
\- \`pe\` (Peru)
\- \`is\` (Iceland)
\- \`ie\` (Ireland).

Feel free to request any additional country at support@screenshotone.com.

\### proxy

If \`proxy\` is set, it overrides the \`ip\_country\_code\` option.

You can use your custom proxy to take screenshots or render HTML with the \`proxy\` option.

It is suitable in many cases. For example, you might want to render a screenshot from the given location and check how the site renders for this location.

Only the \`HTTP\` proxies are supported.

If you need to specify username and password, use the usual URL format like: http://myuser:mypassword@example.com/.

Example of the request:

\`\`\`
https://api.screenshotone.com/take?proxy=http://127.0.0.1:1080&url=https://example.com/&access\_key=
\`\`\`

\### user\_agent

 ScreenshotOne takes care of the browser user agent, if you change the user agent, you might break stealth mode capabilities.
 Change the user agent only when you absolutely need that and know what you are doing.

 If the \[viewport\_device\](#viewport\_device) option is set, the parameter
 overrides it!

A user agent for the request. The default value is the latest version of the browser that \`Puppeteer\` uses.

An example with default user agent:

\`\`\`
https://api.screenshotone.com/take?url=https://www.whatsmyua.info/&access\_key=
\`\`\`

 !\[A screenshot with default user agent by screenshot\
 API\](./default\_user\_agent.png)

{" "}

An example with specified user agent \`user\_agent=screenshoter\`:

\`\`\`
https://api.screenshotone.com/take?user\_agent=screenshoter&url=https://www.whatsmyua.info/&access\_key=
\`\`\`

 !\[A screenshot with custom user agent by screenshot\
 API\](./screenshoter\_user\_agent.png)

\### authorization

Set the \`Authorization\` header for the request.

Setting the authorization header is proper when you want to take a screenshot of the protected page by basic authentication or token.

For example, if use basic authentication with credentials like \`username:password\`, encode it to Base64 format \`dXNlcm5hbWU6cGFzc3dvcmQ=\` and then use set the value of the authorization header like \`authorization=Basic+dXNlcm5hbWU6cGFzc3dvcmQ=\`.

Also, check our guide about \[how to screenshot authenticated pages\](/docs/guides/authenticated-pages/).

\### cookies

Set cookies for the request in format \`=; Domain=; Secure; HttpOnly\`. You can specify multiple cookies.

An escaped query string might look like:
\`cookies=name1=val1;+Domain=example.com;+Secure;+HttpOnly&cookies=name2=val2;+Domain=example.com;+Secure;+HttpOnly\`

\### headers

Set extra headers for the request in the format of \`Header-Name:Header-Value\`

Headers can override all other previously implicitly set headers by options like \`cookies\` or \`authorization\`.

You can specify multiple headers at once \`headers=X-Header-1:Value-1&headers=X-Header-2:Value-2\`:

\`\`\`
https://api.screenshotone.com/take?headers=X-Header-1:Value-1&headers=X-Header-2:Value-2&url=http://myhttpheader.com/&access\_key=
\`\`\`

 !\[A screenshot with custom headers by screenshot API\](./custom\_headers.png)

\### time\_zone

Sets time zone for the request. Available time zones are:

\- \`America/Belize\`
\- \`America/Cayman\`
\- \`America/Chicago\`
\- \`America/Costa\_Rica\`
\- \`America/Denver\`
\- \`America/Edmonton\`
\- \`America/El\_Salvador\`
\- \`America/Guatemala\`
\- \`America/Guayaquil\`
\- \`America/Hermosillo\`
\- \`America/Jamaica\`
\- \`America/Los\_Angeles\`
\- \`America/Mexico\_City\`
\- \`America/Nassau\`
\- \`America/New\_York\`
\- \`America/Panama\`
\- \`America/Port-au-Prince\`
\- \`America/Santiago\`
\- \`America/Tegucigalpa\`
\- \`America/Tijuana\`
\- \`America/Toronto\`
\- \`America/Vancouver\`
\- \`America/Winnipeg\`
\- \`Asia/Kuala\_Lumpur\`
\- \`Asia/Shanghai\`
\- \`Asia/Tashkent\`
\- \`Europe/Berlin\`
\- \`Europe/Kiev\`
\- \`Europe/Lisbon\`
\- \`Europe/London\`
\- \`Europe/Madrid\`
\- \`Pacific/Auckland\`
\- \`Pacific/Majuro\`

Default time zone is \`GMT +/- 00:00\`.

An example with \`time\_zone=Europe/Madrid\`:

\`\`\`
https://api.screenshotone.com/take?time\_zone=Europe/Madrid&url=https://whatismytimezone.com/&access\_key=
\`\`\`

 !\[A screenshot with custom time zone by screenshot\
 API\](./europe\_madrid\_time\_zone.png)

\### bypass\_csp

In rare cases, especially when you trying to add \[custom scripts\] to a website, you need to bypass the content security policies of the website. You need to simplify the set \`bypass\_csp\` to \`true\`, by default it is \`false\`.

\## Wait

These are one of the most tricky parameters when rendering screenshots of a site. Read on \[how to wait until the page is ready\](/blog/puppeteer-wait-until-the-page-is-ready/) if you are curious. Or use these \`wait\` options directly.

\### wait\_until

Use \`wait\_until\` to wait until an event occurred before taking a screenshot or rendering HTML or PDF.

The default value of \`wait\_until\` is \`\['load'\]\`. Allowed values are:

\- \`load\`: the navigation is successful when the load even is fired;
\- \`domcontentloaded\`: the navigation is finished when the DOMContentLoaded even is fired;
\- \`networkidle0\`: the navigation is finished when there are no more than 0 network connections for at least 500 ms;
\- \`networkidle2\`: consider navigation to be finished when there are no more than 2 network connections for at least 500 ms.

The parameter accepts many values. It means that screenshots will be taken after all events occur altogether.

An example of the request with \`wait\_until=networkidle2&wait\_until=domcontentloaded\`:

\`\`\`
https://api.screenshotone.com/take?wait\_until=networkidle2&wait\_until=domcontentloaded&url=https://example.com/&access\_key=
\`\`\`

\### delay

Specify the \`delay\` option in seconds to wait before taking a screenshot or rendering HTML or PDF.

It is suitable when the \[wait\_until\](#wait\_until) option does not work well for you, and you want to ensure that everything is ready.

The default value is 0.

The delay value can be more than 30 seconds, only if \[the timeout option\](#timeout) is larger than 300 seconds which is only allowed for asynchronous requests.

An example of the request with \`delay=5\`:

\`\`\`
https://api.screenshotone.com/take?delay=5&url=https://example.com/&access\_key=
\`\`\`

\### timeout

Specify \`timeout\` (in seconds) of when to abort the request if screenshot or rendering is still impossible. The default value is \`60\` seconds and the max value is \`90\`.

An example of the request with \`timeout=20\`:

\`\`\`
https://api.screenshotone.com/take?timeout=20&url=https://example.com/&access\_key=
\`\`\`

\### navigation\_timeout

Specify \`navigation\_timeout\` (in seconds) of when to abort the request if the target site doesn't respond. The default and max value is \`30\`.

An example of the request with \`navigation\_timeout=20\`:

\`\`\`
https://api.screenshotone.com/take?navigation\_timeout=20&url=https://example.com/&access\_key=
\`\`\`

\### wait\_for\_selector

 If you are already screenshotting an element by the same selector, waiting
 for a selector is not effective and won't be used.

Specify \`wait\_for\_selector\` to wait until the element appears in DOM, which is not necessarily visible.

If you specify a few selectors separated by commas, it will be enough to wait for only one. To change the behavior and wait
for all selectors, check out the \[wait\_for\_selector\_algorithm\](#wait\_for\_selector\_algorithm) option.

An example of the request with \`wait\_for\_selector=.dynamically-loaded-element\`:

\`\`\`
https://api.screenshotone.com/take?wait\_for\_selector=.dynamically-loaded-element&url=https://example.com/&access\_key=
\`\`\`

\### wait\_for\_selector\_algorithm

The default value is \`at\_least\_one\` that means to wait for at least one selector matched.

You can set it to \`at\_least\_by\_count\` to wait for all selectors matched at least. But it doesn't mean all elements matched.

E.g. if you specify '.class1,.class2' and there are 2 elements in the DOM that match this selector, it will be enough to stop waiting.
It can also mean that there are 2 elements of \`.class1\`.

\## Caching

There is \[a dedicated page about caching\](/docs/caching/) and how to use it.

:::note
\*\*Screenshots are not cached by default and not stored on ScreenshotOne servers, unless storage or similar options are used and JSON response type is requested.\*\*

\*\*During processing\*\*, rendered content may be temporarily stored to pass through internal system components (such as queues, message brokers, or temporary buffers).
:::

Screenshots are cached by the combination of all specified request options. And the \[cache\_key\](#cache\_key) option allows having different cached versions of the same screenshot.

Cached screenshots are not counted by quota and are not logged anywhere. They are served directly from the cache. Screenshots are cached in a combination of Cloudflare CDN and R2 storage (like Amazon S3).

There is a header \`x-screenshotone-cache-url\` that provides a direct link to the cached image, PDF or video. The file exist as long as it was defined in the \[cache\_ttl\](#cache\_ttl) parameter when API request was performed with \`cache=true\`.

And if the \`response\_type\` option is specified as \`json\`, you can find a cache URL in the JSON response too:

\`\`\`json
{
 "cache\_url": "https://cache.screenshotone.com/..."
}
\`\`\`

What is the benefits of using the cache URL?

1\. You don't share API keys and don't complicate your code with \[signed links\](/docs/signed-requests/).
2\. You control when to regenerate the cache, but a user with a link to the screenshot can't regenerate it. Because if you shared a link to an API request, once the cache is expired, it would be regenerated.

\### cache

The \`cache\` option enables or disables caching of a screenshot, rendering HTML, or PDF. The default value is \`false\`.

The \`false\` option forces disabling caching and always generate a free screenshot or render HTML or PDF without caching.

An example of the request with \`cache=false\`:

\`\`\`
https://api.screenshotone.com/take?cache=false&url=https://example.com/&access\_key=
\`\`\`

\### cache\_ttl

The \`cache\` option must be set to \`true\` to use the \`cache\_ttl\` parameter.

The \`cache\_ttl\` option (in seconds) hints at how long the cached screenshot should be stored. The minimum value is \`14400\` seconds (4 hours), and the maximum value is \`2592000\` seconds (one month).

An example of the request with \`cache\_ttl=20000\`:

\`\`\`
https://api.screenshotone.com/take?cache=true&cache\_ttl=20000&url=https://example.com/&access\_key=
\`\`\`

\### cache\_key

The \`cache\` option must be set to \`true\` to use the \`cache\_key\` parameter.

Screenshots are cached by the combination of all specified request options. The \[cache\_key\](#cache\_key) option allows having different cached versions of the same screenshot.

An example of the request with \`cache\_key=abc123\`:

\`\`\`
https://api.screenshotone.com/take?cache=true&cache\_key=abc123&url=https://example.com/&access\_key=
\`\`\`

\## Storing

 When the \[cache option\](#cache) is set to true, the upload will be triggered
 only on the cache miss. It means that if you want to upload screenshots
 anytime, you take them, please set the \[cache option\](#cache) to false.

You can use any S3-compatible storage to store screenshots,
rendered HTML or PDF to the configured S3 bucket.

:::note
ScreenshotOne \*\*does not\*\* store the generated content anywhere (except if you specify other storage options, caching or requesting JSON response type). Using \`storage\_\*\` and similar options, you can store screenshots, rendered HTML or PDF to your S3 storage.

\*\*During processing\*\*, rendered content may be temporarily stored to pass through internal system components (such as queues, message brokers, or temporary buffers).

This ensures your rendered content remains private unless you choose to store it.
:::

In case you don't care about getting the actual but only want to upload the rendering result to storage, specify \[response\_type=empty\](#response\_type).

An example of the request with \`response\_type=empty\`:

\`\`\`
https://api.screenshotone.com/take?response\_type=empty&url=https://example.com/&access\_key=
\`\`\`

\### store

Default value is \`false\`. Use \`store=true\` to trigger upload of the taken screenshot, rendered HTML or
PDF to the configured S3 bucket. Make sure you configured \[access to S3\](https://dash.screenshotone.com/access).

An example of the request with \`store=true\`:

\`\`\`
https://api.screenshotone.com/take?store=true&url=https://example.com/&access\_key=
\`\`\`

\### storage\_path

The parameter is required if you set \`store=true\`. You must specify the key for the file, but don't
specify an extension, it will be added automatically based on the \[format\](#format) you specified.

You can also specify "subdirectories" in the path part.

An example of the request with \`storage\_path=latest/example\`:

\`\`\`
https://api.screenshotone.com/take?store=true&storage\_path=latest/example&url=https://example.com/&access\_key=
\`\`\`

\### storage\_endpoint

Leave empty for Amazon S3, specify only when needed. Any S3-compatible storage is supported, e.g. \`"https://.r2.cloudflarestorage.com"\` for Cloudlfare R2 storage.

\### storage\_access\_key\_id

Access key ID. It overrides the one specified in the dashboard configuration.

\### storage\_secret\_access\_key

Secret access key. It overrides the one specified in the dashboard configuration.

\### storage\_bucket

You can override the default bucket you configured with \`storage\_bucket=\`.

An example of the request with \`storage\_bucket=temporary\`:

\`\`\`
https://api.screenshotone.com/take?storage\_bucket=temporary&store=true&storage\_path=latest/example&url=https://example.com/&access\_key=
\`\`\`

\### storage\_class

The default value is \`standard\`.

Storage class allows you to specify \[the object storage class\](https://aws.amazon.com/s3/storage-classes/).

Allowed values:

\- \`standard\`;
\- \`reduced\_redundancy\`;
\- \`standard\_ia\`;
\- \`onezone\_ia\`;
\- \`intelligent\_tiering\`;
\- \`glacier\`;
\- \`deep\_archive\`;
\- \`outposts\`;
\- \`glacier\_ir\`.

An example of the request with \`storage\_class=glacier\_ir\`:

\`\`\`
https://api.screenshotone.com/take?storage\_class=glacier\_ir&store=true&storage\_path=latest/example&url=https://example.com/&access\_key=
\`\`\`

\### storage\_acl

The default value is not set.

Specify \[the ACL value\](https://docs.aws.amazon.com/AmazonS3/latest/userguide/acl-overview.html#canned-acl) when uploading the file.

Allowed values:

\- (not set) (\*\*default\*\*);
\- \`public-read\`.

An example of the request with \`storage\_acl=public-read\`:

\`\`\`
https://api.screenshotone.com/take?storage\_acl=public-read&store=true&storage\_path=latest/example&url=https://example.com/&access\_key=
\`\`\`

\### storage\_return\_location

You can require to return the file location returned by S3.

An example of the request with \`storage\_return\_location=true\`:

\`\`\`
https://api.screenshotone.com/take?storage\_return\_location=true&store=true&storage\_path=latest/example&url=https://example.com/&access\_key=
\`\`\`

You will receive the location as a header \`X-ScreenshotOne-Store-Location\` or if you set \`response\_type=json\` as a property of JSON \`store.location\`.

\## Metadata

You can extract different properties of the site or a screenshot on demand. They might impact performance, and that's why they are disabled by default.

\### metadata\_image\_size

The default value is \`false\`.

Set to \`true\` to get the screenshot's actual image width and height. If response\_type is set to \`json\`, you can get it from \`metadata.image\_size{width,height}\` property. Otherwise, read from response headers such as \`X-ScreenshotOne-Image-Width\` and \`X-ScreenshotOne-Image-Height\`.

\### metadata\_fonts

The default value is \`false\`.

Get the fonts used by a website.

Check out \[our guide on how to detect website fonts\](/docs/guides/how-to-detect-website-fonts/) for more details.

\### metadata\_icon

Get the favicon used by a website.

The default value is \`false\`.

\`\`\`
https://api.screenshotone.com/take?metadata\_icon=true&url=https://screenshotone.com/&access\_key=
\`\`\`
As headers:

\`\`\`
X-ScreenshotOne-Icon: {"url":"https://screenshotone.com/favicon-32x32.png","type":"image/png"}
\`\`\`

As JSON:
\`\`\`json
{
 "metadata": {
 "icon": {
 "url": "https://screenshotone.com/favicon-32x32.png",
 "type": "image/png"
 }
 }
}
\`\`\`

:::danger
Do not render the icon from the URL directly in your web application, it might be used to attack your site, always check and sanitize it.

Also, sometimes, it can return data URLs for the icon URL, like: \`data:image/svg+xml,
\`\`\`

If you use JSON response type, you will get:

\`\`\`json
{
 "content": {
 "url": "https://example.com/...",
 "expires": "Wed, 21 Oct 2015 07:28:00 GMT",
 "format": "markdown"
 }
}
\`\`\`

The default value is \`html\`.

\### metadata\_http\_response\_status\_code

Set to \`true\` to get the host HTTP response headers.

If you render a binary screenshot, not JSON, you can get that data from the API response headers as \`X-ScreenshotOne-HTTP-Response-Status-Code\`.

In JSON, it will look like:

\`\`\`json
https://api.screenshotone.com/take?
&url=https://example.com/
...
&metadata\_http\_response\_headers=true
&metadata\_http\_response\_status\_code=true

{
 ...
 "http\_response": {
 "status\_code": 200,
 "headers": {
 "accept-ranges": "bytes",
 "age": "56658",
 "cache-control": "max-age=604800",
 "content-encoding": "gzip",
 "content-length": "648",
 "content-type": "text/html; charset=UTF-8",
 "date": "Fri, 02 Aug 2024 10:26:35 GMT",
 "etag": "\\"3147526947\\"",
 "expires": "Fri, 09 Aug 2024 10:26:35 GMT",
 "last-modified": "Thu, 17 Oct 2019 07:18:26 GMT",
 "server": "ECAcc (nyd/D13E)",
 "vary": "Accept-Encoding",
 "x-cache": "HIT"
 }
 }
 ...
}
\`\`\`

\### metadata\_http\_response\_status\_headers

Set to \`true\` to get the host HTTP response status code.

If you render a binary screenshot, not JSON, you can get that data from the API response headers as \`X-ScreenshotOne-HTTP-Response-Headers\`.

In JSON, it will look like:

\`\`\`json
https://api.screenshotone.com/take?
&url=https://example.com/
...
&metadata\_http\_response\_headers=true
&metadata\_http\_response\_status\_code=true

{
 ...
 "http\_response": {
 "status\_code": 200,
 "headers": {
 "accept-ranges": "bytes",
 "age": "56658",
 "cache-control": "max-age=604800",
 "content-encoding": "gzip",
 "content-length": "648",
 "content-type": "text/html; charset=UTF-8",
 "date": "Fri, 02 Aug 2024 10:26:35 GMT",
 "etag": "\\"3147526947\\"",
 "expires": "Fri, 09 Aug 2024 10:26:35 GMT",
 "last-modified": "Thu, 17 Oct 2019 07:18:26 GMT",
 "server": "ECAcc (nyd/D13E)",
 "vary": "Accept-Encoding",
 "x-cache": "HIT"
 }
 }
 ...
}
\`\`\`

\## Async and Webhooks

There is a \[complete guide about asynchronous requests and webhooks\](/docs/async-and-webhooks/).

\### async

You can execute any request asynchronously by setting the \`async\` option to \`true\`. The API will return an empty response immediately. It is \`false\` by default.

Usually, it is in \[combination with webhooks\](/docs/async-and-webhooks/) to \[upload rendered screenshots or PDFs to S3\](/docs/upload-to-s3/).

\### webhook\_url

You can receive the result of the screenshot execution at your desired URL. To do it, specify the \`webhook\_url\` parameter. E.g. \`webhook\_url=https://example.com\`.

Usually, it is in \[combination with async\](/docs/async-and-webhooks/) to \[upload rendered screenshots or PDFs to S3\](/docs/upload-to-s3/).

\### webhook\_sign

Signing webhook request body takes time. If you are sure that your webhooks are unique and secret, you might want to disable signing to improve performance by using \`webhook\_sign=false\`.

It is \`true\` by default.

\### webhook\_errors

Set to \`true\` to get the error details in the webhook request body (if JSON response type is used) or headers.

It is \`false\` by default.

\## Error options

\### ignore\_host\_errors

When the site responds within the range of 200-299 status code, you can ignore errors and take a screenshot of the error page anyway. To do that, set the option \`ignore\_host\_errors\` to true. It is \`false\` by default.

It is helpful when you want to create a gallery of error pages or, for some reason, you need to render error pages.

\### error\_on\_selector\_not\_found

If \[a selector\](#selector) or a \[scroll\_into\_view option\](#scroll\_into\_view) is specified and \`error\_on\_selector\_not\_found=true\`, the error will be returned if the element by selector is not visible or it took more than \`timeout\` seconds to render it, but not more than 30 seconds.

Default value is \`false\`.

\### fail\_if\_request\_failed

The option forces the request to fail if any network request fails during page loading. By default, it is not specified, which means the screenshot will be taken even if some resources (like images, scripts, or stylesheets) fail to load.

Setting \`fail\_if\_request\_failed\` is useful when you need to ensure that all resources are properly loaded before taking a screenshot. This can help identify issues with missing assets or network problems.

An example of the API request that will fail if any request URL that matches \*example.com\* fails:

\`\`\`
https://api.screenshotone.com/take?access\_key=&fail\_if\_request\_failed=\*example.com\*&url=https://example.com/
\`\`\`

Failed requests are not counted against your rendering quota.

\### fail\_if\_content\_missing

The option forces the request to fail if the specified text is missing on the page content. Case insensitive.

It can be specified multiple times. And the request will fail if any of the specified strings is missing on the page content.

Failed requests are not counted against your rendering quota.

\### fail\_if\_content\_contains

The option forces the request to fail if the specified text is matched on the page content. Case insensitive.

It can be specified multiple times. And the request will fail if any of the specified strings is matched on the page content.

Check out the guide on \[how to fail rendering if the content contains a string\](/docs/guides/fail-if-content-contains/) for more details.

Failed requests are not counted against your rendering quota.

\### fail\_if\_gpu\_rendering\_fails

The options forces the request to fail if GPU rendering fails. Otherwise, the request will be retried. Or sent to the CPU-based rendering services.

\# C# (.NET) SDK and Code Examples

import Alert from "@/components/Alert.astro";

 If you have any questions, please, reach out at \`support@screenshotone.com\`.

 Massive thanks and rays of goodness to Andy Robinson (\[Indie\
 Hackers\](https://www.indiehackers.com/TheOrigin),
 \[GitHub\](https://github.com/theorigin)) for providing the fully-featured
 high-quality C# (.NET) SDK.

\### Installation

Add the library via nuget using the package manager console:

\`\`\`bash
PM> Install-Package ScreenshotOne.dotnetsdk
\`\`\`

Or from the .NET CLI as:

\`\`\`bash
dotnet add package ScreenshotOne.dotnetsdk
\`\`\`

\### Usage

Don't forget to \[sign up\](https://dash.screenshotone.com/sign-up) to get access and secret keys.

Generate a screenshot URL without executing request:

\`\`\`csharp
var client = new Client("<access key>", "<secret key>");
var options = TakeOptions.Url("https://www.amazon.com")
 .FullPage(true)
 .Format(Format.PNG)
 .BlockCookieBanners(true);

var url = client.GenerateTakeUrl(options);

// url = https://api.screenshotone.com/take?url=https%3A%2F%2Fwww.amazon.com&full\_page=true&format=png&block\_cookie\_banners=true&access\_key=\_OzqMIjpCw-ARQ&signature=8a08e62d13a5c3490fda0734b6707791d3decc9ab9ba41e8cc045288a39db502

\`\`\`

Take a screenshot and save the image in the file:

\`\`\`csharp
var client = new Client("<access key>", "<secret key>");
var options = TakeOptions.Url("https://www.google.com")
 .FullPage(true)
 .Format(Format.PNG)
 .BlockCookieBanners(true);

var bytes = await client.Take(options);

File.WriteAllBytes(@"c:\\temp\\example.png", bytes);
\`\`\`

Check out \[other SDKs and code examples\](/docs/code-examples/).

\# Go SDK and Code Examples

import Alert from "@/components/Alert.astro";

 If you have any questions, please, reach out at \`support@screenshotone.com\`.

It takes minutes to start taking screenshots in Go. Just \[sign up\](https://dash.screenshotone.com/sign-up) to get access and secret keys, import the client, and you are ready to go.

\### Installation

\`\`\`shell
go get github.com/screenshotone/gosdk
\`\`\`

\### Usage

Import the library:

\`\`\`go
import screenshots "github.com/screenshotone/gosdk"
\`\`\`

Generate a screenshot URL without executing request:

\`\`\`go
client, err := screenshots.NewClient("IVmt2ghj9TG\_jQ", "Sxt94yAj9aQSgg")
if err != nil {
 // ...
}

options := screenshots.NewTakeOptions("https://scalabledeveloper.com").
 Format("png").
 FullPage(true).
 DeviceScaleFactor(2).
 BlockAds(true).
 BlockTrackers(true)

u, err := client.GenerateTakeURL(options)
if err != nil {
 // ...
}

fmt.Println(u.String())
// Output: https://api.screenshotone.com/take?access\_key=IVmt2ghj9TG\_jQ&block\_ads=true&block\_trackers=true&device\_scale\_factor=2&format=png&full\_page=true&url=https%3A%2F%2Fscalabledeveloper.com&signature=85aabf7ac251563ec6158ef6839dd019bb79ce222cc85288a2e8cea0291a824e
\`\`\`

Take a screenshot and save the image in the file:

\`\`\`go
client, err := screenshots.NewClient("IVmt2ghj9TG\_jQ", "Sxt94yAj9aQSgg")
if err != nil {
 // ...
}

options := screenshots.NewTakeOptions("https://example.com").
 Format("png").
 FullPage(true).
 DeviceScaleFactor(2).
 BlockAds(true).
 BlockTrackers(true)

image, err := client.Take(context.TODO(), options)
if err != nil {
 // ...
}

defer image.Close()
out, err := os.Create("example.png")
if err != nil {
 // ...
}

defer out.Close()
io.Copy(out, image)
\`\`\`

Check out \[other SDKs and code examples\](/docs/code-examples/).

\# SDK and Code Examples

import Alert from "@/components/Alert.astro";

 If you have any questions, please, reach out at \`support@screenshotone.com\`.

\## Postman

You can run ScreenshotOne API requests in \[Postman\](https://www.postman.com/) using the following collection:

[![Run in Postman](https://run.pstmn.io/button.svg)](https://god.gw.postman.com/run-collection/50121564-7b48803f-b44f-4f5b-892b-f624c9d124b8?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D50121564-7b48803f-b44f-4f5b-892b-f624c9d124b8%26entityType%3Dcollection%26workspaceId%3D192aa74a-dd79-4388-8bdd-10d7cbaa8435)

\## SDKs and Code Examples

There is a set of native SDKs you can use:

\\* \[Go\](/docs/code-examples/go/)
\\* \[Java\](/docs/code-examples/java/)
\\* \[PHP\](/docs/code-examples/php/)
\\* \[Ruby\](/docs/code-examples/ruby/)
\\* \[Python\](/docs/code-examples/python/)
\\* \[C# (.NET)\](/docs/code-examples/c-net/)
\\* \[JavaScript and TypeScript (Node.js)\](/docs/code-examples/c-net/)

If your language is not supported, please, reach out to support@screenshotone.com and we will try to close it quickly. Otherwise, you can always use any HTTP client.

\# Java SDK and Code Examples

import Alert from "@/components/Alert.astro";

 If you have any questions, please, reach out at \`support@screenshotone.com\`.

It takes minutes to start taking screenshots in Java. Just \[sign up\](https://dash.screenshotone.com/sign-up) to get access and secret keys, import the client, and you are ready to go.

\### Installation

Add dependency to your \`pom.xml\`:

\`\`\`xml
com.screenshotone.jsdkscreenshotone-api-jsdk\[1.0.0,2.0.0)\
\`\`\`\
\
\### Usage\
\
Generate a screenshot URL without executing request:\
\
\`\`\`java\
import com.screenshotone.jsdk.Client;\
import com.screenshotone.jsdk.TakeOptions;\
\
public class App {\
 public static void main(String\[\] args) throws Exception {\
 final Client client = Client.withKeys("IVmt2ghj9TG\_jQ", "Sxt94yAj9aQSgg");\
 TakeOptions takeOptions = TakeOptions.url("https://scalabledeveloper.com")\
 .fullPage(true)\
 .deviceScaleFactor(1)\
 .viewportHeight(1200)\
 .viewportWidth(1200)\
 .format("png")\
 .omitBackground(true);\
 final String url = client.generateTakeUrl(takeOptions);\
\
 System.out.println(url);\
 // Output: https://api.screenshotone.com/take?access\_key=IVmt2ghj9TG\_jQ&device\_scale\_factor=1&format=png&full\_page=true&omit\_background=true&url=https%3A%2F%2Fscalabledeveloper.com&viewport\_height=1200&viewport\_width=1200&signature=3c0c5543599067322e8c84470702330e3687c6a08eef6b7311b71c32d04e1bd5\
 }\
}\
\`\`\`\
\
Usually you generate URL to place it inside the image tag () or to share it.\
\
Take a screenshot and save the image in the file:\
\
\`\`\`java\
import com.screenshotone.jsdk.Client;\
import com.screenshotone.jsdk.TakeOptions;\
\
import java.io.File;\
import java.nio.file.Files;\
\
public class App {\
 public static void main(String\[\] args) throws Exception {\
 final Client client = Client.withKeys("IVmt2ghj9TG\_jQ", "Sxt94yAj9aQSgg");\
 TakeOptions takeOptions = TakeOptions.url("https://scalabledeveloper.com")\
 .fullPage(true)\
 .deviceScaleFactor(1)\
 .viewportHeight(1200)\
 .viewportWidth(1200)\
 .format("png")\
 .omitBackground(true);\
 final byte\[\] image = client.take(takeOptions);\
\
 Files.write(new File("./example.png").toPath(), image);\
 }\
}\
\`\`\`\
\
Check out \[other SDKs and code examples\](/docs/code-examples/).\
\
\# PHP SDK and Code Examples\
\
import Alert from "@/components/Alert.astro";\
\
 If you have any questions, please, reach out at \`support@screenshotone.com\`.\
\
\### Installation\
\
Run the next command to install the PHP SDK to take screenshots:\
\
\`\`\`shell\
composer require screenshotone/sdk:^1.0\
\`\`\`\
\
\### Usage\
\
Don't forget to \[sign up\](https://dash.screenshotone.com/sign-up) to get access and secret keys.\
\
Generate a screenshot URL without executing the request. Or download the screenshot. It is up to you:\
\
\`\`\`php\
', '');\
\
$options = TakeOptions::url("https://example.com")\
 ->fullPage(true)\
 ->delay(2)\
 ->geolocationLatitude(48.857648)\
 ->geolocationLongitude(2.294677)\
 ->geolocationAccuracy(50);\
\
$url = $client->generateTakeUrl($options);\
echo $url.PHP\_EOL;\
// expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com...\
\
$image = $client->take($options);\
file\_put\_contents('example.png', $image);\
// the screenshot is stored in the example.png file\
\`\`\`\
\
Check out \[other SDKs and code examples\](/docs/code-examples/).\
\
\# Python SDK and Code Examples\
\
import Alert from "@/components/Alert.astro";\
\
 If you have any questions, please, reach out at \`support@screenshotone.com\`.\
\
\### Installation\
\
Run the next command to install the Python SDK to take screenshots:\
\
\`\`\`shell\
pip install screenshotone\
\`\`\`\
\
\### Usage\
\
Don't forget to \[sign up\](https://dash.screenshotone.com/sign-up) to get access and secret keys.\
\
Generate a screenshot URL without executing the request. Or download the screenshot. It is up to you:\
\
\`\`\`python\
import shutil\
from screenshotone import Client, TakeOptions\
\
\# create API client\
client = Client('', '')\
\
\# set up options\
options = (TakeOptions.url('https://screenshotone.com')\
 .format("png")\
 .viewport\_width(1024)\
 .viewport\_height(768)\
 .block\_cookie\_banners(True)\
 .block\_chats(True))\
\
\# generate the screenshot URL and share it with a user\
url = client.generate\_take\_url(options)\
\# expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fscreenshotone.com&viewport\_width=1024&viewport\_height=768&block\_cookie\_banners=True&block\_chats=True&access\_key=&signature=6afc9417a523788580fa01a9f668ea82c78a9d2b41441d2a696010bf2743170f\
\
\# or render a screenshot and download the image as stream\
image = client.take(options)\
\
\# store the screenshot the example.png file\
with open('example.png', 'wb') as result\_file:\
 shutil.copyfileobj(image, result\_file)\
\`\`\`\
\
Check out \[other SDKs and code examples\](/docs/code-examples/).\
\
\# Ruby SDK and Code Examples\
\
import Alert from "@/components/Alert.astro";\
\
 If you have any questions, please, reach out at \`support@screenshotone.com\`.\
\
 Massive thanks and rays of goodness to \[Gustavo\
 Garcia\](https://twitter.com/theluctus) from\
 \[Dailytics\](https://dailytics.com/) for providing the fully-featured\
 high-quality Ruby SDK.\
\
\### Installation\
\
Update your Gemfile:\
\
\`\`\`\
gem 'screenshotone'\
\`\`\`\
\
Then execute:\
\
\`\`\`shell\
bundle install\
\`\`\`\
\
\### Usage\
\
Don't forget to \[sign up\](https://dash.screenshotone.com/sign-up) to get access and secret keys.\
\
Generate a screenshot URL without executing the request. Or download the screenshot. It is up to you:\
\
\`\`\`ruby\
\# If you don't need to add a signature\
client = ScreenshotOne::Client.new('my\_access\_key')\
\
\# If you do need to add a signature\
client = ScreenshotOne::Client.new('my\_access\_key', 'my\_secret\_key')\
\
\# You can set any available option, in a camel\_case format, for example:\
options = ScreenshotOne::TakeOptions.new(url: 'https://example.com').\
 full\_page(true).\
 delay(2).\
 geolocation\_latitude(48.857648).\
 geolocation\_longitude(2.294677).\
 geolocation\_accuracy(50)\
\
\# Verify all the parameters are valid (we will validate the parameters that should be\
\# numeric, booleans or that accept only certain values)\
options.valid?\
=\> true\
\
\# To simply get the final url:\
client.generate\_take\_url(options)\
=\> "https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com..."\
\
\# To actually get the image (the response body of a request to the previous url)\
client.take(options)\
=\> "\\xFF\\xD8\\xFF\\xE0\\x00\\x10JFIF\\x00\\x01\\x01\\x00\\x00\\x01\\x00\\x01\\x00\\x00\\xFF\\..."\
\`\`\`\
\
Check out \[other SDKs and code examples\](/docs/code-examples/).\
\
\# How to render website screenshots with Bubble\
\
Bubble is a full-stack no-code app builder. It is a platform, where you can design, build, and launch fully functional web and mobile applications. They also handle all the technical details, like servers, integrations, and security.\
\
In case if you are going to build a website directory or your application needs website screenshots, you can use ScreenshotOne to do that for you.\
\
\## Community Plugins and Integrations\
\
To integrate ScreenshotOne with Bubble for rendering website screenshots, you can use \[a ScreenshotOne plugin for Bubble provided Revido\](https://bubble.io/plugin/screenshotone-1732272787355x675035896606359600).\
\
The plugin is developed and supported by \[Revido—a company that build products for their customers through low-code\](https://revido.co).\
\
\# How to render website screenshots with Make\
\
import { YouTube } from 'astro-embed';\
\
Make (formerly Integromat) is a powerful visual platform for creating automated workflows (often called “scenarios” or “blueprints”) between different apps and services—without needing to write code.\
\
It helps to save time, reduce manual work, and connect various tools in an organized, automated way.\
\
And with ScreenshotOne you can integrate website screenshot rendering into your Make workflows.\
\
There is no official integration for Make yet, but there is a lot of ways you can use ScreenshotOne to render website screenshots in your Make workflows.\
\
\## Community Integrations\
\
There are integrations that are not officially made by ScreenshotOne, but you can use any of \[the community-supported integrations\](https://www.make.com/en/integrations/screenshotone-community).\
\
\## Tutorials\
\
\### How to Automate ScreenshotOne with Make by Synergetic\
\
A tutorial by \[Synergetic\](https://www.go-synergetic.com/apps/screenshotone) on how to automate ScreenshotOne with Make:\
\
\### How to generate Scrolling Screenshots ScreenshotOne with Make by Synergetic\
\
In his guide on \[how to multiply your leads tenfold using text-to-video AI automation\](https://www.youtube.com/watch?v=Fild563M2Qo), Jack Roberts uses ScreenshotOne\
to generate scrolling screenshots:\
\
The same method can be applied to regular and full-page screenshots as well.\
\
\## Support\
\
If you have any questions, don't hesitate to reach out to our support at \[support@screenshotone.com\](mailto:support@screenshotone.com).\
\
\# How to automate website screenshots with n8n\
\
\[n8n\](https://n8n.io/) is a free and open-source workflow platform.\
\
It allows create workflows using a lot of different integrations with simple and intuitive drag-and-drop interface:\
\
\[!\[n8n UI\](./n8n.webp)\](https://n8n.io/)\
\
\## Community nodes\
\
There is an official \[ScreenshotOne node\](https://www.npmjs.com/package/n8n-nodes-screenshotone) available for n8n.\
\
\[!\[ScreenshotOne node\](./n8n-integration.png)\](https://www.npmjs.com/package/n8n-nodes-screenshotone)\
\
You can also find it in the \[n8n community nodes\](https://docs.n8n.io/integrations/community-nodes/) section.\
\
\## Guides\
\
Guides on how to automate website screenshots with n8n:\
\
1\. \[Capture URL Screenshots Automatically from Google Sheets & Drive with ScreenshotOne & Gmail Alerts\](https://n8n.io/workflows/3321-capture-url-screenshots-from-google-sheets-with-screenshotone-and-save-to-drive-with-gmail-alerts/).\
\
\[!\[Capture URL Screenshots Automatically from Google Sheets & Drive with ScreenshotOne & Gmail Alerts\](./guide.png)\](https://n8n.io/workflows/3321-capture-url-screenshots-from-google-sheets-with-screenshotone-and-save-to-drive-with-gmail-alerts/)\
\
\# How to automate website screenshots with Zapier\
\
Zapier is a powerful automation platform that lets you connect your apps and automate workflows without writing any code. These automated workflows, called "Zaps", can connect thousands of apps to help you save time and reduce manual work.\
\
With ScreenshotOne's Zapier integration, you can easily incorporate website screenshot generation into your automated workflows, making it simple to capture and process screenshots as part of your business processes.\
\
You can use Zapier to automatically trigger screenshot captures and send them to your favorite apps like Google Drive, Slack, or any of the thousands of apps Zapier supports.\
\
\## Integrations\
\
Check out \[ScreenshotOne integrations on Zapier\](https://zapier.com/apps/screenshotone/integrations) and \[a help guide provided by Zapier\](https://help.zapier.com/hc/en-us/articles/16307799273613-How-to-get-started-with-ScreenshotOne-on-Zapier).\
\
\## Tutorials\
\
\### Screenshots to Google Drive with Zapier\
\
A guide by \[Toolfolio\](https://toolfolio.io/) on \[how to automate website screenshots upload to Google Drive with Zapier\](https://toolfolio.io/productive-value/automate-website-screenshots-with-zapier-screenshotone).\
\
\### Troubleshooting\
\
\#### Timeouts\
\
Zapier has \[a timeout limit of 30 seconds for executing a Zap\](https://docs.zapier.com/platform/build/troubleshoot-action-timeouts). If you encounter timeouts, you can try the following:\
\
1\. If it is \[a full-page screenshot, try to optimize it\](/docs/guides/performance/). E.g. disable full page scrolling.\
2\. Or use \[webhooks instead and asynchronous requests\](/docs/async-and-webhooks/).\
\
\## Support\
\
If you have any questions, don't hesitate to reach out to our support at \[support@screenshotone.com\](mailto:support@screenshotone.com).\
\
\# How to automate website screenshots in Clay with ScreenshotOne\
\
:::tip\
\
ScreenshotOne is now available as a \[data provider in Clay\](https://www.clay.com/integrations/data-provider/screenshotone).\
\
You can use ready-to-use templates. Use the guide below in case if you want to have more control over the integration and use more features than the official ScreenshotOne integration on Clay provides.\
:::\
\
\[Clay\](https://clay.com/) is a powerful data-automation tool that lets teams enrich, filter, and transform leads from hundreds of sources without writing code. With Clay, you can build dynamic workflows that connect CRMs, APIs, and enrichment tools in minutes.\
\
\[!\[Clay\](clay.png)\](https://clay.com/)\
\
Integration with \[ScreenshotOne\](/) lets you automatically generate high-quality website screenshots inside your Clay tables—perfect for lead research, prospecting, directory building, and any workflow where visual context matters.\
\
\## How to use ScreenshotOne in Clay\
\
\### 1\. Get a ScreenshotOne API key\
\
1\\. Sign up for \[ScreenshotOne\](https://screenshotone.com/) and get your API key at the \[access page\](https://dash.screenshotone.com/access/). Click on the "Create API key" button:\
\
!\[ScreenshotOne / Create an API key\](screenshotone-create-api-key.png)\
\
2\\. Enter a name for the API key, e.g. "Clay Integration" and click "Create API key":\
\
!\[ScreenshotOne / Name the API key\](screenshotone-enter-key-name.png)\
\
3\\. Copy the API key to use it in Clay:\
\
!\[ScreenshotOne / Copy the API key\](screenshotone-copy-keys.png)\
\
\### 2\. Integrate ScreenshotOne in Clay as HTTP API\
\
One of the ways to integrate ScreenshotOne in Clay is to use the \[HTTP API\](https://university.clay.com/docs/http-api-integration-overview).\
\
With the HTTP API, you can use ScreenshotOne in Clay as a HTTP API endpoint and use all our API methods and options.\
\
For example, let's take screenshots of the website URLs stored in the Clay table:\
\
1\\. Create a Website URL column in your Clay table and fill it with the website URLs you want to screenshot:\
\
!\[Clay / Create a Website URL column\](clay-website-url-column.png)\
\
2\\. Add new column with enrichment step and use the HTTP API type of enrichment:\
\
!\[Clay / Add enrichment step and use the HTTP API type of enrichment\](clay-add-enrichment-http-api.png)\
\
3\\. Configure the enrichment with the API key, API method and options:\
\
!\[Clay / Configure the enrichment\](clay-configure-enrichment.png)\
\
4\\. Save the enrichment step and run the workflow, once it is done, add the output as the new column or map it to the existing column.\
\
\## Support\
\
In case if you need any help or have any questions, please, contact us at \[support@screenshotone.com\](mailto:support@screenshotone.com).\
\
\# Notifications\
\
When you reach 90% or 100% of your screenshot limit, you will receive a notification to your email and/or Slack.\
\
\## Email\
\
By default, you will receive an email notification when you reach 90% or 100% of your screenshot limit. You can disable these notifications in the \[dashboard\](https://dash.screenshotone.com/notifications), but they are enabled by default:\
\
!\[Email notifications\](./notifications.png)\
\
\## Slack\
\
You can also enable Slack notifications in the \[dashboard\](https://dash.screenshotone.com/notifications), in addition to the email notifications.\
\
To enable Slack notifications, you need to specify a Slack webhook URL in the \[dashboard\](https://dash.screenshotone.com/notifications):\
\
!\[Slack notifications\](./slack-webhook-url-input.png)\
\
To configure a Slack webhook URL, you need to create a new webhook in your Slack workspace.\
\
\### 1\. Create a Slack application\
\
\[Create a new Slack application\](https://api.slack.com/apps/new).\
\
!\[Create a Slack application\](./1-create-slack-app.png)\
\
\### 2\. Enable incoming webhooks\
\
Go to \[your application settings\](https://api.slack.com/apps) and enable incoming webhooks:\
\
!\[Enable incoming webhooks\](./2-enable-incoming-webhooks.png)\
\
\### 3\. Add new webhook to your workspace\
\
Click on the "Add New Webhook to Workspace" button:\
\
!\[Add new webhook\](./3-add-new-webhook-to-workspace.png)\
\
And then choose the target channel:\
\
!\[Incoming webhook channel\](./3-incoming-webhook-channel.png)\
\
\### 4\. Copy the webhook URL\
\
!\[Copy webhook URL\](./4-copy-webhook-url.png)\
\
In this example, the webhook URL is:\
\
\`\`\`\
https://hooks.slack.com/services/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\
\`\`\`\
\
\### 5\. Save and test the webhook URL\
\
Paste the webhook URL in the \[dashboard\](https://dash.screenshotone.com/notifications):\
\
!\[Paste webhook URL\](./5-paste-webhook-url.png)\
\
And check the integration test message in the target channel:\
\
!\[Integration test message\](./6-check-integration-message.png)\
\
\### 6\. Get notifications when you reach limits\
\
Once you reach your limit, you will receive a notification in the target channel like this or similar:\
\
!\[Limit example message\](7-limit-example-message.png)\
\
\## Summary\
\
These are the most important notifications you need to recieve from ScreenshotOne. If you have more ideas or issues with configuring or receiving notifications, please, reach out to us via \`support@screenshotone.com\`.\
\
\# Storage Access Denied\
\
It is an API error returned when the API can't upload a screenshot your S3 storage because the access is denined:\
\
\`\`\`json\
{\
 "is\_successful": false,\
 "error\_message": "Failed to upload the screenshot to the storage since access was denied. Check the API keys you specify when using the storage integration.",\
 "error\_code": "storage\_access\_denied",\
 "documentation\_url": "https://screenshotone.com/docs/errors/storage-access-denied/"\
}\
\`\`\`\
\
\## Reasons and how to fix\
\
Let's quickly consider possible reasons and possible solutions.\
\
\### Perform configuration testing\
\
In \[the dashboard\](https://dash.screenshotone.com/integrations/s3), you can test configuration and get the detailed error description:\
\
!\[Configuration Testing\](configuration\_testing.jpg)\
\
\### Check credentials and URL\
\
Make sure and double check that all your credentials and the storage URL is correct.\
\
\## Reach out to support\
\
If nothing helps you, please, reach out to \`support@screenshotone.com\` and we will try to help you as fast as possible.\
\
\# How to render Google Slides as scrolling screenshots with ScreenshotOne\
\
import Video from "@/components/Video.astro";\
\
By default, you can not render Google Slides as scrolling screenshots with the ScreenshotOne API. But if you managed to export it as HTML, you can make it work.\
\
\## Make Google Slides available as HTML\
\
To make Google Slides available as HTML, you need to export it as HTML from the Google Slides editor.\
\
I created \[a simple example Google Slides presentation\](https://docs.google.com/presentation/d/1fsaM1LaLUEzNn9pTPRdY0XBz1WxaFcWBD2WY50SrqwY/edit?usp=sharing) to demonstrate how to do that.\
\
(1) For you presentation, go to share settings:\
\
!\[The Google Slides share settings\](./google-slides-share-settings.png)\
\
(2) Change the settings to make the presentation public and shareable:\
\
!\[The Google Slides share settings\](./google-slides-share-settings-make-public.png)\
\
After that you can use either Google Slides API or make the link shareable and public to everyone and then modify it to the link like:\
\`https://docs.google.com/presentation/d//export/html\`\
\
\## Render Google Slides as scrolling screenshots\
\
Get your ScreenshotOne API key at the \[ScreenshotOne dashboard\](https://dashboard.screenshotone.com/).\
\
And then implement the following example in TypeScript or any other language you want:\
\
\`\`\`typescript\
// validate URL\
const presentationUrl = new URL(url);\
if (!presentationUrl.hostname.includes("docs.google.com")) {\
 throw new Error("Invalid URL: Must be a Google Slides presentation URL");\
}\
\
// Extract presentation ID from the Google Slides URL\
const match = presentationUrl.pathname.match(/presentation\\/d\\/(\[\\w-\]+)/);\
if (!match) {\
 throw new Error("Invalid Google Slides URL format");\
}\
\
const presentationId = match\[1\];\
const exportUrl = \`https://docs.google.com/presentation/d/${presentationId}/export/html\`;\
url = exportUrl;\
\
// Prepare ScreenshotOne API parameters\
const params: Record = {\
 url: url,\
 access\_key: SCREENSHOTONE\_ACCESS\_KEY as string,\
 format: "mp4",\
 scenario: "scroll",\
 delay: "2", // wait for 2 seconds before starting to scroll\
};\
\
const apiUrl = \`https://api.screenshotone.com/animate\`;\
console.log("Making request to ScreenshotOne API...");\
\
// Make request to ScreenshotOne API\
const screenshotResponse = await axios({\
 method: "post",\
 url: apiUrl,\
 data: params,\
 headers: {\
 "Content-Type": "application/json",\
 },\
 responseType: "stream",\
 maxContentLength: Infinity,\
 maxBodyLength: Infinity,\
 timeout: 60000, // increase timeout to 60 seconds\
});\
\
// Process the video\
\`\`\`\
\
Notice that we use a POST HTTP request to the \`https://api.screenshotone.com/animate\` endpoint. It is good if you want to send HTML yourself, but also works with URLs. Also, you can just send a regular GET request.\
\
The resulting video will be something like:\
\
\## Custom styles\
\
You can set custom styles via the \`style\` option:\
\
\`\`\`\
style=\
\`\`\`\
\
\## A working example\
\
You can find a fully working example (written in Node.js/TypeScript) in the \[ScreenshoOne integration examples directory\](https://github.com/screenshotone/examples/tree/main/nodejs/google-slides-scrolling-screenshots). However, it downloads HTML to render it with ScreenshotOne, but today you do not need that, you can render Google Documents and Slides directly with ScreenshotOne.\
\
\## Suggestions\
\
1\. If possible, use the official Google Slides API to get the HTML. It is more reliable and easier to use.\
2\. If you build this solution for third-party use, consider if you can automate the processing of authentication with Google Slides and extract the HTML.\
\
\## Google Documents\
\
Check out \[our guide on how to render Google Documents as screenshots\](/docs/guides/screenshot-google-docs/).\
\
\## Support\
\
In case you have any questions or suggestions, feel free to reach out at \`support@screenshotone.com\`.\
\
\# How to take screenshots of multiple URLs\
\
ScreenshotOne API supports taking screenshots of multiple URLs in one request—\[bulk screenshots\](/docs/bulk-screenshots/). But since it is a simple wrapper around the regular screenshot API, you might find it much better to implement your own bulk screenshot solution.\
\
A few tips:\
\
1\. Use proxies if needed.\
2\. Retry failed requests.\
3\. Use a queue to process the URLs in batches, even internal onces.\
4\. Respect the concurrency limit. Build your solution based on dynamically calculated quota from \[the "get usage" API endpoint\](/docs/get-usage/).\
\
Check out working example in the \[ScreenshotOne examples\](https://github.com/screenshotone/examples) repository—\[bulk screenshots example\](https://github.com/screenshotone/examples/tree/main/nodejs/bulk-screenshots).\
\
In case you need help, feel free to reach out to support at \[support@screenshotone.com\](mailto:support@screenshotone.com).\
\
\# JavaScript and TypeScript (Node.js) SDK and Code Examples\
\
:::note\
If you have any questions, please, reach out at \`support@screenshotone.com\`.\
:::\
\
\### Installation\
\
Run the next command to install the JavaScript and TypeScript Node.js SDK to take screenshots:\
\
\`\`\`shell\
npm install screenshotone-api-sdk --save\
\`\`\`\
\
\### Usage\
\
Don't forget to \[sign up\](https://dash.screenshotone.com/sign-up) to get access and secret keys.\
\
:::danger\
By default, the generated URL by SDK is not signed, and you can't share it,\
because the API key will be leaked.\
\
Use the method designated to generate a signed URL specifically—\`generateSignedTakeURL()\`.\
\
Notice, in the recent versions of the SDK, all methods are asynchronous.\
:::\
\
Generate a screenshot URL without executing the request. Or download the screenshot. It is up to you:\
\
\`\`\`javascript\
import \* as fs from "fs";\
import \* as screenshotone from "screenshotone-api-sdk";\
\
// create API client\
const client = new screenshotone.Client("", "");\
\
// set up options\
const options = screenshotone.TakeOptions.url("https://example.com")\
 .delay(3)\
 .blockAds(true);\
\
// generate URL\
const url = client.generateTakeURL(options); // or generateSignedTakeURL(options) for signed URLs\
console.log(url);\
// expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com&delay=3&block\_ads=true&access\_key=%3Caccess+key%3E\
\
// or download the screenshot\
const imageBlob = await client.take(options);\
const buffer = Buffer.from(await imageBlob.arrayBuffer());\
fs.writeFileSync("example.png", buffer);\
// the screenshot is store in the example.png file\
\`\`\`\
\
Check out \[other SDKs and code examples\](/docs/code-examples/).\
\
\# How to use proxies\
\
ScreenshotOne doesn't include rotating residential proxies as part of the product, but you can plug in easily any external proxy provider you like, in three simple steps.\
\
:::tip\[Did you know?\]\
If you need to use proxies to bypass CAPTCHAs, \[check out our guide on how to bypass CAPTCHAs\](/docs/guides/how-to-bypass-captchas).\
:::\
\
\## 1\. Sign up to a proxy provider\
\
There are plenty of them, like \[Decodo\](https://decodo.com/https://smartproxy.com/), \[Bright Data\](https://brightdata.com/), or \[Geonode\](https://geonode.com/).\
\
You can find the Internet proxy providers that you prefer by price and quality. Choose and sign up for the proxy provider.\
\
Not because it is the best one or the cheapest one, but in this guide, I will use \[Decodo\](https://decodo.com/) as an example.\
\
\## 2\. Get the proxy URL\
\
:::tip\
In this guide, we use residential proxies as an example, but \*\*we highly recommend using data center proxies first, as their cost is much lower than that of residential proxies\*\*. If that doesn't work for you, only then should you switch to residential or even mobile proxies.\
:::\
\
Choose pay-as-you-go residential proxies in Decodo or any other proxy provider you picked in the previous step.\
\
And your goal is to copy the HTTP URL of the proxy with the desired configuration.\
\
In the case of Decodo, it would look like:\
\
!\[An example of picking the HTTP proxy endpoint in Decodo\](decodo.jpg).\
\
\## 3\. Use the proxy with the ScreenshotOne API\
\
Once you have the HTTP proxy URL, not HTTPS, nor SOCKS5. You can specify it when sending an API request with the \[proxy\](/docs/options/#proxy) parameter, just like this:\
\
\`\`\`\
https://api.screenshotone.com/take?proxy=&access\_key=&url=\
\`\`\`\
\
Where \`\` is your proxy URL, or in the case of our example is \`http://user12345:somepass@us.smartproxy.com:10000\`.\
\
\## Recommendations\
\
A few tips to improve your success rate when using proxies:\
\
1\. \*\*Consider using data center proxies first\*\*, as the cost is much lower than residential proxies. If they don't work for you, only then switch to residential or even mobile proxies.\
\
2\. \*\*Don't use random location proxies.\*\* Use proxies located in the United States or your specific location, rather than random locations. For most proxy providers, stability is unlikely when using random locations.\
\
3\. \*\*Don't send many requests through the same proxy.\*\* If you plan to send many requests in parallel through the same proxy, consider using different ports if available or even different proxies. Using a single channel is highly likely to slow down your API requests, cause timeouts, and result in more errors.\
\
4\. If you encounter network issues, check the balance and reach out the proxy provider support, but we also noticed that for some providers, you sometimes need to recreate your proxy user/account to make it work again.\
\
\## Reach out if anything\
\
You see, it was that easy. In case if you have any questions or encounter any problems, please, don't hesitate to reach out at \`support@screenshotone.com\`.\
\
\# Detect website fonts\
\
\## How to use the font detection API\
\
The font detection API is available in the \[ScreenshotOne API "take" method as an additional option\](/docs/options/#metatada\_fonts).\
\
\`\`\`\
https://api.screenshotone.com/take?metatada\_fonts=true&url=https://example.com&access\_key=&response\_type=json\
\`\`\`\
\
The result is:\
\
\`\`\`json\
{\
 "fonts": \[\
 {\
 "first": "Arial",\
 "fallback": \["Helvetica", "sans-serif"\],\
 "elements": \["p"\]\
 }\
 // ...\
 \]\
}\
\`\`\`\
\
\## Use cases\
\
There are many use cases for using the font detection API by ScreenshotOne:\
\
\- \*\*\[Design tools font detection\](/use-cases/design-apps-font-detection/)\*\*: integrate font detection to help designers identify and analyze typography on any website.\
\- \*\*\[Brand consistency font checks\](/use-cases/brand-consistency-font-checks/)\*\*: automatically verify font consistency across web pages to maintain brand integrity.\
\- \*\*\[Automated web audits with font analysis\](/use-cases/automated-web-audits-fonts/)\*\*: generate comprehensive typography reports to optimize websites for aesthetics and performance.\
\- \*\*\[Educational font detection tool\](/use-cases/educational-font-detection/)\*\*: enable students to explore and learn from typography used in real-world web applications.\
\- \*\*\[Font accessibility checks\](/use-cases/font-accessibility-checks/)\*\*: analyze whether websites use readable fonts for people with visual impairments or reading disabilities.\
\- \*\*\[Font marketplace enhancement\](/use-cases/font-marketplace-enhancement/)\*\*: show how fonts look on live websites to enhance the customer purchasing experience.\
\- \*\*\[Font trends analysis\](/use-cases/font-trends/)\*\*: provide insights into typography trends of top-ranking websites across various industries.\
\- \*\*\[UX font analysis\](/use-cases/ux-font-analysis/)\*\*: examine the impact of different fonts on user engagement and website usability.\
\- \*\*\[Browser extension font detection\](/use-cases/browser-extension-font-detection/)\*\*: allow users to identify and learn about fonts on any website with a single click.\
\- \*\*\[Font legal compliance check\](/use-cases/font-legal-compliance/)\*\*: ensure fonts used on websites are legally compliant to avoid copyright issues.\
\
\## Support\
\
In case you have any questions or feedback, please, feel free to reach out at \`support@screenshotone.com\` and we will be happy to help.\
\
\# How to render Google Documents as JPEG, PNG or WebP screenshots\
\
import Video from "@/components/Video.astro";\
\
By default, you can not render Google Docs as screenshots with the ScreenshotOne API. But if you managed to export it as HTML, you can make it work.\
\
\## Make Google Documents available as HTML\
\
To make Google Documents available as HTML, you need to export it as HTML from the Google Docs editor.\
\
I created \[a simple Google Documents example\](https://docs.google.com/document/d/1cY0QhA2GGCdhsoFCJYBCeCproSMzWwvUqkbnylwUGog/edit?usp=sharing) to demonstrate how to do that.\
\
(1) For document, go to share settings:\
\
!\[The Google Docs share settings\](./google-docs-share-settings.png)\
\
(2) Change the settings to make the document public and shareable:\
\
!\[The Google Docs share settings\](./google-docs-share-settings-make-public.png)\
\
After that you can use either Google Docs API or make the link shareable and public to everyone and then modify it to the link like:\
\`https://docs.google.com/document/d//export/html\`.\
\
\## Render Google Documents as screenshots\
\
Get your ScreenshotOne API key at the \[ScreenshotOne dashboard\](https://dashboard.screenshotone.com/).\
\
And then implement the following example in TypeScript or any other language you want:\
\
\`\`\`typescript\
// validate URL\
const documentUrl = new URL(url);\
if (!documentUrl.hostname.includes("docs.google.com")) {\
 throw new Error("Invalid URL: Must be a Google Doc document URL");\
}\
\
// Extract document ID from the Google Doc URL\
const match = documentUrl.pathname.match(/document\\/d\\/(\[\\w-\]+)/);\
if (!match) {\
 throw new Error("Invalid Google Docs URL format");\
}\
\
const documentId = match\[1\];\
// for documents, change to "document"\
const exportUrl = \`https://docs.google.com/document/d/${documentId}/export/html\`;\
url = exportUrl;\
\
// Prepare ScreenshotOne API parameters\
const params: Record = {\
 url: url,\
 access\_key: SCREENSHOTONE\_ACCESS\_KEY as string,\
};\
\
const apiUrl = \`https://api.screenshotone.com/take\`;\
console.log("Making request to ScreenshotOne API...");\
\
// Make request to ScreenshotOne API\
const screenshotResponse = await axios({\
 method: "post",\
 url: apiUrl,\
 data: params,\
 headers: {\
 "Content-Type": "application/json",\
 },\
 responseType: "stream",\
 maxContentLength: Infinity,\
 maxBodyLength: Infinity,\
 timeout: 60000, // increase timeout to 60 seconds\
});\
\
// Process the image\
\`\`\`\
\
Notice that we use a POST HTTP request to the \`https://api.screenshotone.com/take\` endpoint. It is good if you want to send HTML yourself, but also works with URLs. Also, you can just send a regular GET request.\
\
The resulting video will be something like:\
\
\## Set custom styles\
\
In case, you do not like how Google Slides or Documents look like by default, you can set custom styles via the \`style\` option:\
\
\`\`\`\
style=\
\`\`\`\
Adding such a style option to Google Documents, will make look them differently.\
\
\## A working example\
\
You can find a fully working example (written in Node.js/TypeScript) in the \[ScreenshoOne integration examples directory\](https://github.com/screenshotone/examples/tree/main/nodejs/google-slides-scrolling-screenshots). However, it is for Google Slides\
and downloads HTML to render it with ScreenshotOne, but today you do not need that, you can render Google Documents and Slides directly with ScreenshotOne.\
\
\## Suggestions\
\
1\. If possible, use the official Google Docs API to get the HTML. It is more reliable and easier to use.\
2\. If you build this solution for third-party use, consider if you can automate the processing of authentication with Google Docs and extract the HTML.\
\
\## Google Slides\
\
Check out \[our guide on how to render Google Slides as scrolling screenshots\](/docs/guides/google-slides-as-scrolling-screenshots/).\
\
\## Support\
\
In case you have any questions or suggestions, feel free to reach out at \`support@screenshotone.com\`.\
\
\# How to screenshot an area of a site\
\
import Alert from "@/components/Alert.astro";\
\
When rendering website screenshots with the ScreenshotOne Screenshot API, you can specify \[clip options\](https://screenshotone.com/docs/options/#clip) to render only a specific area of the website.\
\
You must specify all clip options, otherwise, it won't work.\
\
For example, let's clip a square of the ScreenshotOne landing page:\
\
\`\`\`\
https://api.screenshotone.com/take?access\_key=&url=https://screenshotone.com&clip\_x=100&clip\_y=100&clip\_width=500&clip\_height=500\
\`\`\`\
\
The resulting image will be:\
\
!\[A clip example\](./clip\_example.png)\
\
In case you can rely on a selector, it is better to use \[the selector option\](https://screenshotone.com/docs/options/#selector) than precise coordinates. It will allow you to produce more stable results. But in case you know what you do and prefer to rely on specific coordinates, it is OK to use clip options.\
\
A few typical uses of the feature:\
\
1\. \*\*Content Monitoring\*\*. Businesses can use this feature to monitor their website's content regularly, ensuring that updates are correctly deployed and that there are no visual anomalies or layout issues.\
\
2\. \*\*Competitor Analysis\*\*. Companies can clip and analyze key sections of competitors' websites, such as product pages or promotional banners, to stay informed about market trends and competitor strategies.\
\
3\. \*\*QA Testing\*\*. Web developers and QA teams can automate the process of taking screenshots of different sections of a webpage across various devices and browsers for testing purposes, ensuring consistency and identifying layout issues.\
\
Enjoy it. If you have any questions, please, feel free to send an email to \`support.screenshotone.com\`.\
\
\# How to render screenshots with different emoji styles\
\
It might happen that you need to render screenshots with different emoji styles rather than the default emoji style provided by the ScreenshotOne API.\
\
There are many emoji libraries out there that can help. For example, \[emoji-js\](https://www.npmjs.com/package/emoji-js) is a popular library that can be used to render emojis in different styles.\
\
:::note\
Whatever library you decided to use, or whatever emoji style you decided to use, make sure you do not violate any license of the emoji set you are using.\
\
E.g. if you use \[emojis provided by Twitter\](https://github.com/twitter/twemoji), you must follow their license requirements.\
:::\
\
You can use it to replace emojis in the page with the desired style. E.g. you can replace all emojis with the emojis that look like Twitter emojis:\
\
\`\`\`js\
const stylesheet = document.createElement("link");\
stylesheet.href = "https://cdn.jsdelivr.net/npm/emoji-js@3.8.1/lib/emoji.min.css";\
stylesheet.rel = "stylesheet";\
document.head.appendChild(stylesheet);\
\
const script = document.createElement("script");\
script.onload = () => {\
 // change to one you are interested in,\
 // check the library documentation for the list of available emoji sets\
 const img\_set = "apple";\
\
 const emoji = new window.EmojiConvertor();\
\
 emoji.img\_sets\[img\_set\].path =\
 \`https://cdn.jsdelivr.net/npm/emoji-datasource-${img\_set}@15.1.2/img/${img\_set}/64/\`;\
 emoji.img\_sets\[img\_set\].sheet =\
 \`https://cdn.jsdelivr.net/npm/emoji-datasource-${img\_set}@15.1.2/img/${img\_set}/sheets/64.png\`;\
 emoji.img\_set = img\_set;\
\
 emoji.replace\_mode = "img";\
\
 function replaceEmojisInTextNodes(node) {\
 if (node.nodeType === Node.TEXT\_NODE) {\
 if (node.textContent && node.textContent.trim()) {\
 const span = document.createElement("span");\
 const replaced = emoji.replace\_unified(node.textContent);\
 span.innerHTML = replaced;\
\
 if (replaced.trim() !== node.textContent.trim()) {\
 const parent = node.parentNode;\
 if (parent) {\
 while (span.firstChild) {\
 parent.insertBefore(span.firstChild, node);\
 }\
 parent.removeChild(node);\
 }\
 }\
 }\
 } else if (node.nodeType === Node.ELEMENT\_NODE) {\
 if (node.tagName === "SCRIPT" \|\| node.tagName === "STYLE") {\
 return;\
 }\
\
 const childNodes = Array.from(node.childNodes);\
 childNodes.forEach((child) => replaceEmojisInTextNodes(child));\
 }\
 }\
\
 replaceEmojisInTextNodes(document.body);\
};\
\
script.src = "https://cdn.jsdelivr.net/npm/emoji-js@3.8.1/lib/emoji.min.js";\
script.crossOrigin = "anonymous";\
\
document.body.appendChild(script);\
\`\`\`\
\
To use this script with the ScreenshotOne API, you can use \`scripts\` parameter to pass a script that will be executed on the page after it is loaded, and it will be rendered in the screenshot:\
\
\`\`\`\
https://api.screenshotone.com/take?access\_key=&url=&scripts=\
\`\`\`\
\
Where \`\` is the URL-encoded script above.\
\
E.g. like this:\
\
\`\`\`\
https://api.screenshotone.com/take?access\_key=&url=https://example.com&scripts=const%20stylesheet%20%3D%20document.createElement%28%27link%27%29%3B%0Astylesheet.href%20%3D%20%27https%3A%2F%2Fcdn.jsdelivr.net%2Fnpm%2Femoji-js%403.8.1%2Flib%2Femoji.min.css%27%3B%0Astylesheet.rel%20%3D%20%27stylesheet%27%3B%0Adocument.head.appendChild%28stylesheet%29%3B%0A%0Aconst%20script%20%3D%20document.createElement%28%27script%27%29%3B%0Ascript.onload%20%3D%20%28%29%20%3D%3E%20%7B%0A%20%20%20%20%2F%2F%20change%20to%20one%20you%20are%20interested%20in%2C%20%0A%20%20%20%20%2F%2F%20check%20the%20library%20documentation%20for%20the%20list%20of%20available%20emoji%20sets%0A%20%20%20%20const%20img\_set%20%3D%20%27apple%27%3B%0A%0A%20%20%20%20const%20emoji%20%3D%20new%20window.EmojiConvertor%28%29%3B%20%20%20%20%0A%20%20%20%20%0A%20%20%20%20emoji.img\_sets%5Bimg\_set%5D.path%20%3D%20%60https%3A%2F%2Fcdn.jsdelivr.net%2Fnpm%2Femoji-datasource-%24%7Bimg\_set%7D%4015.1.2%2Fimg%2F%24%7Bimg\_set%7D%2F64%2F%60%3B%0A%20%20%20%20emoji.img\_sets%5Bimg\_set%5D.sheet%20%3D%20%60https%3A%2F%2Fcdn.jsdelivr.net%2Fnpm%2Femoji-datasource-%24%7Bimg\_set%7D%4015.1.2%2Fimg%2F%24%7Bimg\_set%7D%2Fsheets%2F64.png%60%3B%0A%20%20%20%20emoji.img\_set%20%3D%20img\_set%3B%0A%0A%20%20%20%20emoji.replace\_mode%20%3D%20%27img%27%3B%0A%0A%20%20%20%20function%20replaceEmojisInTextNodes%28node%29%20%7B%0A%20%20%20%20%20%20%20%20if%20%28node.nodeType%20%3D%3D%3D%20Node.TEXT\_NODE%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20%28node.textContent%20%26%26%20node.textContent.trim%28%29%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20const%20span%20%3D%20document.createElement%28%27span%27%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20const%20replaced%20%3D%20emoji.replace\_unified%28node.textContent%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20span.innerHTML%20%3D%20replaced%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20%28replaced.trim%28%29%20%21%3D%3D%20node.textContent.trim%28%29%29%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20const%20parent%20%3D%20node.parentNode%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20%28parent%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20while%20%28span.firstChild%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20parent.insertBefore%28span.firstChild%2C%20node%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20parent.removeChild%28node%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%20else%20if%20%28node.nodeType%20%3D%3D%3D%20Node.ELEMENT\_NODE%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20%28node.tagName%20%3D%3D%3D%20%27SCRIPT%27%20%7C%7C%20node.tagName%20%3D%3D%3D%20%27STYLE%27%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20const%20childNodes%20%3D%20Array.from%28node.childNodes%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20childNodes.forEach%28child%20%3D%3E%20replaceEmojisInTextNodes%28child%29%29%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20replaceEmojisInTextNodes%28document.body%29%3B%0A%7D%3B%0A%0Ascript.src%20%3D%20%27https%3A%2F%2Fcdn.jsdelivr.net%2Fnpm%2Femoji-js%403.8.1%2Flib%2Femoji.min.js%27%3B%0Ascript.crossOrigin%20%3D%20%27anonymous%27%3B%0A%0Adocument.body.appendChild%28script%29%3B\
\`\`\`\
\
In case you have any issues, do not hesitate to reach out to us at support@screenshotone.com.\
\
\# How to handle API errors\
\
Error handling is an essential part of any high-quality application. Make sure you handle all errors returned by the ScreenshotOne API correctly and provide informative explanations to your customers or react to them accordingly.\
\
\## Following HTTP standards\
\
The ScreenshotOne API is on-purpose built using HTTP protocol and follows HTTP standards as much as possible. To make sure the API will be stable and can support customers for years to come.\
\
In general, if the resulting status code is in the range of 400-599, then we are dealing with errors.\
\
\`\`\`\
GET https://api.screenshotone.com/?\[options\]\
\
Content-Type: application/json\
\
{\
 "is\_successful":false,\
 "error\_code": "an\_error\_code",\
 "error\_message": "An error message"\
}\
\`\`\`\
\
\## Errors caused by API consumers\
\
All errors caused by invalid requests, absent credentials, or any reasons caused by you, an API consumer, are marked with status codes 400-499. It means, that until you find a way to fix them, the request won't be executed successfully.\
\
\## API internal errors\
\
Errors with status codes in the range 500-599 are caused by the API internal reasons and you have almost little influence over that.\
\
But you can safely retry them.\
Except in a few cases. When you get a network error (\`network\_error\`), it might be because the site blocks the API, and there is no sense in retrying the request. Or if the site returned an error (\`host\_returned\_error\`) and it is an error within the range 400-499, it means that the API is either blocked, or you need to change the request to the site.\
\
You still might want to try to retry errors like \`network\_error\` and \`host\_returned\_error\` (if the host's error is \`403\` in the \`returned\_status\_code\` property of the response), but try to add a residential rotating proxy to that API request. Maybe the second time you can succeed and the request will work for you.\
\
An example of the code that retries the request with a residential rotating proxy:\
\
\`\`\`javascript\
const response = await fetch(\
 "https://api.screenshotone.com/take?url=https://example.com&access\_key=..."\
);\
if (!response.ok) {\
 const error = await response.json();\
 if (\
 // add more error codes\
 error.error\_code === "network\_error" \|\|\
 (error.error\_code === "host\_returned\_error" && error.returned\_status\_code == 403)\
 ) {\
 const proxy = "http://...";\
 const proxyResponse = await fetch(\
 \`https://api.screenshotone.com/take?url=https://example.com&access\_key=...&proxy=${proxy}\`\
 );\
 if (!proxyResponse.ok) {\
 const proxyError = await proxyResponse.json();\
 // you can try to retry again\
 }\
\
 // the retry was sucessful\
 const screenshot = await proxyResponse.blob();\
 }\
}\
\`\`\`\
\
\## Showing errors to your end users\
\
In general, you can try to just return the error message provided by the API, but if you want to show a more user-friendly message, you can use the following code:\
\
\`\`\`javascript\
const response = await fetch("https://api.screenshotone.com/...");\
\
// after retries and other processing, once you decide to show an error to your end user\
if (!response.ok) {\
 const errorData = await response.json();\
\
 const errorMessage = generateUserFriendlyErrorMessage(errorData);\
\
 // show the error to your end user in your UI, CLI or any other way\
 showErrorToUser(errorMessage);\
}\
\
function generateUserFriendlyErrorMessage(error) {\
 // these are error messages for your public users, not for you\
 switch (error.error\_code) {\
 case "screenshots\_limit\_reached":\
 return "The screenshot rendering is not available. Please, retry later.";\
 case "concurrency\_limit\_reached":\
 case "temporary\_unavailable":\
 return "Please try again in a moment.";\
 case "request\_not\_valid":\
 return "Please, make sure your request is valid and try again.";\
 case "selector\_not\_found":\
 return "The target element was not found on the page";\
 case "name\_not\_resolved":\
 return "Unable to resolve the domain name. Check that there is no typo in the URL. If this is a new site, please wait for DNS propagation.";\
 case "network\_error":\
 return "Unable to connect to the requested URL. The site may be blocking access or temporarily down.";\
 case "host\_returned\_error":\
 if (\[401, 403, 429\].includes(error.returned\_status\_code)) {\
 return "The target website blocks automated screenshot rendering.";\
 }\
 if (error.returned\_status\_code >= 500) {\
 return "The target website is temporarily down. Please, retry later.";\
 }\
 if (error.returned\_status\_code == 404) {\
 return "The target website returned a 404 HTTP error—the page not found.";\
 }\
\
 return \`The target website returned a ${error.returned\_status\_code} HTTP error.\`;\
 case "timeout\_error":\
 return "The screenshot rendering timed out. Please, try again.";\
 case "storage\_returned\_transient\_error":\
 case "internal\_application\_error":\
 case "request\_aborted":\
 return "Failed to render the screenshot. Please try your request again";\
 case "access\_key\_required":\
 case "access\_key\_invalid":\
 case "signature\_is\_required":\
 case "signature\_is\_not\_valid":\
 case "invalid\_storage\_configuration":\
 case "script\_triggers\_redirect":\
 case "storage\_access\_denied":\
 case "content\_contains\_specified\_string":\
 case "invalid\_cookie\_parameter":\
 case "resulting\_image\_too\_large":\
 // these are errors that often are not caused by the end user action,\
 // and they need to be fixed on your or our side\
 return "The screenshot rendering failed. Please, reach out to support.";\
 default:\
 // return a generic error message\
 // or the message provided by the API error.error\_message\
 return "The screenshot rendering failed. Please, reach out to support.";\
 }\
}\
\`\`\`\
\
These are the most common errors often caused by end users. If you want to process more codes, check out \[all our errors\](/docs/errors/).\
\
\## Reporting errors\
\
All ScreenshotOne API errors are logged and we are acknowledged by them. And will react to them as fast as possible.\
\
In general, you don't need to report to us any errors. But if it blocks your work or you want us to prioritize fixing them, please, feel free to report an error at \`support@screenshotone.com\`.\
\
\## Error reference\
\
All API errors are listed in \[the error reference\](/docs/errors/).\
\
\# Fail rendering if the content contains a string\
\
There is a set of use cases when you want to fail screenshot rendering and retry it if the content of the page contains a string.\
\
For example, if you use residential rotating proxies and a site blocks you with some specific test, you might want to retry the request instead of getting the successful screenshot of the page with the CAPTCHA or an error.\
\
:::tip\[Did you know?\]\
You don't pay for failed and cached screenshots with ScreenshotOne.\
:::\
\
That's exactly what you need the option \`fail\_if\_content\_contains\` for.\
\
Let's quickly see how it works and how you can use it. Let's first render the example.com page:\
\
\`\`\`\
https://api.screenshotone.com/take?access\_key=&url=https://example.com\
\`\`\`\
\
The result is:\
\
!\[The example.com website\](example.com.png)\
\
Now, let's try to fail it:\
\
\`\`\`\
https://api.screenshotone.com/take?fail\_if\_content\_contains=Illustrative+Examples+In+Documents&access\_key=&url=https://example.com\
\`\`\`\
\
The result is:\
\
\`\`\`json\
{\
 "is\_successful": false,\
 "error\_message": "The page content contains the specified string by the \`fail\_if\_content\_contains\` option. If it seems to be a mistake or not what you expected, please, reach out to \`support@screenshotone.com\` as quickly as possible, and will assist and try to resolve your problem.",\
 "error\_code": "content\_contains\_specified\_string",\
 "documentation\_url": "https://screenshotone.com/docs/errors/content-contains-specified-string/"\
}\
\`\`\`\
\
As you might notice, the match is case insensitive, it is done for simplicity.\
\
You can also specify multiple strings to fail if any of them is matched on the page content:\
\
\`\`\`\
https://api.screenshotone.com/take?fail\_if\_content\_contains=Prior&fail\_if\_content\_contains=Example&access\_key=&url=https://example.com\
\`\`\`\
\
\## A few more similar options\
\
Check out the other similar options:\
\
\- \[Fail rendering if the content is missing a string\](/docs/options/#fail\_if\_content\_missing)\
\- \[Fail rendering if the request fails\](/docs/options/#fail\_if\_request\_failed)\
\
\## Support\
\
If you have any questions or need help, please, reach out to \`support@screenshotone.com\` as quickly as possible, and we will assist and try to resolve your problem.\
\
\# How to bypass CAPTCHAs\
\
:::note\
If you screenshot your websites or websites of your customers, follow our guide on \[how to unblock ScreenshotOne in Cloudflare\](/docs/guides/unblock-cloudflare-challenges/) (if relevant).\
:::\
\
Since the the launch of ScreenshotOne API, it was designed to perform ethical screenshotting, hence the ScreenshotOne API doesn't support bypassing CAPTCHAs, by default.\
\
However, if you need to do that, and you know what you are doing within the legal boundaries, you can use a third-party services as a proxy with ScreenshotOne API.\
\
For, example \[Web Unlocker by Bright Data\](https://brightdata.com/products/web-unlocker) is a service that can be used to bypass CAPTCHAs as a proxy.\
\
\## Web Unlocker by Bright Data\
\
:::danger\
\
\*\*Use it only as the last resort and if you are ready to pay for the increased usage of Web Unlocker.\*\*\
\
You will see increased usage of your requests for in your Web Unlocker account. One ScreenshotOne API request might be equal to 100-500 requests (sometimes even more) for the Web Unlocker proxy.\
\
The Web Unlocker solution is not designed to work well with browser automation tools like the ScreenshotOne API uses. Cause every browser request is counted as a separate request for the Web Unlocker: loading images, CSS files, scripts and similar.\
\
Prefer using the residential \[proxies\](/docs/guides/how-to-use-proxies/) if you need to bypass CAPTCHAs.\
:::\
\
The Web Unlocker by Bright Data is a great way to bypass CAPTCHAs if you need to. However, be aware that the API response time might be slower than the normal one, and sometimes the requests even might fail. It relates to how proxies operate and depends on the stability of the proxy provider.\
\
\[Brigh Data Web Unlocker\](https://brightdata.com/products/web-unlocker) solution has \`pay-as-you-go\` pricing model, and it is a great way to bypass CAPTCHAs if you need to.\
\
However, be aware that the API response time might be slower than the normal one, and sometimes the requests even might fail. It relates to how proxies operate and depends on the stability of the proxy provider.\
\
\### 1\. Create the Web Unlocker proxy\
\
To create the Web Unlocker proxy, sign up to \[Bright Data\](https://brightdata.com/), and once you log in, choose \`Web Unlocker\` from the "Add" menu:\
\
!\[The Bright Data Dashboard\](dashboard.png)\
\
Make sure to enable the CAPTCHA solver and premium domains if needed:\
\
!\[The Web Unlocker creation screen\](create.png)\
\
Once created, you can choose the Node.js code example and copy the proxy URL:\
\
!\[The Web Unlocker code example\](proxy\_url.png)\
\
\### 2\. Use the Web Unlocker proxy with the ScreenshotOne API\
\
In this example, the proxy URL is:\
\
\`\`\`\
http://brd-customer-hl\_99a0bd97-zone-your\_unlocker\_name:can1v3iuf18x@brd.superproxy.io:22225\
\
\`\`\`\
\
Now, you can use this proxy URL in the ScreenshotOne API request:\
\
\`\`\`\
https://api.screenshotone.com/take?key=&url=https://example.com&proxy=http://brd-customer-hl\_99a0bd97-zone-your\_unlocker\_name:can1v3iuf18x@brd.superproxy.io:22225\
\`\`\`\
\
\## Residential proxies\
\
It is worth to mention, that using residential proxies might also prevent CAPTCHAs from even showing up. Check out our guide on \[how to use proxies\](/docs/guides/how-to-use-proxies) to learn more.\
\
It happens because with the residential IP addresses, usually there is no need to even show CAPTCHAs, since it looks like that the requests are coming from real users, not bots.\
\
\## Cost optimizations\
\
To save money on proxies, you can try to use the option \[fail\_if\_content\_contains\](/docs/options/#fail\_if\_content\_contains) to fail the request if the content contains a certain string that might hint you that there is a CAPTCHA on the page.\
\
The option returns a specific error code like:\
\`\`\`\
{\
 "is\_successful": false,\
 "error\_code": "content\_contains\_specified\_string",\
 "error\_message": "The page content contains the specified string by the \`fail\_if\_content\_contains\` option. If it seems to be a mistake or not what you expected, please, reach out to \`support@screenshotone.com\` as quickly as possible, and we will assist and try to resolve your problem.",\
 "documentation\_url": "https://screenshotone.com/docs/errors/content-contains-specified-string/"\
}\
\`\`\`\
\
Since you don't pay for the failed requests, you can only then retry the request with the same parameters, but with the proxy that bypasses CAPTCHAs.\
\
\## Any questions?\
\
Read more about \[how to use proxies\](/docs/guides/how-to-use-proxies) in the ScreenshotOne API and if you have any questions, feel free to reach out to us at \[support@screenshotone.com\](mailto:support@screenshotone.com).\
\
\# Screenshot authenticated pages\
\
:::note\
If you screenshot your websites or websites of your customers and you have a problem with Cloudflare challenges, follow our guide on \[how to unblock ScreenshotOne in Cloudflare\](/docs/guides/unblock-cloudflare-challenges/) (if relevant).\
:::\
\
There is a few methods to screenshot authenticated pages:\
\
1\. \[If the website is yours or it allows to send a custom HTTP header with the authentication token when rendering the page.\](#1-custom-http-header)\
2\. \[If the website is yours, allow to bypass authentication for ScreenshotOne servers.\](#2-allow-bypassing-authentication-for-screenshotone-servers)\
3\. \[Using cookies.\](#3-using-cookies)\
\
\## 1\. Custom HTTP header\
\
If the website is yours or it allows to send a custom HTTP header with the authentication token when rendering the page, you can use the following method:\
\
\`\`\`\
https://api.screenshotone.com/take?access\_key=&url=https://example.com&headers=Authorization: Bearer\
\`\`\`\
\
Or:\
\
\`\`\`\
https://api.screenshotone.com/take?access\_key=&url=https://example.com&authorization=Bearer\
\`\`\`\
\
Support the header name is different, e.g. \`X-API-Key\`, you can use the following syntax:\
\
\`\`\`\
https://api.screenshotone.com/take?access\_key=&url=https://example.com&headers=X-API-Key:\
\`\`\`\
\
\## 2\. Allow bypassing authentication for ScreenshotOne servers\
\
This method is complicated and requires for you to configure your firewall to \[allow the ScreenshotOne servers\](/docs/ip-ranges/) to access the website.\
\
\## 3\. Using Cookies\
\
If the website you are trying to screenshot uses cookies to authenticate users and doesn't block automation or it is yours, you can use cookies with the ScreenshotOne API to render pages behind authentication.\
\
I will use \[ScreenshotOne's Dashboard\](https://dash.screenshotone.com/) as an example. Suppose, I want screenshot the dashboard page (\`https://dash.screenshotone.com/dashboard\`):\
\
!\[ScreenshotOne's Dashboard\](./dashboard.png)\
\
If I screenshot it straight away like:\
\
\`\`\`\
https://api.screenshotone.com/take?access\_key=&url=https://dash.screenshotone.com/dashboard\
\`\`\`\
\
I will get the following result:\
\
!\[Unauthenticated\](./unauthenticated.jpeg)\
\
It is an authenticated form.\
\
Let's check cookies for the page, after I logged in:\
\
!\[Cookies\](./cookies.png)\
\
Make sure to copy all the cookie parameters, including the \`domain\`, \`path\` and other parameters:\
\
\`\`\`\
\_\_Secure-better-auth.session\_token=ZFmIsN7BVPU0Fzzd9aJ7lZU4TLSvu2L2.buMSGkHDIxhT%2B7YIl6tS82eGGLAAeRzk7FMp1YiTtK8%3D\
domain=dash.screenshotone.com\
path=/\
HttpOnly\
Secure\
Lax\
\`\`\`\
\
Then format it as required by the ScreenshotOne API:\
\
\`\`\`\
\_\_Secure-better-auth.session\_token=ZFmIsN7BVPU0Fzzd9aJ7lZU4TLSvu2L2.buMSGkHDIxhT%2B7YIl6tS82eGGLAAeRzk7FMp1YiTtK8%3D; domain=dash.screenshotone.com; path=/; HttpOnly; Secure; Lax\
\`\`\`\
\
And then try to screenshot the page again but with the cookies now:\
\
\`\`\`\
https://api.screenshotone.com/take?access\_key=&url=https://dash.screenshotone.com/dashboard&cookies=\_\_Secure-better-auth.session\_token=ZFmIsN7BVPU0Fzzd9aJ7lZU4TLSvu2L2.buMSGkHDIxhT%2B7YIl6tS82eGGLAAeRzk7FMp1YiTtK8%3D; domain=dash.screenshotone.com; path=/; HttpOnly; Secure; Lax\
\`\`\`\
\
The result will be as expected:\
\
!\[Authenticated\](./authenticated.jpeg)\
\
One pitfall is that likely you will need to write your own code to sign in to the website and get the cookies.\
\
\## Support\
\
If you need help with screenshotting authenticated pages and any of the above methods does not work for you, please, contact us at \`support@screenshotone.com\`.\
\
\# Customize websites before screenshotting\
\
ScreenshotOne supports a few options that can help you add any customizations to any website before rendering screenshots of it.\
\
\## Hide any element by CSS selectors\
\
If you just need to quickly hide a few elements on the website, just use \[the hide\_selectors\](https://screenshotone.com/docs/options/#hide\_selectors) option and specify as many CSS selectors as you wish.\
\
For example, let's hide the main header on the example.com website with:\
\
\`\`\`\
https://api.screenshotone.com/take?url=https://example.com&hide\_selectors=h1&access\_key=\
\`\`\`\
\
Before hiding:\
\
!\[A customized version of the example.com website\](with\_header.png)\
\
After hiding:\
\
!\[A customized version of the example.com website\](without\_header.png)\
\
You can specify as many selectors as you wish, e.g.:\
\
\`\`\`\
https://api.screenshotone.com/take?url=https://example.com&hide\_selectors\[\]=h1&hide\_selectors\[\]=p&access\_key=\
\`\`\`\
\
\## Add custom CSS styles\
\
But often you want to do more than just hide a few elements. Maybe you want to change some colors of the elements, or font size, or whatever. Then you can simply add custom CSS styles with \[the styles option\](https://screenshotone.com/docs/options/#styles).\
\
Don't forget to encode the code. And often, you must add a \`!important\` attribute to every property you use.\
\
Let's try it with the example.com website:\
\
\`\`\`\
https://api.screenshotone.com/take?url=https://example.com&styles=h1%20%7Bcolor%3A%20red%20%21important%3B%7D&access\_key=\
\`\`\`\
\
Notice, that the styles parameter is URL-encoded. Let's look at the result:\
\
!\[A customized version of the example.com website\](example\_com\_with\_styles.webp)\
\
\## Execute custom JavaScript code\
\
But what if hiding elements and adding styles is not enough? We got you covered! You can any custom JavaScript code you want.\
\
You can check out a more complex example of using scripting for integrating \[Google Translate API when screenshotting websites\](/docs/guides/how-to-translate-and-render-a-website-as-a-screenshot/).\
\
:::caution\
If your script causes navigation and makes the page reload, make sure to specify \[the scripts\_wait\_until option\](/docs/options/#scripts\_wait\_until) if you want to wait or large enough \[delay\](/docs/options/#delay).\
:::\
\
Let's execute an extreme example and just override the page content with:\
\
\`\`\`javascript\
scripts = document.body.innerHTML = "Hello, world!";\
\`\`\`\
\
The URL would look like:\
\
\`\`\`\
https://api.screenshotone.com/take?scripts=document.body.innerHTML="Hello,%20world!"&url=https://example.com/&access\_key=\
\`\`\`\
\
And the result is:\
\
!\[A customized version of the example.com website\](hello\_world\_example.webp)\
\
\## Click\
\
If you use scripting to only click on some element by selector, there is a popular shortcut for that \[the click option\](/docs/options/#click).\
\
\`\`\`\
https://api.screenshotone.com/take?click=.a-some-button-class-selector&url=https://example.com&access\_key=\
\`\`\`\
\
Just specify any selector of any element and it will be clicked.\
\
\# Full-page screenshots\
\
By default, the only thing you need to do is to set the \`full\_page\` parameter to \`true\`:\
\
\`\`\`\
https://api.screenshotone.com/take?url=https://example.com&full\_page=true&access\_key=...\
\`\`\`\
\
The API tuned to balance performance and quality for the full-page screenshots. However, if you need to improve the quality of rendering, for the full-page screenshots, there is a few things you can do:\
\
1\. \[Understand how viewport dimensions affect full-page screenshots.\](#viewport-dimensions)\
2\. \[Try different rendering algorithms.\](#different-rendering-algorithms)\
3\. \[Tune scrolling of the page.\](#tune-scrolling)\
4\. \[Reduce animations.\](#reduce-animations)\
5\. \[Wait more.\](#wait-more)\
\
However, improving the quality of rendering might lead to a performance degradation.\
\
\## Viewport dimensions\
\
The \`viewport\_width\` and \`viewport\_height\` options play an important role in full-page screenshots:\
\
\### Viewport width and height\
\
The \`viewport\_width\` option directly determines the \*\*width of your final full-page screenshot\*\* because:\
\
\- \*\*Responsive design\*\*: Different viewport widths trigger different layouts and CSS breakpoints. A mobile viewport (e.g., 375px) will render a mobile layout, while a desktop viewport (e.g., 1920px) will render a desktop layout.\
\- \*\*Content visibility\*\*: Wider viewports may show navigation menus, sidebars, or multi-column layouts that are hidden or stacked differently on narrower viewports.\
\
By default, the viewport width is \`1280\` pixels.\
\
The \`viewport\_height\` option affects full-page screenshots differently depending on the algorithm used:\
\
\*\*For the default algorithm:\*\*\
\- The viewport height is temporarily stretched to match the full page height during rendering.\
\- Your specified \`viewport\_height\` is less relevant as it gets overridden.\
\
\*\*For the "by\_sections" algorithm:\*\*\
\- The \`viewport\_height\` determines the \*\*size of each section\*\* that is captured.\
\- The API scrolls by the viewport height, captures a screenshot, then scrolls again.\
\- This affects lazy-loaded content: elements that load when they enter the viewport are triggered as the page scrolls through each section.\
\- Smaller viewport heights mean more sections and more scroll events, which can trigger more lazy-loaded content but takes longer.\
\
By default, the viewport height is \`1024\` pixels.\
\
\### Capturing beyond viewport\
\
The \`capture\_beyond\_viewport\` option works together with viewport dimensions to control how content is captured:\
\
\*\*Default behavior (\`capture\_beyond\_viewport=true\`):\*\*\
\
\- The browser can capture content that extends beyond your \`viewport\_width\` and \`viewport\_height\`.\
\- This is the default for full-page screenshots and is essential for capturing the entire page height.\
\- The viewport dimensions still control the initial page layout and width of the screenshot.\
\
\*\*When set to \`false\`:\*\*\
\`\`\`\
capture\_beyond\_viewport=false\
\`\`\`\
\- Content is clipped to the exact viewport dimensions.\
\- For full-page screenshots, this usually produces undesired results as it clips the page.\
\- Only useful in specific cases where you want to limit the capture area strictly to the viewport.\
\
\*\*Important note for "by\_sections" algorithm:\*\*\
\- When using \`full\_page\_algorithm=by\_sections\`, the \`capture\_beyond\_viewport\` option is automatically set to \`false\` internally.\
\- This is because the algorithm captures each section within the viewport and stitches them together.\
\- You don't need to worry about this option when using the "by\_sections" algorithm.\
\
\## Different rendering algorithms\
\
By default, the API uses the \`full\_page\` uses a simple algorithm to screenshot the full page—it asks the browser to render it and usually that means that the browser just stretches the viewport to render the full-page screenshot. It rarely but leads to rendering issues.\
\
You can try to use a different algorithm instead—by\_sections:\
\
\`\`\`\
full\_page\_algorithm=by\_sections\
\`\`\`\
\
It might be better in most cases. Since it will try to scroll the page and render it section by section, and then stitch all the sections into one image.\
\
But while scrolling the page, not every element might triggered due the speed of the scrolling and the delay between the scrolls. Try to tune scrolling.\
\
\## Tune scrolling\
\
Try to decrease or increase the size of the scroll step:\
\
\`\`\`\
full\_page\_scroll\_by=500\
\`\`\`\
\
And increase the delay between the scrolls, it might help to render the page correctly\
\
\`\`\`\
full\_page\_scroll\_delay=1500\
\`\`\`\
\
It might help to render the page better and trigger more lazy-loaded elements.\
\
\## Reduce animations\
\
Request websites to reduce the number of animations by adding the \`reduced\_motion\` parameter:\
\
\`\`\`\
reduced\_motion=true\
\`\`\`\
\
\## Wait more\
\
Add from 5 to 10 seconds to wait for the page to load:\
\
\`\`\`\
delay=5\
\`\`\`\
\
\## Block ads, trackers, banners and other elements\
\
Request the API to block ads, trackers, banners and other elements by use the following parameters:\
\
\`\`\`\
block\_ads=true&block\_trackers=true&block\_cookie\_banners=true&block\_chats=true&block\_banners\_by\_heuristics=true\
\`\`\`\
\
\## Summary\
\
Combining all the tips above, you might try to get the best results with something like that:\
\
\`\`\`\
https://api.screenshotone.com/take?access\_key=...&url=https://example.com&full\_page=true&full\_page\_algorithm=by\_sections&full\_page\_scroll\_by=500&full\_page\_scroll\_delay=1500&reduced\_motion=true&delay=5&block\_ads=true&block\_trackers=true&block\_cookie\_banners=true&block\_chats=true&block\_banners\_by\_heuristics=true\
\`\`\`\
\
\## Support\
\
Rendering full-page screenshots reliably is a real challenge. And even after a lot of tuning, it might not work for all the pages.\
\
If you have any questions or suggestions, please contact us at \[support@screenshotone.com\](mailto:support@screenshotone.com).\
\
\# How to Unblock ScreenshotOne in Cloudflare\
\
:::note\
You also can use the guide to unblock ScreenshotOne when screenshotting websites of your customers. Just replace the User-Agent or the secret header with the one you are using for your customers.\
:::\
\
If your website is protected by \*\*Cloudflare\*\* and ScreenshotOne requests are blocked by Firewall Rules, Bot Protection, or Challenges, you can allow only your screenshot requests by creating a secure allow rule based on a \*\*secret User-Agent or custom header\*\*.\
\
The following guide shows how to unblock ScreenshotOne in Cloudflare to bypass:\
\
\- Bot Fight Mode;\
\- Managed Challenge;\
\- JS Challenge;\
\- WAF Firewall rules;\
\- Security level restrictions.\
\
\*\*Without disabling security for everyone.\*\*\
\
\## Choose a secret User-Agent or header\
\
Instead of using a public User-Agent like:\
\
\`\`\`\
ScreenshotOneBot\
\`\`\`\
\
Use something unguessable, for example:\
\
\`\`\`\
MyCompanyScreenshotBot/9f3aXK29\_secret\
\`\`\`\
\
Treat this as a secret API key.\
\
Or send a custom HTTP header with the secret value:\
\
\`\`\`\
X-Screenshot-Secret: k29Fj3l2\_very\_secret\_value\
\`\`\`\
\
The idea is to make sure nobody can guess it bypass your challenges.\
\
\## 2\. Send it from ScreenshotOne\
\
When using ScreenshotOne, send it as:\
\
\`\`\`\
https://api.screenshotone.com/take?access\_key=&url=https://example.com&headers=user-agent:\
\`\`\`\
\
Or if you are sending POST requests with JSON:\
\
\`\`\`json\
{\
 "headers": \["user-agent:"\]\
}\
\`\`\`\
\
\## 3\. Create a Cloudflare Firewall Rule\
\
Open Cloudflare Dashboard and:\
\
1\. Choose your website from the list.\
2\. Go to \*\*Security → Security Rules\*\*.\
3\. Click \*\*Create rule\*\*.\
\
!\[Cloudflare Security Rules\](./cloudflare-security-rules.png)\
\
Name the rule as \`Allow ScreenshotOne API\` or similar. The rule expression should be:\
\
\`\`\`\
(http.user\_agent eq "MyCompanyScreenshotBot/9f3aXK29\_secret")\
\`\`\`\
\
Or if you are using a custom header:\
\
\`\`\`\
(any(http.request.headers\["x-screenshotone-secret"\]\[\*\] eq "k29Fj3l2\_very\_secret\_value"))\
\`\`\`\
\
The action should be \*\*Skip\*\* and choose to skip:\
\
Then choose to skip:\
\
\- All WAF rules\
\- All Rate limiting rules\
\- All Managed rules\
\- Browser Integrity Check.\
\- All Super Bot Fight Mode Rules.\
\- And everything related to the challenges.\
\
Save the rule.\
\
!\[Cloudflare Security Rules\](./cloudflare-security-rule.png)\
\
You might need to play a bit with it to make it work. By checking the events and the rule details.\
\
Most issues usually arise from what you are skipping or if you have any other results that block\
the request.\
\
\## Testing\
\
After setting rule:\
\
1\. Trigger screenshot request.\
2\. Check Cloudflare → Security → Events.\
3\. Confirm action shows \*\*Skipped\*\*.\
\
If it still blocks:\
\
\- Move rule higher;\
\- Ensure expression matches exactly;\
\- Verify header capitalization.\
\
\## Best Security Practices\
\
\### 1\. Treat User-Agent or Header as a Secret\
\
Do not:\
\
\- Expose it publicly\
\- Commit it to GitHub\
\- Use simple values like \`screenshot-bot\`\
\
Generate something random and long.\
\
\### 2\. Rotate Secret Periodically\
\
Change it occasionally like you would rotate API keys.\
\
\### 3\. Use Rate Limiting\
\
Even if bypassing challenge:\
\
\- Keep rate limits active\
\- Protect login and admin routes separately\
\
\## Summary\
\
This allows ScreenshotOne to bypass Cloudflare challenges securely without weakening your website security.\
\
In case you encounter any issues, please, reach out at \`support@screenshotone.com\` and we will be happy to help.\
\
\# Rendering performance\
\
\> "You are never done working on performance."\
>\
\> Guillermo Rauch\
\
ScreenshotOne's API is optimized for performance on permanent basis. However, due to a huge set of parameters that can be used to customize the rendering, there are some use cases where the default performance is not optimal.\
\
The goal of this guide is to help you to tune the rendering parameters for your specific use case.\
\
Of course, if you have any questions or need more help or assistance in performance tuning, please, reach out at \`support@screenshotone.com\`.\
\
\## Disable blocking ads and banners\
\
Blocking ads, banners and other content seriously affects the performance of rendering since the API starts to listen for all the requests, waiting for elements to be shown, and many more tricks and heuristics are used to hide this type of content from the rendering.\
\
In case if you render pages that do not contain any ads, banners or the pages belong to you and you can hide that content for the API, make sure to disable blocking ads, banners, and other content:\
\
\`\`\`\
block\_ads=false\
block\_cookie\_banners=false\
block\_banners\_by\_heuristics=false\
block\_chats=false\
\`\`\`\
\
Set these parameters explicitly to \`false\`, otherwise you rely on the default values that are not optimal for your use case and might be even changed in the future.\
\
\## Disable or enable tracking scripts\
\
There is a lot of analytics and tracking scripts that might downgrade the performance of rendering. You can disable them by:\
\
\`\`\`\
block\_tracking=true\
\`\`\`\
\
\*\*However!\*\* If you know that the websites you render doesn't have tracking scripts, you can disable them by:\
\
\`\`\`\
block\_tracking=true\
\`\`\`\
\
If you do not need them, disable blocking tracking scripts:\
\
\`\`\`\
block\_tracking=false\
\`\`\`\
\
Because, to block tracking scripts, the API needs to sniff all the requests, analyze them and block.\
\
This is a parameter that you need to play with for use case, and see what works the best.\
\
\## Image format and quality\
\
Use either \`JPEG\` or \`WebP\` format for images:\
\
\`\`\`\
format=jpeg or format=webp\
\`\`\`\
\
It is faster to generate, the size is usually smaller than other formats, so it is also faster to transfer these.\
\
The limitation of the \`WebP\` format is that you can't use it for the huge full page screenshots. In general, it is not recommended to use it for the full page screenshots,\
or if you do you use it make sure to set \`full\_page\_max\_height\` and check that the rendering is not broken for your use case.\
\
In many cases, especially if you generate just tiny previews of the websites, you also don't need high quality images. Try to set lower image quality for the images:\
\
\`\`\`\
image\_quality=80\
\`\`\`\
\
And see if it satisfies your needs. However, for some formats reducing the quality might degrade performance. It is better to play with it.\
\
\## Viewport size and device scale factor\
\
For huge viewport size, screenshot rendering will take more time. But one of the critical parameters is the \`device\_scale\_factor\`.\
\
When you set its value to more than \`1\`, you double the size of the screenshot. If you are screenshots are not planned to be used for the high DPI displays, you can set it to \`1\` to reduce the size of the screenshot and rendering time.\
\
\`\`\`\
device\_scale\_factor=1\
\`\`\`\
\
Make sure to check that the quality fits your needs.\
\
It is also changed automatically to higher values if you use the \`viewport\_device\` parameter with a device that automatically increases it:\
\
\`\`\`\
viewport\_device=iphone\_16\
\`\`\`\
\
\`device\_scale\_factor\` will be set to 3. Try to set it explicitly to \`1\` and see if it works for your use case:\
\
\`\`\`\
viewport\_device=iphone\_16\
device\_scale\_factor=1\
\`\`\`\
\
\## Wait options\
\
Try to play with the \`wait\_until\` option. Start with \`load\` and see if it works for your case. Set it explicitly:\
\
\`\`\`\
wait\_until=load\
\`\`\`\
\
If you anyway plan to render to full page screenshots and use scrolling, you don't need to wait for everything to loaded since\
the page anyway will be scrolled to the bottom and likely this will cover and load all the content.\
\
\## Full page screenshots\
\
\### Try different algorithms\
\
There are two algorithms for the full page screenshots: \`by\_sections\` and \`default\`.\
\
The default algorithm is the best one for the most of the cases. Try to use it first with disabled \`full\_page\_scroll\` and see if it works for your use case.\
\
\`\`\`\
full\_page\_algorithm=default\
\`\`\`\
\
However, if you need to try to use the \`by\_sections\` algorithm:\
\
\`\`\`\
full\_page\_algorithm=by\_sections\
\`\`\`\
\
It will render the page by sections, and will scroll anyway. It might be better algorithm if you need to trigger lazy loaded.\
\
\### Disable full page scrolling\
\
If you do not need full page scrolling, disable it by:\
\
\`\`\`\
full\_page\_scroll=false\
\`\`\`\
\
It will dramatically reduce the rendering time. However, if your page contains lazy loaded content, it won't be loaded.\
\
\### Tune full page scrolling\
\
If you anyway need to scroll pages, try to play with the settings of the scrolling algorithm:\
\
\`\`\`\
full\_page\_scroll\_delay=100\
\`\`\`\
\
If that still allows to render most of the images for your use case, go for it.\
\
\## Summary\
\
It is hard to make the API product to satisfies all the use cases and still be performant. But with some tuning, it is achievable.\
\
Please, feel free to reach out at \`support@screenshotone.com\` if you have any questions or need more help or assistance in performance tuning.\
\
\# How to translate and render a website as a screenshot\
\
It is possible to translate and take a screenshot of the translated website with ScreenshotOne because the API supports scripts via the \`scripts\` option.\
\
You can use any translation API of your choice. But as an example, in this guide, I will go with Google Translate API.\
\
\## Get your Google Translate API key\
\
To get your Google API key:\
\
1\. Go to \[the API credentials page in Google Cloud Platform\](https://console.cloud.google.com/apis/credentials).\
2\. Generate your API key and make sure you restrict it to using only for Google Translate.\
3\. Make sure you set budgets, and notifications, and follow other \[best practices\](https://cloud.google.com/blog/products/ai-machine-learning/four-best-practices-for-translating-your-website) for Google Translate.\
\
\## Write a script to translate your websites\
\
You need to write a script that efficiently will check all text nodes on the website, batch them, and send requests efficiently to save your costs.\
\
:::danger\
Please, make sure to optimize the script for your use case and that it doesn't overuse your quota. It is an example script and ScreenshotOne is not responsible for you using it and causing any damage to your business by the script. Use it at your own risk.\
:::\
\
Here is an example script you can try and use as a basis, but I highly recommend writing yours for production and making sure it has retries and other necessary logic:\
\
\`\`\`javascript\
const translateTextAsync = async (texts, targetLang, apiKey) => {\
 const url = \`https://translation.googleapis.com/language/translate/v2?key=${apiKey}\`;\
 const data = {\
 q: texts,\
 target: targetLang,\
 };\
\
 const response = await fetch(url, {\
 method: "POST",\
 headers: { "Content-Type": "application/json" },\
 body: JSON.stringify(data),\
 });\
\
 if (!response.ok) throw new Error("Network response was not ok.");\
\
 const json = await response.json();\
 return json.data.translations.map((t) => t.translatedText);\
};\
\
const isVisible = (element) => {\
 return element.offsetWidth > 0 && element.offsetHeight > 0;\
};\
\
const shouldTranslate = (node) => {\
 return (\
 node.nodeType === Node.TEXT\_NODE &&\
 node.nodeValue.trim() &&\
 isVisible(node.parentElement) &&\
 !isDescendantOf(node, \["script", "code"\])\
 );\
};\
\
const isDescendantOf = (node, tagNames) => {\
 let parent = node.parentElement;\
 while (parent && parent !== document.body) {\
 if (tagNames.includes(parent.tagName.toLowerCase())) {\
 return true;\
 }\
 parent = parent.parentElement;\
 }\
 return false;\
};\
\
const batchTranslate = async (nodes, targetLang, apiKey) => {\
 let batch = \[\];\
 let totalLength = 0;\
 const results = \[\];\
\
 for (const node of nodes) {\
 const text = node.nodeValue.trim();\
 if (text.length + totalLength > 5000 \|\| batch.length >= 128) {\
 // Translate current batch\
 const translations = await translateTextAsync(\
 batch,\
 targetLang,\
 apiKey\
 );\
 translations.forEach((translatedText, index) => {\
 results.push({ node: nodes\[index\], translatedText });\
 });\
\
 // Reset for next batch\
 batch = \[text\];\
 totalLength = text.length;\
 } else {\
 batch.push(text);\
 totalLength += text.length;\
 }\
 }\
\
 // Translate remaining batch\
 if (batch.length > 0) {\
 const translations = await translateTextAsync(\
 batch,\
 targetLang,\
 apiKey\
 );\
 translations.forEach((translatedText, index) => {\
 results.push({\
 node: nodes\[nodes.length - batch.length + index\],\
 translatedText,\
 });\
 });\
 }\
\
 return results;\
};\
\
const translatePageContent = async (element, targetLang, apiKey) => {\
 const textNodes = \[\];\
 const walker = document.createTreeWalker(\
 element,\
 NodeFilter.SHOW\_TEXT,\
 {\
 acceptNode: (node) => {\
 return shouldTranslate(node)\
 ? NodeFilter.FILTER\_ACCEPT\
 : NodeFilter.FILTER\_REJECT;\
 },\
 },\
 false\
 );\
\
 let node;\
 while ((node = walker.nextNode())) {\
 textNodes.push(node);\
 }\
\
 const translations = await batchTranslate(textNodes, targetLang, apiKey);\
 translations.forEach(({ node, translatedText }) => {\
 node.nodeValue = translatedText;\
 });\
};\
\
// Replace with your actual API key\
const apiKey = "";\
// Target language code (e.g., 'es' for Spanish)\
const targetLang = "es";\
\
translatePageContent(document.body, targetLang, apiKey)\
 .then(() => console.log("Translation completed"))\
 .catch((error) => console.error("Translation error:", error));\
\`\`\`\
\
\## Rendered translated websites\
\
Once you have a working script, make sure you URL-encode it and then send it to ScreenshotOne when rendering a screenshot. You can use either POST or GET requests.\
\
But in this example, I will share with you a GET request example:\
\
\`\`\`\
https://api.screenshotone.com/take?access\_key=&url=https://example.com&scripts=&delay=10\
\`\`\`\
\
You can see the example.com website rendered in the Spanish language:\
\
!\[The example.com website rendered in the Spanish language\](example.com.spanish.jpeg)\
\
I hope the guide helps you translate and render any HTML or website content, and have a nice day!\
\
\# Upload to S3\
\
You can use \[ScreenshotOne screenshot API\](https://screenshotone.com/) to take website screenshots and upload them directly to Amazon S3 and any other S3-compatible storage like \[Cloudflare R2\](https://www.cloudflare.com/products/r2/), \[Backblaze\](https://www.backblaze.com/), and others.\
\
I will guide through a few simple steps of how you can do it.\
\
Today's UI for Amazon AWS console or ScreenshotOne might be a bit different, and things can change after a while, but you should sense the overall approach from the post you need to apply to make it work.\
\
If you are familiar with AWS, you can go straight away to \[configure access to S3 in ScreenshotOne\](#configure-access-to-s3-in-screenshotone).\
\
\## Prepare the bucket and credentials\
\
Open the \[S3 console\](https://console.aws.amazon.com/s3/) and click on the "Create bucket" button:\
\
!\[Create bucket\](create\_bucket\_button.png)\
\
Type the bucket name, choose a region, and other important for you settings:\
\
!\[A bucket form\](create\_bucket\_form.png)\
\
Now, let's create access keys to upload to the S3 bucket.\
\
:::danger\
Never, ever, don't share the access key to your main account with ScreenshotOne or another service. Create an IAM user with as narrow access as possible and share its keys.\
:::\
\
\> \[AWS Identity and Access Management (IAM) user\](https://docs.aws.amazon.com/IAM/latest/UserGuide/id\_users.html) is an entity that you create in AWS to represent the person or application that uses it to interact with AWS. A user in AWS consists of a name and credentials.\
\
Before creating a user, we will create a narrow policy to restrict access to the bucket we created and only for putting objects into it.\
\
\> You manage access in AWS by creating \[policies\](https://docs.aws.amazon.com/IAM/latest/UserGuide/access\_policies.html) and attaching them to IAM identities (users, groups of users, or roles) or AWS resources. A policy is an object in AWS that, when associated with an identity or resource, defines their permissions. AWS evaluates these policies when an IAM principal (user or role) makes a request. Permissions in the policies determine whether the request is allowed or denied.\
\
Open \[the IAM management console\](https://console.aws.amazon.com/iam/), navigate to "Policies", then click on the "Create policy" button. And one the following screen, select \`S3\` as a service, then allow only \`PutObject\` operation for the bucket with the name \`screenshotone\`:\
\
!\[Create policy\](policy\_s3\_put\_object.png)\
\
After clicking on the "Create policy" button and entering the policy name:\
\
!\[Create policy\](policy\_s3\_review\_policy.png)\
\
I gave a clear name to the policy as an example. You can provide whatever you like.\
\
Then open \[the IAM management console\](https://console.aws.amazon.com/iam/) again and navigate to users. Once you are here, click on the "Add users" button:\
\
!\[Add users\](iam\_console.png)\
\
After that, type username and select "Access key - Programmatic access":\
\
!\[Username and credentials\](username\_and\_access.png)\
\
We need to select and attach the policy we created earlier to the user:\
\
!\[Select policy\](select\_policy.png)\
\
The user is primarily ready, so we can skip the following steps and get to the end, where we can see credentials:\
\
!\[Credentials\](user\_is\_created.png)\
\
Copy the credentials and store them in safe place like password manager. We will need them in the next step to configure ScreenshotOne to upload screenshots.\
\
I will save the credentials for our example to use in the next section:\
\
\`\`\`\
Access key ID: AKIAURGNZP6VM5HASWIF\
Secret access key: wVd8OgAnGIEdlQaWxDwzVcOQNO03G1dgFiDyHLPT\
\`\`\`\
\
\## Configure access to S3 in ScreenshotOne\
\
:::caution\
If you haven't created the bucket in the \`us-east-1\` AWS region, please, specify your bucket region through an endpoint in a format like \`https://s3..amazonaws.com\`.\
:::\
\
You can set credentials (\[Access Key ID\](https://screenshotone.com/docs/options/#storage\_access\_key\_id) and \[Secret Access Key\](https://screenshotone.com/docs/options/#storage\_secret\_access\_key)) when sending an API request or you cat to go to the \[access page\](https://dash.screenshotone.com/access). And put all the credentials you got from Amazon AWS for S3 into the "S3 access" configuration form:\
\
!\[Access page\](access\_page.png)\
\
I specified the default bucket, but you can use many buckets to upload screenshots and then override the target bucket with \[the storage\_bucket option\](https://screenshotone.com/docs/options/#storage\_bucket) when using API. But for example, I use only one bucket—it is enough.\
\
\## Take a website screenshot through API with \`storing\` options\
\
ScreenshotOne API has \[a bunch of options related to uploading screenshots to S3 storage\](https://screenshotone.com/docs/options/#storing):\
\
\- \[store\](https://screenshotone.com/docs/options/#store) triggers upload of the taken screenshot, rendered HTML or PDF to the configured S3 bucket.\
\- \[storage\_path\](https://screenshotone.com/docs/options/#storage\_path)—specifies the key for the file, but not an extension. The extension will be added automatically based on the specified \[format\](https://screenshotone.com/docs/options/#format).\
\- \[storage\_bucket\](https://screenshotone.com/docs/options/#storage\_bucket)—overrides the default bucket configured in the \[access page\](https://dash.screenshotone.com/access).\
\- \[storage\_class\](https://screenshotone.com/docs/options/#storage\_class)—allows to specify \[the object storage class\](https://aws.amazon.com/s3/storage-classes/).\
\
Let's take a screenshot and upload it to S3:\
\
\`\`\`\
https://api.screenshotone.com/take?access\_key=0MpjJxw8Vk7ZAw&url=https://nextjs.org&store=true&storage\_path=nextjs.org\
\`\`\`\
\
The result is:\
\
!\[Next.js\](nextjs.org.jpg)\
\
And let's check S3:\
\
!\[S3 results\](s3\_nextjs.png)\
\
In case you don't need to return the resulting image and speed up uploading, add \`response\_type=empty\` to the request:\
\
\`\`\`\
https://api.screenshotone.com/take?access\_key=0MpjJxw8Vk7ZAw&url=https://example.com&store=true&storage\_path=example.com&response\_type=empty\
\`\`\`\
\
The result is a white screen—zero bytes sent from the ScrenshotOne API in response. And let's again check that the screenshot is uploaded:\
\
!\[S3 results\](s3\_all.png)\
\
That's it. But if you want to do it asynchronously?\
\
\## Async and Webhooks\
\
ScreenshotOne supports \[asynchronous screenshot rendering and webhooks\](/docs/async-and-webhooks/). You can upload your screenshots to S3 asynchronously without waiting and then receive the resulting upload URL to your server.\
\
To do that, specify additional parameters \`async\`, \`webhook\_url\`, \`storage\_return\_location\`. And only JSON response type is supported.\
\
So the full request might look like:\
\
\`\`\`\
https://api.screenshotone.com/take?access\_key=0MpjJxw8Vk7ZAw&url=https://example.com&store=true&storage\_path=example.com&response\_type=json&async=true&webhook\_url=https://example.com&storage\_return\_location=true\
\`\`\`\
\
Read more about \[asynchronous screenshot rendering and webhooks\](/docs/async-and-webhooks/).\
\
\## Why upload to S3\
\
I don't know your use case and would be happy to know it, but there are a few reasons why customers of ScreenshotOne upload website screenshots to S3.\
\
One is to use CDN that pulls images from S3 storage, and the other is to archive screenshots, process them later, or even compare them.\
\
\## Instead of summary\
\
It makes me happy to help people solve their problems. And even happier when people pay for that. I hope today I solved yours. Have a good day or even night, and be happy 👌

----
url: https://screenshotone.com/use-cases/design-apps-font-detection
----

Automate Website Screenshots

1 min read

Design Tools Font Detection

===========================

Use our font detection API to help designers identify and analyze typography on any website.

Build **design tools and applications to detect fonts** use case leverages the [ScreenshotOne font detection API](/font-detection-api/) to automatically identify and analyze fonts on any website. This feature is invaluable for designers who want to understand and emulate successful typography strategies.

Why ScreenshotOne font detection API?

-------------------------------------

Integrating ScreenshotOne’s font detection capabilities into design software or tools enables users to instantly discover what fonts are being used on any website. This eliminates the guesswork and manual inspection that designers typically go through when trying to identify typography.

Check out [our guide on how to detect website fonts](/docs/guides/how-to-detect-website-fonts/) for more details.

Value for Design Professionals

------------------------------

For designers working on new projects, understanding the typography choices of successful websites provides valuable inspiration and insights. The API returns comprehensive font information including font families, weights, and styles, making it easy to recreate or adapt typography strategies.

Time and Cost Savings

---------------------

Building font detection capabilities in-house would require significant development effort and ongoing maintenance. By integrating ScreenshotOne API, design tool developers can offer this powerful feature to their users without the complexity of handling browser automation, rendering engines, and font analysis logic.

Working with Dmytro from ScreenshotOne has been an overwhelmingly positive and refreshing experience. He’s incredibly responsive, quick to act, and genuinely committed to making his service work for our needs.

Barnabás Ürmössy

Development Manager, [Kinsta](https://screenshotone.com/blog/kinsta/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

### UX Font Analysis

Examine the impact of different fonts on user engagement and website usability.

[Read more →](/use-cases/ux-font-analysis/)

### Brand Consistency Font Checks

Use ScreenshotOne font detection API to automatically verify font consistency across web pages to maintain brand integrity.

[Read more →](/use-cases/brand-consistency-font-checks/)

### Font Legal Compliance Check

Ensure fonts used on websites are legally compliant to avoid copyright issues.

[Read more →](/use-cases/font-legal-compliance/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/contributors/nabil-kazi
----

Nabil Kazi

----------

View all Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [How BugSmash automates website screenshot rendering](/blog/bugsmash-story/)

How and why BugSmash uses ScreenshotOne for critical screenshot rendering tasks.

Written by

[Nabil Kazi](/contributors/nabil-kazi/), [Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Apr 27, 2025

•

2 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/pdfs/from_canvas.pdf
----

Hello, world  Peace and love to everybody.

----
url: https://screenshotone.com/changelog/n8n-integration
----

Add ScreenshotOne to n8n workflows

==================================

You can now use ScreenshotOne in n8n workflows to render website screenshots, PDFs, scrolling screenshots and videos.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jun 26, 2025

We have built and published [n8n integration for ScreenshotOne](/docs/no-code/n8n/) 🥳

In a few clicks, you can:

*   📸 render website screenshots;

*   📄 PDFs from HTML or URLs;

*   🎬 scrolling screenshots and videos;

*   🔥 and more…

All as part of your workflows in your favorite automation platform.

If you are interested in why we built this integration, check out [our n8n integration announcement blog post](/blog/n8n-integration/).

If you have any questions or need any assistance, please, reach out at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [ScreenshotOne integration with Dirstarter](/changelog/dirstarter-integration/)

Build a directory with Dirstarter and add website screenshots automatically with ScreenshotOne.

Read more →

1 min read

#### [Get favicon used by a website with ScreenshotOne API](/changelog/metadata-icon/)

Now you can get favicon used by a website with ScreenshotOne API in just one simple API call.

Read more →

1 min read

#### [Remove organization members](/changelog/remove-organization-member/)

Improvements to the organization management.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/get-usage
----

[Skip to content](#_top)

Get Usage

=========

Copy page

You can get your current plan usage by:

    1GET https://api.screenshotone.com/usage?access_key=<YOUR ACCESS KEY>`2

    3{4    "total": 10000,5    "available: 950,6    "used": 9050,7    "concurrency": {8        "limit":20,9        "remaining":20,10        "reset":168164694777543726411    }12}

A bit of clarification:

*   `total` is the total number of requests allowed in the current billing plan period;

*   `available` is the number of available requests until the end of the current period;

*   `used` is the number of successfully executed requests.

*   `concurrency.limit` is the total number of concurrent requests allowed per interval;

*   `concurrency.remaining` is the number of available concurrent requests allowed per interval;

*   `concurrency.reset` is the time when the limitation will be reset, in UNIX timestamp format in nanoseconds.

----
url: https://screenshotone.com/docs/notifications
----

[Skip to content](#_top)

Notifications

=============

Copy page

When you reach 90% or 100% of your screenshot limit, you will receive a notification to your email and/or Slack.

Email

-----

By default, you will receive an email notification when you reach 90% or 100% of your screenshot limit. You can disable these notifications in the [dashboard](https://dash.screenshotone.com/notifications), but they are enabled by default:

Slack

-----

You can also enable Slack notifications in the [dashboard](https://dash.screenshotone.com/notifications), in addition to the email notifications.

To enable Slack notifications, you need to specify a Slack webhook URL in the [dashboard](https://dash.screenshotone.com/notifications):

To configure a Slack webhook URL, you need to create a new webhook in your Slack workspace.

### 1\. Create a Slack application

[Create a new Slack application](https://api.slack.com/apps/new).

### 2\. Enable incoming webhooks

Go to [your application settings](https://api.slack.com/apps) and enable incoming webhooks:

### 3\. Add new webhook to your workspace

Click on the “Add New Webhook to Workspace” button:

And then choose the target channel:

### 4\. Copy the webhook URL

In this example, the webhook URL is:

    1https://hooks.slack.com/services/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

### 5\. Save and test the webhook URL

Paste the webhook URL in the [dashboard](https://dash.screenshotone.com/notifications):

And check the integration test message in the target channel:

### 6\. Get notifications when you reach limits

Once you reach your limit, you will receive a notification in the target channel like this or similar:

Summary

-------

These are the most important notifications you need to recieve from ScreenshotOne. If you have more ideas or issues with configuring or receiving notifications, please, reach out to us via `support@screenshotone.com`.

----
url: https://screenshotone.com/blog/tags/customer-stories/2
----

Customer Stories

----------------

Customer stories and case studies from teams using ScreenshotOne.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [How Forge IQ automates visual CRO audits with ScreenshotOne](/blog/forge-iq/)

A story about how Forge IQ automates its CRO audit by integrating ScreenshotOne into their workflow to produce visual reports.

Written by

[William Prud’homme](/contributors/william-prudhomme/)

Published on

May 23, 2025

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Taking care of WordPress Sites with ScreenshotOne](/blog/kinsta/)

How Kinsta uses ScreenshotOne to deliver reliable automatic updates.

Written by

[Roger Williams](/contributors/roger-williams/), [Barnabás Ürmössy](/contributors/barnabs-rmssy/)

Published on

Apr 29, 2025

•

2 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How BugSmash automates website screenshot rendering](/blog/bugsmash-story/)

How and why BugSmash uses ScreenshotOne for critical screenshot rendering tasks.

Written by

[Nabil Kazi](/contributors/nabil-kazi/), [Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Apr 27, 2025

•

2 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Magic Pages: Showcasing Product Adoption with Screenshots](/blog/magic-pages/)

How and why "Magic Pages" used ScreenshotOne to showcase how their customers use their product.

Written by

[Jannis Fedoruk-Betschki](/contributors/jannis-fedorukbetschki/), [Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 28, 2025

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Using AI screenshot analysis to identify leads for a design agency](/blog/ai-screenshot-analysis-for-finding-customers/)

Elias shares his process for discovering high-quality leads for a design agency by using AI screenshot analysis within the Clay platform.

Written by

[Elias Stravik](/contributors/elias-stravik/)

Published on

Dec 23, 2024

•

4 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Integrating ScreenshotOne into the directory management platform](/blog/makeadir-feedback/)

How and why "Make a Directory" used ScreenshotOne to automate screenshots for directory websites.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Bohdan Shulha](/contributors/bohdan-shulha/)

Published on

Dec 23, 2024

•

3 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Automating screenshots for directory websites with ScreenshotOne](/blog/directify-feedback/)

How and why "Directify" used ScreenshotOne to automate screenshots for directory websites.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Sergey Karakhanyan](/contributors/sergey-karakhanyan/)

Published on

Dec 15, 2024

•

2 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Branding 5 uses ScreenshotOne for competitor analysis](/blog/how-branding5-uses-screenshotone/)

If you are interested in diving deeper into the Branding 5 use case and discover if ScreenshotOne might be useful for you, too, keep reading.

Written by

[Matthias Neumayer](/contributors/matthias-neumayer/), [Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Oct 4, 2024

•

2 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/screenshotone-november-2025-updates
----

ScreenshotOne November 2025 updates

===================================

Error metrics in the dashboard, Postman Public API Network, and Landing Gallery customer story.

[Blog post](/blog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Dec 2, 2025

Today, I want to share a short summary of the product updates, company news and learnings in November 2025.

Error metrics in the dashboard

------------------------------

[Monitor errors](/changelog/error-metrics/): A new error metrics widget in the dashboard helps you quickly understand what errors are happening and how often. See error counts, percentages, and get quick access to logs and documentation.

[](/changelog/error-metrics/)

Postman Public API Network

--------------------------

[Play with the API in Postman](/changelog/postman-public-collections/): ScreenshotOne API is now verified and available on the Postman Public API Network. Use our public collection with all API endpoints and examples to quickly get started and test integrations.

[](/changelog/postman-public-collections/)

How Landing Gallery uses ScreenshotOne

--------------------------------------

[Landing Gallery](/blog/landing-gallery/) is a landing page inspiration site that helps you find the best landing pages for your new venture.

[](/blog/landing-gallery/)

Chris Jayden, the founder of Landing Gallery, [shared how ScreenshotOne helps automate screenshot workflow for his design-inspiration platform](/blog/landing-gallery/). He chose ScreenshotOne over building his own solution because he didn’t want to manage screenshotting infrastructure.

Summary

-------

November was a productive month focused on improving developer experience with better error visibility in the dashboard and Postman integration.

Questions or feedback? Reach out at `support@screenshotone.com`.

Read more posts

---------------

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

[View all posts](/blog/)

#### [How to build a Programmatic SEO site with automated website screenshots using ScreenshotOne, Airtable, and Launchman](/blog/how-to-build-a-programmatic-seo-site-with-automated-website-screenshots-using-screenshotone-airtable-and-launchman/)

Programmatic SEO is a great growth hacking strategy where you create a large number of content pages that rank for long-tailed keywords on Google.

Read more

#### [n8n integration for ScreenshotOne](/blog/n8n-integration/)

You can now use ScreenshotOne in n8n workflows to render website screenshots, PDFs, scrolling screenshots and videos.

Read more

#### [Using Clobbr to quickly load test the ScreenshotOne API](/blog/using-clobbr-to-quickly-load-test-the-screenshotone-api/)

Google Cloud gives $300 in credits for 3 months for experimenting. And I decided to give it a try, but not because of the free credits.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/seobot-automates-screenshot-generation-for-articles
----

SEOBot uses ScreenshotOne API to generate screenshots for articles

==================================================================

Customers can your product in unpredictable and surprising ways. SEOBot now uses ScreenshotOne API to enhance its articles with screenshots, making content more engaging and visually appealing.

[Customer story](/blog/tags/customer-stories/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [John Rush](/contributors/john-rush/)

#### Published on

Feb 27, 2024

Why add website thumbnails to blog posts

----------------------------------------

Adding screenshots to blog posts makes them easier to understand and more interesting. These pictures show readers exactly what you’re talking about, like how a website looks or how to do something step by step. This makes the post more fun to read and helps people trust what you’re saying because they can see the evidence.

Including screenshots also helps more people find your blog. When you use images with good descriptions, your blog can show up in image searches. This brings more visitors to your site. Plus, posts with pictures get shared more on social media, so more people see your work. In short, screenshots make your posts clearer, more engaging, and help attract more readers.

How ScreenshotOne helps SEOBot

------------------------------

Here is what we discovered on [the SEOBot blog](https://seobotai.com/blog/):

> SEOBot now uses ScreenshotOnE API to enhance its articles with screenshots, making content more engaging and visually appealing. This integration offers automatic, customizable screenshots, improving SEO and user experience.

You can read more about [how and why SEOBot uses our screenshot API under the hood](https://seobotai.com/blog/seobot-uses-screenshotone-api-under-the-hood/).

More Examples and Use Cases

---------------------------

You might be also interested in how [Stagetimer automates Open Graph image generation](/blog/how-stagetimer-automates-og-image-generation/).

ScreenshotOne supports a huge variety of uses including but not only:

*   [Automating screenshots for landing page inpsiration collections](/use-cases/collect-design-inspirations/).

*   [Generating personalized videos](/use-cases/automate-personalized-videos/).

*   [Rendering site thumbnails for search previews](/use-cases/preview-search-results/)

And [many more](/use-cases/).

Read more customer stories

--------------------------

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

[View all posts](/blog/tags/customer-stories/)

#### [How Outrank enriches content generation with ScreenshotOne](/blog/outrank/)

A short story about how and why Outrank uses ScreenshotOne for screenshot generation to enrich SEO content.

Read more

#### [Why FrameKit chose ScreenshotOne for their business](/blog/framekit/)

A short story about how and why FrameKit chose ScreenshotOne for their use case.

Read more

#### [How AdKit automated onboarding](/blog/adkit/)

A short story by the founder of AdKit about how they use ScreenshotOne for onboarding automation.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/contributors/jannis-fedorukbetschki
----

Jannis Fedorukbetschki

----------------------

View all Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [Magic Pages: Showcasing Product Adoption with Screenshots](/blog/magic-pages/)

How and why "Magic Pages" used ScreenshotOne to showcase how their customers use their product.

Written by

[Jannis Fedoruk-Betschki](/contributors/jannis-fedorukbetschki/), [Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 28, 2025

•

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/summit-integration
----

ScreenshotOne is now integrated into Summit

===========================================

The ScreenshotOne screenshot API is now natively integrated into Summit and you can perform anything on top of the powerful screenshot automation and Summit models—only the sky is the limit.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jul 20, 2024

[Summit](https://usesummit.com/) is a no-code platform for creating small programs (called models) that can be used inside the most popular workflow builders. They are on a mission to be the best way to harness AI and the unstructured data that flows through your automation.

Summit can be used to build both major categories of steps (components) in workflows: actions and triggers. While not all platforms allow you to build custom triggers, most (Zapier, Make, Glide, Customer.io, and HubSpot) allow you to create custom actions.

Depending on your preferred platform, these custom actions are sometimes called apps, HTTP requests, or API connections. However they’re named, Summit can plug into them!

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Improved the behavior and stability of the "scroll\_into\_view" option](/changelog/improved-scroll-into-view/)

Before the change, there was a subset of cases when the rendering requests were failing when using the scroll\_into\_view option. Now, it is improved and will make rendering more stable.

Read more →

1 min read

#### [ScreenshotOne integration with Dirstarter](/changelog/dirstarter-integration/)

Build a directory with Dirstarter and add website screenshots automatically with ScreenshotOne.

Read more →

1 min read

#### [ScreenshotOne CLI is available](/changelog/cli-integration/)

Use command line interface to automate screenshots in your workflows with ScreenshotOne.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/5
----

Automate Website Screenshots

----------------------------

Guides, Product Updates, and Helpful Resources from ScreenshotOne.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [How Outrank enriches content generation with ScreenshotOne](/blog/outrank/)

A short story about how and why Outrank uses ScreenshotOne for screenshot generation to enrich SEO content.

Written by

[Eugene Zolotarenko](/contributors/eugene-zolotarenko/), [Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jun 29, 2025

•

1 min read

#### [n8n integration for ScreenshotOne](/blog/n8n-integration/)

You can now use ScreenshotOne in n8n workflows to render website screenshots, PDFs, scrolling screenshots and videos.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jun 26, 2025

•

1 min read

#### [ScreenshotOne on LaunchDay!](/blog/itslaunchday/)

ScreenshotOne participated in the first launch batch of the LaunchDay platform

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jun 20, 2025

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Forge IQ automates visual CRO audits with ScreenshotOne](/blog/forge-iq/)

A story about how Forge IQ automates its CRO audit by integrating ScreenshotOne into their workflow to produce visual reports.

Written by

[William Prud’homme](/contributors/william-prudhomme/)

Published on

May 23, 2025

•

1 min read

[Playwright guides](/blog/tags/playwright-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to render screenshots with Playwright](/blog/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](/contributors/dmytro-krasun/)

Published on

Apr 29, 2025

•

10 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Taking care of WordPress Sites with ScreenshotOne](/blog/kinsta/)

How Kinsta uses ScreenshotOne to deliver reliable automatic updates.

Written by

[Roger Williams](/contributors/roger-williams/), [Barnabás Ürmössy](/contributors/barnabs-rmssy/)

Published on

Apr 29, 2025

•

2 min read

[Crawling and scraping](/blog/tags/crawling-and-scraping/)

#### [3 best scraping APIs in 2026](/blog/best-scraping-apis/)

ScreenshotOne is not a scraping API, but what if you could achieve your goals with it and get perfect screenshots as an additional benefit?

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jan 6, 2026

•

2 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How BugSmash automates website screenshot rendering](/blog/bugsmash-story/)

How and why BugSmash uses ScreenshotOne for critical screenshot rendering tasks.

Written by

[Nabil Kazi](/contributors/nabil-kazi/), [Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Apr 27, 2025

•

2 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/how-to-convert-html-to-pdf-in-javascript
----

How to convert HTML to PDF in JavaScript

========================================

Nowadays, you have various options to generate PDFs from HTML or any given URL: generating PDF in the browser, on the server-side (Node.js), or even using a modern and friendly API to generate PDF.

[Blog post](/blog/) 3 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

May 2, 2025

#### Tags

[PDF rendering](/blog/tags/pdf-rendering/)

But only you who know your context and requirements can decide the best options for you. But let me guide you through existing solutions and describe their pros and cons.

Using html2canvas and jsPDF

---------------------------

You can use a combination of [html2canvas](https://html2canvas.hertzen.com/) and [jsPDF](https://github.com/parallax/jsPDF) libraries to generate PDF from HTML right away from the browser. Let’s do it first and then quickly discuss the pros and cons of generating PDFs in the browser.

Let’s install the necessary libraries first:

Terminal window

    1npm install jspdf dompurify html2canvas --save

And then generate a PDF document from simple HTML:

src/index.js

    1import { jsPDF } from "jspdf";2

    3function generateAndDownload() {4    const doc = new jsPDF();5    doc.html("<h1>Hello, world</h1><h2>Peace and love to everybody.</h2>", {6        callback: function (doc) {7            doc.save();8        }9    });10}11

    12window.addEventListener('DOMContentLoaded', () => {13    document.getElementById('generate').addEventListener('click', () => {14        generateAndDownload();15    });16});

To make it work, use the following `webpack.config.js`:

    1const path = require('path');2

    3module.exports = {4    entry: './src/index.js',5    output: {6        path: path.resolve(__dirname, 'dist'),7        filename: 'bundle.js',8    }9};

And UI:

    1<!DOCTYPE html>2<html>3  <head>4    <meta charset="utf-8" />5  </head>6  <body>7    <button id="generate">Generated and download a document</button>8    <script src="dist/bundle.js"></script>9  </body>10</html>

And the result is [a PDF document](/pdfs/from_canvas.pdf).

Pros and cons:

1.  Rendering PDF in the browser saves computation resources for your servers. But it uses your users’ computational resources, and they might have unpleasant experiences after using your application.

2.  Each browser version is different, and the `html2canvas` library might produce various rendering artifacts. You don’t have control over what your potential users see. Hence, it would help if you considered this when rendering HTML on the client.

3.  It is not easy to render HTML from a URL. You can’t fetch any URL in the browser due to security reasons. So you need to prepare your HTML in advance or use some proxy.

But there is a solution to avoid the pitfalls of rendering PDFs on the client side.

Using Puppeteer

---------------

In addition to [rendering screenshots](/blog/how-to-take-a-screenshot-with-puppeteer/), Puppeteer can render PDFs.

To ensure that PDFs are rendered as you expect for every user, you can use [Puppeteer](https://pptr.dev/) on the server side. Puppeteer is a browser automation library written for headless browsers that support [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/).

Install Puppeteer:

Terminal window

    1npm i puppeteer

And then:

    1const puppeteer = require('puppeteer');2

    3(async () => {4    const browser = await puppeteer.launch({ headless: true });5    try {6        const page = await browser.newPage();7

    8        await page.setViewport({ width: 1280, height: 1024 });9

    10        await page.goto('https://example.com/', { waitUntil: ['load', 'domcontentloaded', 'networkidle0'] });11

    12        await page.pdf({ type: 'png', path: 'example.pdf' });13    } catch (e) {14        console.log(e)15    } finally {16        await browser.close();17    }18})();

And the result is [a PDF document](/pdfs/example.com.pdf).

It has a lot of nuances, pros and cons. Check our [guide on how to generate PDFs with Puppeteer](/blog/how-to-generate-pdf-with-puppeteer/) for more details and nuances.

But also there is a solution to avoid most Puppeteer issues with rendering PDFs. It is using [ScreenshotOne’s PDF rendering API](/).

Using modern and scalable URL or HTML to PDF API

------------------------------------------------

If you don’t want to deal with all the burdens of managing headless browsers, you can use [ScreenshotOne PDF Generation API](/pdf-generation-api/) to render PDFs from HTML or any URL. It is a free PDF to HTML API for up to 100 requests. The PDF generation API from ScreenshotOne is easy to use. It is scalable, covers a variety of use cases, and solves all the issues related to rendering PDFs in headless browsers.

Let’s take a look at how easy it is to render a PDF with a straightforward call:

    1https://api.screenshotone.com/take?url=https://example.com&format=pdf&access_key=<your access key>

And the result is [a PDF document](/pdfs/example.com.pdf).

Summary

-------

If you do not want to make your backend more complex, render PDFs using `html2canvas` and `jsPDF`.

If you need scaling and want to ensure that PDFs are rendered the same way for any of your users, go with the `Puppeteer` library.

But if you don’t want to manage headless browsers and issues when rendering PDFs, feel free to use and sign up for [ScreenshotOne HTML or URL to PDF API](/pdf-generation-api/).

A few related articles you might be interested in:

--------------------------------------------------

1.  [A complete guide on how to take screenshots with Puppeteer](/blog/how-to-take-a-screenshot-with-puppeteer/).

2.  [How to take website screenshots with JavaScript or TypeScript (Node.js).](/blog/how-to-take-website-screenshots-with-javascript-or-typescript-node.js/)

Read more PDF rendering

-----------------------

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

[View all posts](/blog/tags/pdf-rendering/)

#### [How to generate PDFs with Puppeteer](/blog/how-to-generate-pdf-with-puppeteer/)

A practical and working guide on how to generate PDFs with Puppeteer.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/errors/invalid-storage-configuration
----

[Skip to content](#_top)

Invalid Storage Configuration

=============================

Copy page

It is an API error returned when the storage configuration for S3 is invalid.

    1{2    "is_successful": false,3    "error_code": "invalid_storage_configuration",4    "error_message": "If you haven't created the bucket in the `us-east-1` AWS region, please, specify your bucket region through an endpoint in a format like https://s3.<your-region>.amazonaws.com.",5    "documentation_url": "https://screenshotone.com/docs/errors/invalid-storage-configuration/"6}

Reasons and how to fix

----------------------

### Incorrect AWS S3 Bucket Region

One common reason for the “invalid\_storage\_configuration” error is that the S3 bucket is not created in the `us-east-1` region and the bucket region is not specified correctly.

To fix this, you can:

1.  **Specify the bucket Region**: Ensure you specify your bucket region in the endpoint format like `https://s3.<your-region>.amazonaws.com`. Replace `<your-region>` with the actual AWS region where your bucket is located.

### Missing or misconfigured Bucket

If the S3 bucket does not exist or is misconfigured, this can lead to the “invalid\_storage\_configuration” error.

To fix this, consider:

1.  **Verify bucket existence**: Check that the S3 bucket exists in your AWS account and is accessible.

2.  **Correct bucket configuration**: Ensure the bucket is configured correctly, including permissions and policies.

### Incorrect Endpoint URL

The endpoint URL might be incorrectly formatted, causing the API to fail in accessing the specified S3 bucket.

To fix this, ensure the endpoint URL is correctly formatted as `https://s3.<your-region>.amazonaws.com`, with the correct region specified.

### AWS IAM Permissions

Inadequate permissions set in the AWS IAM policies might prevent the API from accessing the S3 bucket, leading to this error.

To fix this, ensure that the IAM roles and policies associated with your bucket have the necessary permissions to allow access from the API.

Reach out to support

--------------------

If you continue to face issues or need further assistance, please reach out to `support@screenshotone.com`, and we will assist you as soon as possible.

----
url: https://screenshotone.com/integrations/n8n
----

Integrations

1 min read

n8n

===

Use ScreenshotOne in n8n workflows to render website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

No-Code Automation

Resources

---------

*   [ScreenshotOne on the n8n platform](https://n8n.io/integrations/screenshotone/)

DS.Emotion is a branding, marketing & placemaking agency with more than 100 national websites in our care. We've used ScreenshotOne to keep an eye on our whole portfolio. It means at a glance we can see if there are issues.

I'm a strategist (not a developer) so the fact that I was able to easily integrate it into AppSheet shows how simple it is to use and how good the support is.

Lawrence Alexander

Strategy & Innovation Director, [DS.Emotion](https://dsemotion.com/)

Check more Integrations

-----------------------

No-code tools, AI, code libraries, and more.

[Check more Integrations](/integrations/)

No-Code Automation

### Make

Use ScreenshotOne with Make to automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

[Read more →](/integrations/make/)

Code API

### SDK and Code Examples

Use the SDKs and code examples to take screenshots in your own code.

[Read more →](/integrations/code/)

No-Code Automation

### Clay

Generate website screenshots inside Clay to qualify leads, assess content, and enrich rows with visual context automatically.

[Read more →](/integrations/clay/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/postman-public-collections
----

ScreenshotOne on the Postman Public API Network

===============================================

You can now play with the ScreenshotOne API in Postman using many examples as starting points for integrations.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Nov 18, 2025

ScreenshotOne API is now available in the [Postman Public API Network](https://www.postman.com/screenshotone).

[](https://www.postman.com/screenshotone)

We provide a public collection with all the API endpoints and examples. You can use it to play with the API and get started quickly. You can run ScreenshotOne API requests in [Postman](https://www.postman.com/) using the following collection:

[](https://god.gw.postman.com/run-collection/50121564-7b48803f-b44f-4f5b-892b-f624c9d124b8?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D50121564-7b48803f-b44f-4f5b-892b-f624c9d124b8%26entityType%3Dcollection%26workspaceId%3D192aa74a-dd79-4388-8bdd-10d7cbaa8435)

If you have any questions, please, reach out at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Trigger screenshot download](/changelog/attachment-name/)

Now you can set attachment filename to trigger screenshot download in the browser.

Read more →

1 min read

#### [Fixed a validation issue in the playground](/changelog/fixed-a-playground-issue/)

We fixed a validation issue in the ScreenshotOne playground caused by selector scroll into view.

Read more →

1 min read

#### [Better and more extensible PDF rendering](/changelog/better-and-more-extensible-pdf-rendering/)

ScreenshotOne supports PDF rendering for a long time but it was used till recently by a small group of customers. Growing demand in PDF rendering required updating the API. And today, we introduce new options for PDF customization.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/integrations/airtable
----

Integrations

1 min read

Airtable

========

Add website screenshots to your Airtable content.

Low-Code Automation

Resources

---------

*   [Documentation](https://screenshotone.com/blog/how-to-build-a-programmatic-seo-site-with-automated-website-screenshots-using-screenshotone-airtable-and-launchman/)

ScreenshotOne helps us easily make instant OG images for all our clients at our [SEO agency](http://magicspace.agency), it's the easiest way to make quick screenshots fast and they look amazing.

Ilias Ism

Founder, [ogimage.org](https://ogimage.org/)

Check more Integrations

-----------------------

No-code tools, AI, code libraries, and more.

[Check more Integrations](/integrations/)

No-Code Automation

### Zapier

Automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos in Zapier.

[Read more →](/integrations/zapier/)

No-Code Automation

### n8n

Use ScreenshotOne in n8n workflows to render website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

[Read more →](/integrations/n8n/)

No-Code Automation

### Make

Use ScreenshotOne with Make to automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

[Read more →](/integrations/make/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/selenium-python-screenshots
----

Website Screenshots with Selenium in Python

===========================================

Complete guide to taking screenshots with Selenium in Python. Learn save\_screenshot(), element screenshots, full page workarounds, and headless mode setup.

[Blog post](/blog/) 5 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jan 11, 2026

#### Tags

[Screenshot rendering](/blog/tags/screenshot-rendering/)

[Selenium](https://www.selenium.dev/) is one of the oldest browser automation tools, and it’s still widely used. If you already have Selenium in your stack, you can take screenshots without adding another dependency. Let me quickly show you how.

If you don’t want to read and just save time,I created a dedicated repository with [tested and working examples of how to take screenshots with Selenium in Python](https://github.com/screenshotone/python-selenium-examples).

However, if you don’t use Selenium and building from scratch, I recommend using [Playwright](/blog/playwright-python-screenshots/) instead, it is a modern and actively developed library for browser automation. Especially if that’s the only functionality you need. Or check out our guide to [how to take website screenshots Python](/blog/how-to-take-website-screenshots-in-python/).

Quick Start

-----------

Install `Selenium` and `webdriver-manager`:

Terminal window

    1pip install selenium webdriver-manager

Using `webdriver-manager` eliminates the need to manually download ChromeDriver:

    1from selenium import webdriver2from selenium.webdriver.chrome.service import Service as ChromeService3from webdriver_manager.chrome import ChromeDriverManager4

    5# automatically download and use the correct ChromeDriver6driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()))7

    8driver.get('https://example.com')9driver.save_screenshot('screenshot.png')10driver.quit()

If you are familiar with `example.com`, you should not be surprised by the result:

Screenshot Methods

------------------

Selenium provides three ways to capture screenshots:

### 1\. Save to File

    1driver.save_screenshot('screenshot.png')

### 2\. Get as Bytes (PNG)

    1png_bytes = driver.get_screenshot_as_png()2

    3# Save manually4with open('screenshot.png', 'wb') as f:5    f.write(png_bytes)

### 3\. Get as Base64 String

    1base64_string = driver.get_screenshot_as_base64()2

    3# Useful for embedding in HTML or sending via API4import base645png_bytes = base64.b64decode(base64_string)

Waiting for Page Load

---------------------

Taking a screenshot too early means incomplete content:

### Explicit Wait for Elements

    1from selenium.webdriver.support.ui import WebDriverWait2from selenium.webdriver.support import expected_conditions as EC3from selenium.webdriver.common.by import By4

    5driver.get('https://example.com')6

    7# Wait for specific element to be visible8wait = WebDriverWait(driver, 10)9wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.main-content')))10

    11driver.save_screenshot('screenshot.png')

### Fixed Timeout

    1import time2

    3driver.get('https://example.com')4time.sleep(3)  # Wait 3 seconds5driver.save_screenshot('screenshot.png')

### Combine Both

    1from selenium.webdriver.support.ui import WebDriverWait2from selenium.webdriver.support import expected_conditions as EC3from selenium.webdriver.common.by import By4import time5

    6driver.get('https://example.com')7

    8# Wait for main content9try:10    wait = WebDriverWait(driver, 10)11    wait.until(EC.presence_of_element_located((By.TAG_NAME, 'body')))12except:13    pass14

    15# Extra buffer for JavaScript16time.sleep(1)17

    18driver.save_screenshot('screenshot.png')

Element Screenshots

-------------------

Capture a specific element instead of the full viewport:

    1from selenium.webdriver.common.by import By2

    3driver.get('https://example.com')4

    5# Find element and screenshot it6element = driver.find_element(By.CSS_SELECTOR, '.hero-section')7element.screenshot('hero.png')

Viewport Settings

-----------------

Control the browser window size:

    1# Set window size before navigating2driver.set_window_size(1920, 1080)3driver.get('https://example.com')4driver.save_screenshot('screenshot.png')

Or maximize:

    1driver.maximize_window()

Full Page Screenshots

---------------------

This is where Selenium falls short. Unlike [Playwright](/blog/playwright-python-full-page-website-screenshots/), Selenium doesn’t have native full-page support. Here’s the workaround:

    1from selenium import webdriver2from selenium.webdriver.chrome.options import Options3from PIL import Image4import io5import time6

    7def full_page_screenshot(driver, output_path, scroll_wait):8    metrics = driver.execute_script(9        """10        const body = document.body;11        const html = document.documentElement;12        const totalHeight = Math.max(13            body.scrollHeight, body.offsetHeight, body.clientHeight,14            html.scrollHeight, html.offsetHeight, html.clientHeight15        );16        const viewportHeight = window.innerHeight;17        return { totalHeight, viewportHeight };18        """19    )20    total_height = int(metrics["totalHeight"])21    viewport_height = int(metrics["viewportHeight"])22    if viewport_height <= 0:23        raise RuntimeError("Viewport height is zero")24    last_scroll = max(total_height - viewport_height, 0)25    positions = list(range(0, total_height, viewport_height))26    if not positions or positions[-1] != last_scroll:27        positions.append(last_scroll)28    screenshots = []29    for offset in positions:30        driver.execute_script(31            "document.documentElement.scrollTo(0, arguments[0]);"32            "document.body.scrollTo(0, arguments[0]);",33            offset,34        )35        time.sleep(scroll_wait)36        png = driver.get_screenshot_as_png()37        screenshots.append(Image.open(io.BytesIO(png)))38    if not screenshots:39        raise RuntimeError("No screenshots captured")40    scale = screenshots[0].height / viewport_height41    total_height_px = int(total_height * scale)42    total_width_px = screenshots[0].width43    stitched = Image.new("RGB", (total_width_px, total_height_px))44    y = 045    for img in screenshots:46        remaining = total_height_px - y47        if remaining <= 0:48            break49        if img.height > remaining:50            img = img.crop((0, 0, img.width, remaining))51        stitched.paste(img, (0, y))52        y += img.height53    stitched.save(output_path)54

    55options = Options()56options.add_argument('--headless')57driver = webdriver.Chrome(options=options)58driver.set_window_size(1920, 1080)59driver.get('https://screenshotone.com')60full_page_screenshot(driver, 'fullpage.png', 0.2)61driver.quit()

It did screenshot the full page, but it had some issue. E.g. it screenshots scrollbar, you can try to fix that by executing the following JavaScript code:

    1document.body.style.overflow = "hidden";

Another issue was that the top navigation bar appeared in the screenshot a few times:

There are many ways to fix that:

1.  Try to fixate all the elements.

2.  Do not stitch pages together, but take a screenshot of the whole page by applying different techniques. However that will also have its own issues.

But unfortunately, it is out of the scope of this guide. Check out [our Playwright (Python) guide to how to take full page screenshots](/blog/playwright-python-full-page-website-screenshots/) for some examples on that can be solved.

If full-page screenshots is a critical part of your workflow, consider using [our API](/) instead.

Headless Mode

-------------

For server environments:

    1from selenium import webdriver2from selenium.webdriver.chrome.options import Options3

    4options = Options()5options.add_argument('--headless')6options.add_argument('--no-sandbox')7options.add_argument('--disable-dev-shm-usage')8options.add_argument('--disable-gpu')9options.add_argument('--window-size=1920,1080')10

    11driver = webdriver.Chrome(options=options)12driver.get('https://example.com')13driver.save_screenshot('screenshot.png')14driver.quit()

Chrome Options for Screenshots

------------------------------

Useful options for screenshot automation:

    1options = Options()2options.add_argument('--headless')3options.add_argument('--window-size=1920,1080')4options.add_argument('--hide-scrollbars')5options.add_argument('--force-device-scale-factor=2')  # Retina6options.add_argument('--lang=en-US')7options.add_argument('--disable-extensions')

Error Handling

--------------

    1from selenium import webdriver2from selenium.common.exceptions import TimeoutException, WebDriverException3from selenium.webdriver.support.ui import WebDriverWait4from selenium.webdriver.support import expected_conditions as EC5from selenium.webdriver.common.by import By6

    7def safe_screenshot(url, output_path):8    driver = None9    try:10        driver = webdriver.Chrome()11        driver.set_window_size(1920, 1080)12

    13        driver.get(url)14

    15        # Wait for page16        wait = WebDriverWait(driver, 10)17        wait.until(EC.presence_of_element_located((By.TAG_NAME, 'body')))18

    19        driver.save_screenshot(output_path)20        return True21

    22    except TimeoutException:23        print(f"Timeout loading {url}")24        return False25    except WebDriverException as e:26        print(f"WebDriver error: {e}")27        return False28    finally:29        if driver:30            driver.quit()

Multiple Screenshots

--------------------

Process multiple URLs:

    1from selenium import webdriver2from selenium.webdriver.chrome.options import Options3

    4urls = [5    'https://example.com',6    'https://github.com',7]8

    9options = Options()10options.add_argument('--headless')11

    12driver = webdriver.Chrome(options=options)13driver.set_window_size(1920, 1080)14

    15for i, url in enumerate(urls):16    try:17        driver.get(url)18        driver.implicitly_wait(5)19        driver.save_screenshot(f'screenshot_{i}.png')20        print(f'Success: {url}')21    except Exception as e:22        print(f'Failed: {url} - {e}')23

    24driver.quit()

[Check our guide how to take bulk screenshots with Selenium in Python](/blog/bulk-screenshots-python/) for more details.

Playwright vs Selenium for Screenshots

--------------------------------------

Feature

Selenium

Playwright

Native full page

No

Yes

Async support

No

Yes

Element screenshots

Yes

Yes

Wait mechanisms

Explicit only

Multiple options

Setup complexity

Higher

Lower

Speed

Slower

Faster

**My recommendation**: If you’re starting fresh, use [Playwright](/blog/playwright-python-screenshots/). If you already have Selenium in your project, it works fine for basic screenshots.

When to Use a Screenshot API

----------------------------

Selenium is fine for small volumes, but at scale:

*   Browser process management becomes complex.

*   Memory leaks are common.

*   No native full-page support.

The best use case for that is when you perform testing of your websites: your run and screenshot pages and then close the browser and forget about resources. In that case, resource management is less of an issue.

For production workloads, consider a [screenshot API like ScreenshotOne](/screenshot-api/python/). See the [main Python screenshot guide](/blog/how-to-take-website-screenshots-in-python/) for all options.

Summary

-------

Selenium screenshot basics:

1.  Use `save_screenshot()` for simple saves

2.  Use `webdriver-manager` to avoid driver management.

3.  Always wait for content before capturing.

4.  Full page requires workarounds (body element or scroll+stitch).

5.  Use headless mode for servers.

Frequently Asked Questions

--------------------------

If you read the article, but still have questions. Please, check the most frequently asked. And if you still have questions, feel free reach out at [support@screenshotone.com](mailto:support@screenshotone.com).

### How to take screenshot in Selenium Python?

Use driver.save\_screenshot('screenshot.png') to save directly to file, or driver.get\_screenshot\_as\_png() to get the screenshot as bytes for further processing.

### How to take full page screenshot in Selenium Python?

Selenium doesn't have native full page support. You need to scroll through the page, capture sections, and stitch them together. Or use the body element screenshot method in headless mode.

### What is the difference between save\_screenshot and get\_screenshot\_as\_png?

save\_screenshot() saves directly to a file, while get\_screenshot\_as\_png() returns the image as bytes. Use get\_screenshot\_as\_png() when you need to process the image in memory.

Read more Screenshot rendering

------------------------------

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

[View all posts](/blog/tags/screenshot-rendering/)

#### [How to Take Bulk Screenshots in Python with a Screenshot API](/blog/bulk-screenshots-python/)

Learn how to automate bulk website screenshots in Python using ScreenshotOne API. Process thousands of URLs efficiently with async requests, rate limiting, and error handling.

Read more

#### [Take a screenshot "from the surface" in Puppeteer and Chrome DevTools Protocol](/blog/take-a-screenshot-from-the-surface-in-puppeteer-and-chrome-devtools-protocol/)

Let's talk about the fromSurface parameter introduced in Chrome DevTools Protocol which will soon be supported by Puppeteer or even supported now at the time when you are reading the post.

Read more

#### [Puppeteer waitUntil: how to wait for page load](/blog/puppeteer-wait-until-the-page-is-ready/)

Join me in exploring how to find the ideal wait time or event of when to take the page screenshot with Puppeteer.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/no-code/clay
----

[Skip to content](#_top)

How to automate website screenshots in Clay with ScreenshotOne

==============================================================

Copy page

Tip

ScreenshotOne is now available as a [data provider in Clay](https://www.clay.com/integrations/data-provider/screenshotone).

You can use ready-to-use templates. Use the guide below in case if you want to have more control over the integration and use more features than the official ScreenshotOne integration on Clay provides.

[Clay](https://clay.com/) is a powerful data-automation tool that lets teams enrich, filter, and transform leads from hundreds of sources without writing code. With Clay, you can build dynamic workflows that connect CRMs, APIs, and enrichment tools in minutes.

[](https://clay.com/)

Integration with [ScreenshotOne](/) lets you automatically generate high-quality website screenshots inside your Clay tables—perfect for lead research, prospecting, directory building, and any workflow where visual context matters.

How to use ScreenshotOne in Clay

--------------------------------

### 1\. Get a ScreenshotOne API key

1\. Sign up for [ScreenshotOne](https://screenshotone.com/) and get your API key at the [access page](https://dash.screenshotone.com/access/). Click on the “Create API key” button:

2\. Enter a name for the API key, e.g. “Clay Integration” and click “Create API key”:

3\. Copy the API key to use it in Clay:

### 2\. Integrate ScreenshotOne in Clay as HTTP API

One of the ways to integrate ScreenshotOne in Clay is to use the [HTTP API](https://university.clay.com/docs/http-api-integration-overview).

With the HTTP API, you can use ScreenshotOne in Clay as a HTTP API endpoint and use all our API methods and options.

For example, let’s take screenshots of the website URLs stored in the Clay table:

1\. Create a Website URL column in your Clay table and fill it with the website URLs you want to screenshot:

2\. Add new column with enrichment step and use the HTTP API type of enrichment:

3\. Configure the enrichment with the API key, API method and options:

4\. Save the enrichment step and run the workflow, once it is done, add the output as the new column or map it to the existing column.

Support

-------

In case if you need any help or have any questions, please, contact us at [support@screenshotone.com](mailto:support@screenshotone.com).

----
url: https://screenshotone.com/changelog/mcp-server
----

Rendering website screenshots in LLMs

=====================================

Integrate ScreenshotOne to render website screenshots with any LLM that supports MCP.

[Changelog](/changelog/) 3 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Feb 24, 2025

Model Context Protocol

----------------------

In November 2024, [Anthropic announced and open-sourced the Model Context Protocol (MCP)](https://www.anthropic.com/news/model-context-protocol). And since then we have seen a lot of companies building and launching their MCP servers to enable agentic workflows.

You can now integrate Google Drive, Slack, GitHub, Git, SQL databases, Puppeteer, and whatever you can think of with your IDE, LLM chats, and any other application that supports MCP.

[MCP](https://modelcontextprotocol.io) is basically a protocol that allows LLMs to interact with external tools and services.

A few thoughts about the future

-------------------------------

In March 2023, OpenAI launched plugins for ChatGPT and [I built an integration for ScreenshotOne](https://screenshotone.com/blog/screenshotone-is-available-as-a-chatgpt-plugin/). I thought it would be the future of integrations with LLMs. But it was painful to build, integrate and maintain plugins.

And eventually they abandoned support for them in favor of custom GPTs that have access to external APIs. I didn’t build a custom GPT for ScreenshotOne, but I saw they support the OpenAPI specification, so it wouldn’t be a problem. But I didn’t want to invest time in something that might be deprecated in a few months, again.

I saw the launch of the MCP protocol by Anthropic, but also didn’t rush to spend my time on it. However, when I noticed that Cursor picked up on the MCP, and people started to use them, I decided to check them out—this post is basically a result of my exploration of MCP.

I can imagine the marketplace or many directories in the future that will allow use to find and use MCP servers for any task.

Maybe with AGI you won’t need external tools at all, but today we have a lot of great software products that can be integrated with LLMs. And specilization is still a thing.

Imagine, you have an agentic workflow that screenshots websites for competitor research and sends reports to you. In that case, including the external tool like [ScreenshotOne (the best screenshot API)](https://screenshotone.com/) could be super helpful. It would save you a lot of time, but not only that. I constantly improve the API, fix issues, polish corners cases and so on.

In that example, ScreenshotOne is a highly specialized tool, and building the one yourself might take a lot of time and effort and distract from you from the main task.

That’s why I can see many tools still being built and useful till the AGI era comes.

Using MCP to render websites screenshots with LLMs

--------------------------------------------------

I will share an example of how to use the MCP server to render a screenshot of a website with [Claude for Desktop](https://claude.ai/download). But the algorithm should be similar for any other LLM or application that supports MCP.

### 1\. Download the MCP Server

Download the MCP Server from the [GitHub repository](https://github.com/screenshotone/mcp).

### 2\. Build it

Always install dependencies and build it first:

Terminal window

    1npm run install && npm run build

### 3\. Get your ScreenshotOne API key

Sign up at [ScreenshotOne](https://screenshotone.com) and get your API key.

### 4\. Add the MCP Server to Claude for Desktop

Add the following to your `~/Library/Application\ Support/Claude/claude_desktop_config.json`:

    1{2    "mcpServers": {3        "screenshotone": {4            "command": "node",5            "args": ["path/to/screenshotone/mcp/build/index.js"],6            "env": {7                "SCREENSHOTONE_API_KEY": "<your api key>"8            }9        }10    }11}

### 5\. Try it out

For example, ask to render a screenshot of any website, or like I did, I asked it render a screenshot of [BoltAI](https://boltai.com/) and convert it into HTML and CSS:

 Sorry, your browser doesn't support embedded videos.

More MCP servers

----------------

More and more companies are building and launching their MCP servers to enable agentic workflows:

1.  [Stripe](https://docs.stripe.com/agents) to interact with the Stripe API.

2.  [Grafana](https://github.com/grafana/mcp-grafana) to search dashboards, investigate incidents and query datasources in your Grafana instance.

3.  [Cloudflare](https://github.com/cloudflare/mcp-server-cloudflare) to deploy, configure & interrogate your resources on the Cloudflare developer platform.

And many more! One of the best go-to resources to check out for more MCP servers is [the MCP official GitHub repository](https://github.com/modelcontextprotocol/servers).

Support

-------

In case if you have any ideas, questions or issues about using the MCP Server, feel free to contact us at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Improved uploading and error handling to S3-compatible storage](/changelog/improved-storage-upload/)

Today, the new version of ScreenshotOne API was deployed to production that enables a retries mechanism when uploading to an S3 storage and more granular error handling.

Read more →

1 min read

#### [Set locale and language of the browser](/changelog/language-and-locale/)

A new version of the ScreenshotOne API has been just deployed. It allows you to set both locale and language of the browser when rendering screenshots with one simple option.

Read more →

1 min read

#### [ScreenshotOne Dashboard performance has been improved](/changelog/upgraded-dashboard-underlying-framework/)

ScreenshotOne Dashboard has been upgraded to Next.js 16

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/error-on-click-selector-not-found
----

Fail if there is nothing to click on

====================================

A new option has been added to fail or not to fail the screenshot rendering if there is nothing to click on.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Nov 13, 2024

ScreenshotOne API has a `click` option which allows you to click on a specific element on a page. But there is a one problem, till today you didn’t have an option to fail or not to fail the screenshot rendering if the element to click on is not found.

You don’t pay for failed and cached screenshots with ScreenshotOne.

With `error_on_click_selector_not_found=true` option, you can fail the screenshot rendering if the element to click on is not found or you can still get the screenshot with `error_on_click_selector_not_found=false`.

If you have any questions or feedback, please let us know at [support@screenshotone.com](mailto:support@screenshotone.com).

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Set locale and language of the browser](/changelog/language-and-locale/)

A new version of the ScreenshotOne API has been just deployed. It allows you to set both locale and language of the browser when rendering screenshots with one simple option.

Read more →

1 min read

#### [Choose the full page screenshot algorithm](/changelog/full-page-algorithm/)

Now, you can choose the full page screenshot algorithm.

Read more →

1 min read

#### [Better and more extensible PDF rendering](/changelog/better-and-more-extensible-pdf-rendering/)

ScreenshotOne supports PDF rendering for a long time but it was used till recently by a small group of customers. Growing demand in PDF rendering required updating the API. And today, we introduce new options for PDF customization.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/screenshot-api/ruby
----

[What's new API error insights API error insights in the dashboard](/changelog/error-metrics/)

Ruby Screenshot API

===================

Capture pixel-perfect website screenshots in Ruby with a simple API call. No browser management, no Selenium setup—just clean, reliable screenshots.

----------------------

----------------------------

------------------------------------

Take screenshots with Ruby

--------------------------

Use our official Ruby SDK or send simple HTTP requests to capture screenshots.

    1# Add this gem to your Gemfile:2# gem 'screenshotone'3

    4# If you don't need to add a signature5client = ScreenshotOne::Client.new('<access key>')6

    7# Or ff you do need to add a signature8client = ScreenshotOne::Client.new('<access key>', '<secret key>')9

    10# You can set any available option, in a camel_case format, for example:11options = ScreenshotOne::TakeOptions.new(url: 'https://example.com').12            full_page(true).13            delay(2).14            geolocation_latitude(48.857648).15            geolocation_longitude(2.294677).16            geolocation_accuracy(50)17

    18# Verify all the parameters are valid (we will validate the parameters that should be19# numeric, booleans or that accept only certain values)20options.valid?21=> true22

    23# To simply get the final url:24client.generate_take_url(options)25=> "https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com..."26

    27# To actually get the image (the response body of a request to the previous url)28client.take(options)29=> "\xFF\xD8\xFF\xE0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xFF\..."

Mike Roberts

Founder, [SpyFu](https://www.spyfu.com/)

> ScreenshotOne is the best product on the market - and that's before you take into account how responsive and easy Dmytro is to work with.

> 

> Any time we've found a rare edge case, it's been resolved in hours.

> 

> Great company, great founder - can't say enough!

Without writing a line of code

No-code integrations

--------------------

Quickly render website screenshots with Zapier, Airtable, Make and other popular no-code platforms of your choice.

[](/integrations/zapier/)[](/integrations/airtable/)[](/integrations/make/)[](/integrations/bubble/)[](/integrations/n8n/)

Read

Lessons from running screenshot rendering infrastructure

--------------------------------------------------------

Practical guides and real updates based on our experience operating rendering infrastructure at production scale.

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots in Ruby](/blog/how-to-take-website-screenshots-in-ruby/)

Let's examine what Ruby proposes for us to render HTML or URL as a screenshot dynamically.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Dec 15, 2022

•

5 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Taking care of WordPress Sites with ScreenshotOne](/blog/kinsta/)

How Kinsta uses ScreenshotOne to deliver reliable automatic updates.

Written by

[Roger Williams](/contributors/roger-williams/), [Barnabás Ürmössy](/contributors/barnabs-rmssy/)

Published on

Apr 29, 2025

•

2 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Typeshare uses ScreenshotOne for image generation](/blog/how-typeshare-uses-screenshotone/)

Typeshare is a digital writing platform designed to enhance the writing experience by offering a suite of tools aimed at reducing common barriers writers face.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Apr 14, 2024

•

2 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/animated-screenshots
----

[Skip to content](#_top)

Animated Screenshots

====================

Copy page

In case you need a custom scenario or have propositions, feel free to reach out at `support@screenshotone.com`.

You can rely on ScreenshotOne API to generate animated screenshots and handle image and video streaming infrastructure.

ScreenshotOne supports animated (including scrollable) screenshots of different types, caching based on the world’s fastest and most potent CDN (Cloudflare), blocking ads, cookie banners, and chats.

In just one API request, you can quickly generate animated screenshots. And if you need more, various scenarios with many options are covered.

Grasp how simple it is:

    1https://api.screenshotone.com/animate?url=https://tailwindcss.com&scenario=scroll&access_key=<your access key>

The result might differ a bit in case default options are changed, but as for now, it is similar to what I have shown in the video:

 Sorry, your browser doesn't support embedded videos.

Don’t forget that you can use [signed links to share videos and GIF images publicly](https://screenshotone.com/docs/signed-requests/), [caching](https://screenshotone.com/docs/options/#caching), [block ads](/docs/options/#block_ads), [block cookie banners](/docs/options/#block_cookie_banners), and [many other options](#all-supported-options).

Scenarios

---------

Select a basic scenario of how you want to animate screenshots or render ed HTML. Specify additional options and tune the scenario for your use case. And you are good to go.

### Default (stand still)

Use the `scenario=default` parameter, or don’t specify `scenario` at all when sending a request to `/animate`.

The default scenario is to record animation after loading the site without additional animations.

The use case is when you generate animated screenshots of sites that have animations and you want to showcase it.

Look at [the Handwrytten site](https://www.handwrytten.com/) as an example. It has a default animation when loaded. So, we won’t scroll it or add any other activities.

We will record the site as is after load:

    1https://api.screenshotone.com/animate?url=https://www.handwrytten.com/&access_key=<your access key>

The result:

 Sorry, your browser doesn't support embedded videos.

### Scrollable (scrolling) screenshot

Use the `scenario=scroll` parameter, or don’t specify `scenario` at all when sending a request to `/animate`.

There is an example for scrolling [Senja](https://senja.io):

    1https://api.screenshotone.com/animate?url=https://senja.io&scenario=scroll&access_key=<your access key>

The result is:

 Sorry, your browser doesn't support embedded videos.

These are supported options for scrolling screenshot animation:

*   `scroll_delay`—delay in milliseconds between scrolls. The default value is `500`.

*   `scroll_duration`—duration in milliseconds of one scroll. The default value is `1500`. The scroll duration is not the duration of the video or animated GIF. Please, use the `duration` parameter to specify the length of the video or animated GIF.

*   `scroll_by`—by how many pixes scroll. The default value is `1000`.

*   `scroll_start_immediately`—scroll immediately or wait for the `scroll_delay` milliseconds before scrolling. The default value is `true`.

*   `scroll_start_delay`—wait time (in milliseconds) till starting scrolling. The default value is \`0“.

*   `scroll_back`—scroll back or not. The default value is `true`.

*   `scroll_back_algorithm`—`once` is by default and means that it will scroll back immediately once with the easing you have defined. But if you set `repeat`, it will repeat the same algorithm the API used to scroll to the bottom of the page.

*   `scroll_back_after_duration`—scroll back after the specified duration in milliseconds.

*   `scroll_complete`—stop recording animation when full scrolling is completed. The option `true` by default.

*   `scroll_stop_after_duration`—stop scrolling after the specified duration in milliseconds. Use `scroll_complete=false` and `scroll_back=false`, to stop and just stand still after the specified duration.

*   `scroll_easing`—use it to define the scrolling easing effect. The default value is `ease_in_out_quint`. There is a list of all available options:

    *   `linear`–no easing, no acceleration;

    *   `ease_in_quad`–accelerating from zero velocity;

    *   `ease_out_quad`–decelerating to zero velocity;

    *   `ease_in_out_quad`–acceleration until halfway, then deceleration;

    *   `ease_in_cubic`–accelerating from zero velocity;

    *   `ease_out_cubic`–decelerating to zero velocity;

    *   `ease_in_out_cubic`–acceleration until halfway, then deceleration;

    *   `ease_in_quart`–accelerating from zero velocity;

    *   `ease_out_quart`–decelerating to zero velocity;

    *   `ease_in_out_quart`–acceleration until halfway, then deceleration;

    *   `ease_in_quint`–accelerating from zero velocity;

    *   `ease_out_quint`–decelerating to zero velocity;

    *   `ease_in_out_quint`–acceleration until halfway, then deceleration.

*   `scroll_try_navigate`—navigate while scrolling and record the new opened page.

*   `scroll_navigate_after`—navigate after duration in milliseconds, by default it is half of the duration.

*   `scroll_navigate_to_url`—to what URL navigate;

*   `scroll_navigate_link_hints`—if the URL is not specified, the hints of what links to use, by default `'pricing', 'about', 'customers'`. E.g. “pricing” means to open any internal link which has the “pricing” keyword in its text;

*   `scroll_till_selector`—scroll till the selector is visible;

*   `scroll_till_selector_adjust_top`—adjust the top position of the selector in the viewport;

*   `scroll_to_end_after`—scroll to the end after the specified duration in milliseconds with the specified easing in one scroll.

There is an example of applying custom options for scrolling [Senja](https://senja.io):

    1https://api.screenshotone.com/animate?url=https://senja.io&scenario=scroll&scroll_delay=400&scroll_by=400&access_key=<your access key>

The result is:

 Sorry, your browser doesn't support embedded videos.

### Navigation

You can record a page navigation when recording scrolling screenshot video. It allows render less boring and more engaging videos.

 Sorry, your browser doesn't support embedded videos.

It is rendered with a simple request like:

    1https://api.screenshotone.com/animate?url=https://screenshotone.com/&scenario=scroll&duration=10&scroll_try_navigate=true&scroll_navigate_link_hints=pricing&access_key=<YOUR KEY>

You need to specify either the “scroll\_navigate\_to\_url” or the “scroll\_navigate\_link\_hints” options. If neither is specified, any first random visible internal link will be used for navigation if available.

The `scroll_navigate_link_hints` option can be used as an array:

    1scroll_navigate_link_hints[]=pricing&scroll_navigate_link_hints[]=about

The API will attempt to find any internal links that match the hints.

All supported options

---------------------

### Animation specific

#### format

Available response formats:

*   `mp4`

*   `mov`

*   `avi`

*   `webm`

*   `gif`

Default value is `mp4`.

#### duration

If you need a longer animation, please, reach out at `support@screenshotone.com` and describe your use case.

The default value is `5` seconds (`duration=5`).

The minimum value is `1` and the maximum is `30`.

Suppose `scroll_complete` is set to `true`, which is by default, and [the scrolling scenario](/docs/animated-screenshots/#scrollable-scrolling-screenshot)) is completed earlier than the specified `duration`. In that case, the recording will be stopped, and the resulting animation will be short.

Since GIFs are not videos, but images, the duration might not be mapped exactly to the number of frames and represent the duration as is for the video. It is better to consider it as a duration of recording of the video, and then frames glued together into a GIF.

#### width

You must specify both the `width` and [height](#height) parameters. You can’t specify only one. By default, the width and the height parameters are the same as [viewport width](/docs/options/#viewport_width) and [viewport height](/docs/options/#viewport_height) parameters.

[The device scale factor](/docs/options/#device_scale_factor) is taken into consideration. If you set the viewport width and height to `1000x500`, with `device_scale_factor=1`, the resulting resolution of the video will be `1000x500`, but with `device_scale_factor=2`, it will be `2000x1000`.

If [aspect ratio](#aspect_ratio) is specified, `width` and `height` are not used. And API will try to fit the video of the viewport size into the specified aspect ratio.

#### height

You must specify both the [width](#width) and `height` parameters. You can’t specify only one. By default, the width and the height parameters are the same as [viewport width](/docs/options/#viewport_width) and [viewport height](/docs/options/#viewport_height) parameters.

[The device scale factor](/docs/options/#device_scale_factor) is taken into consideration. If you set the viewport width and height to `1000x500`, with `device_scale_factor=1`, the resulting resolution of the video will be `1000x500`, but with `device_scale_factor=2`, it will be `2000x1000`.

If [aspect ratio](#aspect_ratio) is specified, `width` and `height` are not used. And API will try to fit the video of the viewport size into the specified aspect ratio.

#### aspect ratio

If [aspect ratio](#aspect_ratio) is specified, `width` and `height` are not used. And API will try to fit the video of the viewport size into the specified aspect ratio.

#### scenario

Available scenarios formats:

*   not specified or `default` is for [the default animation scenario](#default-stand-still).

*   `scroll` is for [the scrolling screenshots](#scrollable-scrolling-screenshot).

The default value is `default`.

#### clip

You can clip part of the video. But currently, it is only available when the format is `gif`.

Use `clip_width`, `clip_height,` clip\_x`and`clip\_y\` to specify the clip size and coordinates.

### Regular

Animated screenshots also support most options supported by regular image screenshots. There is a list of supported options:

*   `omit_background` but only for the `mov` format;

*   [credentials](/docs/options/#credentials);

*   [essentials](/docs/options/#essentials), except `selector` and with different values for [format](#format);

*   [viewport](/docs/options/#viewport);

*   [emulations](/docs/options/#emulations);

*   [customization](/docs/options/#customization);

*   [blocking](/docs/options/#blocking);

*   [geolocation](/docs/options/#geolocation);

*   [request](/docs/options/#request);

*   [wait](/docs/options/#wait);

*   [caching](/docs/options/#caching);

*   [storing](/docs/options/#storing).

----
url: https://screenshotone.com/changelog/screenshotone-can-now-return-screenshots-and-html-in-one-request
----

ScreenshotOne can now return screenshots and HTML in one request

================================================================

Starting from today ScreenshotOne can return both a website screenshot and the content in one simple API request.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Dec 8, 2023

Until you chat with your customers, you often don’t realize that they might have some bit complex use cases that you could just automate for them to make their lives easier.

That is what the case with rendering both screenshots and requesting the HTML content of the URL. Some ScreenshotOne customers, needed to perform 2 requests to accomplish that task. And in rare cases, the screenshot wasn’t synchronized with the HTML.

Also, the good news is that you won’t be charged twice now since you don’t need to execute 2 requests to perform the same task. It will also reduce expenses for customers, who need both—screenshots and HTML.

The only thing you need to do is to specify [metadata\_content=true](https://screenshotone.com/docs/options/#metadata_content) and you will get the URL of the content as a header or in JSON.

If you have any feedback or questions, please, feel free to reach out at `hey@screenshotone.com` and we will be happy to help.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Rendering Google Documents and Slides is now available](/changelog/google-docs-and-slides/)

You can now easily render Google Documents and Slides with ScreenshotOne.

Read more →

1 min read

#### [Improved blocking of banners and popups](/changelog/improved-blocking-of-banners-and-popups/)

Improved generic algorithm to bypass blockers and better banner exclusion heuristics.

Read more →

1 min read

#### [Improved full-page screenshot rendering](/changelog/improved-full-page-rendering/)

Fixed a few issues related to full-page screenshots rendering.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/framekit
----

Why FrameKit chose ScreenshotOne for their business

===================================================

A short story about how and why FrameKit chose ScreenshotOne for their use case.

[Customer story](/blog/tags/customer-stories/) 1 min read

#### Written by

[Anatoly Pashias](/contributors/anatoly-pashias/)

#### Published on

Mar 2, 2026

A short story by Anatoly Pashias, Co-Founder of [Framekit](https://framekit.ai/), to learn more about how they use ScreenshotOne for their use case—high-quality site previews.

* * *

We are building an AI website builder for creative entrepreneurs, and needed screenshots for previews of our client sites (when they’re on the dashboard). We tried browser local screenshots with modern-screenshot JS library, that didn’t work out well. Screenshots were not professional, distorted images and text etc.

To solve this, I was going to use Puppeeter but didn’t want to host it, plus we are serverless so it would be a pain configuring (Google Cloud Run) or build it, since it was not plug and play.

I found ScreenshotOne through an AI agent (great GEO btw 😁), you had good docs and looked solid, had it up and running and working in 10 minutes, with Cursor.

Modern premium site screenshots on publish with extensive easy configuration like browser with + height, hiding certain elements very easy (like our branding) by targeting etc.

Read more customer stories

--------------------------

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

[View all posts](/blog/tags/customer-stories/)

#### [How Ilias Ism, a founder of the MagicSpace SEO agency, uses ScreenshotOne daily](/blog/how-ilias-ism-a-founder-of-the-magicspace-seo-agency-uses-screenshotone-daily/)

We would love to share a quick review of ScreenshotOne by Ilias Ism, a founder of MagicSpace SEO agency and OG Image Generator on how he uses the API daily to generate screenshots and automate regular tasks associated with screenshots.

Read more

#### [How Landing Gallery uses ScreenshotOne to automate screenshot generation](/blog/landing-gallery/)

How and why "Landing Gallery" uses ScreenshotOne to automate screenshot generation for their landing page inspiration platform.

Read more

#### [How Branding 5 uses ScreenshotOne for competitor analysis](/blog/how-branding5-uses-screenshotone/)

If you are interested in diving deeper into the Branding 5 use case and discover if ScreenshotOne might be useful for you, too, keep reading.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/contributors/dmytro-krasun/9
----

Dmytro Krasun

-------------

With more than a decade of experience in software engineering, I share the best practices and solutions you can apply to your problems in the space of headless browsers. You can also find me on [Twitter](https://twitter.com/DmytroKrasun) and [LinkedIn](https://www.linkedin.com/in/dmytrokrasun)

View all Changelog

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to add custom scripts to a page in Puppeteer](/blog/how-to-add-custom-scripts-to-a-page-in-puppeteer/)

How to add custom scripts to a page in Puppeteer. Let's discover how it works quickly."

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jun 24, 2022

•

2 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to add custom styles to a page in Puppeteer](/blog/how-to-add-custom-styles-to-a-page-in-puppeteer/)

To add custom styles to any page use Puppeteer's page method \`page.addStyleTag(options)\`. Let's discover how it works quickly.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jun 24, 2022

•

2 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots with PHP](/blog/how-to-take-website-screenshots-with-php/)

The article examines how you can take screenshots of any URL with PHP by using Selenium, Puppeteer alternatives, or screenshot API as a service.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jun 14, 2022

•

3 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots with JavaScript or TypeScript (Node.js)](/blog/how-to-take-website-screenshots-with-javascript-or-typescript-nodejs/)

The article examines how you can take screenshots of any URL with Javascript and TypeScript (Node.js) by using Selenium, Puppeteer alternatives, Playwright, or screenshot API as a service.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jun 14, 2022

•

4 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots with Java](/blog/how-to-take-website-screenshots-with-java/)

The article examines how you can take screenshots of any URL with Java by using Selenium, Puppeteer alternatives, Playwright, or screenshot API as a service.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jun 10, 2022

•

3 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots with Go](/blog/how-to-take-website-screenshots-with-go/)

The article examines how you can take screenshots of any URL with Go (a.k.a. Golang) by using Selenium, Puppeteer alternatives, Playwright, or screenshot API as a service.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jun 10, 2022

•

4 min read

#### [How to set a time zone in Puppeteer for page](/blog/how-to-set-a-time-zone-in-puppeteer-for-page/)

Puppeteer allows changing the time zone on a per-page basis. In automation testing, you can use it to test how the website behaves for different time zones. Or you can use it for scrapping to imitate the user from the expected time zone by the site.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jun 23, 2022

•

1 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [How to block requests with Puppeteer](/blog/how-to-block-requests-with-puppeteer/)

Puppeteer allows blocking any outgoing requests while loading the page. Whether you want to block ads, tracking scripts, or different types of resources, it is relatively easy to do with Puppeteer.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jul 14, 2022

•

3 min read

#### [How to take a screenshot of the element with Puppeteer](/blog/how-to-take-a-screenshot-of-the-element-with-puppeteer/)

Puppeteer allows you to automate everything you can do in the browser manually and even more. You can take screenshots of the entire page and the specific elements.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jun 18, 2022

•

1 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [How to use proxy per page with Puppeteer](/blog/how-to-use-proxy-per-page-with-puppeteer/)

It is easy to use proxy globally for the puppeteer instance, but there is a trick to use proxy on a per-page basis.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Apr 29, 2025

•

2 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take screenshots with Puppeteer](/blog/how-to-take-a-screenshot-with-puppeteer/)

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

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Apr 29, 2025

•

11 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/an-improved-screenshot-history-page
----

An improved screenshot history page

===================================

Daily, I work as hard as I can to ensure that ScreeenshotOne is the best screenshot API out there possible. But I rarely share updates but trust me, a ton of them might go unnoticed. Let's fix this situation.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Apr 7, 2023

Today, I want to share a quick update on the screenshot history page that a few lovely customers requested.

I tried to keep UI as simple as possible for the history page, but it wasn’t enough for a few customers since they were using this page heavily. So, here it goes—the renowned screenshot history page:

I have added the following:

1.  Possibility to filter by dates.

2.  Allow to hide and show columns.

3.  Filter by any word in the query string of the request.

4.  Sort by date, size, or run time.

5.  The number of requests to show per page and go to any page directly.

Thanks for your attention, and I hope the new update will help you to use ScreenshotOne more efficiently.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Error metrics in the dashboard](/changelog/error-metrics/)

You can now see error metrics in the dashboard to quickly understand what errors are happening and how often.

Read more →

1 min read

#### [Failed payment alerts in the dashboard](/changelog/failed-payment-alerts/)

Starting today, you will see an alert in the dashboard when a payment fails.

Read more →

1 min read

#### [Fail ScreenshotOne API requests on purpose](/changelog/fail-if-request-failed/)

Use a new option to fail ScreenshotOne API requests on purpose.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/improving-performance-and-stability-by-consolidating-validation-and-access-check-logic-in-the-api-gateway
----

Improving performance and stability by consolidating validation and access check logic in the API gateway

=========================================================================================================

For the past few days, I have been working on improving the stability and performance of the ScreenshotOne API. I started from low-hanging fruits—moving validations and access key management from rendering services to ScreenshotOne's API gateway. The API will be more stable and performant as a result. If you are curious why, please continue reading.

[Changelog](/changelog/) 2 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jul 30, 2023

Before Refactoring

------------------

A few words about how the ScreenshotOne API worked before the refactoring and why it was done the way done:

An API Gateway service (built on top of [the Cloudflare Workers platform](https://workers.cloudflare.com/)) received all requests and sent them to rendering services ([Google Cloud Run](https://cloud.google.com/run)). And the rendering services, each on their own, were sending requests for validating requests, checking quotas, signatures, and so on to the access management services.

That architecture had evolved organically:

1.  The API started as one simple service hosted on one server.

2.  Then, for scalability, it was moved to Render and eventually to Google Cloud Run, which required decoupling key management and other common logic from the rendering services.

3.  Later, the API gateway was added to use Cloudflare Caching and Storage.

It worked nicely, but in the past few months, ScreenshotOne grew dramatically. And the setup revealed a few bottlenecks:

Each request to the ScreenshotOne API spins up a new Google Cloud Run instance. Propagating back takes time, and the number of instances is limited after all. So, when an error happens in the validation and key management services, it propagates back through the Google Cloud Run instances and increases the response time. In addition to that, on rare occasions, there might be no available instances.

After refactoring

-----------------

It is obvious, yes, how to solve it? And, yes, the solution was simple. I moved validation and access check logic to the API gateway.

The new approach means that validation in case of invalid requests will be super fast. And new instances won’t be used. It implies that ScreenshotOne customers can enjoy improved stability at the end of the day.

What’s next?

------------

ScreenshotOne has [a public roadmap](/roadmap/), but I invest time in improving what the API already has to offer.

I am now improving observability, and the quality of rendering is one of the core metrics for the API. I am eliminating errors and issues I find, and customers report one by one to make the API as great as possible.

If you have any questions or want to share some ideas, feel free to write at `hey@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [ScreenshotOne is available on Pipedream](/changelog/pipedream-integration/)

Automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos in Pipedream.

Read more →

1 min read

#### [Rendering errors in webhooks](/changelog/screenshotone-webhook-errors/)

Check out how to get notified about rendering errors when using webhooks.

Read more →

1 min read

#### [Added support of Slack notifications](/changelog/slack-notifications/)

We added support of Slack notifications to ScreenshotOne. Now you can set up and get Slack notifications when you reach your quota limits.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/bulk-screenshots-playwright-python
----

How to Take Bulk Screenshots with Playwright in Python

======================================================

Learn how to automate bulk website screenshots with Playwright in Python. Master async batch processing, concurrent screenshots, rate limiting, and error handling for large-scale screenshot automation.

[Blog post](/blog/) 7 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jan 14, 2026

#### Tags

[Screenshot rendering](/blog/tags/screenshot-rendering/) [Playwright guides](/blog/tags/playwright-guides/)

To get familiar with Playwright in Python, you can check out [our guide on how to take website screenshots with Playwright in Python](/blog/playwright-python-screenshots/) or [the guide about the full page screenshots](/blog/playwright-python-full-page-website-screenshots/).

The following guide is fully focused on bulk screenshots with Playwright in Python only.

Taking one screenshot is easy. Taking thousands while handling failures, managing memory, and maintaining speed is another challenge entirely. Let me show you how to build a robust bulk screenshot system.

Basic Batch Processing

----------------------

Let’s start simple—processing a list of URLs:

    1from playwright.sync_api import sync_playwright2

    3urls = [4    'https://example.com',5    'https://github.com',6    'https://stackoverflow.com',7]8

    9with sync_playwright() as p:10    browser = p.chromium.launch()11

    12    for i, url in enumerate(urls):13        page = browser.new_page()14        try:15            page.goto(url, timeout=30000)16            page.screenshot(path=f'screenshot_{i}.png')17        except Exception as e:18            print(f'Failed: {url} - {e}')19        finally:20            page.close()21

    22    browser.close()

This works, but it’s slow. Each screenshot waits for the previous one to complete.

Concurrent Processing with Async

--------------------------------

The real power comes from async processing:

    1import asyncio2from playwright.async_api import async_playwright3

    4async def take_screenshot(browser, url, output_path):5    """Take a single screenshot."""6    page = await browser.new_page()7    try:8        await page.goto(url, timeout=30000)9        await page.wait_for_load_state('networkidle', timeout=10000)10        await page.screenshot(path=output_path, full_page=True)11        return {'url': url, 'status': 'success', 'path': output_path}12    except Exception as e:13        return {'url': url, 'status': 'failed', 'error': str(e)}14    finally:15        await page.close()16

    17async def process_urls(urls):18    """Process multiple URLs concurrently."""19    async with async_playwright() as p:20        browser = await p.chromium.launch()21

    22        tasks = [23            take_screenshot(browser, url, f'screenshots/{i}.png')24            for i, url in enumerate(urls)25        ]26

    27        results = await asyncio.gather(*tasks)28        await browser.close()29

    30        return results31

    32# Run it33urls = ['https://example.com', 'https://github.com', 'https://stackoverflow.com']34results = asyncio.run(process_urls(urls))35

    36for r in results:37    print(f"{r['url']}: {r['status']}")

This processes all URLs concurrently. On my machine, it’s about 5x faster than sequential processing.

Reading URLs from CSV

---------------------

For real-world use, you’ll often read URLs from a file:

    1import asyncio2import csv3from playwright.async_api import async_playwright4from pathlib import Path5from urllib.parse import urlparse6

    7def sanitize_filename(url):8    """Convert URL to safe filename."""9    parsed = urlparse(url)10    name = parsed.netloc.replace('.', '_')11    return f"{name}.png"12

    13async def take_screenshot(browser, url, output_dir):14    """Take screenshot with safe filename."""15    filename = sanitize_filename(url)16    output_path = output_dir / filename17

    18    page = await browser.new_page()19    try:20        await page.goto(url, timeout=30000)21        await page.wait_for_load_state('networkidle', timeout=10000)22        await page.screenshot(path=str(output_path), full_page=True)23        return {'url': url, 'status': 'success', 'path': str(output_path)}24    except Exception as e:25        return {'url': url, 'status': 'failed', 'error': str(e)}26    finally:27        await page.close()28

    29async def process_csv(csv_path, output_dir):30    """Process URLs from CSV file."""31    output_dir = Path(output_dir)32    output_dir.mkdir(exist_ok=True)33

    34    # Read URLs from CSV35    urls = []36    with open(csv_path, 'r') as f:37        reader = csv.reader(f)38        next(reader)  # Skip header39        urls = [row[0] for row in reader if row]40

    41    print(f"Processing {len(urls)} URLs...")42

    43    async with async_playwright() as p:44        browser = await p.chromium.launch()45

    46        tasks = [take_screenshot(browser, url, output_dir) for url in urls]47        results = await asyncio.gather(*tasks)48

    49        await browser.close()50

    51    # Summary52    success = sum(1 for r in results if r['status'] == 'success')53    failed = len(results) - success54    print(f"Complete: {success} success, {failed} failed")55

    56    return results57

    58# Usage59asyncio.run(process_csv('urls.csv', 'screenshots'))

Batch Processing for Large Volumes

----------------------------------

Processing thousands of URLs at once will exhaust memory. Use batching:

    1import asyncio2from playwright.async_api import async_playwright3

    4async def take_screenshot(browser, url, output_path):5    page = await browser.new_page()6    try:7        await page.goto(url, timeout=30000)8        await page.screenshot(path=output_path, full_page=True)9        return {'url': url, 'status': 'success'}10    except Exception as e:11        return {'url': url, 'status': 'failed', 'error': str(e)}12    finally:13        await page.close()14

    15async def process_batch(browser, batch, start_index):16    """Process a batch of URLs."""17    tasks = [18        take_screenshot(browser, url, f'screenshots/{start_index + i}.png')19        for i, url in enumerate(batch)20    ]21    return await asyncio.gather(*tasks)22

    23async def process_all_urls(urls, batch_size=10):24    """Process all URLs in batches."""25    all_results = []26

    27    async with async_playwright() as p:28        browser = await p.chromium.launch()29

    30        for i in range(0, len(urls), batch_size):31            batch = urls[i:i + batch_size]32            print(f"Processing batch {i//batch_size + 1} ({len(batch)} URLs)...")33

    34            results = await process_batch(browser, batch, i)35            all_results.extend(results)36

    37            # Optional: brief pause between batches38            await asyncio.sleep(0.5)39

    40        await browser.close()41

    42    return all_results43

    44# Usage45urls = [f'https://example{i}.com' for i in range(100)]46results = asyncio.run(process_all_urls(urls, batch_size=10))

Rate Limiting

-------------

Some servers may rate-limit or block rapid requests. Add delays:

    1import asyncio2from playwright.async_api import async_playwright3

    4class RateLimiter:5    def __init__(self, requests_per_second=2):6        self.delay = 1.0 / requests_per_second7        self.last_request = 08

    9    async def wait(self):10        import time11        now = time.time()12        wait_time = self.last_request + self.delay - now13        if wait_time > 0:14            await asyncio.sleep(wait_time)15        self.last_request = time.time()16

    17async def take_screenshot_with_rate_limit(browser, url, output_path, limiter):18    await limiter.wait()19    page = await browser.new_page()20    try:21        await page.goto(url, timeout=30000)22        await page.screenshot(path=output_path)23        return {'url': url, 'status': 'success'}24    except Exception as e:25        return {'url': url, 'status': 'failed', 'error': str(e)}26    finally:27        await page.close()

Progress Tracking

-----------------

For long-running jobs, track progress:

    1import asyncio2from playwright.async_api import async_playwright3from tqdm import tqdm4

    5async def process_with_progress(urls):6    results = []7

    8    async with async_playwright() as p:9        browser = await p.chromium.launch()10

    11        with tqdm(total=len(urls), desc="Screenshots") as pbar:12            for i, url in enumerate(urls):13                result = await take_screenshot(browser, url, f'screenshots/{i}.png')14                results.append(result)15                pbar.update(1)16                pbar.set_postfix({17                    'success': sum(1 for r in results if r['status'] == 'success'),18                    'failed': sum(1 for r in results if r['status'] == 'failed')19                })20

    21        await browser.close()22

    23    return results

Retry Failed URLs

-----------------

Don’t lose failed screenshots—retry them:

    1import asyncio2from playwright.async_api import async_playwright3

    4async def take_screenshot_with_retry(browser, url, output_path, max_retries=3):5    """Take screenshot with automatic retry."""6    for attempt in range(max_retries):7        page = await browser.new_page()8        try:9            await page.goto(url, timeout=30000)10            await page.screenshot(path=output_path)11            await page.close()12            return {'url': url, 'status': 'success', 'attempts': attempt + 1}13        except Exception as e:14            await page.close()15            if attempt == max_retries - 1:16                return {'url': url, 'status': 'failed', 'error': str(e)}17            await asyncio.sleep(2 ** attempt)  # Exponential backoff18

    19async def process_with_retry(urls, batch_size=10):20    results = []21    failed = []22

    23    async with async_playwright() as p:24        browser = await p.chromium.launch()25

    26        # First pass27        for i in range(0, len(urls), batch_size):28            batch = urls[i:i + batch_size]29            batch_results = await asyncio.gather(*[30                take_screenshot_with_retry(browser, url, f'screenshots/{i+j}.png')31                for j, url in enumerate(batch)32            ])33            results.extend(batch_results)34

    35        await browser.close()36

    37    # Log failures38    failed = [r for r in results if r['status'] == 'failed']39    if failed:40        with open('failed_urls.txt', 'w') as f:41            for r in failed:42                f.write(f"{r['url']}\t{r.get('error', 'Unknown')}\n")43

    44    return results

Memory Management

-----------------

Long-running screenshot jobs can leak memory. Tips:

1.  **Close pages after each screenshot**

2.  **Restart browser periodically**

3.  **Process in batches**

    1async def process_with_browser_restart(urls, batch_size=50, restart_every=200):2    """Restart browser periodically to prevent memory leaks."""3    results = []4

    5    async with async_playwright() as p:6        browser = await p.chromium.launch()7        screenshots_since_restart = 08

    9        for i, url in enumerate(urls):10            # Restart browser if needed11            if screenshots_since_restart >= restart_every:12                await browser.close()13                browser = await p.chromium.launch()14                screenshots_since_restart = 015                print(f"Browser restarted at screenshot {i}")16

    17            result = await take_screenshot(browser, url, f'screenshots/{i}.png')18            results.append(result)19            screenshots_since_restart += 120

    21        await browser.close()22

    23    return results

When to Use an API Instead

--------------------------

Playwright is great for moderate volumes, but at scale you’ll face:

*   Server costs for compute resources

*   Memory management complexity

*   Browser crashes and recovery

*   Rate limiting from target sites

For high-volume screenshot automation, a [screenshot API like ScreenshotOne](/blog/bulk-screenshots-python/) handles the infrastructure. See the [comparison in our bulk screenshots API guide](/blog/bulk-screenshots-python/).

Complete Production Script

--------------------------

Here’s a production-ready script combining all techniques:

    1import asyncio2import csv3import json4from pathlib import Path5from datetime import datetime6from playwright.async_api import async_playwright7from urllib.parse import urlparse8

    9class BulkScreenshotter:10    def __init__(self, output_dir='screenshots', batch_size=10, max_retries=3):11        self.output_dir = Path(output_dir)12        self.output_dir.mkdir(exist_ok=True)13        self.batch_size = batch_size14        self.max_retries = max_retries15        self.results = []16

    17    def _get_filename(self, url, index):18        parsed = urlparse(url)19        safe_name = parsed.netloc.replace('.', '_').replace(':', '_')20        return f"{index:05d}_{safe_name}.png"21

    22    async def _screenshot(self, browser, url, index):23        filename = self._get_filename(url, index)24        output_path = self.output_dir / filename25

    26        for attempt in range(self.max_retries):27            page = await browser.new_page()28            try:29                await page.goto(url, timeout=30000)30                await page.wait_for_load_state('networkidle', timeout=10000)31                await page.screenshot(path=str(output_path), full_page=True)32                await page.close()33                return {34                    'url': url,35                    'status': 'success',36                    'path': str(output_path),37                    'attempts': attempt + 138                }39            except Exception as e:40                await page.close()41                if attempt == self.max_retries - 1:42                    return {43                        'url': url,44                        'status': 'failed',45                        'error': str(e),46                        'attempts': attempt + 147                    }48                await asyncio.sleep(2 ** attempt)49

    50    async def process(self, urls):51        async with async_playwright() as p:52            browser = await p.chromium.launch()53

    54            for i in range(0, len(urls), self.batch_size):55                batch = urls[i:i + self.batch_size]56                tasks = [57                    self._screenshot(browser, url, i + j)58                    for j, url in enumerate(batch)59                ]60                batch_results = await asyncio.gather(*tasks)61                self.results.extend(batch_results)62

    63                success = sum(1 for r in self.results if r['status'] == 'success')64                print(f"Progress: {len(self.results)}/{len(urls)} ({success} success)")65

    66            await browser.close()67

    68        self._save_report()69        return self.results70

    71    def _save_report(self):72        report = {73            'timestamp': datetime.now().isoformat(),74            'total': len(self.results),75            'success': sum(1 for r in self.results if r['status'] == 'success'),76            'failed': sum(1 for r in self.results if r['status'] == 'failed'),77            'results': self.results78        }79        with open(self.output_dir / 'report.json', 'w') as f:80            json.dump(report, f, indent=2)81

    82# Usage83urls = ['https://example.com', 'https://github.com']84screenshotter = BulkScreenshotter(batch_size=5)85results = asyncio.run(screenshotter.process(urls))

Summary

-------

Building a bulk screenshot system:

1.  Use async Playwright for concurrent processing

2.  Process in batches to manage memory

3.  Implement retry logic for resilience

4.  Track progress and save reports

5.  Restart browser periodically for long jobs

Frequently Asked Questions

--------------------------

If you read the article, but still have questions. Please, check the most frequently asked. And if you still have questions, feel free reach out at [support@screenshotone.com](mailto:support@screenshotone.com).

### How to automatically screenshot multiple websites in Python?

Use Playwright's async API with asyncio.gather() to process multiple URLs concurrently. Read URLs from a CSV or list, create async tasks for each, and process them in batches to manage memory.

### How to handle failed screenshots in bulk processing?

Implement try-except blocks around each screenshot, log failures to a separate file, and optionally retry failed URLs. Keep track of success/failure counts for monitoring.

### How to speed up bulk screenshot processing?

Use async Playwright with concurrent processing, reuse browser contexts, process in batches, and consider using a screenshot API for very large volumes. Concurrent processing can be 5-10x faster than sequential.

Read more Screenshot rendering

------------------------------

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

[View all posts](/blog/tags/screenshot-rendering/)

#### [Uploading website screenshots to any S3-compatible storage](/blog/uploading-website-screenshots-to-any-s3-compatible-storage/)

In this note, I share how I take website screenshots or render HTML and upload the resulted images or PDF to any S3-compatible storage like Amazon S3, Cloudflare R2, or Backblaze B2.

Read more

#### [How to take website screenshots with Go](/blog/how-to-take-website-screenshots-with-go/)

The article examines how you can take screenshots of any URL with Go (a.k.a. Golang) by using Selenium, Puppeteer alternatives, Playwright, or screenshot API as a service.

Read more

#### [How to Take Bulk Screenshots in Python with a Screenshot API](/blog/bulk-screenshots-python/)

Learn how to automate bulk website screenshots in Python using ScreenshotOne API. Process thousands of URLs efficiently with async requests, rate limiting, and error handling.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/11
----

Automate Website Screenshots

----------------------------

Guides, Product Updates, and Helpful Resources from ScreenshotOne.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

#### [Unveil the Power of Automation with ScreenshotOne and Zapier](/blog/unveil-the-power-of-automation-with-screenshotone-and-zapier/)

I am thrilled to announce an exciting update for the ScreenshotOne users – the much-anticipated integration of ScreenshotOne with Zapier. This powerful combination is here to enhance your automation journey and expand your workflow capabilities to new heights.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jun 1, 2023

•

2 min read

#### [Embracing the Future of Web Archiving with ScreenshotOne API](/blog/embracing-the-future-of-web-archiving-with-screenshotone-api/)

Enter the ScreenshotOne API – a revolutionary tool designed to change the face of web archiving.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Apr 17, 2023

•

2 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots with C# (.NET)](/blog/how-to-take-website-screenshots-with-csharp-dotnet/)

The article examines how you can take screenshots of any URL with C# (.NET) by using PuppeteerSharp, or screenshot API as a service.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 24, 2023

•

3 min read

#### [A friendly guide on how to render HTML or site screenshots in Google Sheets in less than 10 minutes](/blog/a-friendly-guide-on-how-to-render-html-or-site-screenshots-in-google-sheets-in-less-than-10-minutes/)

It is not the first time that one of the ScreenshotOne users asked how to render screenshots in Google Sheets. I wrote a simple but complete tutorial once and for all.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 5, 2023

•

3 min read

#### [How to build a Programmatic SEO site with automated website screenshots using ScreenshotOne, Airtable, and Launchman](/blog/how-to-build-a-programmatic-seo-site-with-automated-website-screenshots-using-screenshotone-airtable-and-launchman/)

Programmatic SEO is a great growth hacking strategy where you create a large number of content pages that rank for long-tailed keywords on Google.

Written by

[Sukh](/contributors/sukh/)

Published on

Jan 10, 2023

•

3 min read

#### [Optimize for speed when rendering screenshots in Puppeteer and Chrome DevTools Protocol](/blog/optimize-for-speed-when-rendering-screenshots-in-puppeteer-and-chrome-devtools-protocol/)

Let's talk about the optimizeForSpeed parameter introduced in Chrome DevTools Protocol which will soon be supported by Puppeteer or even supported now at the time when you are reading the post.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 4, 2023

•

1 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Take a screenshot "from the surface" in Puppeteer and Chrome DevTools Protocol](/blog/take-a-screenshot-from-the-surface-in-puppeteer-and-chrome-devtools-protocol/)

Let's talk about the fromSurface parameter introduced in Chrome DevTools Protocol which will soon be supported by Puppeteer or even supported now at the time when you are reading the post.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 3, 2023

•

1 min read

[PDF rendering](/blog/tags/pdf-rendering/)

#### [How to convert HTML to PDF in JavaScript](/blog/how-to-convert-html-to-pdf-in-javascript/)

Nowadays, you have various options to generate PDFs from HTML or any given URL: generating PDF in the browser, on the server-side (Node.js), or even using a modern and friendly API to generate PDF.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

May 2, 2025

•

3 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/contributors/bohdan-shulha
----

Bohdan Shulha

-------------

View all Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [Integrating ScreenshotOne into the directory management platform](/blog/makeadir-feedback/)

How and why "Make a Directory" used ScreenshotOne to automate screenshots for directory websites.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Bohdan Shulha](/contributors/bohdan-shulha/)

Published on

Dec 23, 2024

•

3 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/upgraded-dashboard-underlying-framework
----

ScreenshotOne Dashboard performance has been improved

=====================================================

ScreenshotOne Dashboard has been upgraded to Next.js 16

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Oct 27, 2025

ScreenshotOne Dashboard is built with [Next.js](https://nextjs.org/). Today, it has been upgraded to [Next.js 16](https://nextjs.org/blog/next-16).

This is a major upgrade and it includes a lot of new features and improvements.

For you, as a ScreenshotOne customer, this means that you will get a better performance and better user experience when using the dashboard.

If you are a developer, consider upgrading your project to Next.js 16 to get the benefits of the new features and improvements.

If you have any questions or suggestions, please reach out at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Added support of external identifiers](/changelog/screenshotone-external-identifier/)

Check out how to use the external identifier to improve tracking of webhook executions.

Read more →

1 min read

#### [Support for multiple API keys](/changelog/multiple-api-keys/)

You can now use multiple API keys to the access ScreenshotOne API.

Read more →

1 min read

#### [Improved design of the authentication pages](/changelog/updated-design-of-authentication-pages/)

We updated the design of the authentication pages to make them more user-friendly and consistent.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/proxy-option-in-playground
----

Proxy option in the ScreenshotOne Playground

============================================

You can now take screenshots with a proxy in the ScreenshotOne Playground.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Sep 29, 2025

Proxy option in the ScreenshotOne Playground

--------------------------------------------

You can now take screenshots with a proxy in the ScreenshotOne Playground.

It is located under the “Request” section.

Documentation

-------------

Read more about the proxy option in the [ScreenshotOne API documentation](/docs/options/#proxy) and our [guide on how to use proxies](/docs/guides/how-to-use-proxies).

Your feedback is appreciated

----------------------------

If you have any questions, suggestions, or need any assistance, please, reach out at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Detect any website fonts with a ScreenshotOne API](/changelog/detect-any-website-fonts-with-a-screenshotone-api/)

Now you can detect fonts used by any website with ScreenshotOne API in just one simple API call.

Read more →

1 min read

#### [Set locale and language of the browser](/changelog/language-and-locale/)

A new version of the ScreenshotOne API has been just deployed. It allows you to set both locale and language of the browser when rendering screenshots with one simple option.

Read more →

1 min read

#### [An improved screenshot history page](/changelog/an-improved-screenshot-history-page/)

Daily, I work as hard as I can to ensure that ScreeenshotOne is the best screenshot API out there possible. But I rarely share updates but trust me, a ton of them might go unnoticed. Let's fix this situation.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/integrations
----

Integrations

Automate website screenshots in your workflows

----------------------------------------------

Render website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos with any no-code platform, and not only.

All AI API Automation CMS Code Enterprise Low-Code No-Code WordPress

23 integrations

Code API

### SDK and Code Examples

Use the SDKs and code examples to take screenshots in your own code.

[Read more →](/integrations/code/)

* * *

No-Code Automation

### Make

Use ScreenshotOne with Make to automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

[Read more →](/integrations/make/)

* * *

No-Code Automation

### n8n

Use ScreenshotOne in n8n workflows to render website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

[Read more →](/integrations/n8n/)

* * *

No-Code Automation

### Zapier

Automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos in Zapier.

[Read more →](/integrations/zapier/)

* * *

No-Code Automation

### Clay

Generate website screenshots inside Clay to qualify leads, assess content, and enrich rows with visual context automatically.

[Read more →](/integrations/clay/)

* * *

Low-Code Automation

### Airtable

Add website screenshots to your Airtable content.

[Read more →](/integrations/airtable/)

* * *

Code API AI

### CLI

Use command line interface to automate screenshots in your workflows with ScreenshotOne.

[Read more →](/integrations/cli/)

* * *

No-Code Automation CMS

### Bubble

Add website screenshots to your Bubble content with a plugin.

[Read more →](/integrations/bubble/)

* * *

No-Code Automation WordPress

### FlowMattic

Use ScreenshotOne with FlowMattic, a WordPress automation platform, to automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

[Read more →](/integrations/flowmattic/)

* * *

Low-Code Automation

### Google Sheets

Render website screenshots in Google Sheets.

[Read more →](/integrations/google-sheets/)

* * *

AI Enterprise Automation

### NemoClaw

Use ScreenshotOne with NemoClaw to capture website screenshots for enterprise AI agents, browser verification, secure reporting, and visual audit trails.

[Read more →](/integrations/nemoclaw/)

* * *

Code API AI

### MCP

Use ScreenshotOne with MCP Server to render website screenshots with any LLM that supports MCP.

[Read more →](/integrations/mcp/)

* * *

AI Automation

### OpenClaw

Use ScreenshotOne to automate website screenshots inside OpenClaw workflows for visual checks, proactive monitoring, and image-based reporting.

[Read more →](/integrations/openclaw/)

* * *

No-Code Automation

### Pipedream

Automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos in Pipedream.

[Read more →](/integrations/pipedream/)

* * *

Low-Code Code API

### Postman

You can use the Postman Collections provided by ScreenshotOne to play with the API and get started quickly.

[Read more →](/integrations/postman-api-network/)

* * *

No-Code Code API

### RapidAPI

Integrate ScreenshotOne through RapidAPI to automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

[Read more →](/integrations/rapidapi/)

* * *

No-Code AI

### Ravenala

Use ScreenshotOne with Ravenala.

[Read more →](/integrations/ravenala/)

* * *

Code API

### S3

Upload screenshots to Amazon S3 or any other S3-compatible storage.

[Read more →](/integrations/s3/)

* * *

Code API

### Signed Links

Use signed links to share screenshots publicly.

[Read more →](/integrations/signed-links/)

* * *

Low-Code CMS

### Sanity

Add website screenshots to your Sanity content with a plugin.

[Read more →](/integrations/sanity/)

* * *

No-Code Automation CMS

### Directify

Build a website directory and add website screenshots with ScreenshotOne.

[Read more →](/integrations/directify/)

* * *

No-Code Automation

### viaSocket

Automate website screenshots, animated scrolling captures, and visual documentation workflows with ScreenshotOne and viaSocket.

[Read more →](/integrations/viasocket/)

* * *

Code CMS

### Dirstarter

Build a directory with Dirstarter and add website screenshots with ScreenshotOne.

[Read more →](/integrations/dirstarter/)

No integrations found matching your search.

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/nemoclaw
----

[What's new API error insights API error insights in the dashboard](/changelog/error-metrics/)

Website Screenshots for NemoClaw

================================

ScreenshotOne helps NemoClaw agents capture reliable website screenshots for browser tasks, visual verification, and evidence-rich reports.

[Get started for free ->](https://dash.screenshotone.com/sign-up)

> ScreenshotOne is the best product on the market - and that's before you take into account how responsive and easy Dmytro is to work with.

> 

> Any time we've found a rare edge case, it's been resolved in hours.

> 

> Great company, great founder - can't say enough!

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/charging-extra
----

[Skip to content](#_top)

Charging Extra

==============

Copy page

You can set the hard limit for screenshots higher than the limit in your current plan. And by doing this, you are enabling charging for extra screenshots. The option is available only for paying customers who are organization owners.

Once the charging extra is enabled (at [your subscription page](https://dash.screenshotone.com/subscription)), you will be charged for successful not cached requests that go over your plan limitation.

Examples

--------

Note

**Your price per extra screenshot depends on the plan you have**. You can see all prices at the [ScreenshotOne Pricing page](https://screenshotone.com/pricing) or check out your price at [your subscription page](https://dash.screenshotone.com/billing).

Let’s look at different examples of an artificial subscription plan. Imagine you have a limit of 10000 screenshots monthly, and let’s assume the price of one extra screenshot is $0.004 (this is an example price, not a real price):

1.  The plan limit is 10000, the hard limit is 15000, and you rendered 12000 screenshots. You will be charged for 2000 extra screenshots. $0.004 x 2000 = $8.

2.  The plan limit is 10000, the hard limit is 15000, and you rendered 12500 screenshots. You will be charged for 3000 extra screenshots. $0.004 x 3000 = $12.

Why for 3000 extra screenshots?

**It is because extra charges are rounded to the close upper bound of a thousand screenshots.**

If you render only one extra screenshot, you pay for 1000 screenshots. If you render 1001, you pay for 2000, and so on. If you render 999, you pay for 1000, and so on.

Upgrading subscription

----------------------

Once you upgrade your subscription, your hard limit is reset. And you need to set it up again.

Cancelling or downgrading subscription

--------------------------------------

Before you cancel your subscription, ScreenshotOne will try to charge you for extra screenshots and only then cancel it.

For downgrading, charging happens only when downgrading to a free plan. Otherwise, there is no need.

When you are charged

--------------------

ScreenshotOne charges you periodically over the extra usage if needed, usually once per 1000 screenshots.

Or you also might be charged in one “batch” for the extra usage. It depends on the internal logic of the service.

Maximum hard limit

------------------

Every new customer has a maximum hard limit of 100,000 screenshots. If you need to upgrade it and make it higher, feel free to write to `support@screenshotone.com`. Please, describe your use case.

ScreenshotOne is a scalable and highly performant API that has paying customers who make render more than 100,000 screenshots monthly. Still, there is a need to make sure that there is no service abuse and that high-quality service can be delivered. That’s why the maximum hard limit for new customers is applied.

----
url: https://screenshotone.com/changelog/improved-dashboard-authentication
----

Better authentication for ScreenshotOne dashboard

=================================================

Email and password authentication, email change flow, email verification, GitHub authentication, and improved UX/UI.

[Changelog](/changelog/) 6 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jan 28, 2025

Since ScreenshotOne was launched in 2022, the authentication process hasn’t changed much except for the migration from Go to TypeScript and, as a consequence, using Next.js and NextAuth.js for the dashboard authentication instead of Go and raw HTML with CSS.

The authentication flow just worked, but accumulated a lot of feature requests and UI/UX issues.

I decided to fix most of them at once and share with you the results and the reasoning behind of the decisions.

By the way, you can try the new flow at [the dashboard sign-in page](https://dash.screenshotone.com/sign-in). Any feedback is much appreciated, feel free to email `support@screenshotone.com`.

Migrated from NextAuth.js (v4) to Better Auth

---------------------------------------------

NextAuth.js (v4) and its successor Auth.js are great libraries. I had been using NextAuth.js (v4) and it was time to upgrade to Auth.js. While researching all available authentication libraries for Next.js, I discovered Better Auth.

The main reasons why I chose Better Auth and went with it:

1.  It supports email and password authentication out of the box, which I planned to add anyway.

2.  Change email flow is also supported out of the box.

3.  It has feature parity with NextAuth.js (v4) and provides a simple migration path—there was nothing to lose.

4.  It is in active development and has a lot of potential.

I even managed to made a tiny contribution to it:

[](https://github.com/better-auth/better-auth/pull/1225)

Email and password

------------------

It was a few lines of code to add it with Better Auth:

That type of authentication was requested by many users. But I didn’t hurry to implement it. I was weighing upsides and downsides of adding it. Plus, NextAuth.js (v4) didn’t support it out of the box.

Today, after seeing email providers having outages, I think it is worth adding it. At least users who already signed up, will be able to sign in the case if emailing is not working.

Change email flow

-----------------

Once a year, a ScreenshotOne user requests to change their email. I didn’t implement it from the start and often did manually when I received support tickets.

But, luckily, Better Auth has a built-in flow for that:

 Sorry, your browser doesn't support embedded videos.

It took me a few hours to implement, test and deploy the new change email flow.

Email verification is always required

-------------------------------------

I made email verification a required step for the new sign-up flow, except if the email was already verified by third-party providers like Google or GitHub.

It might reduce the number of successful sign-ups, especially if due to some reasons verification emails are going to spam.

But I want to make sure that all users have a real verified email address. For an API product like ScreenshotOne it is a must, because if something happens with integrations, billing, or quota limits are reached, users must be notified and able to react.

Otherwise, one of their critical integrations might fail and they will not be able to know about it and react.

In case, if it was a casual SaaS product or not a critical component for businesses, I would consider, not requiring email verification.

Check your inbox

----------------

Once a verification email is sent, instead of showing a successful “toaster” message:

Now, you will be redirected to a dedicated page:

 Sorry, your browser doesn't support embedded videos.

It will reduce the frustration and support tickets. Since not everyone notice that the email was sent and often request to send it again.

GitHub

------

ScreenshotOne is not only, but mostly a product for developers and most of them have a GitHub account. Adding GitHub authentication as an option should simplify the sign-up process.

And indeed, the hypothesis was correct. Only a few days after launching GitHub authentication, there were already users signing up with it.

Closed authentication for authenticated users

---------------------------------------------

One of the NextAuth.js (v4) features is linking accounts for signed-in users. It led to creating one user with the primary email and then many linked accounts with different emails.

It also led to users having multiple accounts with the same email address if they signed up later with a non-primary email.

All of that caused more confusion and support tickets, so I closed it.

But with Better Auth, it should be irrelevant altogether since it links accounts by email. Anyway, it is still better to close the authentication flow for authenticated users.

Improved error rendering

------------------------

Before the update, the error rendering was not very user-friendly. The toast message was used to display the error.

But did users see the error?

To make sure that users always see the error and can react to it, the error message is now displayed clearly right in the form:

That way, users will never miss it.

Last used method

----------------

Often users forget which method they used last time to sign in. In general, it is not a problem, since ScreenshotOne will link verified accounts automatically.

For example, if your GitHub email differs from the Google email you used to sign up for ScreenshotOne, this might lead to creating an additional unnecessary account.

For such cases, it is better to know which method was used last time. There is nothing to lose in UX/UI, but only gain for users who return and sign in often.

Added legal links

-----------------

Added terms of service and privacy policy links to the sign-up and sign-in pages.

In case if potential customers have any doubts or questions, they can read the terms of service and privacy policy and be able to figure out what they sign up for.

Improved email sending

----------------------

### Migrated to Resend

I migrated to Resend and subscribed to a paid plan even though I don’t need to.

One of the important features of the product for me is that its makers do take care of it.

When I got a transactional authentication email from Resend, I replied to it to check if they respond and how much time it will take.

They not only responded but helped me troubleshoot some other issues.

The same applies when I mentioned minor UX/UI issues—their founder replied that they will take care of it:

Also, DX of Resend is one of the best in the market, and it seems [it will be cheaper for my needs than Mailgun](https://resend.com/migrate/mailgun) long term.

### Configured a different domain

It is a good practice to use subdomains for emails instead of the main domain to avoid losing sender reputation in case something goes wrong.

I configured a different domain for email sending to make it more recognizable and avoid being marked as spam—`notifications.screenshotone.com`.

I will send transactional emails only from this domain, using the `team@notifications.screenshotone.com` address.

### Changed the HTML template

I installed the [React Email](https://react.email/) library to render emails with React and created a custom template instead of using the one provided by the NextAuth.js (v4) library.

Before:

After:

Improved validation

-------------------

### No disposable emails allowed

There is no drawback to blocking disposable emails.

Seriously oriented customers who see the value of the product and know why they are signing up never use disposable emails anyway and sign up with their work emails.

ScreenshotOne will not allow disposable emails when signing up anymore. In the majority of cases, they were used to sign up for the free plan and exhaust its credits.

### Normalization of emails

However, users will still be able to sign up with email aliases.

While I haven’t seen paying customers signing up with aliases, or if it was very rare, I decided to allow using email aliases.

Organization-related improvements

---------------------------------

### Allowed more members

One of the organizations reached their max member count of 10, and I had to increase it to 50 to forget about it for a while. 50 members seems to be a good number for most organizations and it is way out of the typical pattern ScreenshotOne currently has.

An average organization as an entity in ScreenshotOne has 2-5 members, even when represent really large companies.

A few thoughts and ideas

------------------------

If you have any suggestions or questions, please feel free to contact at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Improved blocking of cookie banners](/changelog/improved-blocking-of-cookie-banners/)

We just released an updated version of our algorithm to block cookie banners by heuristics.

Read more →

1 min read

#### [Convert any website to Markdown format with ScreenshotOne API](/changelog/website-to-markdown-format/)

Now you can convert any website to Markdown format with ScreenshotOne API in just one simple API call.

Read more →

1 min read

#### [Use cases in the ScreenshotOne playground](/changelog/improved-playground/)

Having documentation and code examples is great, but not enough to allow developers to quickly integrate the API and assess all available features of the ScreenshotOne API.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/updated-design-of-authentication-pages
----

Improved design of the authentication pages

===========================================

We updated the design of the authentication pages to make them more user-friendly and consistent.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Apr 8, 2025

This is not precisely a product update, but I think it’s still worth sharing.

We updated the design of the authentication pages to make them more user-friendly and consistent.

Before:

After:

The idea was to reiterate on the benefits of using ScreenshotOne for new potential customers. And to strengthen the trust by sharing testimonials from existing customers.

And to ensure consistency with the rest of the dashboard in the color scheme and styles.

If you have any feedback, please reach out to us at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Improved Supabase Storage integration](/changelog/better-supabase-storage-support/)

Improved Supabase storage integration.

Read more →

1 min read

#### [Fail if there is nothing to click on](/changelog/error-on-click-selector-not-found/)

A new option has been added to fail or not to fail the screenshot rendering if there is nothing to click on.

Read more →

1 min read

#### [Improved guards for full-page screenshots by sections](/changelog/guards-for-full-page-screenshots-by-sections/)

Improved guards for full-page screenshots by sections.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/the-new-screenshotone-dashboard-is-out
----

The new ScreenshotOne dashboard is out

======================================

It is a long-term move and rebuilding the ScreenshotOne dashboard was a decision to continue improving customer experience. The previous version of the dashboard was outdated and didn't serve new arising customer needs well.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Dec 23, 2023

The previous dashboard was written quickly by using Go, HTML/CSS, and pure JavaScript. And there is absolutely nothing wrong with that. And it worked well and fast. Customers were satisfied.

But their needs were growing—some asked for more filters on the history page, some wanted to set the hard limit for screenshot quota, and so on. All these requests often required changing UI and building interactive interfaces, sometimes complex, like in the case of updating the playground.

The stack of technologies just didn’t satisfy the needs and often required more work than reasonable to accomplish building new features or improving existing ones.

So there was a rising demand to improve the technology stack and since it is a long-term project it seemed to be a worthwhile bet.

Also, the UI needed to be upgraded and improved. Using the latest UI libraries could help a lot in that.

So the decision was made, and the dashboard was rewritten. Currently, everything is preserved as in the old dashboard and they are almost identical, but soon the new one will be improved by a lot. And I hope you will enjoy the new experience.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [ScreenshotOne integration with Dirstarter](/changelog/dirstarter-integration/)

Build a directory with Dirstarter and add website screenshots automatically with ScreenshotOne.

Read more →

1 min read

#### [Stop scrolling screenshots when a given selector is visible](/changelog/animated-scrolling-till-selector/)

New options were added to the ScreenshotOne API to stop scrolling screenshots when a given selector is reached.

Read more →

1 min read

#### [Async, Webhooks, and Extra Limits](/changelog/async-webhooks-and-extra-limits/)

May was a great month and full of new and exciting updates. Let's check them out quickly.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/screenshotone-api-supports-gpu-rendering
----

ScreenshotOne API supports GPU Rendering

========================================

From today ScreenshotOne supports GPU rendering for both regular and animated website screenshots. The API now leverages the latest in graphics processing technology to bring your screenshot needs to a whole new level.

[Changelog](/changelog/) 2 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Nov 21, 2023

Chrome/Chromium Headless GPU rendering matters

----------------------------------------------

With GPU you get:

*   **Enhanced Performance**: because of ensuring faster and more efficient rendering of complex web pages.

*   **Superior WebGL Support**: ScreenshotOne API now fully supports performant WebGL content, making it effortless to capture high-quality, dynamic 3D graphics and interactive visualizations.

*   **Dynamic Video Rendering**: Need to [capture videos from web pages](https://screenshotone.com/docs/animated-screenshots/)? Our GPU rendering feature can handle that with ease, providing crisp, clear video screenshots.

Key Use Cases

-------------

You don’t always need GPU rendering. In most case, probably 99% of them, using regular CPU rendering is enough.

### High-End Visual Content

It is perfect for capturing sophisticated web applications that utilize WebGL or require high-end graphics processing.

### Video Content Screenshots

And you can easily capture [animated web pages as video](/docs/animated-screenshots/), maintaining high fidelity and clarity.

Availability

------------

Currently, the screenshot GPU rendering feature is exclusively available for our highly paid plans.

Alternatives and Their Limitations Compared to ScreenshotOne API

----------------------------------------------------------------

A few thoughts about alternatives:

*   **Standard Puppeteer Without GPU Rendering**: While regular Puppeteer setups can capture basic web content, they lack the GPU acceleration feature. This limitation results in slower rendering times and challenges in capturing high-end graphics or WebGL content efficiently.

*   **Basic Screenshot Tools Without WebGL Support**: Standard screenshot tools often fail to properly render complex WebGL content. ScreenshotOne API’s advanced WebGL support ensures that even the most sophisticated 3D graphics are captured accurately and effortlessly.

*   **Traditional Screen Capture Software**: Conventional screen capture software might not support hardware acceleration, leading to slower processing times and reduced efficiency, especially for dynamic or video content. ScreenshotOne API’s integration with Chrome’s headless GPU capabilities provides a significant advantage in speed and performance.

By choosing ScreenshotOne API, developers gain access to advanced GPU rendering capabilities, ensuring fast, efficient, and high-quality captures of even the most complex web content.

How to use and what is supported

--------------------------------

To enable GPU rendering simply specify [request\_gpu\_rendering=true](/docs/options/#request_gpu_rendering):

    1https://api.screenshotone.com/take?access_key=<your access key>&url=...&request_gpu_rendering=true

The request will be routed to GPU rendering servers. Almost all the time it is guaranteed to be satisfied, but if not, CPU rendering and software acceleration can be used as alternatives.

An example of rendering [a WebGL sample](https://akirodic.com/p/jellyfish/):

 Sorry, your browser doesn't support embedded videos.  

These are hardware accelerated rendering features supported by ScreenshotOne API:

Stay ahead

----------

Stay ahead of the curve with ScreenshotOne’s GPU screenshot rendering. [Sign up](https://dash.screenshotone.com/sign-up) and upgrade to our premium plans today and experience the joy of rendering perfect website screenshots!

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Stop scrolling screenshots when a given selector is visible](/changelog/animated-scrolling-till-selector/)

New options were added to the ScreenshotOne API to stop scrolling screenshots when a given selector is reached.

Read more →

1 min read

#### [Fixed a validation issue in the playground](/changelog/fixed-a-playground-issue/)

We fixed a validation issue in the ScreenshotOne playground caused by selector scroll into view.

Read more →

1 min read

#### [Improved proxy validation](/changelog/improved-proxy-validation/)

Stricter proxy option validation to prevent misconfiguration.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/contributors/eugene-zolotarenko
----

Eugene Zolotarenko

------------------

View all Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [How Outrank enriches content generation with ScreenshotOne](/blog/outrank/)

A short story about how and why Outrank uses ScreenshotOne for screenshot generation to enrich SEO content.

Written by

[Eugene Zolotarenko](/contributors/eugene-zolotarenko/), [Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jun 29, 2025

•

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/how-to-take-website-screenshots-with-php
----

How to take website screenshots with PHP

========================================

The article examines how you can take screenshots of any URL with PHP by using Selenium, Puppeteer alternatives, or screenshot API as a service.

[Blog post](/blog/) 3 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jun 14, 2022

#### Tags

[Screenshot rendering](/blog/tags/screenshot-rendering/)

Today, there are many options to make screenshots of any URL with PHP:

1.  [Selenium WebDriver client for PHP](#selenium-webdriver-client-for-php).

2.  You can use [the PHP analog of Puppeteer](#php-analog-of-puppeteer).

3.  Or [Screenshot API as a service](#screenshot-api-as-a-service).

They might overlap, but there is no best solution. Each depends on your use case and requirements.

Selenium WebDriver client for PHP

---------------------------------

Selenium is a well-known kid in the QA automation area, so it is easy to start taking screenshots if you plan to write automation tests or already do it.

Install [Selenium WebDriver client for PHP](https://github.com/php-webdriver/php-webdriver) into your project:

Terminal window

    1$ composer require php-webdriver/webdriver

Download the latest version [ChromeDriver](https://sites.google.com/chromium.org/driver/), run it:

Terminal window

    1chromedriver --port=4444

And you are ready to use it:

    1<?php2

    3require_once __DIR__ . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';4

    5use Facebook\WebDriver\Remote\RemoteWebDriver;6use Facebook\WebDriver\Remote\DesiredCapabilities;7use Facebook\WebDriver\WebDriverBy;8

    9$serverUrl = 'http://localhost:4444';10

    11$driver = RemoteWebDriver::create($serverUrl, DesiredCapabilities::chrome());12

    13$driver->get('https://example.com');14

    15$driver->takeScreenshot('example.png');16

    17$driver->quit();

If you just want to take one or two screenshots locally, the Selenium WebDriver client is not the best fit. As I wrote earlier, it better serves you already write automation tests with Selenium or plan to write them.

PHP analog of Puppeteer

-----------------------

[PuPHPeteer](https://github.com/rialto-php/puphpeteer) is the closest analog to [Node.js Puppeteer](https://screenshotone.com/blog/how-to-take-a-screenshot-with-puppeteer/) in PHP, a faster, more straightforward way to drive browsers supporting the [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/) in PHP.

While you can also use `PuPHPeteer` for automation testing, it is much light weighter and simpler than Selenium and allows any automation over the browser. Everything you can do manually with a browser, you can also do with `PuPHPeteer`.

And it is super easy to use:

Terminal window

    1composer require nesk/puphpeteer2npm install @nesk/puphpeteer

And then just:

    1<?php2

    3require_once __DIR__ . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';4

    5use Nesk\Puphpeteer\Puppeteer;6

    7$puppeteer = new Puppeteer;8$browser = $puppeteer->launch();9

    10$page = $browser->newPage();11$page->goto('https://example.com');12$page->screenshot(['path' => 'example.png']);13

    14$browser->close();

It is very lightweight compared to Selenium and allows a broad spectrum for automation of the browser. You can use it for crawling, scrapping, taking screenshots, etc.

If you need the simplest way to take screenshots, you do not expect to take millions of them, and I would go with `PuPHPeteer`. But if you want to take screenshots from different browsers or think about managing instances of browsers, there is a more straightforward way to go.

Screenshot API as a service

---------------------------

We specialize in taking screenshots and managing browser instances at scale. We provide [a high-quality PHP client to take screenshots](https://github.com/screenshotone/phpsdk) and cover a variety of use cases.

Easy to install:

Terminal window

    1 composer require screenshotone/sdk:^1.0

And easy to use:

    1<?php2

    3use ScreenshotOne\Sdk\Client;4use ScreenshotOne\Sdk\TakeOptions;5

    6$client = new Client('<access key>', '<secret key>');7

    8$options = TakeOptions::url("https://example.com")9    ->fullPage(true)10    ->delay(2)11    ->geolocationLatitude(48.857648)12    ->geolocationLongitude(2.294677)13    ->geolocationAccuracy(50);14

    15$url = $client->generateTakeUrl($options);16echo $url.PHP_EOL;17// expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com...18

    19$image = $client->take($options);20file_put_contents('example.png', $image);21// the screenshot is stored in the example.png file

If you feel that it is the best fit for you, feel free [to sign up for our screenshot API](https://screenshotone.com/) and get the access key.

Summary

-------

Pick the solution which suits your needs best. If you decide to go with our API, please ask any questions and mail us at [support@screenshotone.com](mailto:support@screenshotone.com). And have a nice day 👋

By the way, you might also find interesting how to:

*   [take web screenshots with Java](/blog/how-to-take-website-screenshots-with-java/)

*   [take web screenshots with JavaScript or TypeScript (Node.js)](/blog/how-to-take-website-screenshots-with-javascript-and-typescript-nodejs)

*   [take web screenshots in Go](/blog/how-to-take-website-screenshots-with-go/)

Read more Screenshot rendering

------------------------------

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

[View all posts](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots in Ruby](/blog/how-to-take-website-screenshots-in-ruby/)

Let's examine what Ruby proposes for us to render HTML or URL as a screenshot dynamically.

Read more

#### [How to hide chat widgets when taking a screenshot with Puppeteer](/blog/how-to-hide-chat-widgets-when-taking-a-screenshot-with-puppeteer/)

When you want to take chat widgets, there are annoying chat widgets that you would love to hide. It is easy to do.

Read more

#### [How to take website screenshots in Python](/blog/how-to-take-website-screenshots-in-python/)

With Python, you can take website screenshots in multiple ways. But the best way to do it depends solely on your needs and your use case. Let's quickly examine all the options.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/tags/desktop-screen-capture
----

Desktop Screen Capture

----------------------

Guides for capturing screenshots on desktop and native apps.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

[Desktop screen capture](/blog/tags/desktop-screen-capture/)

#### [How to Capture Desktop Screenshots in Python](/blog/python-screen-capture/)

Complete guide to desktop screen capture in Python. Compare Python MSS, DXcam, PyAutoGUI for capturing monitors, windows, and screen regions.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 19, 2026

•

3 min read

[Desktop screen capture](/blog/tags/desktop-screen-capture/)

#### [How to Take Screenshots with Python MSS](/blog/mss-python-screen-capture/)

Complete guide to the MSS Python screen capture library. Learn installation, capturing monitors, regions, performance optimization, and common errors like xgetimage() failed.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 15, 2026

•

4 min read

[Desktop screen capture](/blog/tags/desktop-screen-capture/)

#### [How to Capture Desktop Screen with DXcam in Python](/blog/dxcam-python-screenshots/)

Complete guide to DXcam, the fastest Python screen capture library. Learn high-FPS capture, video mode, region capture, and DXcam vs Python MSS performance comparison.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 14, 2026

•

4 min read

[Desktop screen capture](/blog/tags/desktop-screen-capture/)

#### [How to Take Screenshots with PyAutoGUI in Python](/blog/pyautogui-python-screenshots/)

Complete guide to taking screenshots with PyAutoGUI in Python. Learn screenshot(), region parameters, locateOnScreen(), and common errors with ImageNotFoundException.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 13, 2026

•

3 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/how-ilias-ism-a-founder-of-the-magicspace-seo-agency-uses-screenshotone-daily
----

How Ilias Ism, a founder of the MagicSpace SEO agency, uses ScreenshotOne daily

===============================================================================

We would love to share a quick review of ScreenshotOne by Ilias Ism, a founder of MagicSpace SEO agency and OG Image Generator on how he uses the API daily to generate screenshots and automate regular tasks associated with screenshots.

[Customer story](/blog/tags/customer-stories/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Dec 5, 2023

Here is what Ilias shared with us:

> Sometimes you notice a piece of software that is so simple but yet so useful. ScreenshotOne is one of those tools and I couldn’t be more excited in using it. It solves a lot of real pains for me as a developer and SEO consultant. With over 5,000 screenshots taken so far, ScreenshotOne saves me tons of time while delivering reliable, high-quality results.

> The best tools, are those that make you money when using them, for me this was when I adopted ScreenshotOne into my OG Image Generator, it was an easy setup, and now my social preview images are nice and clean screenshot of the page, without just being blank or a random image.

> Let’s dive into what ScreenshotOne is, and how I’m using it.

You can read [the full review on the Ilias site](https://il.ly/reviews/screenshotone).

Read more customer stories

--------------------------

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

[View all posts](/blog/tags/customer-stories/)

#### [ScreenshotOne took away one major complexity off the Supawrite plate](/blog/supawrite/)

A short story about how ScreenshotOne helps a content marketing platform automate their screenshot workflow.

Read more

#### [How Branding 5 uses ScreenshotOne for competitor analysis](/blog/how-branding5-uses-screenshotone/)

If you are interested in diving deeper into the Branding 5 use case and discover if ScreenshotOne might be useful for you, too, keep reading.

Read more

#### [How AdKit automated onboarding](/blog/adkit/)

A short story by the founder of AdKit about how they use ScreenshotOne for onboarding automation.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/contributors/william-prudhomme
----

William Prudhomme

-----------------

View all Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [How Forge IQ automates visual CRO audits with ScreenshotOne](/blog/forge-iq/)

A story about how Forge IQ automates its CRO audit by integrating ScreenshotOne into their workflow to produce visual reports.

Written by

[William Prud’homme](/contributors/william-prudhomme/)

Published on

May 23, 2025

•

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/rankpill
----

How RankPill uses ScreenshotOne

===============================

Sharing how RankPill uses ScreenshotOne to automate website screenshot generation for SEO and GEO automation.

[Customer story](/blog/tags/customer-stories/) 1 min read

#### Written by

[Modest Mitkus](/contributors/modest-mitkus/), [Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Nov 6, 2025

RankPill: SEO and GEO automation to get traffic

-----------------------------------------------

[RankPill](https://rankpill.com) is an SEO and GEO automation tool designed to help businesses get organic traffic from Google, ChatGPT, and other search platforms. The platform automates many aspects of SEO strategy, helping companies improve their visibility and reach their target audience more effectively.

[](https://rankpill.com)

In SEO and GEO content generation, enriching content with screenshots is essential for providing visual context in the posts and helping customers understand insights quickly. Screenshots can also help to rank images on Google and other search engines.

ScreenshotOne as a solution

---------------------------

> “ScreenshotOne allows us to get website screenshots for our customers. Super fast and helpful support, stable, and a nice product!”

Modest Mitkus, the founder of RankPill, discovered ScreenshotOne on X (formerly Twitter) and recognized its potential for their SEO and GEO automation platform.

Once it integrated (he claims it was pretty easy), it allowed them to get website screenshots for their customers content. The API worked as expected and the support was helpful.

More examples and use cases

---------------------------

You might also be interested in how [SpyFu uses ScreenshotOne for RivalFlowAI for competitive content analysis with AI](/blog/rivalflowai-by-spyfu/).

ScreenshotOne supports a huge variety of uses including but not only:

*   [Automating Open Graph image generation](/use-cases/open-graph-images/).

*   [Generating personalized videos](/use-cases/automate-personalized-videos/).

And [many more](/use-cases/).

If you have any questions about how ScreenshotOne can help automate screenshot generation for your SEO platform or any other project, feel free to reach out to our support team at `support@screenshotone.com`. We’re always happy to help you find the best solution for your needs.

Read more customer stories

--------------------------

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

[View all posts](/blog/tags/customer-stories/)

#### [How BugSmash automates website screenshot rendering](/blog/bugsmash-story/)

How and why BugSmash uses ScreenshotOne for critical screenshot rendering tasks.

Read more

#### [Automating screenshots for directory websites with ScreenshotOne](/blog/directify-feedback/)

How and why "Directify" used ScreenshotOne to automate screenshots for directory websites.

Read more

#### [How Elias Stråvik uses GPT-4 Vision and Zapier for landing page feedback automation](/blog/generating-landing-page-feedback-with-vision/)

A quick review of ScreenshotOne by Elias Stråvik, a founder of Roast as A Service on how he uses the ScreenshotOne daily to automate regular tasks associated with screenshots.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/5
----

Changes and updates

-------------------

Stay updated with the latest information about new features, bug fixes, and optimizations at ScreenshotOne

### Product updates in the last 12 months

Jul 4, 2025

#### [Set PDF margins](/changelog/pdf-margin/)

Now you can set PDF margins for the resulting PDF file.

Read more →

1 min read

Jun 26, 2025

#### [Add ScreenshotOne to n8n workflows](/changelog/n8n-integration/)

You can now use ScreenshotOne in n8n workflows to render website screenshots, PDFs, scrolling screenshots and videos.

Read more →

1 min read

Jun 10, 2025

#### [Support for multiple API keys](/changelog/multiple-api-keys/)

You can now use multiple API keys to the access ScreenshotOne API.

Read more →

1 min read

May 7, 2025

#### [Rendering Google Documents and Slides is now available](/changelog/google-docs-and-slides/)

You can now easily render Google Documents and Slides with ScreenshotOne.

Read more →

1 min read

May 5, 2025

#### [Download request content in the dashboard](/changelog/download-request-content/)

You can now download request content in the dashboard.

Read more →

1 min read

Apr 25, 2025

#### [Added support of external identifiers](/changelog/screenshotone-external-identifier/)

Check out how to use the external identifier to improve tracking of webhook executions.

Read more →

1 min read

Apr 24, 2025

#### [Rendering errors in webhooks](/changelog/screenshotone-webhook-errors/)

Check out how to get notified about rendering errors when using webhooks.

Read more →

1 min read

Apr 20, 2025

#### [Added support of Slack notifications](/changelog/slack-notifications/)

We added support of Slack notifications to ScreenshotOne. Now you can set up and get Slack notifications when you reach your quota limits.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/errors/script-triggers-redirect
----

[Skip to content](#_top)

Script Trigger Redirect

=======================

Copy page

It is an API error returned when the API detects that the script will trigger a redirect and screenshots won’t be rendered successfully.

    1{2    "is_successful": false,3    "error_code": "script_triggers_redirect",4    "error_message": "The specified \"scripts\" option might trigger a redirect, please, specify the \"scripts_wait_until\" option. If you think it is a mistake, please, reach out at `support@screenshotone.com`.",5    "documentation_url": "https://screenshotone.com/docs/script-triggers-redirect/"6}

Reasons and how to fix

----------------------

Let’s quickly consider possible reasons and possible solutions.

### Add some wait options

Since the custom script you add with the “scripts” options triggers a redirect, you must also set [the “scripts\_wait\_until” option](/docs/options/#scripts_wait_until), too.

And to force the API to wait until the new page is loaded.

Reach out to support

--------------------

If nothing helps you, please, reach out to `support@screenshotone.com` and we will try to help you as fast as possible.

----
url: https://screenshotone.com/docs/errors/host-returned-error
----

[Skip to content](#_top)

Host Returned Error

===================

Copy page

It is an API error returned when the host server does not respond with a successful status code within the range of 200-299.

    1{2    "is_successful": false,3    "error_code": "host_returned_error",4    "error_message": "If the host doesn't respond successfully within the range of 200-299 status codes, the API won't take a screenshot. You can force the API to take a screenshot of the error page by specifying `ignore_host_errors`=true. You can get the returned status code from the site by reading the `returned_status_code` field.",5    "documentation_url": "https://screenshotone.com/docs/errors/host-returned-error/"6}

Reasons and how to fix

----------------------

### Host Returned Non-Success Status Code

The most common reason for the “host\_returned\_error” error is that the host server returned a status code outside the 200-299 range, indicating an unsuccessful response.

To fix this, you can:

1.  **Check host server status**: Ensure the host server is operational and capable of returning a successful status code.

2.  **Review site response**: Investigate the response from the host server to understand why it is not returning a successful status code.

### Forcing Screenshot of Error Pages

If you want the API to take a screenshot of the error page even when the host returns an error, you can use the `ignore_host_errors` option.

To fix this, set `ignore_host_errors` to `true` in your API request:

    1{2    "ignore_host_errors": true3}

Retrieving the Returned Status Code

-----------------------------------

You can get the status code returned by the host server by reading the `returned_status_code` field in the response. This will help in diagnosing and understanding the nature of the error.

Reach out to support

--------------------

If you continue to face issues or need further assistance, please reach out to `support@screenshotone.com`, and we will assist you as soon as possible.

----
url: https://screenshotone.com/contributors/dmytro-krasun
----

Dmytro Krasun

-------------

With more than a decade of experience in software engineering, I share the best practices and solutions you can apply to your problems in the space of headless browsers. You can also find me on [Twitter](https://twitter.com/DmytroKrasun) and [LinkedIn](https://www.linkedin.com/in/dmytrokrasun)

View all Changelog

[Playwright guides](/blog/tags/playwright-guides/)

#### [Playwright "Execution context was destroyed": how to fix navigation and page.evaluate errors](/blog/playwright-execution-context-was-destroyed-most-likely-because-of-a-navigation/)

Fix the Playwright "Execution context was destroyed, most likely because of a navigation" error after click, form submit, redirect, reload, or page.evaluate.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 13, 2026

•

4 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [page.waitForTimeout is not a function in Puppeteer](/blog/page-waitfortimeout-is-not-a-function-in-puppeteer/)

Puppeteer removed page.waitForTimeout(). Learn why the error happens and which modern alternatives to use instead.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 13, 2026

•

2 min read

#### [OpenClaw with Playwright or Puppeteer: how to install browser support](/blog/openclaw-playwright-puppeteer/)

A practical guide to OpenClaw browser automation, why Playwright is the documented path, where Puppeteer fits, how to make screenshots, and when ScreenshotOne is the better choice for screenshot-only flows.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 12, 2026

•

6 min read

#### [What is OpenClaw and how can it help?](/blog/openclaw/)

A short practical introduction to OpenClaw, what it is good at, and why it is useful if you want a proactive AI assistant that lives in your chat apps.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Mar 12, 2026

•

3 min read

#### [NemoClaw an enterprise alternative to OpenClaw by NVIDIA](/blog/openclaw-alternative-by-nvidia/)

A practical look at what NemoClaw appears to be, what OpenClaw already is, and the main differences between them as of March 11, 2026.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 11, 2026

•

5 min read

#### [ScreenshotOne and viaSocket integration](/blog/screenshotone-and-viasocket-integration/)

Use viaSocket with ScreenshotOne to build workflows that include website screenshot automation.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Feb 25, 2026

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Why Promptwatch wins in the AI search space](/blog/promptwatch/)

About how Promptwatch uses ScreenshotOne to automate website screenshots and why that matters.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Klaas Foppen](/contributors/klaas-foppen/)

Updated on

Feb 11, 2026

•

3 min read

[Desktop screen capture](/blog/tags/desktop-screen-capture/)

#### [How to Capture Desktop Screenshots in Python](/blog/python-screen-capture/)

Complete guide to desktop screen capture in Python. Compare Python MSS, DXcam, PyAutoGUI for capturing monitors, windows, and screen regions.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 19, 2026

•

3 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/) [Playwright guides](/blog/tags/playwright-guides/)

#### [How to Take Full Page Screenshots with Playwright in Python](/blog/playwright-python-full-page-website-screenshots/)

Learn how to capture full page screenshots with Playwright in Python. Master the full\_page parameter, handle infinite scroll pages, lazy-loaded images, and maximum size limits.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 17, 2026

•

4 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/) [Playwright guides](/blog/tags/playwright-guides/)

#### [How to Take Website Screenshots with Playwright in Python](/blog/playwright-python-screenshots/)

A complete guide to taking website screenshots with Playwright in Python. Learn page.screenshot() parameters, async patterns, element screenshots, dark mode, and device emulation.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 16, 2026

•

5 min read

[Desktop screen capture](/blog/tags/desktop-screen-capture/)

#### [How to Take Screenshots with Python MSS](/blog/mss-python-screen-capture/)

Complete guide to the MSS Python screen capture library. Learn installation, capturing monitors, regions, performance optimization, and common errors like xgetimage() failed.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 15, 2026

•

4 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to Take Bulk Screenshots in Python with a Screenshot API](/blog/bulk-screenshots-python/)

Learn how to automate bulk website screenshots in Python using ScreenshotOne API. Process thousands of URLs efficiently with async requests, rate limiting, and error handling.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 14, 2026

•

3 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/affiliate-program
----

Updated on Feb 8, 2024

ScreenshotOne Affiliate Program

===============================

If you possess a heavily-visited website, an extensive social media following, or expertise in search engine optimization, web development, content writing, and so on, joining the ScreenshotOne affiliate program can be an excellent means to generate income.

Garner earnings by advocating for ScreenshotOne. Effortlessly transform your audience into a consistent source of revenue in just a few moments. You can accumulate a 15% commission each month for the initial 12 months for every client you direct to us.

Benefits of being a ScreenshotOne affiliate

-------------------------------------------

*   You receive a 15% commission each month for every customer who subscribes through your exclusive referral link, for their initial 12 months as ScreenshotOne clients.

*   The cookie will persist for 60 days on the user’s device. This implies that if the user clicks your affiliate link and becomes a paying customer within 60 days, you will be eligible for the aforementioned commission rate.

*   We keep you informed about your performance by sending real-time notifications when you earn a commission.

*   We offer a dedicated affiliate dashboard where you can access extensive reporting on your visitors, leads, conversions, etc. You will have a transparent understanding of your performance.

*   A hassle-free payments every month with PayPal and a minimum payout threshold of $100.

Sign up as a ScreenshotOne affiliate

------------------------------------

You can [register (via Tolt) as a ScreenshotOne affiliate](https://affiliates.screenshotone.com/) and obtain your distinct link, which you can share with your audience.

ScreenshotOne’s Affiliate Terms of Service:

-------------------------------------------

**Important! If you fail to follow the following guidelines, your traffic and referrals will be discarded, you will not be eligible for any commissions, and your affiliate account will be terminated.**

A few guidelines regarding our affiliate program you should be aware of: no hidden catches, just some conditions to maintain a positive experience for all:

*   Self-referrals are prohibited (for example, registering for ScreenshotOne via your own affiliate link).

*   Engaging in manipulation, exploitation, sharing on coupon/discount websites, or attempting deception will result in a permanent ban of your account.

*   In certain situations, we can attribute credit to an affiliate even if the customer didn’t register via an affiliate link or discount code. If you encounter such a case, please reach out to us, and we’ll do our utmost to assist.

*   No search engine (Google, Bing or similar) advertisements (particularly on branded terms or domain names), Facebook ads, or other ads that would conflict with our marketing and potentially confuse customers.

*   No Facebook ads linking to our site or similar actions that would compete with our own paid marketing, increase our expenses, and potentially create confusion.

*   No impersonating as an authorized representative of us (for instance, as an employee).

*   We retain the right to modify the Terms of Service for our affiliate program at any moment.

*   We hold the right to terminate your affiliate account for any rule violation at our sole discretion. Commissions generated through mechanisms that breach our Terms of Service will not be paid or owed.

**If you fail to follow these guidelines, your traffic and referrals will be discarded, you will not be eligible for any commissions, and your affiliate account will be terminated.**

Contact

-------

[Contact](/contact/) if you have any questions, objections, or requests.

----
url: https://screenshotone.com/comparisons/puppeteer-alternative-for-screenshots
----

[What's new API error insights API error insights in the dashboard](/changelog/error-metrics/)

The Puppeteer alternative for rendering screenshots

===================================================

ScreenshotOne is one of the best Puppeteer alternatives that can render screenshots for you in one simple API call.

The best alternative to Puppeteer

Everything you need to render screenshots

-----------------------------------------

ScreenshotOne takes care of all the headaches related to maintaining Puppeteer and managing headless browsers, while you can focus on other features and code more relevant to your core business.

### Ease of Use and Integration

The ScreenshotOne API offers a simple integration for applications to capture screenshots with a single API call, eliminating the need for understanding browser automation or setup complexities.

### Scalability

ScreenshotOne is a cloud platform that offers scalable and reliable screenshot capture, handling many requests at once without user-managed servers or performance concerns, unlike Puppeteer, which requires complex and time-consuming setup for scaling.

### Reduced Maintenance Overhead

ScreenshotOne often outperforms self-managed Puppeteer setups by using optimized servers and caching for faster screenshot generation, whereas Puppeteer's efficiency varies with server setup, system load, and webpage complexity.

### Performance and Speed

Using our screenshot API offloads maintenance, updates, and compatibility issues to the provider, reducing user workload compared to Puppeteer, where users must manage servers, updates, and system health themselves.

ScreenshotOne takes care of scaling

Use the language you love

-------------------------

No need to worry about scaling headless browsers and handling all the corner cases. Choose your language and library and let's start rendering screenshots.

Java Go Node.js PHP Python Ruby C# (.NET)

    1// add com.screenshotone.jsdk:screenshotone-api-jsdk:[1.0.0,2.0.0)2// to your `pom.xml` or `build.gradle`3

    4import com.screenshotone.jsdk.Client;5import com.screenshotone.jsdk.TakeOptions;6

    7import java.io.File;8import java.nio.file.Files;9

    10public class App {11    public static void main(String[] args) throws Exception {12        final Client client = Client.withKeys("<access key>", "<secret key>");13        TakeOptions takeOptions = TakeOptions.url("https://example.com")14                .fullPage(true)15                .deviceScaleFactor(1)16                .viewportHeight(1200)17                .viewportWidth(1200)18                .format("png")19                .omitBackground(true);20        final String url = client.generateTakeUrl(takeOptions);21

    22        System.out.println(url);23        // Output: https://api.screenshotone.com/take?url=...24

    25        // or download the screenshot26        final byte[] image = client.take(takeOptions);27

    28        Files.write(new File("./example.png").toPath(), image);29        // the screenshot is stored in the example.png file30    }31}

    1// go get github.com/screenshotone/gosdk2

    3import screenshots "github.com/screenshotone/gosdk"4

    5client, err := screenshots.NewClient("<access key>", "<secret key>")6// check err7

    8options := screenshots.NewTakeOptions("https://example.com").9    Format("png").10    FullPage(true).11    DeviceScaleFactor(2).12    BlockAds(true).13    BlockTrackers(true)14

    15u, err := client.GenerateTakeURL(options)16// check err17

    18fmt.Println(u.String())19// Output: https://api.screenshotone.com/take?url=...20

    21// or download the screenshot22image, err := client.Take(context.TODO(), options)23// check err24

    25defer image.Close()26out, err := os.Create("example.png")27// check err28

    29defer out.Close()30io.Copy(out, image)31// the screenshot is stored in the example.png file

    1// $ npm install screenshotone-api-sdk --save2

    3import * as fs from 'fs';4import * as screenshotone from 'screenshotone-api-sdk';5

    6// create API client7const client = new screenshotone.Client("<access key>", "<secret key>");8

    9// set up options10const options = screenshotone.TakeOptions11    .url("https://example.com")12    .delay(3)13    .blockAds(true);14

    15// generate URL16const url = client.generateTakeURL(options);17console.log(url);18// expected output: https://api.screenshotone.com/take?url=...19

    20// or download the screenshot21const imageBlob = await client.take(options);22const buffer = Buffer.from(await imageBlob.arrayBuffer());23fs.writeFileSync("example.png", buffer)24// the screenshot is stored in the example.png file

    1<?php2

    3// composer require screenshotone/sdk:^1.04

    5use ScreenshotOneSdkClient;6use ScreenshotOneSdkTakeOptions;7

    8$client = new Client("<access key>", "<secret key>");9

    10$options = TakeOptions::url("https://example.com")11    ->fullPage(true)12    ->delay(2)13    ->geolocationLatitude(48.857648)14    ->geolocationLongitude(2.294677)15    ->geolocationAccuracy(50);16

    17$url = $client->generateTakeUrl($options);18echo $url.PHP_EOL;19// expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com...20

    21$image = $client->take($options);22file_put_contents('example.png', $image);23// the screenshot is stored in the example.png file

    1# pip install screenshotone2

    3import shutil4from screenshotone import Client, TakeOptions5

    6# create API client7client = Client('<access key>', '<secret key>')8

    9# set up options10options = (TakeOptions.url('https://screenshotone.com')11    .format("png")12    .viewport_width(1024)13    .viewport_height(768)14    .block_cookie_banners(True)15    .block_chats(True))16

    17# generate the screenshot URL and share it with a user18url = client.generate_take_url(options)19# expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fscreenshotone.com&viewport_width=1024&viewport_height=768&block_cookie_banners=True&block_chats=True&access_key=&signature=6afc9417a523788580fa01a9f668ea82c78a9d2b41441d2a696010bf2743170f20

    21# or render a screenshot and download the image as stream22image = client.take(options)23

    24# store the screenshot the example.png file25with open('example.png', 'wb') as result_file:26    shutil.copyfileobj(image, result_file)

    1# Add this gem to your Gemfile:2# gem 'screenshotone'3

    4# If you don't need to add a signature5client = ScreenshotOne::Client.new('<access key>')6

    7# Or ff you do need to add a signature8client = ScreenshotOne::Client.new('<access key>', '<secret key>')9

    10# You can set any available option, in a camel_case format, for example:11options = ScreenshotOne::TakeOptions.new(url: 'https://example.com').12            full_page(true).13            delay(2).14            geolocation_latitude(48.857648).15            geolocation_longitude(2.294677).16            geolocation_accuracy(50)17

    18# Verify all the parameters are valid (we will validate the parameters that should be19# numeric, booleans or that accept only certain values)20options.valid?21=> true22

    23# To simply get the final url:24client.generate_take_url(options)25=> "https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com..."26

    27# To actually get the image (the response body of a request to the previous url)28client.take(options)29=> "\xFF\xD8\xFF\xE0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xFF\..."

    1// Add the library via nuget using the package manager console: PM> Install-Package ScreenshotOne.dotnetsdk2// Or from the .NET CLI as: dotnet add package ScreenshotOne.dotnetsdk3

    4// And generate a screenshot URL without executing request:5var client = new Client("<access key>", "<secret key>");6var options = TakeOptions.Url("https://www.amazon.com")7  .FullPage(true)8  .Format(Format.PNG)9  .BlockCookieBanners(true);10

    11var url = client.GenerateTakeUrl(options);12// url = https://api.screenshotone.com/take?url=https%3A%2F%2Fwww.amazon.com&full_page=true&format=png&block_cookie_banners=true&access_key=_OzqMIjpCw-ARQ&signature=8a08e62d13a5c3490fda0734b6707791d3decc9ab9ba41e8cc045288a39db50213

    14// Or take a screenshot and save the image in the file:15var client = new Client("<access key>", "<secret key>");16var options = TakeOptions.Url("https://www.google.com")17  .FullPage(true)18  .Format(Format.PNG)19  .BlockCookieBanners(true);20

    21var bytes = await client.Take(options);22

    23File.WriteAllBytes(@"c:\temp\example.png", bytes);

Mike Roberts

Founder, [SpyFu](https://www.spyfu.com/)

> ScreenshotOne is the best product on the market - and that's before you take into account how responsive and easy Dmytro is to work with.

> 

> Any time we've found a rare edge case, it's been resolved in hours.

> 

> Great company, great founder - can't say enough!

Without writing a line of code

No-code Puppeteer is now possible

---------------------------------

As a Puppeteer alternative for screenshots, ScreenshotOne supports all its features and even more. But now you can integrate it with the most popular no-code platforms like Zapier, Airtable, Make and similar.

[](/integrations/zapier/)[](/integrations/airtable/)[](/integrations/make/)[](/integrations/bubble/)[](/integrations/n8n/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/contributors/dmytro-krasun/8
----

Dmytro Krasun

-------------

With more than a decade of experience in software engineering, I share the best practices and solutions you can apply to your problems in the space of headless browsers. You can also find me on [Twitter](https://twitter.com/DmytroKrasun) and [LinkedIn](https://www.linkedin.com/in/dmytrokrasun)

View all Changelog

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [What is a screenshot or HTML rendering API?](/blog/what-is-a-screenshot-or-html-rendering-api/)

A screenshot API or a screenshot as a service is usually a cloud or a remote server service that provides the ability to render any website, HTML, Markdown, or even PDF by making a request to the service, be it over HTTP, TCP, or any other protocol.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Nov 27, 2022

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Heart-touching feedback from Gregory](/blog/heart-touching-feedback-from-gregory/)

Daily and nightly, I work on improving the quality and performance of ScreenshotOne (your friendly screenshot API) and ensuring I help customers solve their problems and prosper.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Nov 20, 2022

•

1 min read

#### [Building a website directory with Next.js, Tailwind CSS, and Prisma](/blog/building-a-website-directory-with-nextjs-tailwind-css-and-prisma/)

See how easy it is to build a website directory with screenshots with Next.js, Tailwind CSS, and Prisma.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Nov 17, 2022

•

14 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to hide chat widgets when taking a screenshot with Puppeteer](/blog/how-to-hide-chat-widgets-when-taking-a-screenshot-with-puppeteer/)

When you want to take chat widgets, there are annoying chat widgets that you would love to hide. It is easy to do.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jul 28, 2022

•

1 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [How to hide cookie banners when taking a screenshot with Puppeteer](/blog/how-to-hide-cookie-banners-when-taking-a-screenshot-with-puppeteer/)

When taking a screenshot, you want to ensure that you take a clean screenshot without cookie banners or cookie consent forms. And in this article, I will share with you how you can do it when using Puppeteer.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Nov 12, 2024

•

11 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [How to fix the "Execution context was destroyed" error when using Puppeteer](/blog/puppeteer-execution-context-was-destroyed-most-likely-because-of-a-navigation/)

Fix the Puppeteer "Execution context was destroyed, most likely because of a navigation" error after click, form submit, redirect, reload, or page.evaluate.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Mar 13, 2026

•

5 min read

#### [A complete guide on how to take full page screenshots with Puppeteer, Playwright or Selenium](/blog/a-complete-guide-on-how-to-take-full-page-screenshots-with-puppeteer-playwright-or-selenium/)

You can take a full page screenshot with Pupeeter by specifying the \`fullPage\` parameter as true when taking a screenshot. But there is a caveat. If a site has lazy-loaded images, they won't be rendered. Let's examine how to fix the issue and trigger lazy image loading with Puppeteer.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Oct 19, 2022

•

7 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to create a site thumbnail with Puppeteer](/blog/how-to-create-a-site-thumbnail-with-puppeteer/)

We can consider the screenshot of URL or HTML as a thumbnail, but I write about the thumbnail of a screenshot. How do you take a screenshot within the defined viewport but with different image width and height? Resize!

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jul 17, 2022

•

3 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Taking screenshots with Puppeteer in GIF, JP2, TIFF, AVIF, HEIF, or SVG format](/blog/taking-screenshots-with-puppeteer-in-gif-jp2-tiff-avif-heif-or-svg-format/)

Puppeteer, by default, supports only four formats for taking screenshots or rendering HTML: PNG, JPEG, WebP, and PDF. But what if you want it to take it in a different format like GIF, JP2, TIFF, AVIF, HEIF, or SVG?

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jul 17, 2022

•

6 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Puppeteer waitUntil: how to wait for page load](/blog/puppeteer-wait-until-the-page-is-ready/)

Join me in exploring how to find the ideal wait time or event of when to take the page screenshot with Puppeteer.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Mar 13, 2026

•

8 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Uploading website screenshots to any S3-compatible storage](/blog/uploading-website-screenshots-to-any-s3-compatible-storage/)

In this note, I share how I take website screenshots or render HTML and upload the resulted images or PDF to any S3-compatible storage like Amazon S3, Cloudflare R2, or Backblaze B2.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jul 12, 2022

•

2 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to render HTML with Puppeteer](/blog/how-to-render-html-with-puppeteer/)

Use Puppeteer or screenshot API to generate the Open Graph protocol images, bills, receipts, or invoices PDF or PNG files from the HTML templates.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Mar 13, 2026

•

3 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/legal-evidence-discovery-snapshots
----

Automate Website Screenshots

1 min read

Legal evidence and discovery snapshots

======================================

Preserve any web page exactly as it appeared, in a court‑ready bundle.

Law firms and compliance teams must preserve web pages exactly as seen at a point‑in‑time (court exhibits, trademark disputes, harassment cases).

A tamper‑proof screenshot + hash + PDF bundle is gold for that use case.

[By the way, in case you need to generate a PDF from a Google Document or Slide, ScreenshotOne has you covered](/blog/google-docs-and-slides/).

When a dispute lands on your desk—trademark infringement, defamation, harassment, false‑advertising—you need proof that can survive cross‑examination. A simple browser “Save as PDF” won’t cut it: fonts reflow, ads change, scripts disappear. What law firms and compliance teams really need is a verifiable, read‑only capture showing the page exactly as the judge or jury would have seen it on that day. [ScreenshotOne’s PDF generation API](/pdf-generation-api/) turns that manual chore into a one‑line call:

    1curl https://api.screenshotone.com/take \2  -d url="https://example.com/" \3  -d format="pdf" \4  -d full_page=true \5  -d access_key=<your access key>

Behind the scenes, ScreenshotOne spins up an isolated browser, renders every pixel—including dynamic content—and packages the result as PDF.

Automate that in your case‑management system and you’ve got a tamper‑proof evidence set—no more frantic “did anyone grab the page before it vanished?” moments, and no awkward questions about authenticity when you introduce Exhibit A.

Shoutout to Dmytro Krasun and his product ScrenshotOne, an excellently built product covering almost all of our use cases.

Most importantly and the reason I'm writing this is he provides a crazy good level of support through his support chat, thanks!

Zawwad Ul Sami

Founder, [MailToon](https://mailtoon.io/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/screenshotone-is-available-as-a-chatgpt-plugin
----

ScreenshotOne is available as a ChatGPT plugin

==============================================

From today, you can render screenshots of any website or even raw HTML in ChatGPT—ScreenshotOne is available as a plugin. But at the moment of writing not available yet, in the official store, but it can be available when you read it.

[Changelog](/changelog/) 2 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

May 13, 2023

I want to share a few details about you can use the plugin and, if you need it, how easily you can add your plugin to the ChatGPT store.

Install the ScreenshotOne Plugin

--------------------------------

I hope that at the moment of reading, you can install it from the official store, but if not, follow the simple instruction:

1.  Put `screenshotone.com` when adding the plugin as an unverified plugin:

2.  Proceed when you are asked to be cautious:

3.  Copy your access key form [the access page](https://dash.screenshotone.com/access):

4.  Make sure that requiring signing request is disabled. Since ChatGPT can’t do it for now:

5.  Enable the plugin:

And we are ready to go. Let’s try it.

Prompts to render screenshots in ChatGPT

----------------------------------------

Once our screenshot API plugin is ready, we are ready to play with it. Let’s try a few prompts and see what happens.

### Render a screenshot of any company in ChatGPT

Render a screenshot of any company without even typing the URL. Look how simple it is now:

> Render a screenshot of the Stripe company homepage.

### Render a screenshot in the dark mode

> Render a screenshot of the Tailwind CSS site in the dark mode.

### Render a screenshot in ChatGPT without cookie banners and ads

> Render a screenshot of Yahoo Finance without ads and cookie banners.

And many more. If you have any ideas for more prompts, please, share at `hey@screenshotone.com`.

How to develop your own plugin

------------------------------

OpenAI [has excellent documentation](https://platform.openai.com/docs/plugins/introduction) with examples of how to do it.

ScreenshotOne already had an OpenAPI specification, so it was easy to do it. But I needed to cut a lot of options to make sure it worked. A lot of options currently frustrate ChatGPT, and a prompt might exceed the token limit since ChatGPT generates the prompt, which includes the OpenAPI schema.

So, in ScreenshotOne’s case, it was easy. I just created the plugin manifest file, which you can find at [screenshotone.com/.well-known/ai-plugin.json](https://screenshotone.com/.well-known/ai-plugin.json).

And I generated a separate specification [api.screenshotone.com/plugin/openapi.yml](https://api.screenshotone.com/plugin/openapi.yml) for the plugin since it is tough to make it work with all the options and features ScreenshotOne provides.

That’s it! You see how simple it is to add it.

Summary

-------

The ChatGPT plugin ecosystem delivers a colossal opportunity for developers and companies to reach new users and enrich the chat experience.

If you have issues with the plugin, please, reach out to `support@screenshotone.com`, or if you have any ideas of how to use the plugin or have ideas for partnerships, please, feel free to share at `hey@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [I migrated to Google Cloud](/changelog/i-migrated-to-google-cloud/)

Google Cloud gives $300 in credits for 3 months for experimenting. And I decided to give it a try, but not because of the free credits.

Read more →

4 min read

#### [Better Markdown output](/changelog/better-markdown-output/)

Markdown output is now cleaner by removing non-content HTML blocks during conversion.

Read more →

1 min read

#### [Improved uploading and error handling to S3-compatible storage](/changelog/improved-storage-upload/)

Today, the new version of ScreenshotOne API was deployed to production that enables a retries mechanism when uploading to an S3 storage and more granular error handling.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/how-stagetimer-automates-og-image-generation
----

How Stagetimer automates Open Graph image generation

====================================================

We would love to share a quick review of ScreenshotOne by Lukas Hermann, a co-founder of Stagetimer on how he uses the API daily to generate screenshots and automate regular tasks associated with screenshots.

[Customer story](/blog/tags/customer-stories/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Lukas Hermann](/contributors/lukas-hermann/)

#### Published on

Mar 5, 2024

Open Graph images

-----------------

A quick reminder or introduction about what is Open Graph image before we dive deeper into how Stagetimer uses ScreenshotOne.

When you share a link on social media platforms like Facebook, LinkedIn, or Twitter, the Open Graph (OG) protocol allows these platforms to display a preview of the content with a title, a description, and, most notably, an image.

The image that is displayed in this preview is known as the Open Graph image.

For example, on Facebook the OG image of [Stagetimer](https://stagetimer.io) looks like:

If you are still curious you can check out more [Open Graph examples](https://opengraphexamples.com/).

How ScreenshotOne helps Stagetimer

----------------------------------

Here is what Lukas Hermann, a co-founder of [Stagetimer](https://stagetimer.io/), shared with us:

“At [Stagetimer](https://stagetimer.io/) we use ScreenshotOne to automatically generate page previews for OpenGraph meta tags. Our customers are professionals in the live video and broadcasting space who often use Discord or Slack as communication platform. We want to make sure the generated previews for our links are useful and make for a polished look and feel.”

“With ScreenshotOne I can add signed links to all my static generated pages with a size of 1200×627, perfect for social. The ScreenshotOne caching policy guarantees the image stays up to date and the signature makes the link temper-save. This means I can generate preview images of every page without the need of a dedicated backend or worker.”

More Examples and Use Cases

---------------------------

You might be also interested in how [Elias Stråvik automates generating landing page feedback](/blog/generating-landing-page-feedback-with-vision/).

ScreenshotOne supports a huge variety of uses including but not only:

*   [Automating screenshots for landing page inpsiration collections](/use-cases/collect-design-inspirations/).

*   [Generating personalized videos](/use-cases/automate-personalized-videos/).

*   [Rendering site thumbnails for search previews](/use-cases/preview-search-results/)

And [many more](/use-cases/).

Read more customer stories

--------------------------

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

[View all posts](/blog/tags/customer-stories/)

#### [How Elias Stråvik uses GPT-4 Vision and Zapier for landing page feedback automation](/blog/generating-landing-page-feedback-with-vision/)

A quick review of ScreenshotOne by Elias Stråvik, a founder of Roast as A Service on how he uses the ScreenshotOne daily to automate regular tasks associated with screenshots.

Read more

#### [Integrating ScreenshotOne into the directory management platform](/blog/makeadir-feedback/)

How and why "Make a Directory" used ScreenshotOne to automate screenshots for directory websites.

Read more

#### [How Typeshare uses ScreenshotOne for image generation](/blog/how-typeshare-uses-screenshotone/)

Typeshare is a digital writing platform designed to enhance the writing experience by offering a suite of tools aimed at reducing common barriers writers face.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/tags/screenshot-rendering
----

Screenshot Rendering

--------------------

Best practices for rendering reliable website screenshots.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

[Screenshot rendering](/blog/tags/screenshot-rendering/) [Playwright guides](/blog/tags/playwright-guides/)

#### [How to Take Full Page Screenshots with Playwright in Python](/blog/playwright-python-full-page-website-screenshots/)

Learn how to capture full page screenshots with Playwright in Python. Master the full\_page parameter, handle infinite scroll pages, lazy-loaded images, and maximum size limits.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 17, 2026

•

4 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/) [Playwright guides](/blog/tags/playwright-guides/)

#### [How to Take Website Screenshots with Playwright in Python](/blog/playwright-python-screenshots/)

A complete guide to taking website screenshots with Playwright in Python. Learn page.screenshot() parameters, async patterns, element screenshots, dark mode, and device emulation.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 16, 2026

•

5 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to Take Bulk Screenshots in Python with a Screenshot API](/blog/bulk-screenshots-python/)

Learn how to automate bulk website screenshots in Python using ScreenshotOne API. Process thousands of URLs efficiently with async requests, rate limiting, and error handling.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 14, 2026

•

3 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/) [Playwright guides](/blog/tags/playwright-guides/)

#### [How to Take Bulk Screenshots with Playwright in Python](/blog/bulk-screenshots-playwright-python/)

Learn how to automate bulk website screenshots with Playwright in Python. Master async batch processing, concurrent screenshots, rate limiting, and error handling for large-scale screenshot automation.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 14, 2026

•

7 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to Take Screenshots with pyppeteer in Python](/blog/pyppeteer-python-screenshots/)

Guide to taking screenshots with pyppeteer in Python. Learn the basics, full page captures, and why you should migrate to Playwright.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jan 19, 2026

•

2 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Website Screenshots with Selenium in Python](/blog/selenium-python-screenshots/)

Complete guide to taking screenshots with Selenium in Python. Learn save\_screenshot(), element screenshots, full page workarounds, and headless mode setup.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 11, 2026

•

5 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take bulk screenshots with Puppeteer](/blog/bulk-screenshots-with-puppeteer/)

Learn how to take screenshots of multiple URLs with Puppeteer, including concurrency management, error handling, retries, and proxy support.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Dec 16, 2025

•

8 min read

[Playwright guides](/blog/tags/playwright-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to render screenshots with Playwright](/blog/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](/contributors/dmytro-krasun/)

Published on

Apr 29, 2025

•

10 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/automated-web-audits-fonts
----

Automate Website Screenshots

1 min read

Automated Web Audits with Font Analysis

=======================================

With our font detection API generate comprehensive typography reports to optimize websites for aesthetics and performance.

Automate web audits with font analysis with [ScreenshotOne font detection API](/font-detection-api/) to provide comprehensive reports on typography use, helping users optimize their websites for both aesthetics and performance.

Complete Website Analysis

-------------------------

Modern web audits need to cover all aspects of a website, including typography. Font choices impact page load times, readability, and overall user experience. ScreenshotOne’s font detection API enables audit tools to automatically analyze typography usage across entire websites.

Typography Performance Insights

-------------------------------

The API helps identify potential performance issues related to font loading, such as the use of too many font families or weights. It also provides insights into whether fonts are properly optimized and loaded efficiently, contributing to better Core Web Vitals scores.

Check out [our guide on how to detect website fonts](/docs/guides/how-to-detect-website-fonts/) for more details.

Comprehensive Reporting

-----------------------

Web audit tools integrated with ScreenshotOne can generate detailed typography reports showing font usage patterns, potential issues, and recommendations for improvement. This saves development teams significant time in manual font auditing and provides actionable insights for optimization.

That was a lot of work to get rendering screenshots work right (there's a lot of edge cases in my case) and I just opted for ScreenshotOne because of the pricing and great API.

Bjarn Bronsveld

Founder, [Spectate](https://spectate.net/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

### Personalized Onboarding

Personalize onboarding by analyzing a customer's website visually and using screenshots throughout the setup flow.

[Read more →](/use-cases/personalized-onboarding/)

### Design Tools Font Detection

Use our font detection API to help designers identify and analyze typography on any website.

[Read more →](/use-cases/design-apps-font-detection/)

### Font Trends Analysis

Use our font detection API to provide insights into typography trends of top-ranking websites across various industries.

[Read more →](/use-cases/font-trends/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/playwright-execution-context-was-destroyed-most-likely-because-of-a-navigation
----

Playwright "Execution context was destroyed": how to fix navigation and page.evaluate errors

============================================================================================

Fix the Playwright "Execution context was destroyed, most likely because of a navigation" error after click, form submit, redirect, reload, or page.evaluate.

[Blog post](/blog/) 4 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Mar 13, 2026

#### Tags

[Playwright guides](/blog/tags/playwright-guides/)

Short answer

------------

The core problem is the same as in Puppeteer: your code starts navigation and then tries to use the old page context after the browser already replaced it.

In Playwright, prefer `page.waitForURL()` over `page.waitForNavigation()`, because `page.waitForNavigation()` is deprecated and inherently racy.

    1await Promise.all([2    page.waitForURL("**/dashboard"),3    page.getByRole("link", { name: "Dashboard" }).click(),4]);

If the action does not navigate, do not wait for a URL change. Wait for a locator, response, or another concrete signal instead.

If you are using Puppeteer rather than Playwright, follow the matching guide on [how to fix this error in Puppeteer](/blog/puppeteer-execution-context-was-destroyed-most-likely-because-of-a-navigation/).

Why this error happens

----------------------

Playwright runs `page.evaluate()` and related calls inside the current page execution context. When the page navigates, reloads, redirects, or replaces the frame, the old execution context is destroyed and a new one is created for the new document.

In browser internals, an execution context is the JavaScript environment bound to a specific document, frame, or isolated world. When you call `page.evaluate()`, Playwright sends your function to the browser and asks it to run in that exact context. This is not the same thing as Playwright’s `BrowserContext`, which is an isolated browser session with its own cookies, permissions, and storage.

That distinction matters because the execution context belongs to the current document. After a redirect or reload, any pending `page.evaluate()` call, element handle, or JS handle from the previous document can become invalid immediately.

Typical triggers are:

*   clicking a link that opens the next page;

*   submitting a form;

*   calling `window.location = "..."` or `location.reload()`;

*   unknown page scripts, third-party widgets, consent scripts, or tag manager code that trigger a redirect for you;

*   redirects after login or checkout;

*   evaluating JavaScript while the page is in the middle of navigation.

The error often appears as one of these messages:

*   `Execution context was destroyed, most likely because of a navigation`

*   `page.evaluate: Execution context was destroyed, most likely because of a navigation`

Fix it after click, submit, or redirect

---------------------------------------

When an action triggers navigation, wait for the URL change at the same time as the action:

    1await Promise.all([2    page.waitForURL("**/account", { timeout: 30_000 }),3    page.getByRole("link", { name: "Account" }).click(),4]);

For a form submit:

    1await page.getByLabel("Email").fill("john@example.com");2await page.getByLabel("Password").fill("secret");3

    4await Promise.all([5    page.waitForURL("**/dashboard"),6    page.getByRole("button", { name: "Sign in" }).click(),7]);

For script-triggered navigation:

    1const currentUrl = page.url();2

    3await Promise.all([4    page.waitForURL((url) => url.toString() !== currentUrl),5    page.evaluate(() => {6        window.location.href = "https://example.com/dashboard";7    }),8]);

If you `await` the click first and only then start waiting for the URL, you can miss the transition and end up with the same race condition.

About waitForNavigation in Playwright

-------------------------------------

Playwright still has `page.waitForNavigation()`, but it is deprecated. The Playwright docs explicitly recommend `page.waitForURL()` instead because `waitForNavigation()` is inherently racy.

That is one of the main differences from Puppeteer guidance. The root cause is the same, but the Playwright-native fix should use `waitForURL()`, locators, and Playwright’s built-in auto-waiting model.

Fix page.evaluate errors

------------------------

The `page.evaluate` variant is a common version of this issue:

    1await page.getByRole("link", { name: "Pricing" }).click();2await page.evaluate(() => document.title);

If the click starts navigation, the `evaluate` call can target a context that no longer exists.

Wait for the new page first:

    1await Promise.all([2    page.waitForURL("**/pricing"),3    page.getByRole("link", { name: "Pricing" }).click(),4]);5

    6const title = await page.evaluate(() => document.title);7console.log(title);

The same applies to element handles and JS handles created before navigation. Reacquire them on the new page instead of reusing old handles from the previous document.

In some flows, `page.evaluate()` is only a best-effort step, such as removing a popup, collecting analytics data, or reading a non-critical value. In those cases, it can be acceptable to ignore this specific failure and continue:

    1try {2    await page.evaluate(() => {3        document.querySelector(".popup")?.remove();4    });5} catch (error) {6    // Ignore execution context errors if this step is optional.7}

This can be useful when an unknown inline script, A/B test, consent banner, or third-party redirect interrupts your automation unexpectedly.

When waitForURL is the wrong fix

--------------------------------

Not every page update changes the URL.

If the site updates content with client-side JavaScript and stays on the same page, `page.waitForURL()` is the wrong tool. Use a more specific wait instead.

Wait for a locator:

    1await page.getByRole("button", { name: "Load results" }).click();2await page.locator(".results-loaded").waitFor({3    state: "visible",4    timeout: 30_000,5});

Wait for a response:

    1await page.getByRole("button", { name: "Refresh data" }).click();2await page.waitForResponse((response) => {3    return response.url().includes("/api/results") && response.ok();4});

Wait for a page condition:

    1await page.getByRole("button", { name: "Show price" }).click();2await page.waitForFunction(() => {3    return document.querySelector(".price")?.textContent?.trim().length > 0;4});

Playwright already auto-waits for many actions through locators, but auto-waiting does not solve every navigation race or every asynchronous page update. You still need the right wait primitive for the event you actually expect.

Common mistakes

---------------

*   Using `page.waitForNavigation()` in new Playwright code instead of `page.waitForURL()`.

*   Waiting for the URL only after the click already happened.

*   Assuming Playwright auto-waiting will handle redirects triggered by custom scripts or delayed navigation.

*   Calling `page.evaluate()` or reusing stale handles after reload or redirect.

*   Waiting for a URL change when the page never actually changes URL.

Related reading

---------------

If you need a broader walkthrough of Playwright’s waiting model, auto-waiting, and screenshot flows, follow [how to render screenshots with Playwright](/blog/how-to-render-screenshots-with-playwright/).

If you are working with Puppeteer instead, the matching article is [how to fix “Execution context was destroyed” in Puppeteer](/blog/puppeteer-execution-context-was-destroyed-most-likely-because-of-a-navigation/).

Or use an API

-------------

If this error shows up in a screenshot rendering pipeline, all this synchronization is already built into [our ScreenshotOne URL to Image API](/).

[](/)

You can [start for free](/).

Read more Playwright guides

---------------------------

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

[View all posts](/blog/tags/playwright-guides/)

#### [How to Take Full Page Screenshots with Playwright in Python](/blog/playwright-python-full-page-website-screenshots/)

Learn how to capture full page screenshots with Playwright in Python. Master the full\_page parameter, handle infinite scroll pages, lazy-loaded images, and maximum size limits.

Read more

#### [How to Take Website Screenshots with Playwright in Python](/blog/playwright-python-screenshots/)

A complete guide to taking website screenshots with Playwright in Python. Learn page.screenshot() parameters, async patterns, element screenshots, dark mode, and device emulation.

Read more

#### [How to Take Bulk Screenshots with Playwright in Python](/blog/bulk-screenshots-playwright-python/)

Learn how to automate bulk website screenshots with Playwright in Python. Master async batch processing, concurrent screenshots, rate limiting, and error handling for large-scale screenshot automation.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/open-graph-metadata
----

Extract Open Graph metadata while rendering screenshots

=======================================================

From today, you can get parsed Open Graph metadata and screenshots in one API request.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

May 31, 2024

You can do that with the JSON response type in one simple API request:

    1https://api.screenshotone.com/take?access_key=<YOUR ACCESS KEY>&url=https://screenshotone.com&metadata_open_graph=true&response_type=json&cache=true

And get a result like:

Or you can extract it from the header `X-ScreenshotOne-Open-Graph`.

Enjoy!

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Added a "copy page" button in documentation](/changelog/copy-page-button-in-docs/)

You can now copy the page content as Markdown for LLMs and more.

Read more →

1 min read

#### [Improved errors](/changelog/improved-errors/)

Now, errors will have relevant documentation links. It will be also possible to see why some requests failed in the dashboard and get recommendations on how to address the issue.

Read more →

1 min read

#### [ScreenshotOne Playground has been improved](/changelog/improved-playground-synchronized-all-options/)

A few important updates in ScreenshotOne Playground.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/guides/authenticated-pages
----

[Skip to content](#_top)

Screenshot authenticated pages

==============================

Copy page

Note

If you screenshot your websites or websites of your customers and you have a problem with Cloudflare challenges, follow our guide on [how to unblock ScreenshotOne in Cloudflare](/docs/guides/unblock-cloudflare-challenges/) (if relevant).

There is a few methods to screenshot authenticated pages:

1.  [If the website is yours or it allows to send a custom HTTP header with the authentication token when rendering the page.](#1-custom-http-header)

2.  [If the website is yours, allow to bypass authentication for ScreenshotOne servers.](#2-allow-bypassing-authentication-for-screenshotone-servers)

3.  [Using cookies.](#3-using-cookies)

1\. Custom HTTP header

----------------------

If the website is yours or it allows to send a custom HTTP header with the authentication token when rendering the page, you can use the following method:

    1https://api.screenshotone.com/take?access_key=<your access key>&url=https://example.com&headers=Authorization: Bearer <your authentication token>

Or:

    1https://api.screenshotone.com/take?access_key=<your access key>&url=https://example.com&authorization=Bearer <your authentication token>

Support the header name is different, e.g. `X-API-Key`, you can use the following syntax:

    1https://api.screenshotone.com/take?access_key=<your access key>&url=https://example.com&headers=X-API-Key: <your authentication token>

2\. Allow bypassing authentication for ScreenshotOne servers

------------------------------------------------------------

This method is complicated and requires for you to configure your firewall to [allow the ScreenshotOne servers](/docs/ip-ranges/) to access the website.

3\. Using Cookies

-----------------

If the website you are trying to screenshot uses cookies to authenticate users and doesn’t block automation or it is yours, you can use cookies with the ScreenshotOne API to render pages behind authentication.

I will use [ScreenshotOne’s Dashboard](https://dash.screenshotone.com/) as an example. Suppose, I want screenshot the dashboard page (`https://dash.screenshotone.com/dashboard`):

If I screenshot it straight away like:

    1https://api.screenshotone.com/take?access_key=<your access key>&url=https://dash.screenshotone.com/dashboard

I will get the following result:

It is an authenticated form.

Let’s check cookies for the page, after I logged in:

Make sure to copy all the cookie parameters, including the `domain`, `path` and other parameters:

    1__Secure-better-auth.session_token=ZFmIsN7BVPU0Fzzd9aJ7lZU4TLSvu2L2.buMSGkHDIxhT%2B7YIl6tS82eGGLAAeRzk7FMp1YiTtK8%3D2domain=dash.screenshotone.com3path=/4HttpOnly5Secure6Lax

Then format it as required by the ScreenshotOne API:

    1__Secure-better-auth.session_token=ZFmIsN7BVPU0Fzzd9aJ7lZU4TLSvu2L2.buMSGkHDIxhT%2B7YIl6tS82eGGLAAeRzk7FMp1YiTtK8%3D; domain=dash.screenshotone.com; path=/; HttpOnly; Secure; Lax

And then try to screenshot the page again but with the cookies now:

    1https://api.screenshotone.com/take?access_key=<your access key>&url=https://dash.screenshotone.com/dashboard&cookies=__Secure-better-auth.session_token=ZFmIsN7BVPU0Fzzd9aJ7lZU4TLSvu2L2.buMSGkHDIxhT%2B7YIl6tS82eGGLAAeRzk7FMp1YiTtK8%3D; domain=dash.screenshotone.com; path=/; HttpOnly; Secure; Lax

The result will be as expected:

One pitfall is that likely you will need to write your own code to sign in to the website and get the cookies.

Support

-------

If you need help with screenshotting authenticated pages and any of the above methods does not work for you, please, contact us at `support@screenshotone.com`.

----
url: https://screenshotone.com/integrations/code
----

Integrations

1 min read

SDK and Code Examples

=====================

Use the SDKs and code examples to take screenshots in your own code.

Code API

Resources

---------

*   [Documentation](https://screenshotone.com/docs/code-examples/)

That was a lot of work to get rendering screenshots work right (there's a lot of edge cases in my case) and I just opted for ScreenshotOne because of the pricing and great API.

Bjarn Bronsveld

Founder, [Spectate](https://spectate.net/)

Check more Integrations

-----------------------

No-code tools, AI, code libraries, and more.

[Check more Integrations](/integrations/)

No-Code Automation

### Make

Use ScreenshotOne with Make to automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

[Read more →](/integrations/make/)

No-Code Automation

### Clay

Generate website screenshots inside Clay to qualify leads, assess content, and enrich rows with visual context automatically.

[Read more →](/integrations/clay/)

No-Code Automation

### n8n

Use ScreenshotOne in n8n workflows to render website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

[Read more →](/integrations/n8n/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/4
----

Automate Website Screenshots

----------------------------

Guides, Product Updates, and Helpful Resources from ScreenshotOne.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [How and why Saaspo uses ScreenshotOne to automate screenshot generation](/blog/saaspo/)

Saaspo chose ScreenshotOne to automate tedious and boring work to generate pixel-perfect screenshots for their platform. Why?

Written by

[Andy Hooke](/contributors/andy-hooke/), [Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Nov 4, 2025

•

1 min read

#### [ScreenshotOne October 2025 updates](/blog/screenshotone-october-2025-updates/)

Metadata content format, upgraded dashboard, improved webhooks, updated Go SDK, Make conference, and AWS disruption lessons.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Nov 1, 2025

•

1 min read

#### [Lessons learned from the AWS disruption](/blog/lessons-from-the-aws-us-east-1-disruption/)

Sharing thoughts and lessons learned from the AWS (us-east-1) disruption, including impact on ScreenshotOne.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Oct 30, 2025

•

3 min read

#### [ScreenshotOne made it to the official Make conference](/blog/make-conference/)

One of our friends noticed ScreenshotOne at the official Make conference

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Oct 16, 2025

•

1 min read

#### [ScreenshotOne August 2025 updates](/blog/screenshotone-august-2025-updates/)

Playground presets, screenshot URL in webhooks, improved full‑page rendering, and ownership change for subscribed orgs.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Sep 1, 2025

•

1 min read

#### [ScreenshotOne is available on Ravenala](/blog/ravenala/)

ScreenshotOne is available on Ravenala, a new AI-powered platform for creating and managing content.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Aug 3, 2025

•

1 min read

#### [Is it legal to screenshot websites?](/blog/screenshots-and-law/)

A few thoughts on the topic of screenshots and law.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jul 22, 2025

•

3 min read

[Engineering](/blog/tags/engineering/)

#### [A four day hiking trip into ScreenshotOne infrastructure to solve an issue](/blog/debugging-and-fixing-a-tricky-issue/)

A short story about how I debugged and fixed an uptime issue.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jul 21, 2025

•

3 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/website-archiving-for-compliance
----

Automate Website Screenshots

1 min read

Website Archiving for Compliance

================================

Ensure regulatory compliance through periodic website archiving.

For companies in industries subject to regulatory compliance, maintaining an archive of website versions is a necessity. This requirement can be efficiently addressed by leveraging a screenshot API to periodically capture website states, ensuring compliance with regulations that mandate digital record-keeping.

Why ScreenshotOne API?

----------------------

ScreenshotOne API facilitates the automated capture of website snapshots at scheduled intervals, creating a timestamped archive that can be used to demonstrate compliance with regulatory requirements. This approach is particularly valuable for small companies that may not have the resources for extensive in-house development of compliance solutions.

Value and Time Savings

----------------------

By using ScreenshotOne API, companies can significantly reduce the workload and potential for human error associated with manual archiving processes. It offers a straightforward, reliable, and cost-effective solution for regulatory compliance, allowing businesses to focus on their core activities rather than the complexities of compliance and website archiving.

We needed to build a side product, fast, we signed up and within minutes we were set up and had pulled over 400 picture-perfect screenshots for use in a new directory tool we were launching.

Alex Rainey

Founder, [My AskAI](https://myaskai.com/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/openclaw
----

[What's new API error insights API error insights in the dashboard](/changelog/error-metrics/)

Website Screenshots for OpenClaw

================================

ScreenshotOne helps you automate website screenshots in OpenClaw workflows for monitoring, checks, and reports.

[Get started for free →](https://dash.screenshotone.com/sign-up)

> ScreenshotOne is the best product on the market - and that's before you take into account how responsive and easy Dmytro is to work with.

> 

> Any time we've found a rare edge case, it's been resolved in hours.

> 

> Great company, great founder - can't say enough!

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/tools/scrolling-website-screenshot
----

Make scrolling screenshots

--------------------------

Render scrolling screenshots website online for free and without registration.

[Tools](/tools/) Free Scrolling Website Screenshots

Your website URL

Block banners

Render clean screenshots—block pop-ups, cookie and GDPR banners

Block ads

Remove ads from the website before rendering

Use cache

Speed up rendering of already rendered websites

Viewport width

Viewport height

Render

Screenshot Preview

If you need to automate website screenshot rendering or integrate screenshotting into your application or SaaS, please, check out [the best screenshot API—ScreenshotOne](/).  

Check out more [screenshot tools](/tools/).

Frequently Asked Questions

--------------------------

Discover quick and comprehensive answers to common questions about our platform, services, and features.

What is this scrolling website screenshotter tool about?

The scrolling website screenshot taker is a free tool by ScreenshotOne that captures scrolling screenshots online. You can get any scrolling screenshot without signing up and hassle.

Why is it free to render scrolling screenshots?

It is not free to run that tool. But the tool is built for demonstration purposes to see what's possible to do with ScreenshotOne. The main audience for ScreenshotOne is developers who seek a screenshot API that can automate website screenshotting.

What is ScreenshotOne?

ScreenshotOne is one of the best screenshot APIs in the market which allows you to automate website screenshots fast and renders them with good enough quality.

Integrate today

Automate screenshot rendering with the language you love

--------------------------------------------------------

Send simple HTTP requests or use native libraries for your language of choice.

Java Go Node.js PHP Python Ruby C# (.NET)

    1// add com.screenshotone.jsdk:screenshotone-api-jsdk:[1.0.0,2.0.0)2// to your `pom.xml` or `build.gradle`3

    4import com.screenshotone.jsdk.Client;5import com.screenshotone.jsdk.TakeOptions;6

    7import java.io.File;8import java.nio.file.Files;9

    10public class App {11    public static void main(String[] args) throws Exception {12        final Client client = Client.withKeys("<access key>", "<secret key>");13        TakeOptions takeOptions = TakeOptions.url("https://example.com")14                .fullPage(true)15                .deviceScaleFactor(1)16                .viewportHeight(1200)17                .viewportWidth(1200)18                .format("png")19                .omitBackground(true);20        final String url = client.generateTakeUrl(takeOptions);21

    22        System.out.println(url);23        // Output: https://api.screenshotone.com/take?url=...24

    25        // or download the screenshot26        final byte[] image = client.take(takeOptions);27

    28        Files.write(new File("./example.png").toPath(), image);29        // the screenshot is stored in the example.png file30    }31}

    1// go get github.com/screenshotone/gosdk2

    3import screenshots "github.com/screenshotone/gosdk"4

    5client, err := screenshots.NewClient("<access key>", "<secret key>")6// check err7

    8options := screenshots.NewTakeOptions("https://example.com").9    Format("png").10    FullPage(true).11    DeviceScaleFactor(2).12    BlockAds(true).13    BlockTrackers(true)14

    15u, err := client.GenerateTakeURL(options)16// check err17

    18fmt.Println(u.String())19// Output: https://api.screenshotone.com/take?url=...20

    21// or download the screenshot22image, err := client.Take(context.TODO(), options)23// check err24

    25defer image.Close()26out, err := os.Create("example.png")27// check err28

    29defer out.Close()30io.Copy(out, image)31// the screenshot is stored in the example.png file

    1// $ npm install screenshotone-api-sdk --save2

    3import * as fs from 'fs';4import * as screenshotone from 'screenshotone-api-sdk';5

    6// create API client7const client = new screenshotone.Client("<access key>", "<secret key>");8

    9// set up options10const options = screenshotone.TakeOptions11    .url("https://example.com")12    .delay(3)13    .blockAds(true);14

    15// generate URL16const url = client.generateTakeURL(options);17console.log(url);18// expected output: https://api.screenshotone.com/take?url=...19

    20// or download the screenshot21const imageBlob = await client.take(options);22const buffer = Buffer.from(await imageBlob.arrayBuffer());23fs.writeFileSync("example.png", buffer)24// the screenshot is stored in the example.png file

    1<?php2

    3// composer require screenshotone/sdk:^1.04

    5use ScreenshotOneSdkClient;6use ScreenshotOneSdkTakeOptions;7

    8$client = new Client("<access key>", "<secret key>");9

    10$options = TakeOptions::url("https://example.com")11    ->fullPage(true)12    ->delay(2)13    ->geolocationLatitude(48.857648)14    ->geolocationLongitude(2.294677)15    ->geolocationAccuracy(50);16

    17$url = $client->generateTakeUrl($options);18echo $url.PHP_EOL;19// expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com...20

    21$image = $client->take($options);22file_put_contents('example.png', $image);23// the screenshot is stored in the example.png file

    1# pip install screenshotone2

    3import shutil4from screenshotone import Client, TakeOptions5

    6# create API client7client = Client('<access key>', '<secret key>')8

    9# set up options10options = (TakeOptions.url('https://screenshotone.com')11    .format("png")12    .viewport_width(1024)13    .viewport_height(768)14    .block_cookie_banners(True)15    .block_chats(True))16

    17# generate the screenshot URL and share it with a user18url = client.generate_take_url(options)19# expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fscreenshotone.com&viewport_width=1024&viewport_height=768&block_cookie_banners=True&block_chats=True&access_key=&signature=6afc9417a523788580fa01a9f668ea82c78a9d2b41441d2a696010bf2743170f20

    21# or render a screenshot and download the image as stream22image = client.take(options)23

    24# store the screenshot the example.png file25with open('example.png', 'wb') as result_file:26    shutil.copyfileobj(image, result_file)

    1# Add this gem to your Gemfile:2# gem 'screenshotone'3

    4# If you don't need to add a signature5client = ScreenshotOne::Client.new('<access key>')6

    7# Or ff you do need to add a signature8client = ScreenshotOne::Client.new('<access key>', '<secret key>')9

    10# You can set any available option, in a camel_case format, for example:11options = ScreenshotOne::TakeOptions.new(url: 'https://example.com').12            full_page(true).13            delay(2).14            geolocation_latitude(48.857648).15            geolocation_longitude(2.294677).16            geolocation_accuracy(50)17

    18# Verify all the parameters are valid (we will validate the parameters that should be19# numeric, booleans or that accept only certain values)20options.valid?21=> true22

    23# To simply get the final url:24client.generate_take_url(options)25=> "https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com..."26

    27# To actually get the image (the response body of a request to the previous url)28client.take(options)29=> "\xFF\xD8\xFF\xE0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xFF\..."

    1// Add the library via nuget using the package manager console: PM> Install-Package ScreenshotOne.dotnetsdk2// Or from the .NET CLI as: dotnet add package ScreenshotOne.dotnetsdk3

    4// And generate a screenshot URL without executing request:5var client = new Client("<access key>", "<secret key>");6var options = TakeOptions.Url("https://www.amazon.com")7  .FullPage(true)8  .Format(Format.PNG)9  .BlockCookieBanners(true);10

    11var url = client.GenerateTakeUrl(options);12// url = https://api.screenshotone.com/take?url=https%3A%2F%2Fwww.amazon.com&full_page=true&format=png&block_cookie_banners=true&access_key=_OzqMIjpCw-ARQ&signature=8a08e62d13a5c3490fda0734b6707791d3decc9ab9ba41e8cc045288a39db50213

    14// Or take a screenshot and save the image in the file:15var client = new Client("<access key>", "<secret key>");16var options = TakeOptions.Url("https://www.google.com")17  .FullPage(true)18  .Format(Format.PNG)19  .BlockCookieBanners(true);20

    21var bytes = await client.Take(options);22

    23File.WriteAllBytes(@"c:\temp\example.png", bytes);

Mike Roberts

Founder, [SpyFu](https://www.spyfu.com/)

> ScreenshotOne is the best product on the market - and that's before you take into account how responsive and easy Dmytro is to work with.

> 

> Any time we've found a rare edge case, it's been resolved in hours.

> 

> Great company, great founder - can't say enough!

Without writing a line of code

No-code integrations

--------------------

Quickly render website screenshots with Zapier, Airtable, Make and other popular no-code platforms of your choice.

[](/integrations/zapier/)[](/integrations/airtable/)[](/integrations/make/)[](/integrations/bubble/)[](/integrations/n8n/)

Read

Lessons from running screenshot rendering infrastructure

--------------------------------------------------------

Practical guides and real updates based on our experience operating rendering infrastructure at production scale.

[Playwright guides](/blog/tags/playwright-guides/)

#### [Playwright "Execution context was destroyed": how to fix navigation and page.evaluate errors](/blog/playwright-execution-context-was-destroyed-most-likely-because-of-a-navigation/)

Fix the Playwright "Execution context was destroyed, most likely because of a navigation" error after click, form submit, redirect, reload, or page.evaluate.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 13, 2026

•

4 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [page.waitForTimeout is not a function in Puppeteer](/blog/page-waitfortimeout-is-not-a-function-in-puppeteer/)

Puppeteer removed page.waitForTimeout(). Learn why the error happens and which modern alternatives to use instead.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 13, 2026

•

2 min read

#### [OpenClaw with Playwright or Puppeteer: how to install browser support](/blog/openclaw-playwright-puppeteer/)

A practical guide to OpenClaw browser automation, why Playwright is the documented path, where Puppeteer fits, how to make screenshots, and when ScreenshotOne is the better choice for screenshot-only flows.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 12, 2026

•

6 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/marketing-content-creation
----

Automate Website Screenshots

1 min read

Marketing Content Creation

==========================

Capture dynamic web content for marketing materials.

Creating fresh and engaging content is a constant challenge in the marketing industry. Utilizing a website screenshot API like ScreenshotOne offers a seamless solution for capturing dynamic web content for use in marketing materials, social media posts, and competitor analysis reports.

Why ScreenshotOne API?

----------------------

ScreenshotOne API simplifies the process of generating high-quality screenshots of websites and web applications. It’s invaluable for marketing teams at small companies who need to gather and present web content in their campaigns swiftly. The API provides an efficient way to capture real-time website changes, promotions, and more, without the need for manual screenshots or in-house development of similar tools.

Value and Time Savings

----------------------

By integrating ScreenshotOne API, companies save significant time and resources. Developing a similar solution in-house requires substantial investment in development and maintenance. In contrast, ScreenshotOne API offers a ready-to-use solution that’s both cost-effective and reliable, enabling marketing teams to focus on creating compelling content rather than dealing with technical challenges.

ScreenshotOne is a really helpful service provider. All that I need for my work is combined here.

Service is comfortable, fast, and consistent. It has a nice support service that always stays active to problems of users and has an immediate response time.

I really appreciate and recommend ScreenshotOne to everyone.

Alexandr Bezhan

Chief Product Officer, [AMS Pilot](https://www.amspilot.com/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/contributors/sukh
----

Sukh

----

Today Sukh is building [an SEO platform for B2B companies](https://engyne.ai/). Previously: IBM, Apple. You can also find him on [Twitter](https://twitter.com/thisissukh_).

View all Changelog

#### [How to build a Programmatic SEO site with automated website screenshots using ScreenshotOne, Airtable, and Launchman](/blog/how-to-build-a-programmatic-seo-site-with-automated-website-screenshots-using-screenshotone-airtable-and-launchman/)

Programmatic SEO is a great growth hacking strategy where you create a large number of content pages that rank for long-tailed keywords on Google.

Written by

[Sukh](/contributors/sukh/)

Published on

Jan 10, 2023

•

3 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/integrations/viasocket
----

Integrations

1 min read

viaSocket

=========

Automate website screenshots, animated scrolling captures, and visual documentation workflows with ScreenshotOne and viaSocket.

No-Code Automation

[viaSocket](https://viasocket.com/) is a powerful automation platform that connects thousands of apps to build workflows without writing code. With viaSocket, you can create automated processes that integrate your favorite tools in minutes.

[](https://viasocket.com/)

Integration with [ScreenshotOne](/) lets you automatically capture high-quality website screenshots and animated scrolling videos as part of your automation workflows—perfect for reporting, monitoring, documentation, and any process where visual captures matter.

Available Actions

-----------------

*   **Capture Screenshot** - Capture a webpage and return a downloadable image or document in the chosen format.

*   **Animated Website Screenshot** - Capture a webpage as an animated video or a scrolling GIF/MP4.

Use Cases

---------

*   Generate detailed reports and dashboards from captured content

*   Track project progress through visual documentation

*   Automate notifications based on webpage changes

*   Collaborate on content management across teams

Resources

---------

*   [ScreenshotOne on viaSocket](https://viasocket.com/integrations/screenshotone)

*   [Automated Website Screenshot Monitoring Using ScreenshotOne and viaSocket](https://viasocket.com/blog/automated-website-screenshot-monitoring-using-screenshotone-and-viasocket/)

*   [Learn more about the viaSocket integration in our blog](https://screenshotone.com/blog/screenshotone-and-viasocket-integration/)

I appreciate the fast customer support. Building the product, doing marketing is hard enough. But Dmytro still manages to solve my problems fast. Thank you!

Dan Kulkov

Co-Founder, [FounderPal](https://founderpal.ai/)

Check more Integrations

-----------------------

No-code tools, AI, code libraries, and more.

[Check more Integrations](/integrations/)

Code API

### SDK and Code Examples

Use the SDKs and code examples to take screenshots in your own code.

[Read more →](/integrations/code/)

No-Code Automation

### Make

Use ScreenshotOne with Make to automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

[Read more →](/integrations/make/)

No-Code Automation

### Clay

Generate website screenshots inside Clay to qualify leads, assess content, and enrich rows with visual context automatically.

[Read more →](/integrations/clay/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/blast-banners
----

Blast Banners with ScreenshotOne

================================

A funny game built on top of ScreenshotOne API.

[Blog post](/blog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Oct 29, 2024

[Blast Banners](https://blastbanners.com) is a game in which you are on a mission to destroy banners on websites as fast as possible!

Rumors have it that the game was so annoying that hardly anybody could finish it.

 Sorry, your browser doesn't support embedded videos.

The game is built with [Next.js](https://nextjs.org), [Tailwind CSS](https://tailwindcss.com), and [shadcn/ui](https://ui.shadcn.com), deployed on [Hetzner](https://www.hetzner.com) with [Kamal](https://kamal-deploy.org/).

It uses [ScreenshotOne API](https://screenshotone.com) to render screenshots of the websites. It is open source and you can find the code on [GitHub](https://github.com/screenshotone/blastbanners).

Enjoy the game!

Read more posts

---------------

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

[View all posts](/blog/)

#### [Unveil the Power of Automation with ScreenshotOne and Zapier](/blog/unveil-the-power-of-automation-with-screenshotone-and-zapier/)

I am thrilled to announce an exciting update for the ScreenshotOne users – the much-anticipated integration of ScreenshotOne with Zapier. This powerful combination is here to enhance your automation journey and expand your workflow capabilities to new heights.

Read more

#### [A complete guide on how to take full page screenshots with Puppeteer, Playwright or Selenium](/blog/a-complete-guide-on-how-to-take-full-page-screenshots-with-puppeteer-playwright-or-selenium/)

You can take a full page screenshot with Pupeeter by specifying the \`fullPage\` parameter as true when taking a screenshot. But there is a caveat. If a site has lazy-loaded images, they won't be rendered. Let's examine how to fix the issue and trigger lazy image loading with Puppeteer.

Read more

#### [What is OpenClaw and how can it help?](/blog/openclaw/)

A short practical introduction to OpenClaw, what it is good at, and why it is useful if you want a proactive AI assistant that lives in your chat apps.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/detect-any-website-fonts-with-a-screenshotone-api
----

Detect any website fonts with a ScreenshotOne API

=================================================

Now you can detect fonts used by any website with ScreenshotOne API in just one simple API call.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Nov 30, 2025

The feature was requested by one of our customers but never was urgent for them. Now, it is available for everybody.

Font Detection API

------------------

We added a new option to the ScreenshotOne API to detect fonts used by any website ([a font detection API](/font-detection-api/)):

[](/font-detection-api/)

Yes, it is as simple as that.

[Read more about the feature and on how to detect fonts used by any website in the our documentation](/docs/guides/how-to-detect-website-fonts/).

Support

-------

In case you have any questions or feedback, please, feel free to reach out at `support@screenshotone.com` and we will be happy to help.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Set locale and language of the browser](/changelog/language-and-locale/)

A new version of the ScreenshotOne API has been just deployed. It allows you to set both locale and language of the browser when rendering screenshots with one simple option.

Read more →

1 min read

#### [ScreenshotOne Playground has been improved](/changelog/improved-playground-synchronized-all-options/)

A few important updates in ScreenshotOne Playground.

Read more →

1 min read

#### [I migrated to Google Cloud](/changelog/i-migrated-to-google-cloud/)

Google Cloud gives $300 in credits for 3 months for experimenting. And I decided to give it a try, but not because of the free credits.

Read more →

4 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/roadmap
----

Updated on Jan 15, 2024

Roadmap

=======

It was decided to share the roadmap publicly to update ScreenshotOne customers and fans about the product plans. And to allow customers to see and influence the product development.

The roadmap is more or less stable, and the development plan is executed based on it, but it might be changed since ScreenshotOne handles customer requests dynamically. And if there is more demand for some features, they can be prioritized.

2024

----

### Custom domains

A rarely requested feature, but still important, is to allow rendering screenshots under custom domains. It is under consideration.

### Open-source

ScreenshotOne is based on top of the best open-source libraries, and there is a desire to contribute back to the open-source community.

Both by sponsoring projects and by opening the best parts of the code, which will liberate screenshot rendering.

2023

----

### Supercharged request history

Customers requested improvements for the history page to allow quickly navigate through their request history. All requested features were gathered, collected, and [implemented](/blog/an-improved-screenshot-history-page/).

### Organizations and members

More than three companies requested organization management to separate billing and access key management.

And as a solution, organization management was introduced and successfully adopted by the companies.

### ChatGPT Integration

Integrating ScreenshotOne into ChatGPT by OpenAI allows ChatGPT users to render website screenshots and HTML and even build site galleries in one prompt.

The plugin is [ready for use](/blog/screenshotone-is-available-as-a-chatgpt-plugin/).

### Pay as you go

Many customers on the highly paid plans reached their limits, and some customers periodically ask to top-up their credit balance.

To make the service more excellent for everyone, from now you can opt-in for the pay-as-you-go option for your plan. Check this out, extra screenshots might be much cheaper.

### Asynchronous execution and webhooks

One of the customers requested to add support for simple asynchronous rendering for screenshots and webhooks so that they can render screenshots asynchronously, and when finished, the webhook is called.

Thanks to them, ScreenshotOne now supports [asynchronous screenshot rendering and webhooks](/docs/async-and-webhooks/).

### Integration with Zapier

Integration with Zapier, and other no-code automation tools were always one of the much-requested features. And integration with Zapier is available!

### OpenAI GPT Vision

You can use our screenshot API together with the OpenAI Vision API. It allows you to send screenshots directly to the Vision API without building all the infrastructure yourself.

2022

----

The roadmap was published recently, but internally it was tracked from the end of 2022.

### Scrolling and animated screenshots

A few potential customers approached and asked if ScreenshotOne could render animations through an API or scrolling screenshots.

In 2 weeks, the feature was developed, and since then, it has helped customers generate videos and has served a variety of critical use cases, like generating email campaigns with engaging videos, animations for presentations, and so on.

There is also a blog post on how to [generate videos with Puppeteer](https://screenshotone.com/blog/how-to-record-videos-with-puppeteer/).

Performance, scalability and stability

--------------------------------------

ScreenshotOne is one of the most performant and scalable screenshot APIs on the market.

But there is always room for improvement. And making the product work fast and reliable is the top priority always and is out of the scope of the roadmap. The performance, error rate, and issues are checked and fixed on a daily basis, if any.

If you have any issues or are not satisfied with the product speed, feel free to share your concerns at `support@screenshotone.com`. They will be addressed immediately.

Your proposal

-------------

Your proposal is enormously appreciated. The roadmap is mainly based on the requests of ScreenshotOne’s lovely customers. If you have any proposals or feature requests, please, feel free to share them at `hey@screenshotone.com`.

----
url: https://screenshotone.com/blog/directify-feedback
----

Automating screenshots for directory websites with ScreenshotOne

================================================================

How and why "Directify" used ScreenshotOne to automate screenshots for directory websites.

[Customer story](/blog/tags/customer-stories/) 2 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Sergey Karakhanyan](/contributors/sergey-karakhanyan/)

#### Published on

Dec 15, 2024

[Directify](https://directify.app/) is a no-code platform that allows you to create directory websites.

Their goal was to automate screenshot generation for directory websites—it was a feature requested by their customers.

Challenge

---------

Directify allows to spin a new directory website in minutes. But when it comes to listing website, customers had to manually take screenshots of their listings or didn’t have an option to do it, all.

[](https://directify.canny.io/roadmap/p/ability-to-screenshot-url-automatically)

After customers requested and upvoted this feature, Directify had to implement it themselves or to seek for a solution.

They choose ScreenshotOne to help with that and let’s check out their feedback.

ScreenshotOne as a Solution and Results

---------------------------------------

A few words by Sergey Karakhanyan, a maker behind [Directify](https://directify.app/):

1.  **How did you discover ScreenshotOne?**

> I discovered ScreenshotOne from X (Twitter) by following [Dmytro](https://x.com/DmytroKrasun).

2.  **Did you check any alternatives?**

> I haven’t checked any alternatives before this integration, because I kind of knew what I needed, and ScreenshotOne covered all my needs.

> 

> Previously, for one of my startups I have implemented screenshotting feature by myself, doing it with Puppeteer, but I had issues with it often, it wasn’t stable. With ScreenshotOne on the other hand, you can a lot of nice features, like removing cookie banner for example, ability to specify device specific viewport. I love it!

3.  **How was the integration process?**

> Integration process was very smooth, I used PHP SDK for integration and did integrated it in my Laravel application, it was just piece of cake, easy peasy.

4.  **What is your application about?**

> My application called Directify, it’s about making directory websites with no-code, and as we all know, directories are based on listings.

> 

> I use ScreenshotOne integration to provide customers ability to add cover image and open-graph image for their listings, for easier and faster listing creation.

5.  **How does it help you and your customers in your business?**

> It helps my customers to not do screenshots of the listings manually and them upload it into the listing, instead they can click the button and get the screenshot uploaded to the CDN.

> 

> I also provide listing import ability, some of the customers have more than 1,000 listings, and it will be a real trouble to do that many screenshots and upload them manually.

6.  **Anything you would like to add?**

> I would say for potential customers, who are thinking that they can implement this themselves, as a person who did that before - you can do it yourself, for sure, but the time you spend on implementation and bug fixes, that are a lot with Puppeteer, is not worth the effort - just get ScreenshotOne.

Conclusion

----------

By integrating ScreenshotOne, Directify successfully automated screenshot generation for directory websites, providing an almost seamless experience for their customers.

More Examples and Use Cases

---------------------------

You might be also interested in how [SpyFu uses ScreenshotOne for RivalFlowAI for competitive content analysis with AI](/blog/rivalflowai-by-spyfu/).

ScreenshotOne supports a huge variety of uses including but not only:

*   [Automating Open Graph image generation](/use-cases/open-graph-images/).

*   [Generating personalized videos](/use-cases/automate-personalized-videos/).

*   [Rendering site thumbnails for search previews](/use-cases/preview-search-results/)

And [many more](/use-cases/).

Read more customer stories

--------------------------

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

[View all posts](/blog/tags/customer-stories/)

#### [How AdKit automated onboarding](/blog/adkit/)

A short story by the founder of AdKit about how they use ScreenshotOne for onboarding automation.

Read more

#### [How BugSmash automates website screenshot rendering](/blog/bugsmash-story/)

How and why BugSmash uses ScreenshotOne for critical screenshot rendering tasks.

Read more

#### [Using AI screenshot analysis to identify leads for a design agency](/blog/ai-screenshot-analysis-for-finding-customers/)

Elias shares his process for discovering high-quality leads for a design agency by using AI screenshot analysis within the Clay platform.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/introducing-request-log
----

Improved API request log

========================

A new and improved request log has been deployed. That is a good beginning of the week! Check out why.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jul 29, 2024

A lot of small improvements that will make your experience much better with ScreenshotOne:

1.  **[The history page](https://dash.screenshotone.com/logs) is now named “Logs” or “Request Logs”.** The previous name “History” was a bit counter-intuitive and didn’t reflect the real intent behind the logs—it is to help you.

2.  **More details about the request.** You will now see more details about the request you have sent and there will be much more soon. Everything to help you to debug any issues.

3.  **Report any API request in a few clicks.** From now on, there is no need to write long messages and collect information about the request that has some issues. Just select the issue type and we will be reported about the issue.

And a few minor improvements like changing titles, fixing typos, and so on.

Thanks for checking out these updates and have a nice day!

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Better and more extensible PDF rendering](/changelog/better-and-more-extensible-pdf-rendering/)

ScreenshotOne supports PDF rendering for a long time but it was used till recently by a small group of customers. Growing demand in PDF rendering required updating the API. And today, we introduce new options for PDF customization.

Read more →

1 min read

#### [Added an Above-the-Fold Checker Tool](/changelog/above-the-fold-checker/)

A new ScreenshotOne tool to capture what users see before the first scroll.

Read more →

1 min read

#### [Improved proxy validation](/changelog/improved-proxy-validation/)

Stricter proxy option validation to prevent misconfiguration.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/testimonials
----

What our customers are saying

Product quality and good support are mentioned most often

---------------------------------------------------------

[Get Started](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

Typeshare

Sam Shore

Automated image generation when every pixel matters

> "We have lots of SaaS subscriptions with Typeshare but by far the best value is ScreenshotOne. For a small monthly fee we basically get a full-time developer who handles all our image generation."

[Read the full story ›](/blog/how-typeshare-uses-screenshotone/)

Kinsta

Roger Williams

Delivering reliable automatic software updates with confidence

> "We use ScreenshotOne as part of a visual regression test we run before certain updates. Their service allows us to capture screenshots of our sites before and after changes, helping us easily compare the differences and determine whether a rollback is needed."

[Read the full story ›](/blog/kinsta/)

RivalFlow AI by SpyFu

Mike Roberts

Visual website analysis with AI for competitive research at scale

> "ScreenshotOne is the best product on the market - and that’s before you take into account how responsive and easy Dmytro is to work with. Any time we’ve found a rare edge case, it’s been resolved in hours."

[Read the full story ›](/blog/rivalflowai-by-spyfu/)

Automate website screenshots  

**with ScreenshotOne**

-----------------------------------------------------

[Get Started](https://dash.screenshotone.com/sign-up)

All TestimonialsAI and automationMarketingWebsite DirectoriesWebsite MonitoringCustomer SuccessSocial Media and Writing ToolsVisual Regression TestingBookmarking and ArchivalOpen Graph ImagesAnalytics and Heatmaps

> ScreenshotOne is the best product on the market - and that's before you take into account how responsive and easy Dmytro is to work with.

> 

> Any time we've found a rare edge case, it's been resolved in hours.

> 

> Great company, great founder - can't say enough!

Mike Roberts

Founder, [SpyFu](https://www.spyfu.com/)

> We have lots of SaaS subscriptions with Typeshare but by far the best value is ScreenshotOne.

> 

> For a small monthly fee, we basically get a full-time developer who handles all our image generation.

> 

> We've spent thousands on building this in-house and it was nowhere near as good as what Dmytro Krasun has built.

> 

> Can't recommend ScreenshotOne enough!

Sam Shore

Founder, [Typeshare](https://screenshotone.com/blog/how-typeshare-uses-screenshotone/)

> I’ve been using ScreenshotOne for 3 years and couldn’t run Saaspo without it.

> 

> You can tell Dmytro really cares about the product as it keeps getting better.

> 

> Highly recommend to anyone looking for a screenshot tool!

Andy Hooke

Founder, [Saaspo](https://screenshotone.com/blog/saaspo/)

> “It is super simple, works very well and fast.

Klaas Foppen

Founder, [Promptwatch](https://screenshotone.com/blog/promptwatch/)

> We needed to build a side product, fast, we signed up and within minutes we were set up and had pulled over 400 picture-perfect screenshots for use in a new directory tool we were launching.

Alex Rainey

Founder, [My AskAI](https://myaskai.com/)

> We use ScreenshotOne as part of a visual regression test we run before certain updates. Their service allows us to capture screenshots of our sites before and after changes, helping us easily compare the differences and determine whether a rollback is needed.

> 

> Working with Dmytro from ScreenshotOne has been an overwhelmingly positive and refreshing experience. He’s incredibly responsive, quick to act, and genuinely committed to making his service work for our needs.

> 

> We especially appreciated how he proactively adjusted our screenshot and request rate limits to better suit our use case—prioritizing getting blockers out of the way even before finalizing the commercial details. Dmytro also offered suggestions on how we could optimise our API usage, and when we noticed a method missing from the Node SDK (one already available in the API and critical for us), he had it fixed and released within minutes.

Barnabás Ürmössy

Development Manager, [Kinsta](https://screenshotone.com/blog/kinsta/)

> Capturing screenshots sounds easy until you try to do it yourself and run into N number of cases.

> 

> Dmytro has done a wonderful job in all 3 aspects: The product, The documentation, The wonderful human behind this!

Nabil Kazi

Co-Founder, [BugSmash](https://screenshotone.com/blog/bugsmash-story/)

> ScreenshotOne allows us to get website screenshots for our customers.

> 

> Super fast and helpful support, stable, and a nice product!

Modest Mitkus

Founder, [RankPill](https://screenshotone.com/blog/rankpill/)

> I am a very happy customer of ScreenshotOne by Dmytro Krasun.

> 

> I really wish all APIs would have great documentation, playground and SDKs like that. Dmytro really outdid himself.

> 

> Highly recommend 🤗

Matthias Neumayer

Co-Founder, [Branding 5](https://screenshotone.com/blog/how-branding5-uses-screenshotone/)

> When OpenAI launched GPT-4 Vision I immediately thought that this would be great to give instant feedback to founders on their landing pages.

> 

> I wanted to launch an MVP in just a day or two to try it out and immediately ran into the problem of getting great screenshots of landing pages from a URL. It turned out that cookie banners, animations, and more often got in the way.

> 

> Then I found ScreenshotOne which had a fantastic integration with Zapier. It just immediately worked out of the box. Four weeks later, and hundreds of founders have had thousands of tests run on their landing pages. I couldn't be a happier user of ScreenshotOne!

Elias Stråvik

Founder, [Roast as a Service](https://www.roastasaservice.com/)

> I use ScreenshotOne for Adkit, and it works perfectly! I have my own infrastructure, so I could do it myself, but I need the screenshot at a critical time (when onboarding new users), so it’s “too important to fail”. Screenshot One never failed me once! And it’s also much faster than my own system.

Nicolas Jeannen

Founder, [AdKit](https://screenshotone.com/blog/adkit/)

> ScreenshotOne helps us easily make instant OG images for all our clients at our [SEO agency](http://magicspace.agency), it's the easiest way to make quick screenshots fast and they look amazing.

Ilias Ism

Founder, [ogimage.org](https://ogimage.org/)

> We thought making a screenshot tool for our AI agents would be simple. But we faced countless unexpected problems.

> 

> So, we ditched the idea and chose ScreenshotOne API instead. It saved us lots of time and it just works!

John Rush

Founder, [Unicorn Platform](https://unicornplatform.com)

> That was a lot of work to get rendering screenshots work right (there's a lot of edge cases in my case) and I just opted for ScreenshotOne because of the pricing and great API.

Bjarn Bronsveld

Founder, [Spectate](https://spectate.net/)

> Shout out to ScreenshotOne (by Dmytro Krasun) for being one of those services that just quietly runs in the background doing the thing you want it to do perfectly!

> 

> Been using it to generate screenshots for lead demo sites when I'm not able to embed the site in an iframe (which you shouldn't let your site allow btw). Works so well.

Herman Schutte

Founder, [SiteSpeakAI](https://sitespeak.ai)

> ["ScreenshotOne](/) is our screenshot solution that has powerful and flexible tools. This tool suits ourbusiness, as they are developing what you need precisely and helping integrate it into our business.

> 

> The best is we can reach support in minutes!

> 

> [ScreenshotOne](/) saves us money & time, and best of all, it brings reliability to our business. We just set up & forgot.It works smoothly.

Luvian Cotak

Founder, [PDFflyers.com](https://pdfflyers.com/)

> ScreenshotOne is a terrific Screenshot API. We're taking screenshots at scale at landing.gallery and ScreenshotOne is handling it like an absolute champ.

> 

> The founder is incredibly responsive and the docs are outstanding and get you going within minutes.

Chris Jayden

Maker, [Landing Gallery](https://screenshotone.com/blog/landing-gallery/)

> ScreenshotOne is one of those rare tools that just does its job perfectly. It's simple to integrate, consistently delivers great results, and the support is excellent.

> 

> We tested a few alternatives and ScreenshotOne was the clear winner for both quality and ease of use. We'd love to see the option to capture different screen formats too, like tablet and mobile, to support a more complete analysis.

William Prud'homme

Founder, [Forge IQ](https://screenshotone.com/blog/forge-iq/)

> Screenshotone is a game changer. The product works well and is a huge time saver. Most importantly Dmytro has been an amazing support throughout the process and always went the extra mile. Highly recommend.

Ben Machek

CEO, [Aybee](https://www.getaybee.com/)

> ScreenshotOne is a really helpful service provider. All that I need for my work is combined here.

> 

> Service is comfortable, fast, and consistent. It has a nice support service that always stays active to problems of users and has an immediate response time.

> 

> I really appreciate and recommend ScreenshotOne to everyone.

Alexandr Bezhan

Chief Product Officer, [AMS Pilot](https://www.amspilot.com/)

> We're using ScreenshotOne to build user behavior click heatmaps for Glass Analytics, a comprehensive and powerful Google Analytics alternative.

> 

> ScreenshotOne elegantly solves this problem, allowing our developers to focus on core functionality for our customers, while providing a reliable service we can count on.

Chris Muktar

Co-Founder, [Glass Analytics](https://gl8ss.com/)

> DS.Emotion is a branding, marketing & placemaking agency with more than 100 national websites in our care. We've used ScreenshotOne to keep an eye on our whole portfolio. It means at a glance we can see if there are issues.

> 

> I'm a strategist (not a developer) so the fact that I was able to easily integrate it into AppSheet shows how simple it is to use and how good the support is.

Lawrence Alexander

Strategy & Innovation Director, [DS.Emotion](https://dsemotion.com/)

> [ScreenshotOne](/) is the best screenshot tool with amazing support.

> 

> I wrote to several companies and only [ScreenshotOne](/) took my requests into account and wasable to solve 100% of my problems, most of them in a standard way and for the most complex with customcode.

> 

> I have never seen such efficient and responsive support. It is undoubtedly the best solution for all your screenshot needs today.

> 

> I have more than 10,000 captures to my credit, and the result is incredible, as proof of thecreation of a catalog of WordPress / Divi layouts made entirely with https://layouts.divifree.com.

> 

> This is just the start of using ScreenshotOne. With a subscription of 10,000 screenshots per month, andall the features, I can leverage this tool to automate and create value in many of my projects.

> 

> Amazing tool, thanks to Dmytro Krasun and the ScreenshotOne team.

Gregory Borelli

Creator, [layouts.divifree.com](https://screenshotone.com/blog/heart-touching-feedback-from-gregory/)

> Compared to the tool I used before ScreenshotOne's image generation is very quick. Even the full-page screenshot only takes a couple of seconds.

> 

> I love the URL signing feature! It allows me to use a serverless stack without exposing the API key.

> 

> If you need a screenshot API, ScreenshotOne is the way to go!

Lukas Hermann

Co-Founder, [stagetimer.io](https://stagetimer.io/)

> Including screenshots of tools and websites mentioned in blogs is a fundamental requirement, so automating this entire process wasn't an easy process. The ScreenshotOne API took away one major complexity off my plate for a reasonable cost.

Daniel Kempe

Founder, [Supawrite](https://screenshotone.com/blog/supawrite/)

> I found ScreenshotOne through an AI agent (great GEO btw 😁), you had good docs and looked solid, had it up and running and working in 10 minutes, with Cursor.

> 

> Modern premium site screenshots on publish with extensive easy configuration like browser with + height, hiding certain elements very easy (like our branding) by targeting et

Anatoly Pashias

Co-Founder, [Framekit](https://screenshotone.com/blog/framekit/)

> Awesome product that-just-works™. Took me 10 minutes to add it to my (Rails) stack. Simple pricing. Great support. If you need something like a "Screenshot as a Service" API. Give it a try!

Guillaume Barillot

CTO, [Deepidoo](https://www.deepidoo.com/en/)

> Shoutout to Dmytro Krasun and his product ScrenshotOne, an excellently built product covering almost all of our use cases.

> 

> Most importantly and the reason I'm writing this is he provides a crazy good level of support through his support chat, thanks!

Zawwad Ul Sami

Founder, [MailToon](https://mailtoon.io/)

> Amongst the other features in Writings, the user can mark their content as public and share it on their social network or in private circles. The content needs to be nicely represented by an Open Graph image which should be generated dynamically in correspondence to the title, the text and the author.

> 

> This was difficult for me to achieve by myself. Something always lacked. Either speed or quality.

> 

> For that reason I started using ScreenshotOne—a service that does this for me without a headache. I execute a parametrized HTML request, and I receive a high quality image in response. Very happy with it!

Aleksandar Balalovski

Maker, [Writings](https://writings.so/)

> ScreenshotOne is absolutely amazing! I needed a tool that could take reliable screenshots via Airtable and this checked all the boxes. I was able to generate thousands of screenshots, in two different sizes, all within Airtable in less time than I thought was possible. The added bonus? Zero extra code needed.

> 

> I plan on integrating this into my workflow for a number of upcoming projects. If you want a reliable, no-code, no fuss solution then ScreenshotOne is for you.

Justin Phillips

Maker, [dang.ai](https://dang.ai/)

> After searching far and wide for a solution, only ScreenshotOne was straightforward enough to quickly validate & implement easily. Now it's an integral part of the bookmarking experience for my app.

Sebastian Graz

Maker, [Herding.app](https://herding.app/)

> ScreenshotOne made it possible to ship dynamic meta images for my MVP customers without spending weeks building the support myself. Works like a charm. The caching is the icing on the cake.

Sukh

Founder, Engyne.ai

> Screenshots on Landingfolio are now powered by ScreenshotOne. Much better quality than the one I used before.

> 

> Onboarding was an absolute breeze. Probably put in the credit card within 3 minutes. Great sandbox!

Danny Postma

Maker, [Landingfolio](https://www.landingfolio.com/)

> The best thing about [ScreenshotOne](/) is it just works!

> 

> With all the useful documentation in place and library support,it's very easy to setup ScreenshotOne.

> 

> On top of that, Dmytro's commitment towards improving the appmakes it an easy choice.

Rishi Mohan

Maker, [Pika.style](https://pika.style/)

> ScreenshotOne saves me hours of manual work every month!

> 

> The easy-to-use API was implemented in an existing backend within 15 minutes and has since generated hundreds of screenshots without problems.

> 

> I am a happy customer of [ScreenshotOne](/) and ToolsForCreators wouldn't be what it is without this amazing API!

Jannis Fedoruk-Betschki

Maker, Tools For Creators

> Integrated ScreenshotOne in my production app within minutes. Flexible API that has fit every use case I've thrown at it.

Tim Wheeler

Maker, [BotRoast.io](https://www.botroast.io/)

> Using the API was very simple, I just gave the docs to Cursor. Any issues I encountered were resolved quickly by the support team.

Eugene Zolotarenko

Co-Founder, [Outrank](https://screenshotone.com/blog/outrank/)

> Kudos to the team for building ScreenshotOne. It's been more than 4 months now, and there's hardly been an outage/downtime.

> 

> ScreenshotOne handled even the rarest of edge cases where websites were loading slowly, which I found other products in the market failed to do.

> 

> Lastly, the support has been extremely top-notch, which is like a cherry on top.

Sankeerth Julapally

Founder, [GetWebsite.Report](https://screenshotone.com/blog/how-website-report-uses-screenshotone/)

> I appreciate the fast customer support. Building the product, doing marketing is hard enough. But Dmytro still manages to solve my problems fast. Thank you!

Dan Kulkov

Co-Founder, [FounderPal](https://founderpal.ai/)

> I found ScreenshotOne very easy to get started with. The intuitive playground feature allowed me to seamlessly integrate and test our campaigns.

> 

> I love the playground, and it just works.

Stefan Wirth

Maker, [Bridesmaid For Hire](https://bridesmaidforhire.com/ai-wedding-speech-and-vow-generators)

> ScreenshotOne is an outstanding platform that provides top-quality services for businesses of all sizes. I recently had the pleasure of working with Dmytro, a professional from ScreenshotOne, and the experience was truly exceptional.

> 

> From the very beginning, it was clear that ScreenshotOne is committed to delivering the highest level of customer service and satisfaction. The platform is user-friendly and intuitive, making it easy to navigate and use. Their team of professionals is highly skilled, knowledgeable, and responsive, and they go above and beyond to ensure that their clients are happy with the services they provide.

> 

> What I appreciated most about ScreenshotOne was their attention to detail and their commitment to excellence. They take the time to understand their clients' needs and goals, and they work tirelessly to ensure that they deliver results that exceed expectations.

> 

> Overall, I would highly recommend ScreenshotOne to anyone looking for a top-notch platform that provides outstanding services and support. Their dedication to customer satisfaction is truly impressive, and I look forward to working with them again in the future.

Beto Vides

CEO, Lab #1001

> I would say for potential customers, who are thinking that they can implement this themselves, as a person who did that before - you can do it yourself, for sure, but the time you spend on implementation and bug fixes, that are a lot with Puppeteer, is not worth the effort - just get ScreenshotOne.

Sergey Karakhanyan

Founder, [Directify](https://screenshotone.com/blog/directify-feedback/)

> Being non-VC backed has it's own challenges, but as Dmytro's hands are not tied by investors, he's able to deliver excellent product development performance and support.

> 

> I will recommend ScreenshotOne to anyone who needs to complete similar tasks.

Bohdan Shulha

Founder, [Make a Directory](https://makeadir.com/)

> ScreenshotOne has been a lifesaver for generating screenshots of the tools I’m publishing on my directory websites. Thanks to ScreenshotOne's reliable automation, I can focus on curating and writing content while ensuring each project showcase is visually appealing with minimal effort.

> 

> Their developer-friendly API integrates into my workflow, allowing me to focus on finding new projects to publish. On top of that, Dmytro has been a pleasure to work with and has always been quick to respond to my requests.

Piotr Kulpinski

Founder, [OpenAlternative](https://openalternative.co)

> ScreenshotOne has been my go-to tool for programmatic screenshot generation for several years now. I have used it in different projects and love the simplicity of the API.

> 

> Dmytro really created a developer-friendly tool that solves a need we have all had at one point or another.

> 

> So, if you need to create screenshots of websites on the fly, choose ScreenshotOne!

Jannis Fedoruk-Betschki

Founder, [Magic Pages](https://screenshotone.com/blog/magic-pages/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/integrations/signed-links
----

Integrations

1 min read

Signed Links

============

Use signed links to share screenshots publicly.

Code API

Resources

---------

*   [Documentation](https://screenshotone.com/docs/signed-requests/)

I’ve been using ScreenshotOne for 3 years and couldn’t run Saaspo without it.

You can tell Dmytro really cares about the product as it keeps getting better.

Highly recommend to anyone looking for a screenshot tool!

Andy Hooke

Founder, [Saaspo](https://screenshotone.com/blog/saaspo/)

Check more Integrations

-----------------------

No-code tools, AI, code libraries, and more.

[Check more Integrations](/integrations/)

No-Code Automation

### Zapier

Automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos in Zapier.

[Read more →](/integrations/zapier/)

No-Code Automation

### Clay

Generate website screenshots inside Clay to qualify leads, assess content, and enrich rows with visual context automatically.

[Read more →](/integrations/clay/)

No-Code Automation

### Make

Use ScreenshotOne with Make to automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

[Read more →](/integrations/make/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/tags/puppeteer-guides/2
----

Puppeteer Guides

----------------

How-to posts and troubleshooting guides for Puppeteer-based automation.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Take a screenshot "from the surface" in Puppeteer and Chrome DevTools Protocol](/blog/take-a-screenshot-from-the-surface-in-puppeteer-and-chrome-devtools-protocol/)

Let's talk about the fromSurface parameter introduced in Chrome DevTools Protocol which will soon be supported by Puppeteer or even supported now at the time when you are reading the post.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 3, 2023

•

1 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [Capture beyond viewport in Puppeteer and Chrome DevTools Protocol](/blog/capture-beyond-viewport-in-puppeteer-and-chrome-devtools-protocol/)

Let's talk about the captureBeyondViewport parameter introduced in Chrome DevTools Protocol which will soon be supported by Puppeteer or even supported now at the time when you are reading the post.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 1, 2023

•

3 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [How to record videos with Puppeteer](/blog/how-to-record-videos-with-puppeteer/)

Let's quickly record a video with Puppeteer and see what upsides and downsides the native Puppeteer method of screencasting has. And how they can be tackled.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Apr 9, 2024

•

6 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to hide chat widgets when taking a screenshot with Puppeteer](/blog/how-to-hide-chat-widgets-when-taking-a-screenshot-with-puppeteer/)

When you want to take chat widgets, there are annoying chat widgets that you would love to hide. It is easy to do.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jul 28, 2022

•

1 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [How to hide cookie banners when taking a screenshot with Puppeteer](/blog/how-to-hide-cookie-banners-when-taking-a-screenshot-with-puppeteer/)

When taking a screenshot, you want to ensure that you take a clean screenshot without cookie banners or cookie consent forms. And in this article, I will share with you how you can do it when using Puppeteer.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Nov 12, 2024

•

11 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [How to fix the "Execution context was destroyed" error when using Puppeteer](/blog/puppeteer-execution-context-was-destroyed-most-likely-because-of-a-navigation/)

Fix the Puppeteer "Execution context was destroyed, most likely because of a navigation" error after click, form submit, redirect, reload, or page.evaluate.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Mar 13, 2026

•

5 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to create a site thumbnail with Puppeteer](/blog/how-to-create-a-site-thumbnail-with-puppeteer/)

We can consider the screenshot of URL or HTML as a thumbnail, but I write about the thumbnail of a screenshot. How do you take a screenshot within the defined viewport but with different image width and height? Resize!

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jul 17, 2022

•

3 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Taking screenshots with Puppeteer in GIF, JP2, TIFF, AVIF, HEIF, or SVG format](/blog/taking-screenshots-with-puppeteer-in-gif-jp2-tiff-avif-heif-or-svg-format/)

Puppeteer, by default, supports only four formats for taking screenshots or rendering HTML: PNG, JPEG, WebP, and PDF. But what if you want it to take it in a different format like GIF, JP2, TIFF, AVIF, HEIF, or SVG?

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jul 17, 2022

•

6 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/how-to-take-website-screenshots-in-ruby
----

How to take website screenshots in Ruby

=======================================

Let's examine what Ruby proposes for us to render HTML or URL as a screenshot dynamically.

[Blog post](/blog/) 5 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Dec 15, 2022

#### Tags

[Screenshot rendering](/blog/tags/screenshot-rendering/)

To take website screenshots or generate images from HTML in Ruby, you have the following options:

*   [Selenium](#selenium-for-ruby)\-a library with many headless browser drivers that allows you to automate interactions with a web page and take screenshots.

*   [Watir](#watir)—another wrapper around headless browsers that enables you to automate interactions with a web page and take screenshots.

*   [Capybara](#take-screenshots-with-capybara)—a testing library that allows you to simulate a user interacting with a website and take screenshots.

*   [PhantomJS](#phantomjs-is-obsolete)—a headless browser that allows you to automate interactions with a web page and take screenshots. But it is obsolete.

*   [puppeteer-ruby](#puppeteer-for-ruby)—a JavaScript Puppeteer port for Ruby.

*   [ScreenshotOne API](#url-screenshot-api)—a third-party API that covers various screenshotting and HTML rendering problems.

Let’s quickly check out and examine each option and see what might suit your needs the best.

Selenium for Ruby

-----------------

To take screenshots with `Selenium` in Ruby, you can use the `save_screenshot` method provided by the `Selenium::WebDriver::Driver` class. This method takes a file path as an argument and saves a screenshot of the current page to the specified file.

Add this line to your application’s Gemfile:

    1gem 'selenium-webdriver'

And then execute:

Terminal window

    1bundle install

[Download the Chrome driver](https://sites.google.com/chromium.org/driver/downloads) or install it using Homebrew:

    1brew install chromedriver

Note that `Selenium` requires specific version of the Chrome driver.

So, there is an example of using `Selenium` to take a screenshot of a website:

    1require "selenium-webdriver"2

    3# 1. set up Selenium4driver = Selenium::WebDriver.for :chrome5

    6# 2. navigate to your site7driver.navigate.to "https://screenshotone.com"8

    9# 3. take a screenshot and save it to a file10driver.save_screenshot("screenshotone.png")11

    12# 4. quit Selenium13driver.quit

The result is:

`Selenium` supports various browsers, including Chrome, Firefox, Safari, and Internet Explorer, making it a good choice for testing cross-browser compatibility.

In addition, `Selenium` has a large and active community of users, which means many resources and documentation are available to help you get started and troubleshoot any issues you may encounter.

Watir

-----

To take screenshots with `Watir` in Ruby, you can use the `screenshot` method provided by the `Watir::Browser` class. This method takes a file path as an argument and saves a screenshot of the current page to the specified file.

Add this line to your application’s Gemfile:

    1gem 'watir'

And then execute:

Terminal window

    1bundle install

Here’s an example of using `Watir` to take a screenshot of a website:

    1require "watir"2

    3# 1. set up Watir4browser = Watir::Browser.new :chrome5

    6# 2. navigate to your site7browser.goto "https://ktool.io"8

    9# 3. take a screenshot and save it to a file10browser.screenshot.save("ktool.png")11

    12# 4. quit Watir13browser.quit

The result is:

The main difference between `Watir` and `Selenium` is that `Watir` is specifically designed for testing web applications, while `Selenium` is a more general-purpose tool for automating web browsers.

Both tools can be used effectively for automating web applications, but `Watir` may be a better choice if your primary goal is to write tests, while `Selenium` may be a better choice if you need to do more general-purpose automation tasks.

Take screenshots with Capybara

------------------------------

`Capybara` is an acceptance test framework for web applications that can use `Selenium` as a driver.

Add these lines to your application’s Gemfile:

    1gem 'capybara'2gem 'selenium-webdriver'

And then execute:

    1bundle install

Here’s an example of using `capybara` to take a screenshot of a website:

    1require "capybara"2require "capybara/dsl"3

    4# 1. set up capybara5Capybara.register_driver :selenium_chrome do |app|6    Capybara::Selenium::Driver.new(app, browser: :chrome)7end8

    9Capybara.current_driver = :selenium_chrome10

    11include Capybara::DSL12

    13# 3. navigate to your site14visit "https://famewall.io/"15

    16# 4. take a screenshot and save it to a file17page.save_screenshot("famewall.png")

The result is:

Capybara is a very high-level framework and is too much to use only for taking screenshots. But if you already have it in your stack, you are happy to use it for screenshots.

PhantomJS is obsolete

---------------------

PhantomJS development [is suspended until further notice](https://github.com/ariya/phantomjs/issues/15344). So, it is not recommended to use it in production. The tutorial provides enough alternatives to `PhatomJS` in Ruby, like [Selenium](#selenium-for-ruby), [Watir](#watir), [Capybara](#take-screenshots-with-capybara), [puppeteer-ruby](#puppeteer-for-ruby), and [ScreenshotOne API](#url-screenshot-api).

Puppeteer for Ruby

------------------

[Puppeteer](/blog/how-to-take-a-screenshot-with-puppeteer/) is a library for Node.js that provides a high-level API to control a headless Chrome or Chromium browser, and `puppeteer-ruby` is its port for Ruby.

Add this line to your application’s Gemfile:

    1gem 'puppeteer-ruby'

And then execute:

    1bundle install

To capture a site:

    1require 'puppeteer-ruby'2

    3Puppeteer.launch(headless: false) do |browser|  page = browser.new_page4  page.goto("https://github.com/screenshotone")5  page.screenshot(path: "github.png")6end

The result is:

The puppeteer-ruby library provides access to modern web platform features such as the Chrome DevTools Protocol and the DOM. So, it is a good choice for tasks that require access to the latest browser features.

If you don’t need to take screenshots in different browsers, I will go with puppeteer-ruby.

URL Screenshot API

------------------

One of the most significant downsides of taking screenshots with `Selenium` or `pyppeteer` is handling infrastructure and taking care of browsers. They are resource intensive. You might encounter crashes, memory leaks, and high levels of CPU consumption.

So, if you need to take 5-10 screenshots and not that often, I would go with `Selenium` or `puppeteer-ruby`. But if you need a scale or don’t want to deal with infrastructure issues, I would use a third-party API, like [ScreenshotOne—an URL to screenshot API](https://screenshotone.com/).

It is free to get started and supports various options—like removing chat widgets, blocking cookie banners, rendering in dark mode, and even animations.

Sign up to get your API access and secret key, and let’s try [ScreenshotOne’s official SDK for Ruby](https://rubygems.org/gems/screenshotone):

Massive thanks and rays of goodness to [Gustavo Garcia](https://twitter.com/theluctus) from [Dailytics](https://dailytics.com/) for providing the fully-featured high-quality Ruby SDK.

Add this gem to your Gemfile:

    1gem 'screenshotone'

And then execute:

Terminal window

    1bundle install

And:

    1# If you don't need to add a signature2client = ScreenshotOne::Client.new('my_access_key')3

    4# If you do need to add a signature5client = ScreenshotOne::Client.new('my_access_key', 'my_secret_key')6

    7

    8# You can set any available option, in a camel_case format, for example:9options = ScreenshotOne::TakeOptions.new(url: 'https://example.com').10            full_page(true).11            delay(2).12            geolocation_latitude(48.857648).13            geolocation_longitude(2.294677).14            geolocation_accuracy(50)15

    16# Verify all the parameters are valid (we will validate the parameters that should be17# numeric, booleans or that accept only certain values)18options.valid?19=> true20

    21

    22# To simply get the final url:23client.generate_take_url(options)24=> "https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com..."25

    26# To actually get the image (the response body of a request to the previous url)27client.take(options)28=> "\xFF\xD8\xFF\xE0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xFF\..."

That’s it. The result is:

That’s how simple it was!

Summary

-------

If you already use Selenium, Watir, or Capybara, I would go with them.

Otherwise, I would go with puppeteer-ruby if you don’t need to take screenshots in different browsers.

But if you don’t want to deal with handling browser infrastructure and want to save time and energy, I would go with screenshot as a service like ScreenshotOne.

Read more Screenshot rendering

------------------------------

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

[View all posts](/blog/tags/screenshot-rendering/)

#### [How to Take Screenshots with pyppeteer in Python](/blog/pyppeteer-python-screenshots/)

Guide to taking screenshots with pyppeteer in Python. Learn the basics, full page captures, and why you should migrate to Playwright.

Read more

#### [How to Take Website Screenshots with Playwright in Python](/blog/playwright-python-screenshots/)

A complete guide to taking website screenshots with Playwright in Python. Learn page.screenshot() parameters, async patterns, element screenshots, dark mode, and device emulation.

Read more

#### [How to hide chat widgets when taking a screenshot with Puppeteer](/blog/how-to-hide-chat-widgets-when-taking-a-screenshot-with-puppeteer/)

When you want to take chat widgets, there are annoying chat widgets that you would love to hide. It is easy to do.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/better-markdown-output
----

Better Markdown output

======================

Markdown output is now cleaner by removing non-content HTML blocks during conversion.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Feb 28, 2026

We improved how `format=markdown` converts pages to Markdown.

From now on, ScreenshotOne removes these elements before generating Markdown:

*   `script`

*   `style`

*   `noscript`

*   `iframe`

*   `header`

*   `head`

This makes Markdown responses cleaner and more focused on the main content, which is especially useful for AI/LLM pipelines and downstream parsing.

Use it as usual:

    1https://api.screenshotone.com/take?format=markdown&url=https://example.com/&access_key=<access key>

If you have any questions or suggestions, please let us know at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Extract Open Graph metadata while rendering screenshots](/changelog/open-graph-metadata/)

From today, you can get parsed Open Graph metadata and screenshots in one API request.

Read more →

1 min read

#### [Added support of Slack notifications](/changelog/slack-notifications/)

We added support of Slack notifications to ScreenshotOne. Now you can set up and get Slack notifications when you reach your quota limits.

Read more →

1 min read

#### [Transfer organization ownership](/changelog/organization-transfer-ownership/)

From today, you can transfer organization ownership to another user.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/generate-site-thumbnails
----

Automate Website Screenshots

1 min read

Generate Site Thumbnails

========================

Create small-sized previews of websites for cataloguing or summary purposes.

The **Generate website thumbnails** use case leverages the _website screenshot API_ to dynamically create visual previews of websites. This feature is invaluable for developers in small companies who need to generate quick previews for a large number of websites, be it for a portfolio, a directory, or an internal tool. The _ScreenshotOne API_ simplifies this process by providing a reliable and scalable solution that can capture and resize website screenshots on-demand.

Using the ScreenshotOne API for generating thumbnails is a time-efficient and cost-effective alternative to developing a similar functionality in-house. It eliminates the need for extensive research, development, and maintenance efforts associated with web capturing technologies. Furthermore, the API’s ability to handle various website layouts and dynamic content ensures high-quality thumbnails, enhancing the user experience and value of the product it’s integrated into.

We have lots of SaaS subscriptions with Typeshare but by far the best value is ScreenshotOne.

For a small monthly fee, we basically get a full-time developer who handles all our image generation.

We've spent thousands on building this in-house and it was nowhere near as good as what Dmytro Krasun has built.

Can't recommend ScreenshotOne enough!

Sam Shore

Founder, [Typeshare](https://screenshotone.com/blog/how-typeshare-uses-screenshotone/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/14
----

Automate Website Screenshots

----------------------------

Guides, Product Updates, and Helpful Resources from ScreenshotOne.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Uploading website screenshots to any S3-compatible storage](/blog/uploading-website-screenshots-to-any-s3-compatible-storage/)

In this note, I share how I take website screenshots or render HTML and upload the resulted images or PDF to any S3-compatible storage like Amazon S3, Cloudflare R2, or Backblaze B2.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jul 12, 2022

•

2 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to render HTML with Puppeteer](/blog/how-to-render-html-with-puppeteer/)

Use Puppeteer or screenshot API to generate the Open Graph protocol images, bills, receipts, or invoices PDF or PNG files from the HTML templates.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Mar 13, 2026

•

3 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to add custom scripts to a page in Puppeteer](/blog/how-to-add-custom-scripts-to-a-page-in-puppeteer/)

How to add custom scripts to a page in Puppeteer. Let's discover how it works quickly."

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jun 24, 2022

•

2 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to add custom styles to a page in Puppeteer](/blog/how-to-add-custom-styles-to-a-page-in-puppeteer/)

To add custom styles to any page use Puppeteer's page method \`page.addStyleTag(options)\`. Let's discover how it works quickly.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jun 24, 2022

•

2 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots with PHP](/blog/how-to-take-website-screenshots-with-php/)

The article examines how you can take screenshots of any URL with PHP by using Selenium, Puppeteer alternatives, or screenshot API as a service.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jun 14, 2022

•

3 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots with JavaScript or TypeScript (Node.js)](/blog/how-to-take-website-screenshots-with-javascript-or-typescript-nodejs/)

The article examines how you can take screenshots of any URL with Javascript and TypeScript (Node.js) by using Selenium, Puppeteer alternatives, Playwright, or screenshot API as a service.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jun 14, 2022

•

4 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots with Java](/blog/how-to-take-website-screenshots-with-java/)

The article examines how you can take screenshots of any URL with Java by using Selenium, Puppeteer alternatives, Playwright, or screenshot API as a service.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jun 10, 2022

•

3 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots with Go](/blog/how-to-take-website-screenshots-with-go/)

The article examines how you can take screenshots of any URL with Go (a.k.a. Golang) by using Selenium, Puppeteer alternatives, Playwright, or screenshot API as a service.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jun 10, 2022

•

4 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/pyautogui-python-screenshots
----

How to Take Screenshots with PyAutoGUI in Python

================================================

Complete guide to taking screenshots with PyAutoGUI in Python. Learn screenshot(), region parameters, locateOnScreen(), and common errors with ImageNotFoundException.

[Blog post](/blog/) 3 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jan 13, 2026

#### Tags

[Desktop screen capture](/blog/tags/desktop-screen-capture/)

[PyAutoGUI](https://pyautogui.readthedocs.io/en/latest/) is primarily an automation library—it controls your mouse and keyboard. But it also includes screenshot functionality that’s perfect for simple capture tasks, especially when combined with automation scripts.

However, at the moment of publishing the guide, the library was last updated a few years ago:

So, if you are going to use desktop screen capture for production-ready projects, check out our guide on [Python MSS](/blog/mss-python-screen-capture/), it is still actively maintained.

Installation and Basic usage

----------------------------

Install the library using `pip`:

Terminal window

    1pip install pyautogui

On Linux, you may also need:

Terminal window

    1pip install python3-xlib2sudo apt-get install scrot

    1import pyautogui2

    3# Capture entire screen4screenshot = pyautogui.screenshot()5

    6# Save to file7screenshot.save('screenshot.png')

That’s it. The simplest API of any screenshot library.

Region Capture

--------------

The `region` parameter uses the format `(left, top, width, height)`:

    1import pyautogui2

    3# Capture a 500x500 region starting at (100, 100)4region_screenshot = pyautogui.screenshot(region=(100, 100, 500, 500))5region_screenshot.save('region.png')

**Important**: The order is `(left, top, width, height)`, NOT `(x, y, x2, y2)`.

    1# This captures from (100, 200) with size 300x4002region = (100, 200, 300, 400)3#         left, top, width, height4

    5screenshot = pyautogui.screenshot(region=region)

Understanding the PIL Image Return

----------------------------------

pyautogui returns a PIL Image object:

    1import pyautogui2

    3screenshot = pyautogui.screenshot()4

    5# It's a PIL Image6print(type(screenshot))  # <class 'PIL.Image.Image'>7

    8# Use PIL methods9print(screenshot.size)   # (1920, 1080)10print(screenshot.mode)   # RGB11

    12# Save in different formats13screenshot.save('screenshot.png')14screenshot.save('screenshot.jpg', quality=85)15

    16# Convert to other formats17screenshot_gray = screenshot.convert('L')  # Grayscale

Convert to NumPy Array

----------------------

    1import pyautogui2import numpy as np3

    4screenshot = pyautogui.screenshot()5

    6# Convert to numpy array7img_array = np.array(screenshot)8

    9print(img_array.shape)  # (1080, 1920, 3) for 1080p RGB

locateOnScreen: Find Images on Screen

-------------------------------------

One of pyautogui’s killer features—find where an image appears on screen:

    1import pyautogui2

    3# Find image on screen4location = pyautogui.locateOnScreen('button.png')5

    6if location:7    print(f"Found at: {location}")8    # Box(left=100, top=200, width=50, height=30)9

    10    # Get center point11    center = pyautogui.center(location)12    print(f"Center: {center}")13else:14    print("Image not found")

### With Confidence (Fuzzy Matching)

Requires OpenCV:

Terminal window

    1pip install opencv-python

    1import pyautogui2

    3# Allow some variation in matching4location = pyautogui.locateOnScreen('button.png', confidence=0.9)

Lower confidence = more lenient matching. Default is 1.0 (exact match).

### Find All Occurrences

    1import pyautogui2

    3# Find all matching images4locations = list(pyautogui.locateAllOnScreen('icon.png'))5

    6print(f"Found {len(locations)} matches")7for loc in locations:8    print(f"  {loc}")

Handling ImageNotFoundException

-------------------------------

    1import pyautogui2

    3try:4    location = pyautogui.locateOnScreen('button.png')5except pyautogui.ImageNotFoundException:6    print("Image not found on screen")7    location = None8

    9# Or use the return value10location = pyautogui.locateOnScreen('button.png')11if location is None:12    print("Image not found")

Common causes:

1.  Image file doesn’t exist

2.  Screen content doesn’t match exactly

3.  Resolution or scaling differences

Click on Found Image

--------------------

Combine screenshots with automation:

    1import pyautogui2

    3# Find and click a button4button = pyautogui.locateOnScreen('submit_button.png', confidence=0.9)5

    6if button:7    # Click the center of the button8    pyautogui.click(pyautogui.center(button))9else:10    print("Button not found")

Multiple Screenshots

--------------------

    1import pyautogui2import time3

    4# Capture screenshots every second5for i in range(10):6    screenshot = pyautogui.screenshot()7    screenshot.save(f'screenshot_{i:03d}.png')8    time.sleep(1)

Complete Automation Example

---------------------------

    1import pyautogui2import time3

    4def click_if_found(image_path, timeout=10):5    """Wait for image and click it."""6    start = time.time()7

    8    while time.time() - start < timeout:9        location = pyautogui.locateOnScreen(image_path, confidence=0.9)10        if location:11            center = pyautogui.center(location)12            pyautogui.click(center)13            return True14        time.sleep(0.5)15

    16    return False17

    18def automate_login():19    """Example automation script."""20    # Wait for login button21    if click_if_found('login_button.png'):22        print("Clicked login button")23

    24        # Wait for username field25        time.sleep(1)26        pyautogui.typewrite('myusername')27

    28        # Tab to password29        pyautogui.press('tab')30        pyautogui.typewrite('mypassword')31

    32        # Submit33        pyautogui.press('enter')34

    35        # Screenshot the result36        time.sleep(2)37        pyautogui.screenshot('result.png')38    else:39        print("Login button not found")40

    41# automate_login()

Grayscale for Faster Matching

-----------------------------

    1import pyautogui2

    3# Grayscale is faster for locateOnScreen4location = pyautogui.locateOnScreen('button.png', grayscale=True)

Screenshot with Pause

---------------------

pyautogui has a built-in pause feature:

    1import pyautogui2

    3# Add 0.5 second pause between all pyautogui calls4pyautogui.PAUSE = 0.55

    6screenshot = pyautogui.screenshot()  # 0.5s pause before this7screenshot.save('screenshot.png')

Summary

-------

PyAutoGUI is a simple library for taking screenshots and automating tasks. It is easy to use, but be careful since the library hasn’t been updated for a few years.

Features of PyAutoGUI:

1.  **Simple API**: `pyautogui.screenshot()` returns PIL Image

2.  **Region format**: `(left, top, width, height)`

3.  **locateOnScreen**: Find images on screen

4.  **Slow but simple**: 1-5 FPS, but easy to use

5.  **Best for automation**: Combine with click/type functions

For better performance, use [mss](/blog/mss-python-screen-capture/) or [dxcam](/blog/dxcam-python-screenshots/).

For website screenshots, check out [our guide on website screenshots with Python](/blog/how-to-take-website-screenshots-in-python/) or just use [Playwright for Python](/blog/playwright-python-screenshots/) instead.

Frequently Asked Questions

--------------------------

If you read the article, but still have questions. Please, check the most frequently asked. And if you still have questions, feel free reach out at [support@screenshotone.com](mailto:support@screenshotone.com).

### What is the region parameter order in PyAutoGUI screenshot?

The region parameter is (left, top, width, height). Left is the X coordinate, top is the Y coordinate, then width and height of the capture area.

### Does PyAutoGUI screenshot return a PIL Image?

Yes, pyautogui.screenshot() returns a PIL Image object. You can save it directly with .save() or process it with PIL/Pillow methods.

### How to fix ImageNotFoundException in PyAutoGUI?

This error occurs when locateOnScreen() can't find the image. Ensure the image file exists, the screen content matches exactly, and try lowering the confidence parameter.

Read more Desktop screen capture

--------------------------------

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

[View all posts](/blog/tags/desktop-screen-capture/)

#### [How to Capture Desktop Screen with DXcam in Python](/blog/dxcam-python-screenshots/)

Complete guide to DXcam, the fastest Python screen capture library. Learn high-FPS capture, video mode, region capture, and DXcam vs Python MSS performance comparison.

Read more

#### [How to Take Screenshots with Python MSS](/blog/mss-python-screen-capture/)

Complete guide to the MSS Python screen capture library. Learn installation, capturing monitors, regions, performance optimization, and common errors like xgetimage() failed.

Read more

#### [How to Capture Desktop Screenshots in Python](/blog/python-screen-capture/)

Complete guide to desktop screen capture in Python. Compare Python MSS, DXcam, PyAutoGUI for capturing monitors, windows, and screen regions.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/remove-organization-member
----

Remove organization members

===========================

Improvements to the organization management.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Mar 7, 2025

Remove organization members

---------------------------

Since today, it is possible to remove organization members from the organization if you are an owner. Go to your [organization page](https://dash.screenshotone.com/organization) and click on the remove member button next to the member you want to remove:

 Sorry, your browser doesn't support embedded videos.

Support

-------

In case if you have any ideas, questions or issues, feel free to contact us at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Documentation for LLMs](/changelog/docs-for-llms/)

ScreenshotOne now supports documentation format specifically targeted for LLMs—llms.txt and llms-full.txt.

Read more →

1 min read

#### [Trigger screenshot download](/changelog/attachment-name/)

Now you can set attachment filename to trigger screenshot download in the browser.

Read more →

1 min read

#### [Extract Open Graph metadata while rendering screenshots](/changelog/open-graph-metadata/)

From today, you can get parsed Open Graph metadata and screenshots in one API request.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/half-quota-reached-notifications
----

Notifications when the usage reaches 50% of the limit

=====================================================

You can now get notifications when the usage reaches 50% of the limit.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jan 12, 2026

We added a new option to the dashboard to send notifications when the usage reaches 50% of the limit.

To enable this feature, go to the “Notifications” page in the dashboard and check the “Send notifications when the usage reaches 50% of the limit” checkbox.

Hope you find it helpful, enjoy and have a nice day!

Please, let us know if you have any feedback or suggestions at [support@screenshotone.com](mailto:support@screenshotone.com).

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [ScreenshotOne is available as a ChatGPT plugin](/changelog/screenshotone-is-available-as-a-chatgpt-plugin/)

From today, you can render screenshots of any website or even raw HTML in ChatGPT—ScreenshotOne is available as a plugin. But at the moment of writing not available yet, in the official store, but it can be available when you read it.

Read more →

2 min read

#### [Set locale and language of the browser](/changelog/language-and-locale/)

A new version of the ScreenshotOne API has been just deployed. It allows you to set both locale and language of the browser when rendering screenshots with one simple option.

Read more →

1 min read

#### [Rendering errors in webhooks](/changelog/screenshotone-webhook-errors/)

Check out how to get notified about rendering errors when using webhooks.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/code-examples/c-net
----

[Skip to content](#_top)

C# (.NET) SDK and Code Examples

===============================

Copy page

If you have any questions, please, reach out at `support@screenshotone.com`.

Massive thanks and rays of goodness to Andy Robinson ([Indie Hackers](https://www.indiehackers.com/TheOrigin), [GitHub](https://github.com/theorigin)) for providing the fully-featured high-quality C# (.NET) SDK.

### Installation

Add the library via nuget using the package manager console:

Terminal window

    1PM> Install-Package ScreenshotOne.dotnetsdk

Or from the .NET CLI as:

Terminal window

    1dotnet add package ScreenshotOne.dotnetsdk

### Usage

Don’t forget to [sign up](https://dash.screenshotone.com/sign-up) to get access and secret keys.

Generate a screenshot URL without executing request:

    1var client = new Client("&lt;access key&gt;", "&lt;secret key&gt;");2var options = TakeOptions.Url("https://www.amazon.com")3  .FullPage(true)4  .Format(Format.PNG)5  .BlockCookieBanners(true);6

    7var url = client.GenerateTakeUrl(options);8

    9// url = https://api.screenshotone.com/take?url=https%3A%2F%2Fwww.amazon.com&full_page=true&format=png&block_cookie_banners=true&access_key=_OzqMIjpCw-ARQ&signature=8a08e62d13a5c3490fda0734b6707791d3decc9ab9ba41e8cc045288a39db502

Take a screenshot and save the image in the file:

    1var client = new Client("&lt;access key&gt;", "&lt;secret key&gt;");2var options = TakeOptions.Url("https://www.google.com")3  .FullPage(true)4  .Format(Format.PNG)5  .BlockCookieBanners(true);6

    7var bytes = await client.Take(options);8

    9File.WriteAllBytes(@"c:\temp\example.png", bytes);

Check out [other SDKs and code examples](/docs/code-examples/).

----
url: https://screenshotone.com/blog/building-a-website-directory-with-nextjs-tailwind-css-and-prisma
----

Building a website directory with Next.js, Tailwind CSS, and Prisma

===================================================================

See how easy it is to build a website directory with screenshots with Next.js, Tailwind CSS, and Prisma.

[Blog post](/blog/) 14 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Nov 17, 2022

The article was initially published at a friendly site 👉 [Ship SaaS](https://shipsaas.com/blog/website-directory-next-js-tailwind-prisma), one the best SaaS templates based on Next.js.

And you also might be interested in [building a Programmatic SEO site with automated website screenshots using ScreenshotOne, Airtable, and Launchman](/blog/how-to-build-a-programmatic-seo-site-with-automated-website-screenshots-using-screenshotone-airtable-and-launchman/), instead of writing code.

Before I start, I must admit that I have zero experience or don’t have experience at all with [React](https://reactjs.org/), Tailwind CSS, and Prisma. I also don’t feel that I am profound in JavaScript. And this is excellent news because you will see this stack through the lens of a newcomer, not a passionate fan of these technologies.

Why Next.js, Tailwind CSS, and Prisma

-------------------------------------

### Next.js

I picked up Next.js for testing because it is popular and has good tooling around it. Yes, popularity is a good factor for me. I am tired of searching for solutions to infrequent bugs for the “underground” framework I chose in the past.

I want to find one widespread stack with good developer experience that is performant and scalable. I don’t say Next.js satisfies my criteria, but it looks like it might. That’s why I am building an app to test it.

### Tailwind CSS

I mostly used [Twitter Bootstrap](https://getbootstrap.com/) as a CSS framework, but Tailwind CSS has become quite popular over the last few years. And it proposes a different approach from what you do with the Bootstrap framework.

From the beginning, Twitter Bootstrap focused on providing many convenient components like buttons, sliders, tables, etc.

Tailwind CSS is a utility-first framework. It means that there are no components at all by default, and you decide how you want to style your page.

However, in recent times, I have seen a lot of convergence in both approaches. Twitter Bootstrap adds more and more utility classes, and you can buy [Tailwind UI](https://tailwindui.com/) or take a look at [daisyUI](https://daisyui.com/) and [Flowbite](https://flowbite.com/), which provide many components that you might want to use along with Tailwind CSS.

### Prisma

There are many popular ORM libraries for Node.js: [Prisma](https://www.prisma.io/), [Sequelize](https://sequelize.org/), [TypeORM](https://typeorm.io/), and others.

I decided to try out Prisma first because I like the simplicity of their approach. I don’t need to create a model as in ORMs based on Active Record and Data Mapper patterns.

Prisma gives me a typed abstraction over the database, and I can decide how I want to use it. I can build models or use Prisma directly — it solely depends on my needs.

I picked up SQLite as a database for simplicity of development. But you can use [MySQL, PostgreSQL, MongoDB, and many other DBs supported](https://www.prisma.io/docs/reference/database-reference/supported-databases) by Prisma.

### Wrap up

Next.js, Tailwind CSS, and Prisma can be good starting choices for [indie hackers](https://www.indiehackers.com/), solo entrepreneurs, and small and enterprise teams.

Let’s write some code and taste this stack!

Meet “Landing Page Hunt”

------------------------

Have you ever seen [ProductHunt](https://www.producthunt.com/), [BetaList](https://betalist.com/), or [CtrlAlt.CC](https://ctrlalt.cc/)?

We will build a small application — site directory that contains a list of landing pages with screenshots. An app user can like pages and submit their landing page.

 Sorry, your browser doesn't support embedded videos.

That’s all the functions we are going to implement. I want to focus only on the app’s core functions; everything else is irrelevant. I will expand a bit on the topic of authentication and subscriptions at the end of the post.

The source code of the project is available on [github.com/screenshotone/landing-page-hunt](https://github.com/screenshotone/landing-page-hunt).

Quick start

-----------

Let’s create a Next.js app:

Terminal window

    1npx create-next-app landing-page-hunt && cd landing-page-hunt

Then install Tailwind CSS:

Terminal window

    1npm install -D tailwindcss postcss autoprefixer2npx tailwindcss init -p

We need to update our template paths in `tailwind.config.js` to match the Next.js directory structure:

    1/** @type {import('tailwindcss').Config} */2module.exports = {3  content: [4    "./pages/**/*.{js,ts,jsx,tsx}",5    "./components/**/*.{js,ts,jsx,tsx}",6  ],7  theme: {8    extend: {},9  },10  plugins: [],11}

To enable support for the Tailwind CSS classes we need to import it in `globals.css`:

    1@tailwind base;2@tailwind components;3@tailwind utilities;

Then we can run the app in the development mode and start coding:

Terminal window

    1npm run dev

Let’s quickly create a basic template and render pages:

    1export default function Home({ landingPages }) {2  return (3    <div className="md:container md:mx-auto px-4">4      <h1 className="text-4xl font-bold text-center pt-5">5        Landing Page Hunt6      </h1>7      <h2 className="pb-5 text-center">8        An inspiration bucket for your next landing page.9      </h2>10      <div className="flex flex-row flex-wrap justify-center gap-8">11        {landingPages.map(landingPage =>12        (<div key={landingPage.url} className="p-2">13          <div className="text-2xl text-center py-3">14            <a href={landingPage.url}>{landingPage.name}</a>15          </div>16          <div className="mt-2 shadow-lg">17            <a href={landingPage.url}><img src={landingPage.screenshotUrl} width="400" /></a>18          </div>19          <div className="text-right text-sm py-5">20            {landingPage.likes} 👍21          </div>22        </div>))}23      </div>24    </div>25  )26}27

    28export async function getStaticProps() {29  const accessKey = process.env.SCREENSHOTONE_ACCESS_KEY;30

    31  const screenshotUrl = (url) => {32    return `https://api.screenshotone.com/take?access_key=${accessKey}&url=${url}&cache=true`;33  }34

    35  const landingPages = [36    {37      name: "KTool",38      url: "https://ktool.io",39      likes: 2,40    },41    // ...42    {43      name: "Ship SaaS",44      url: "https://shipsaas.com/",45      likes: 3,46    }47  ];48

    49  for (let landingPage of landingPages) {50    landingPage.screenshotUrl = screenshotUrl(landingPage.url);51  }52

    53  return {54    props: {55      landingPages56    },57  }58}

[Sign up to ScreenshotOne](https://screenshotone.com/) to get a screenshot API access key and to make it work, we need to create a `.env.local` file and set a `SCREENSHOTONE_ACCESS_KEY` environment variable:

    1SCREENSHOTONE_ACCESS_KEY=<YOUR ACCESS KEY>

Let’s examine the result:

A few key highlights:

1.  Next.js is based on React but solves its most popular pains, so we can quickly build components without thinking about routing, server-side rendering, and even API. It is a fully-fledged full-stack framework.

2.  I used the [getStaticProps](https://nextjs.org/docs/basic-features/data-fetching/get-static-props) function to provide data for the index page at build time. It means that our main page is not dynamic. It is static and already rendered — thus it is blazingly fast.

3.  I didn’t set up [Puppeteer](https://github.com/puppeteer/puppeteer) to take screenshots of the sites but decided to use [a screenshot as a service API](https://screenshotone.com/). It gives a bunch of free screenshots to render websites, so that’s enough to play with our project. Because taking screenshots of the site is not a core topic of the post, and using Puppeteer would be a pain in the ass.

Refactoring to use dynamic content

----------------------------------

We started by using static site generation of Next.js, but we want to like pages, submit pages and get updated results. So, we need to refactor the code to use a more sophisticated approach for our needs.

I propose to do two things:

1.  Extract the logic related to landing pages into a separate unit — a `Directory` class representing the landing page directory. It will help us migrate to an actual database instead of an in-memory cache later.

2.  And use [getServerSideProps](https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props) to render pages dynamically on each request.

### Extracting the “business” logic

The `Directory` class will encapsulate all the logic related to the landing page directory:

    1class Directory {2    constructor() {3        const accessKey = process.env.SCREENSHOT_ONE_ACCESS_KEY;4

    5        const screenshotUrl = (url) => {6            return `https://api.screenshotone.com/take?access_key=${accessKey}&url=${url}&cache=true`;7        };8

    9        const landingPages = [10            {11                name: "KTool",12                url: "https://ktool.io",13                likes: 2,14            },15            // ...16            {17                name: "Ship SaaS",18                url: "https://shipsaas.com/",19                likes: 3,20            },21        ];22

    23        for (let landingPage of landingPages) {24            landingPage.slug = landingPage.name.toLowerCase().replace(" ", "");25            landingPage.screenshotUrl = screenshotUrl(landingPage.url);26        }27

    28        this.landingPages = landingPages;29    }30

    31    async loadLandingPages() {32        return this.landingPages;33    }34}35

    36let directory = null;37if (process.env.NODE_ENV === "production") {38    directory = new Directory(prisma);39} else {40    if (!global.directory) {41        global.directory = new Directory(prisma);42    }43

    44    directory = global.directory;45}46

    47export default directory;

To speed up development, I store everything in memory and once the app is ready, we will simply migrate to use a real database.

### getServerSideProps

Instead of using `getStaticProps`, we now switch to use `getServerSideProps`. It will allow us to render the page dynamically on each request. Look how simple it is:

    1import directory from "../lib/directory";2

    3export default function Home(props) {4  // ...5}6

    7// switch to getServerSideProps instead of using getStaticProps8// to render the content on a per-request basis.9export async function getServerSideProps(context) {10  const landingPages = await directory.loadLandingPages();11

    12  return {13    props: {14      landingPages15    },16  }17}

Sending API requests with Next.js

---------------------------------

Let’s see how easy it is to add API handlers on the backend and send API requests from the client side. We are going to implement the “like page” feature.

First, I put the logic in the `lib/directory.js`:

    1class Directory {2    // ...3    async likePage(slug) {4        for (const landingPage of this.landingPages) {5            if (landingPage.slug == slug) {6                landingPage.likes++;7

    8                return landingPage.likes;9            }10        }11

    12        return 0;13    }14    // ...15}

Then we create [an API handler](https://nextjs.org/docs/api-routes/introduction) `pages/api/like.js`:

    1import directory from "../../lib/directory";2

    3export default async function handler(req, res) {4  const { slug } = req.body;5  const likes = await directory.likePage(slug);6

    7  res.status(200).json({ likes: likes });8}

Next.js will handle all the routing issues for us automatically. So, let’s update the page component `pages/index.js` to send an HTTP request to the like API handler:

    1import React, { useState } from "react";2import directory from "../lib/directory";3

    4export default function Home(props) {5  const [landingPages, setLandingPages] = useState(props.landingPages);6

    7  const likePage = async (slug) => {8    try {9      const response = await fetch(10        `/api/like`,11        {12          headers: {13            'Content-Type': 'application/json'14          },15          method: 'POST',16          body: JSON.stringify({ slug })17        }18      );19      const data = await response.json();20      setLandingPages(21        landingPages.map(p => p.slug == slug ? { ...p, ...{ likes: data.likes } } : p)22      );23    } catch (err) {24      console.error(err);25    }26  };27

    28  return (29    <div className="md:container md:mx-auto px-4">30      <h1 className="text-4xl font-bold text-center pt-5 bg-clip-text text-transparent bg-gradient-to-r from-purple-400 to-pink-600">31        Landing Page Hunt32      </h1>33      <h2 className="pb-5 text-center">34        An inspiration bucket for your next landing page.35      </h2>36      <div className="flex flex-row flex-wrap justify-center gap-8">37        {landingPages.map(landingPage =>38        (<div key={landingPage.url} className="p-2">39          <div className="text-2xl text-center py-3">40            <a href={landingPage.url}>{landingPage.name}</a>41          </div>42          <div className="mt-2 shadow-lg">43            <a href={landingPage.url}><img src={landingPage.screenshotUrl} width="400" /></a>44          </div>45          <div className="text-right text-sm py-5">46            <button onClick={async () => await likePage(landingPage.slug)} className="bg-transparent  hover:text-blue-400 text-blue-900 font-semibold py-2 px-4 border hover:border-blue-400 border-blue-900 rounded">47              {landingPage.likes} 👍48            </button>49          </div>50        </div>))}51      </div>52    </div>53  );54}

The result is that we can click on the like button. Then an HTTP request is made to the API handler, likes property of the page updated, and we receive the result so we can re-render all the landing pages.

More pages and forms

--------------------

We need an opportunity to submit a landing page. So, let’s develop the page. It is straightforward to add new pages with Next.js, and as I mentioned before, routing is done for us.

When I create `pages/submit.js`, Next.js will handle all requests to the page under the path `/submit`.

Let’s create a simple submit page:

    1import { useState } from "react";2import Confetti from 'react-confetti';3import { useWindowSize } from 'react-use';4

    5export default function Submit(props) {6  const endpoint = '/api/submit';7  const [landingPage, setLandingPage] = useState(null);8

    9  const handleSubmit = async (event) => {10    event.preventDefault();11    try {12      const response = await fetch(endpoint, {13        method: 'POST',14        headers: {15          'Content-Type': 'application/json',16        },17        body: JSON.stringify({18          name: event.target.name.value,19          url: event.target.url.value,20        }),21      })22

    23      setLandingPage(await response.json());24    } catch (error) {25      console.error(error);26    }27  }28

    29  const { width, height } = useWindowSize();30

    31  return (32    <div className="mx-auto w-1/2">33      <h3 className="text-xl text-center">{landingPage ? "The page has been submitted successfully 🥳" : "Submit a landing page"}</h3>34      {35        landingPage ? (36          <div className="mx-auto py-2 max-w-fit">37            <Confetti opacity={0.5} width={width} height={height} run={landingPage != null} />38            <div className="text-2xl text-center py-3">39              <a href={landingPage.url}>{landingPage.name}</a>40            </div>41            <div className="mt-2 shadow-lg">42              <a href={landingPage.url}><img src={landingPage.screenshotUrl} width="460" /></a>43            </div>44          </div>45        ) : (46          <form onSubmit={handleSubmit} action={endpoint} className="mt-5">47            <div className="mb-6">48              <label htmlFor="name" className="block mb-2 text-sm font-medium text-gray-900">Name</label>49              <input type="text" id="name" className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 " required />50            </div>51            <div className="mb-6">52              <label htmlFor="url" className="block mb-2 text-sm font-medium text-gray-900">URL</label>53              <input type="text" id="url" className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 " required />54            </div>55            <div className="text-right">56              <button type="submit" className="text-white bg-gradient-to-br from-purple-600 to-blue-500 hover:bg-gradient-to-bl font-medium rounded-lg text-sm px-5 py-2.5 text-center mr-2 mb-2">Submit</button>57            </div>58          </form>59        )60      }61    </div>62  );63}

I added confetti after the submission by using the [react-confetti](https://www.npmjs.com/package/react-confetti) library:

 Sorry, your browser doesn't support embedded videos.

On submit, we read the form data and send a request to a submit API handler (`pages/api/submit.js`):

    1import directory from "../../lib/directory";2

    3export default async function handler(req, res) {4    const body = req.body5    if (!body.name || !body.url) {6        return res.status(400).json({ data: 'Name and URL are required' })7    }8

    9    const landingPage = await directory.submitPage(body.name, body.url);10

    11    res.status(200).json(landingPage);12}

And the apparent logic for the submit function in the `Directory` class:

    1class Directory {2    // ...3    async submitPage(name, url) {4        const landingPage = {5            name: name,6            url: url,7            slug: this.slug(name),8            screenshotUrl: this.screenshotUrl(url),9            likes: 0,10        };11

    12        this.landingPages.push(landingPage);13

    14        return landingPage;15    }16

    17    slug(name) {18        return name.toLowerCase().replace(" ", "");19    }20

    21    screenshotUrl(url) {22        const accessKey = process.env.SCREENSHOTONE_ACCESS_KEY;23

    24        return `https://api.screenshotone.com/take?access_key=${accessKey}&url=${url}&cache=true`;25    }26    // ...27}

That’s how simple it is to develop with Next.js. Do you feel it?

Switching to a SQL database — a case for Prisma

-----------------------------------------------

The core functionality of our app is ready and tested. Since it is encapsulated, we can easily switch to storing data in the permanent database, not in temporary memory.

But before that, let’s install and configure Prisma:

Terminal window

    1npm i prisma

Let’s create a directory, `prisma`, where we will store all the Prisma-related configuration and start with the main DB configuration and schema:

    1generator client {2    provider = "prisma-client-js"3}4

    5datasource db {6    provider = "sqlite"7    url      = "file:./dev.db"8}9

    10model LandingPage {11    id    Int    @id @default(autoincrement())12    slug  String @unique()13    name  String14    url   String15    likes Int16

    17    @@index([slug])18}

The schema file is written in [PSL (Prisma Schema Language)](https://www.prisma.io/docs/concepts/components/prisma-schema).

Then, let’s create a seed file `prisma/seed.js` with landing pages:

    1const { PrismaClient } = require('@prisma/client');2

    3const prisma = new PrismaClient();4

    5const landingPages = [6    {7        slug: "ktool",8        name: "KTool",9        url: "https://ktool.io",10        likes: 2,11    },12    // ...13    {14        slug: "shipsaas",15        name: "Ship SaaS",16        url: "https://shipsaas.com/",17        likes: 3,18    }19];20

    21

    22async function main() {23    console.log(`Start seeding ...`)24    for (const lp of landingPages) {25        const user = await prisma.landingPage.create({26            data: lp,27        })28        console.log(`Created landing page with id: ${user.id}`)29    }30    console.log(`Seeding finished.`)31}32

    33main()34    .then(async () => {35        await prisma.$disconnect()36    })37    .catch(async (e) => {38        console.error(e)39        await prisma.$disconnect()40        process.exit(1)41    });

To make it part of the migration process, we need to specify the seed in `package.json`:

    1{2    // ...3    "prisma": {4        "seed": "node prisma/seed.js"5    }6    // ...7}

And after running migrations, including seeding:

Terminal window

    1npx prisma migrate dev

We are ready to use the `Prisma` client in our application. Let’s instantiate the Prisma client in `lib/prisma.js`:

    1import { PrismaClient } from "@prisma/client";2

    3let prisma = null;4if (process.env.NODE_ENV === 'production') {5    prisma = new PrismaClient();6} else {7    if (!global.prisma) {8        global.prisma = new PrismaClient();9    }10

    11    prisma = global.prisma;12}13

    14export default prisma;

`PrismaClient` is attached to the `global` object in development to prevent exhausting your database connection limit.

And we are ready to refactor the `Directory` class to entirely rely on `Prisma`:

    1import prisma from "./prisma";2import screenshotUrl from "./screenshotone";3

    4class Directory {5    constructor(prisma) {6        this.prisma = prisma;7    }8

    9    async submitPage(name, url) {10        const landingPage = await this.prisma.landingPage.create({11            data: {12                slug: this.slug(name),13                name,14                url,15                likes: 0,16            },17        });18

    19        return {20            ...landingPage,21            screenshotUrl: screenshotUrl(url),22        };23    }24

    25    async likePage(slug) {26        const landingPage = await this.prisma.landingPage.update({27            where: {28                slug: slug,29            },30            data: {31                likes: {32                    increment: 1,33                },34            },35        });36

    37        return landingPage.likes;38    }39

    40    async loadLandingPages() {41        const pages = await this.prisma.landingPage.findMany();42

    43        return pages.map((p) => {44            return {45                ...p,46                screenshotUrl: screenshotUrl(p.url),47            };48        });49    }50

    51    slug(name) {52        return name.toLowerCase().replace(" ", "").replace(".", "");53    }54}55

    56let directory = null;57if (process.env.NODE_ENV === "production") {58    directory = new Directory(prisma);59} else {60    if (!global.directory) {61        global.directory = new Directory(prisma);62    }63

    64    directory = global.directory;65}66

    67export default directory;

I chose SQLite for simplicity. I also extracted the link generation logic to a separate module.

Securing API keys for screenshot API

------------------------------------

The rendered screenshots in the app expose the screenshot API access key. For the development stage, it was OK, but for deployment to production, we need to store the key securely.

ScreenshotOne API allows using [signed links](https://screenshotone.com/docs/signed-requests/). It means that every exposed screenshot URL is publicly signed, and if you try to change any parameter and to reuse (steal) an API key, you need to compute a new signature, but you can’t without having a secret key.

In addition to that, you can force ScreenshotOne API to accept only signed requests.

That’s how I generated the signed links with ScreenshotOne API SDK:

    1import * as screenshotone from 'screenshotone-api-sdk';2

    3let client = null;4if (process.env.NODE_ENV === 'production') {5    client = new screenshotone.Client(process.env.SCREENSHOTONE_ACCESS_KEY, process.env.SCREENSHOTONE_SECRET_KEY);6} else {7    if (!global.client) {8        global.client = new screenshotone.Client(process.env.SCREENSHOTONE_ACCESS_KEY, process.env.SCREENSHOTONE_SECRET_KEY);9    }10

    11    client = global.client;12}13

    14export default function url(url) {15    const options = screenshotone.TakeOptions16        .url(url)17        .cache(true)18        .cacheTtl(2000000)19        .blockChats(true)20        .blockCookieBanners(true)21        .blockAds(true);22

    23    return client.generateTakeURL(options);24}

Another solution would be to render screenshots and store screenshots on the backend site and share rendered images with the front end. Or use the [“upload screenshots to S3”](https://screenshotone.com/docs/options/#storing) feature by ScreenshotOne and then serve files from a CDN.

Expanding the app to complete the SaaS solution

-----------------------------------------------

And we have arrived at the stage when we want to make a bit of money with our small, simple project. Imagine allowing accept payments for featuring landing pages. But users will need to sign up. And we need to make sure that voting is fair. There are a few things required to do it:

*   Authentication;

*   Billing and subscriptions;

*   Transactional emails;

*   Dashboard to manage the app;

*   Cover the app with tests;

*   Make sure that the site is SEO-friendly;

*   Internalization if we want to go wide.

Next.js has many solutions you can combine to solve all problems mentioned above.

But I want to propose something interesting if your goal is to ship SaaS and not just play with code like I love to do. I would argue that starting with a SaaS template is better to save time and energy.

Nowadays, there are many SaaS solutions you can pick up to bootstrap your project quickly. Take a look at [Ship SaaS — a SaaS template based on Next.js](https://shipsaas.com/), for example, and the problems it solves for you. It literally can save you thousands of hours.

Instead of summary

------------------

As you might sense, I enjoyed it a lot to build with Next.js, Tailwind CSS, and Prisma. I am impatient to try them for any new idea I will have in the future. Many problems are already solved in these frameworks, and it is easy to use them.

In addition, there are a bunch of good SaaS templates I can use if I want to bootstrap a SaaS quicker.

Read more posts

---------------

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

[View all posts](/blog/)

#### [How to build a Programmatic SEO site with automated website screenshots using ScreenshotOne, Airtable, and Launchman](/blog/how-to-build-a-programmatic-seo-site-with-automated-website-screenshots-using-screenshotone-airtable-and-launchman/)

Programmatic SEO is a great growth hacking strategy where you create a large number of content pages that rank for long-tailed keywords on Google.

Read more

#### [What is OpenClaw and how can it help?](/blog/openclaw/)

A short practical introduction to OpenClaw, what it is good at, and why it is useful if you want a proactive AI assistant that lives in your chat apps.

Read more

#### [ScreenshotOne reached $200K ARR with 400+ paying customers](/blog/200000-arr-and-400-paying-customers/)

It is a good milestone to make a compact snapshot of the insights that (maybe?) led to it.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/6
----

Automate Website Screenshots

----------------------------

Guides, Product Updates, and Helpful Resources from ScreenshotOne.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

#### [ScreenshotOne reached $200K ARR with 400+ paying customers](/blog/200000-arr-and-400-paying-customers/)

It is a good milestone to make a compact snapshot of the insights that (maybe?) led to it.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Apr 10, 2025

•

7 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [How to render screenshots with different emoji styles in Puppeteer](/blog/emojis/)

Learn how to render screenshots with different emoji styles in Puppeteer using emoji-js in a few lines of code.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Apr 4, 2025

•

2 min read

#### [OpenAI 4o image generation and marketing opportunities](/blog/openai-4o-marketing-opportunities/)

OpenAI 4o image generation is a really good model that can change the way you automate marketing

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 30, 2025

•

2 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Magic Pages: Showcasing Product Adoption with Screenshots](/blog/magic-pages/)

How and why "Magic Pages" used ScreenshotOne to showcase how their customers use their product.

Written by

[Jannis Fedoruk-Betschki](/contributors/jannis-fedorukbetschki/), [Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 28, 2025

•

1 min read

#### [Monitoring website changes](/blog/monitoring-website-changes/)

I tried many ways to monitor and detect website changes. But I was always disappointed by the results. I want to share a few tips that might help you to get better results, if you plan to do the same.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Apr 27, 2025

•

4 min read

#### [A Chrome Extension by ScreenshotOne for rendering full-page screenshots](/blog/full-page-chrome-extension/)

We just launched a new full-page screenshot Chrome extension that allows you to take full page screenshots of any websites and annotate them in a few clicks.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Dec 28, 2024

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Using AI screenshot analysis to identify leads for a design agency](/blog/ai-screenshot-analysis-for-finding-customers/)

Elias shares his process for discovering high-quality leads for a design agency by using AI screenshot analysis within the Clay platform.

Written by

[Elias Stravik](/contributors/elias-stravik/)

Published on

Dec 23, 2024

•

4 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Integrating ScreenshotOne into the directory management platform](/blog/makeadir-feedback/)

How and why "Make a Directory" used ScreenshotOne to automate screenshots for directory websites.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Bohdan Shulha](/contributors/bohdan-shulha/)

Published on

Dec 23, 2024

•

3 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/forge-iq
----

How Forge IQ automates visual CRO audits with ScreenshotOne

===========================================================

A story about how Forge IQ automates its CRO audit by integrating ScreenshotOne into their workflow to produce visual reports.

[Customer story](/blog/tags/customer-stories/) 1 min read

#### Written by

[William Prud’homme](/contributors/william-prudhomme/)

#### Published on

May 23, 2025

Automated conversion audits

---------------------------

At [Forge IQ](https://www.forgeiq.ca), we help e-commerce brands and marketing agencies increase their revenue through automated conversion audits. We analyze user behavior, flag UX issues, and deliver clear, actionable reports to improve conversions without wasting dev hours.

[](https://www.forgeiq.ca)

How do you use ScreenshotOne and how does it help you?

------------------------------------------------------

We use ScreenshotOne as part of our lead magnet, a free CRO audit that gives brands a taste of what we can do. The screenshots help us illustrate UX issues clearly, making the audit more visual, engaging, and impactful.

The API is fast, reliable, and plugs right into our automation, saving us time while delivering polished results.

Why did you choose ScreenshotOne? Did you try other alternatives?

-----------------------------------------------------------------

ScreenshotOne is one of those rare tools that just does its job perfectly. It’s simple to integrate, consistently delivers great results, and the support is excellent.

We tested a few alternatives and ScreenshotOne was the clear winner for both quality and ease of use. We’d love to see the option to capture different screen formats too, like tablet and mobile, to support a more complete analysis.

Read more customer stories

--------------------------

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

[View all posts](/blog/tags/customer-stories/)

#### [How AdKit automated onboarding](/blog/adkit/)

A short story by the founder of AdKit about how they use ScreenshotOne for onboarding automation.

Read more

#### [Why FrameKit chose ScreenshotOne for their business](/blog/framekit/)

A short story about how and why FrameKit chose ScreenshotOne for their use case.

Read more

#### [How Stagetimer automates Open Graph image generation](/blog/how-stagetimer-automates-og-image-generation/)

We would love to share a quick review of ScreenshotOne by Lukas Hermann, a co-founder of Stagetimer on how he uses the API daily to generate screenshots and automate regular tasks associated with screenshots.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/credits
----

[Skip to content](#_top)

How credits work in ScreenshotOne

=================================

Copy page

Note

Currently, everything costs 1 credit, be it a full-page screenshot, a scrolling screenshot, a PDF, or a video.

It is done that way to keep the pricing simple and predictable.

Every plan on ScreenshotOne comes with a monthly credit allowance. Credits reset at the start of each billing cycle—regardless of whether you’re on a monthly or annual plan.

*   **Monthly plans**: Credits refresh on the same day you subscribed each month.

*   **Annual plans**: You pay once per year, but your credits still refresh monthly, giving you a predictable reset cadence.

*   **No rollover**: Unused credits expire at the end of the cycle.

*   **Overages**: If you go over your limit and [extra charging is enabled, extra screenshots are billed automatically based on your plan’s per-credit rate](https://screenshotone.com/docs/charging-extra/).

This keeps your usage simple and helps you forecast your monthly screenshot volume, even if you prefer paying annually.

Cancellation

------------

When you cancel a plan, you keep your current billing cycle until it ends. Your credit behavior depends on that cycle:

### You keep your credits until the cycle ends

All remaining credits stay available and usable until the end of your current billing period. Nothing is removed immediately.

### No new credits after cancellation

When your cycle ends, your plan won’t renew and you won’t receive the next month’s credit reset. You will be downgraded to the free plan or if the free plan is not available, you will lose access to the service.

### No refunds for unused credits

Because credits are issued monthly and expire at the end of each cycle, any unused credits at the moment your billing period ends simply expire.

### Annual subscribers

If you’re on an annual plan:

*   You continue to receive monthly credit resets until the end of your paid annual term.

*   Once the annual term ends, no new credits are issued.

*   Any remaining credits at that moment expire.

Support

-------

If you have any questions or need help, please contact our support team at [support@screenshotone.com](mailto:support@screenshotone.com).

----
url: https://screenshotone.com/blog/why-and-how-to-choose-a-screenshot-api
----

Why and how to choose a screenshot API

======================================

You don't need a screenshot API if it is a one-off task for you and you can use some library for screenshotting.

[Blog post](/blog/) 6 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Mar 20, 2024

#### Tags

[Screenshot rendering](/blog/tags/screenshot-rendering/)

But if you plan to scale and don’t want to invest time in this boring job as screenshot automation, consider choosing a screenshot API.

**Disclaimer:** The goal of the post is to help you make a weighed decision and to understand if you really need a screenshot API. But expect [ScreenshotOne](/) to be promoted once in a while as a good option or choose from other [best screenshot APIs](/blog/best-screenshot-apis/).

[](/)

These APIs allow you to capture screenshots of web pages programmatically, which can be useful for a variety of applications such as generating previews, archiving, or monitoring content.

Let’s check why you might want to choose a screenshot API and how to go about selecting one that suits your needs.

Why and when do you need a screenshot API

-----------------------------------------

### 1\. Outsource the pains of scalability

If you need to handle large volumes of screenshots, it is better to consider using a screenshot API.

For example, [ScreenshotOne](/) is a scalable and battle-tested production-ready screenshot API used by many developers. If you need to render 100,000 screenshots a day or 1,000,000 screenshots, it will do that for you and take care of all the infrastructure related to that.

### 2\. Customization

With libraries like [Puppeteer](/blog/how-to-take-a-screenshot-with-puppeteer/) or similar, you can customize any websites however you need before screenshotting them, also you can write a lot of logic.

But! You do need to write code and invest time. And this code might have bugs and you will need to support it.

If it is a one-off task, then it is not a problem. But if your business will rely on it, you might consider using a screenshot API like [ScreenshotOne](/) or [similar](/blog/best-screenshot-apis/).

For example, ScreenshotOne allows you to customize the viewport dimensions, block cookie banners, run in stealth mode, use proxies, perform retries for you, upload to S3 storage, render video, and many other options that are already tested and used by [many customers](/customers/).

### 3\. Integrations

Easily integrate with other tools and workflows, such as content management systems, no-code tools, quality assurance tools, or any other third-party tools.

When you use [a screenshot API like ScreenshotOne](/), you can already set up and use it with Zapier in a few clicks or upload screenshots to any S3-compatible storage with one simple API request.

You don’t need to build integrations yourself anymore. They are ready and battle-tested.

### 4\. Support

If something happens, you don’t spend time on it anymore. You just send a support ticket and the problem gets fixed for you. Usually, with the cheapest plan for screenshot APIs, it costs around $10-20/mo.

What about updating screenshotting libraries, making sure that your headless browsers keep up with the latest website changes, and a hundred other different issues?

Set up any [decent screenshot API](/blog/best-screenshot-apis/) and forget about all these problems.

### 5\. New features and requests

Don’t want to spend time on building new features, just shoot an email and we will consider doing it for you. Most screenshot API platforms are responsive, too.

You won’t spend your precious on developing features for screenshot rendering anymore.

In ScreenshotOne, if fits [our roadmap](/roadmap/), it is an easy request and we might prioritize it.

How to Choose a Screenshot API

------------------------------

When choosing a screenshot API, make sure to consider the following factors:

### 1\. Features

Look for APIs that offer the specific features you need, such as device emulation, custom dimensions, full-page screenshots, and the ability to capture screenshots behind authentication, or even [scrolling screenshots](https://screenshotone.com/scrolling-screenshots/).

If you have a specific request and decide to go with ScreenshotOne, please, reach out to us at `support@screenshotone.com` and we will consider adding the feature you need.

### 2\. Performance

Consider the speed and reliability of the API. A good screenshot API should be able to quickly generate screenshots without significant downtime.

ScreenshotOne simple API request takes less than one second, what can be faster than that?

Of course, more complex sites will take more time to respond, but it will be anyway faster than most APIs can provide.

### 3\. Quality

The API should produce high-quality screenshots that accurately represent the web page. This includes proper rendering of CSS, JavaScript, and images.

Also, you must keep up with the latest browser changes and update them.

ScreenshotOne will do that for you.

### 4\. Ease of Use

The API should have clear documentation and be easy to integrate into your existing systems. Look for APIs that offer libraries or SDKs for your programming language of choice.

ScreenshotOne has native SDKs for the most popular programming languages. Estimate the ease of use for Node.js:

    1// npm install screenshotone-api-sdk --save2

    3import * as fs from "fs";4import * as screenshotone from "screenshotone-api-sdk";5

    6// create API client7const client = new screenshotone.Client("<access key>", "<secret key>");8

    9// set up options10const options = screenshotone.TakeOptions.url("https://example.com")11    .delay(3)12    .blockAds(true);13

    14// generate URL15const url = client.generateTakeURL(options);16console.log(url);17// expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com&delay=3&block_ads=true&access_key=%3Caccess+key%3E&signature=7f3419ece2c53ed2c7923c7d5deef290d662c3643822bf69ec8259ce10b3ea6118

    19// or download the screenshot20const imageBlob = await client.take(options);21const buffer = Buffer.from(await imageBlob.arrayBuffer());22fs.writeFileSync("example.png", buffer);23

    24// the screenshot is store in the example.png file

And, check out our [documentation](/docs/getting-started/)—it has everything for you to get started.

### 5\. Pricing

Compare the cost of different APIs. Pricing models can vary widely, from pay-per-use to subscription-based models. Ensure that the pricing structure fits your usage patterns and budget.

ScreenshotOne is not the cheapest option on the market. But it is certainly worth it, but compare it to [other APIs](/blog/best-screenshot-apis/) to make a grounded choice.

[](/pricing/)

Our pricing structure tries to satisfy most needs and provide maximum value for our customers at the lowest price we can afford without compromising on quality.

### 6\. Security

Ensure the API provider has robust security measures in place, especially if you plan to capture screenshots of sensitive or private content.

ScreenshotOne doesn’t store screenshots except when you cache them. And ScreenshotOne excludes any sensitive information from API requests from logs and database history, like cookies, proxy credentials, and similar.

Privacy is one of our core focuses.

### 7\. Customer Support

Good customer support can be crucial, especially if you encounter issues integrating or using the API. Look for providers that offer timely and helpful support.

[](/customers/)

With ScreenshotOne you can [book a demo call](/book-a-call/) and we can assist with your integration, you can reach out via live chat or email, whatever works best for you, and we will try to solve your issues as fast as possible.

### 8\. Compliance

If your project operates in a regulated industry, make sure the API provider complies with relevant standards and regulations.

### Research and Test

Once you’ve narrowed down your options based on the above criteria, it’s a good idea to test the APIs.

You can check out our guide on [the best screenshot APIs](/blog/best-screenshot-apis/) to choose the APIs from.

Most providers offer a trial period or a free tier that you can use to evaluate performance, quality, and ease of use. Testing also allows you to identify any potential issues or limitations that might affect your project.

Once you considered your needs and evaluated screenshot API providers, based on the mentioned factors, highly likely you will make a good choice.

If you have any questions, please, feel free to [book a demo call](/book-a-call/) or just shoot an email at `support@screenshotone.com`, we won’t sell you anything, but will be happy to choose the best option for you.

Read more Screenshot rendering

------------------------------

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

[View all posts](/blog/tags/screenshot-rendering/)

#### [Let's build a screenshot API](/blog/building-screenshot-api/)

Two years have passed since the launch of ScreenshotOne, and I want to do a fun coding exercise and build a tiny subset of what the API is today, but from scratch.

Read more

#### [How to take website screenshots in Python](/blog/how-to-take-website-screenshots-in-python/)

With Python, you can take website screenshots in multiple ways. But the best way to do it depends solely on your needs and your use case. Let's quickly examine all the options.

Read more

#### [How to Take Screenshots with pyppeteer in Python](/blog/pyppeteer-python-screenshots/)

Guide to taking screenshots with pyppeteer in Python. Learn the basics, full page captures, and why you should migrate to Playwright.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/financial-audit-trail-capture
----

Automate Website Screenshots

1 min read

Landing Page Design Inspiration Collection

==========================================

Financial applications need immutable copies of trade confirmations, order books, swap quotes, or K‑line charts for regulators and SOC 2 audits.

Immutable trade confirmations for compliance‑first Fin‑tech apps

----------------------------------------------------------------

Regulators, auditors, and SOC 2 reviewers all ask for the same thing: **unchangeable evidence** of what really happened on your trading platform. Every filled order, K‑line candle, swap quote, or depth‑of‑book snapshot needs to live forever in a format nobody can edit later. Screenshots are nice for a quick look, but PDFs are safer—self‑contained, hard to tamper with, and easy to sign or hash.

How ScreenshotOne can help?

---------------------------

[ScreenshotOne’s PDF API](/pdf-generation-api/) fits the job perfectly:

*   **Any source, one call.** Pass a live URL or raw HTML and get back a pixel‑perfect PDF of the chart, order book, or confirmation screen—no headless browser to maintain.

*   **Immutable by design.** Store the PDF as‑is, add a SHA‑256 hash to your ledger, and you’ve got write‑once proof that satisfies SOC 2 control CC7 and most securities‑law retention rules.

*   **Scales with the market.** Whether you’re capturing one trade per minute or thousands per second during a crypto surge, the API queues and streams PDFs without throttling your app.

Quick start

-----------

Terminal window

    1curl https://api.screenshotone.com/take \2  -d access_key=<your access key> \3  -d url=https://example.com/receipt \4  -d format=pdf \

The call above grabs the trade‑receipt page, bakes it into an PDF with all CSS intact, and returns it.

**Next step:** Plug the PDF URL or hash into your audit log table, and you’re done—immutable evidence on tap for every trade your platform ever executes.

I am a very happy customer of ScreenshotOne by Dmytro Krasun.

I really wish all APIs would have great documentation, playground and SDKs like that. Dmytro really outdid himself.

Highly recommend 🤗

Matthias Neumayer

Co-Founder, [Branding 5](https://screenshotone.com/blog/how-branding5-uses-screenshotone/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/puppeteer-execution-context-was-destroyed-most-likely-because-of-a-navigation
----

How to fix the "Execution context was destroyed" error when using Puppeteer

===========================================================================

Fix the Puppeteer "Execution context was destroyed, most likely because of a navigation" error after click, form submit, redirect, reload, or page.evaluate.

[Blog post](/blog/) 5 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Mar 13, 2026

#### Tags

[Puppeteer guides](/blog/tags/puppeteer-guides/)

Short answer

------------

The most common reason for this error is a race condition: your code clicks a link, submits a form, or changes `window.location`, and then tries to read or modify the old page context after navigation already started.

The safest fix is to start waiting for navigation before the action that triggers it:

    1const [response] = await Promise.all([2    page.waitForNavigation({3        waitUntil: ["domcontentloaded", "networkidle2"],4    }),5    page.click("a"),6]);

Use the same pattern when a form submit, redirect, reload, or script-triggered navigation is expected.

If your code does not actually navigate, `page.waitForNavigation()` is the wrong tool. In that case, wait for a selector, response, function, or another concrete signal instead.

For more details on `waitUntil`, `load`, `domcontentloaded`, and `networkidle2`, follow the guide on [how to wait for page load in Puppeteer](/blog/puppeteer-wait-until-the-page-is-ready/).

If you use Playwright instead, there is now a dedicated Playwright version of this guide: [how to fix “Execution context was destroyed” in Playwright](/blog/playwright-execution-context-was-destroyed-most-likely-because-of-a-navigation/).

Why this error happens

----------------------

Puppeteer runs functions like `page.evaluate()` and `page.$eval()` inside the current page execution context. When the page navigates, reloads, or replaces the frame, the old context is destroyed and Puppeteer can no longer use it.

In Puppeteer internals, an execution context is the JavaScript environment for a specific page, frame, or isolated world. When you call `page.evaluate()`, Puppeteer serializes your function, sends it to Chrome DevTools Protocol, and asks Chrome to run it in that exact execution context. This is different from Puppeteer’s `BrowserContext`, which is about isolated browser storage like cookies and local storage.

That distinction matters because the execution context is tied to the current document. As soon as the page navigates, reloads, redirects, or swaps frames, Chrome destroys the old context and creates a new one for the new document. Any pending `page.evaluate()` call, element handle, or JS object handle from the previous page can become invalid at that moment, which is why Puppeteer throws this error instead of letting you keep talking to a page that no longer exists.

Typical triggers are:

*   clicking a link that opens the next page;

*   submitting a form;

*   calling `window.location = "..."` or `location.reload()`;

*   unknown page scripts, third-party widgets, or tag manager code that trigger a redirect for you;

*   redirects after login or checkout;

*   evaluating JavaScript while the page is in the middle of navigation.

The error often appears as one of these messages:

*   `Execution context was destroyed, most likely because of a navigation`

*   `page.evaluate: Execution context was destroyed, most likely because of a navigation`

Fix it after click, submit, or redirect

---------------------------------------

When an action triggers navigation, pair it with `page.waitForNavigation()` in the same `Promise.all()` call:

    1const [response] = await Promise.all([2    page.waitForNavigation({3        waitUntil: ["domcontentloaded", "networkidle2"],4        timeout: 30_000,5    }),6    page.click("a.my-link"),7]);8

    9console.log(response?.status());

For a form submit:

    1await page.type('input[name="email"]', "john@example.com");2await page.type('input[name="password"]', "secret");3

    4await Promise.all([5    page.waitForNavigation({6        waitUntil: ["domcontentloaded", "networkidle2"],7    }),8    page.click('button[type="submit"]'),9]);

For script-triggered navigation:

    1await Promise.all([2    page.waitForNavigation({3        waitUntil: ["load", "networkidle2"],4    }),5    page.evaluate(() => {6        window.location.href = "https://example.com/dashboard";7    }),8]);

This matters because `page.click()` can trigger navigation immediately. If you `await page.click()` first and only then call `page.waitForNavigation()`, you can miss the navigation event and get the race condition you were trying to avoid.

Fix page.evaluate errors

------------------------

This page should cover `page.evaluate` explicitly because many searches are for the `page.evaluate: execution context was destroyed` variant.

The problem usually looks like this:

    1await page.click("a");2await page.evaluate(() => {3    return document.title;4});

If the click starts navigation, the `evaluate` call can run against a page context that no longer exists.

Fix it by waiting for the new page state first:

    1await Promise.all([2    page.waitForNavigation({3        waitUntil: ["domcontentloaded", "networkidle2"],4    }),5    page.click("a"),6]);7

    8const title = await page.evaluate(() => document.title);9console.log(title);

The same rule applies to `page.$eval()`, `page.$$eval()`, and element handles from the old page. After navigation, reacquire the elements on the new page instead of reusing stale handles.

In some flows, `page.evaluate()` is only a best-effort step, for example analytics extraction, cosmetic DOM cleanup, or reading a value you do not strictly need. In those cases, it can be reasonable to ignore this specific failure and continue:

    1try {2    await page.evaluate(() => {3        document.querySelector(".popup")?.remove();4    });5} catch (error) {6    // Ignore execution context errors if this step is optional.7}

This is especially useful when the redirect is not triggered by your code directly, but by an unknown inline script, A/B test, consent banner, or third-party script that changes the page while your automation is still running.

When waitForNavigation is the wrong fix

---------------------------------------

Not every page update is a navigation.

If a site updates content with client-side JavaScript and stays on the same page, `page.waitForNavigation()` can just hang until timeout. Use a more specific wait instead:

Wait for an element:

    1await page.click("button.load-results");2await page.waitForSelector(".results-loaded", {3    visible: true,4    timeout: 30_000,5});

Wait for a response:

    1await page.click("button.refresh-data");2await page.waitForResponse((response) => {3    return response.url().includes("/api/results") && response.ok();4});

Wait for a page condition:

    1await page.click("button.show-price");2await page.waitForFunction(() => {3    return document.querySelector(".price")?.textContent?.trim().length > 0;4});

If you are unsure which wait is correct, start by asking: did the page actually navigate, or did it only update part of the DOM?

Common mistakes

---------------

*   Waiting for navigation after the click instead of at the same time.

*   Using `page.waitForNavigation()` when there is no real navigation.

*   Calling `page.evaluate()` or reusing element handles from the old page after reload or redirect.

*   Waiting only for `load` on modern pages that still render important content after initial load.

*   Forgetting to set a timeout and ending up with scripts that hang too long.

For navigation-heavy screenshot flows, the companion guide on [how to wait for page load in Puppeteer](/blog/puppeteer-wait-until-the-page-is-ready/) explains which `waitUntil` values are usually safer.

If you are taking screenshots

-----------------------------

If this error happens while taking screenshots, the root cause is usually the same: the page changed context before your script finished interacting with it.

The fix is still to synchronize navigation and page actions correctly. If you want a broader walkthrough, see [how to take a screenshot with Puppeteer](/blog/how-to-take-a-screenshot-with-puppeteer/).

Or use an API

-------------

If you encounter this error while building a screenshot rendering pipeline, all these issues and this synchronization is already built into [our ScreenshotOne URL to Image API](/).

[](/)

And in addition to that we solve most if not all the issues related to rendering screenshots in headless browsers including blocking ads, banners, rendering lazy-loaded elements, and more.

You can [start for free](/).

Read more Puppeteer guides

--------------------------

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

[View all posts](/blog/tags/puppeteer-guides/)

#### [How to hide chat widgets when taking a screenshot with Puppeteer](/blog/how-to-hide-chat-widgets-when-taking-a-screenshot-with-puppeteer/)

When you want to take chat widgets, there are annoying chat widgets that you would love to hide. It is easy to do.

Read more

#### [How to add custom scripts to a page in Puppeteer](/blog/how-to-add-custom-scripts-to-a-page-in-puppeteer/)

How to add custom scripts to a page in Puppeteer. Let's discover how it works quickly."

Read more

#### [Puppeteer versus Playwright](/blog/puppeteer-versus-playwright/)

When to use Playwright and when to use Puppeteer.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/clay-integration
----

Add ScreenshotOne to Clay

=========================

Generate website screenshots inside Clay to qualify leads, assess content, and enrich rows with visual context automatically.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jan 7, 2026

[ScreenshotOne is now available as a data provider in Clay](https://www.clay.com/integrations/data-provider/screenshotone).

With ScreenshotOne and Clay, you can enrich data automatically with:

*   📸 website screenshots;

*   📄 PDFs from HTML or URLs;

*   🎬 scrolling screenshots and videos;

*   🔥 and more…

Check out [our Clay integration page](/integrations/clay/) for more details.

If you have any questions or need any assistance, please, reach out at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Improved favicon detection for metadata\_icon](/changelog/improved-metadata-icon-detection/)

Improved \`metadata\_icon\` to check common favicon link variants more reliably.

Read more →

1 min read

#### [Screenshot URL in webhooks](/changelog/screenshot-url-in-webhooks/)

Now, you can get the screenshot URL in the webhook response.

Read more →

1 min read

#### [Support of the OpenAI GPT Vision API in ScreenshotOne](/changelog/support-of-the-openai-gpt-vision-api-in-screenshotone/)

From today, you can use our screenshot API together with the OpenAI Vision API. It allows you to send screenshots directly to the Vision API without building all the infrastructure yourself.

Read more →

2 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/contributors/elias-stravik
----

Elias Stravik

-------------

View all Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [Using AI screenshot analysis to identify leads for a design agency](/blog/ai-screenshot-analysis-for-finding-customers/)

Elias shares his process for discovering high-quality leads for a design agency by using AI screenshot analysis within the Clay platform.

Written by

[Elias Stravik](/contributors/elias-stravik/)

Published on

Dec 23, 2024

•

4 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Elias Stråvik uses GPT-4 Vision and Zapier for landing page feedback automation](/blog/generating-landing-page-feedback-with-vision/)

A quick review of ScreenshotOne by Elias Stråvik, a founder of Roast as A Service on how he uses the ScreenshotOne daily to automate regular tasks associated with screenshots.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Elias Stravik](/contributors/elias-stravik/)

Updated on

Mar 4, 2024

•

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/fail-if-content-contains
----

Fail rendering if the content contains a string

===============================================

There is a set of use cases when you want to fail screenshot rendering and retry it if the content of the page contains a string.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Mar 17, 2024

For example:

1.  If you use residential rotating proxies and a site blocks you with some specific test, you might want to retry the request instead of getting the successful screenshot of the page with the CAPTCHA or an error.

2.  Setting `fail_if_content_contains=Coming Soon` for your screenshot requests allows you to automatically ignore captures showing “Coming Soon” on a product page, ensuring you only get notified when the page updates to show the product is available for purchase.

3.  To focus monitoring on actual uptime and avoid capturing screenshots during nightly maintenance, configure your requests with `fail_if_content_contains=Maintenance`, thereby skipping any maintenance messages displayed on your application’s homepage.

You don’t pay for failed and cached screenshots with ScreenshotOne.

That’s exactly what you need the option `fail_if_content_contains` for.

Let’s quickly see how it works and how you can use it. Let’s first render the example.com page:

    1https://api.screenshotone.com/take?access_key=<your access key>&url=https://example.com

The result is:

Now, let’s try to fail it:

    1https://api.screenshotone.com/take?fail_if_content_contains=Illustrative+Examples+In+Documents&access_key=<your access key>&url=https://example.com

The result is:

    1{2    "is_successful": false,3    "error_message": "The page content contains the requested string `Prior` by the `fail_if_content_contains` option. If it seems to be a mistake or not what you expected, please, reach out to `support@screenshotone.com` as quickly as possible, and will assist and try to resolve your problem.",4    "error_code": "content_contains_requested_string"5}

As you might notice, the match is case insensitive, it is done for simplicity.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Updated the official Go SDK](/changelog/updated-gosdk/)

We updated the Go SDK to support the latest API features.

Read more →

1 min read

#### [Stop scrolling screenshots when a given selector is visible](/changelog/animated-scrolling-till-selector/)

New options were added to the ScreenshotOne API to stop scrolling screenshots when a given selector is reached.

Read more →

1 min read

#### [New hover option](/changelog/hover-option/)

Use the new hover option to interact with elements before rendering, and choose whether to fail if the hover selector is not found.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/error-metrics
----

Error metrics in the dashboard

==============================

You can now see error metrics in the dashboard to quickly understand what errors are happening and how often.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Nov 28, 2025

We have added a new error metrics widget to the dashboard that shows you the errors happening with your rendering requests.

The widget displays:

1.  Total number of errors for the selected time period (last 24 hours, 7 days, 15 days, or 30 days).

2.  Each error with its title, count, and percentage.

3.  Detailed tooltips with error descriptions, HTTP status codes, and links to documentation.

4.  Quick access to logs by clicking on any error.

The errors are sorted by count, so you can quickly see the most common errors and take action:

If you have any questions, suggestions, or feedback, please [contact us](mailto:support@screenshotone.com).

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Documentation for LLMs](/changelog/docs-for-llms/)

ScreenshotOne now supports documentation format specifically targeted for LLMs—llms.txt and llms-full.txt.

Read more →

1 min read

#### [Improved the behavior and stability of the "scroll\_into\_view" option](/changelog/improved-scroll-into-view/)

Before the change, there was a subset of cases when the rendering requests were failing when using the scroll\_into\_view option. Now, it is improved and will make rendering more stable.

Read more →

1 min read

#### [Added an Above-the-Fold Checker Tool](/changelog/above-the-fold-checker/)

A new ScreenshotOne tool to capture what users see before the first scroll.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/what-is-a-screenshot-or-html-rendering-api
----

What is a screenshot or HTML rendering API?

===========================================

A screenshot API or a screenshot as a service is usually a cloud or a remote server service that provides the ability to render any website, HTML, Markdown, or even PDF by making a request to the service, be it over HTTP, TCP, or any other protocol.

[Blog post](/blog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Nov 27, 2022

#### Tags

[Screenshot rendering](/blog/tags/screenshot-rendering/)

The most popular screenshot APIs are usually implemented over HTTP. [ScreenshotOne](https://screenshotone.com) is one of them.

Let’s send an example request to [ScreenshotOne.com API](https://screenshotone.com) to generate a screenshot of Apple’s website:

Terminal window

    1GET https://api.screenshotone.com/take?url=https://apple.com&access_key=<sign up to get your access key>

The resulting image is:

In addition to that, you can render HTML as an image:

Terminal window

    1GET https://api.screenshotone.com/take?html=<h1>Hello, world!</h1>&access_key=<sign up to get your access key>

Or even render Markdown (`# Hello, world!`) as an image too:

Terminal window

    1GET https://api.screenshotone.com/take?markdown=%23%20Hello%2C%20world%21&access_key=<sign up to get your access key>

The resulting image is the same for both requests:

Use cases

---------

There is a ton of ways how screenshot API can be used. Imagination is the only limitation.

Customers of [ScreenshotOne](https://screenshotone.com/) use it for:

*   [generating Open Graph images](/blog/open-graph-images/);

*   automating and generating marketing visuals;

*   taking website screenshots to share them in website directories; and many more.

Alternatives to a screenshot as a service

-----------------------------------------

One of the most popular alternatives to screenshot APIs is using [Puppeteer to render websites and HTML](https://screenshotone.com/blog/how-to-take-a-screenshot-with-puppeteer/).

Puppeter is a Node library that interacts with browsers that support [Chrome DevTools Protocol (CDP)](https://chromedevtools.github.io/devtools-protocol/). It is not only Chrome and Chromium, but [Firefox also has partial support of CDP](https://firefox-source-docs.mozilla.org/remote/index.html#remote-protocol-cdp).

When to prefer a screenshot API to alternatives?

------------------------------------------------

In case if you don’t have time and energy to invest in developing screenshot features for your apps, it is better to use a screenshot API and save time.

What is the best screenshot API?

--------------------------------

There is [a list of the best screenshot APIs](https://screenshotone.com/the-best-screenshot-api/) compared by features and by pricing.

Read more Screenshot rendering

------------------------------

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

[View all posts](/blog/tags/screenshot-rendering/)

#### [How to Take Bulk Screenshots in Python with a Screenshot API](/blog/bulk-screenshots-python/)

Learn how to automate bulk website screenshots in Python using ScreenshotOne API. Process thousands of URLs efficiently with async requests, rate limiting, and error handling.

Read more

#### [How to take website screenshots in Ruby](/blog/how-to-take-website-screenshots-in-ruby/)

Let's examine what Ruby proposes for us to render HTML or URL as a screenshot dynamically.

Read more

#### [Puppeteer waitUntil: how to wait for page load](/blog/puppeteer-wait-until-the-page-is-ready/)

Join me in exploring how to find the ideal wait time or event of when to take the page screenshot with Puppeteer.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/guides/how-to-detect-website-fonts
----

[Skip to content](#_top)

Detect website fonts

====================

Copy page

How to use the font detection API

---------------------------------

The font detection API is available in the [ScreenshotOne API “take” method as an additional option](/docs/options/#metatada_fonts).

    1https://api.screenshotone.com/take?metatada_fonts=true&url=https://example.com&access_key=<your access key>&response_type=json

The result is:

    1{2    "fonts": [3        {4            "first": "Arial",5            "fallback": ["Helvetica", "sans-serif"],6            "elements": ["p"]7        }8        // ...9    ]10}

Use cases

---------

There are many use cases for using the font detection API by ScreenshotOne:

*   **[Design tools font detection](/use-cases/design-apps-font-detection/)**: integrate font detection to help designers identify and analyze typography on any website.

*   **[Brand consistency font checks](/use-cases/brand-consistency-font-checks/)**: automatically verify font consistency across web pages to maintain brand integrity.

*   **[Automated web audits with font analysis](/use-cases/automated-web-audits-fonts/)**: generate comprehensive typography reports to optimize websites for aesthetics and performance.

*   **[Educational font detection tool](/use-cases/educational-font-detection/)**: enable students to explore and learn from typography used in real-world web applications.

*   **[Font accessibility checks](/use-cases/font-accessibility-checks/)**: analyze whether websites use readable fonts for people with visual impairments or reading disabilities.

*   **[Font marketplace enhancement](/use-cases/font-marketplace-enhancement/)**: show how fonts look on live websites to enhance the customer purchasing experience.

*   **[Font trends analysis](/use-cases/font-trends/)**: provide insights into typography trends of top-ranking websites across various industries.

*   **[UX font analysis](/use-cases/ux-font-analysis/)**: examine the impact of different fonts on user engagement and website usability.

*   **[Browser extension font detection](/use-cases/browser-extension-font-detection/)**: allow users to identify and learn about fonts on any website with a single click.

*   **[Font legal compliance check](/use-cases/font-legal-compliance/)**: ensure fonts used on websites are legally compliant to avoid copyright issues.

Support

-------

In case you have any questions or feedback, please, feel free to reach out at `support@screenshotone.com` and we will be happy to help.

----
url: https://screenshotone.com/contributors/dmytro-krasun/5
----

Dmytro Krasun

-------------

With more than a decade of experience in software engineering, I share the best practices and solutions you can apply to your problems in the space of headless browsers. You can also find me on [Twitter](https://twitter.com/DmytroKrasun) and [LinkedIn](https://www.linkedin.com/in/dmytrokrasun)

View all Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [Boosting email CTR for "Bridesmaid For Hire" with ScreenshotOne](/blog/braidsmade-for-hire-case-study/)

How and why "Bridesmaid for Hire" used ScreenshotOne to boost their email campaign CTR.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

May 21, 2024

•

1 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to screenshot websites in Next.js](/blog/nextjs-screenshots/)

There 3 simple ways to render website screenshots in Next.js—using Puppeteer, Cloudflare Browser Rendering, and a screenshot API like ScreenshotOne or similar.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

May 7, 2024

•

5 min read

#### [Cloudflare Browser Rendering](/blog/cloudflare-browser-rendering/)

Cloudflare recently launched a new Browser Rendering platform. I decided to dive into it and quickly check if I could use it in ScreenshotOne to provide a faster and better customer experience.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

May 7, 2024

•

5 min read

[Playwright guides](/blog/tags/playwright-guides/)

#### [What is Playwright](/blog/playwright/)

What is Playwright and what you can use it for.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

May 6, 2024

•

2 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Playwright guides](/blog/tags/playwright-guides/)

#### [Puppeteer versus Playwright](/blog/puppeteer-versus-playwright/)

When to use Playwright and when to use Puppeteer.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

May 6, 2024

•

2 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [What is Puppeteer](/blog/puppeteer/)

What is Puppeteer and what you can use it for.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

May 6, 2024

•

4 min read

[PDF rendering](/blog/tags/pdf-rendering/) [Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [How to generate PDFs with Puppeteer](/blog/how-to-generate-pdf-with-puppeteer/)

A practical and working guide on how to generate PDFs with Puppeteer.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

May 2, 2025

•

2 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Typeshare uses ScreenshotOne for image generation](/blog/how-typeshare-uses-screenshotone/)

Typeshare is a digital writing platform designed to enhance the writing experience by offering a suite of tools aimed at reducing common barriers writers face.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Apr 14, 2024

•

2 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How RivalFlowAI uses ScreenshotOne to help its customers improve existing content](/blog/rivalflowai-by-spyfu/)

RivalFlowAI is a new product by SpyFu, launched in 2023. The product helps to improve existing content with AI by finding the missing pieces your page needs to rank.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Apr 9, 2024

•

1 min read

#### [ScreenshotOne is featured on MicroLaunch](/blog/featured-on-microlaunch/)

ScreenshotOne is featured on MicroLaunch

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Apr 7, 2024

•

1 min read

#### [How to make beautiful screenshots on macOS](/blog/screenshots-on-macos/)

I do write a lot about how to automate website screenshots, but I rarely share about what tools I use to make beautiful screenshots on the daily basis.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Apr 7, 2024

•

1 min read

[Engineering](/blog/tags/engineering/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Let's build a screenshot API](/blog/building-screenshot-api/)

Two years have passed since the launch of ScreenshotOne, and I want to do a fun coding exercise and build a tiny subset of what the API is today, but from scratch.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

May 26, 2024

•

16 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/url-to-markdown-tool
----

Added a URL to Markdown Tool

============================

A new free ScreenshotOne tool to convert any public webpage URL into Markdown.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Mar 10, 2026

We have launched a new [URL to Markdown tool](/tools/url-to-markdown/).

The tool takes any public webpage URL, renders the page, and returns the result as Markdown instead of a screenshot or raw HTML.

Markdown is useful when you want content in a clean, portable format that is easy to copy into docs, notes, knowledge bases, and AI workflows.

[](/tools/url-to-markdown/)

This makes it simpler to turn website content into something you can read, edit, compare, store, or process with LLMs.

[Open the URL to Markdown tool](/tools/url-to-markdown/) and let us know what other tools you want to see at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [ScreenshotOne is available as a ChatGPT plugin](/changelog/screenshotone-is-available-as-a-chatgpt-plugin/)

From today, you can render screenshots of any website or even raw HTML in ChatGPT—ScreenshotOne is available as a plugin. But at the moment of writing not available yet, in the official store, but it can be available when you read it.

Read more →

2 min read

#### [Control scrolling into view when taking screenshots by selector](/changelog/selector-scroll-into-view-option/)

You can now control scrolling into view when taking screenshots by selector. It allows render more accurate screenshots.

Read more →

1 min read

#### [Trigger screenshot download](/changelog/attachment-name/)

Now you can set attachment filename to trigger screenshot download in the browser.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/viasocket-integration
----

ScreenshotOne is available on viaSocket

=======================================

Automate website screenshots, animated scrolling captures, and visual documentation workflows with ScreenshotOne and viaSocket.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Mar 2, 2026

[ScreenshotOne is now available on viaSocket](https://viasocket.com/integrations/screenshotone).

With ScreenshotOne and viaSocket, you can automate your workflows with:

*   📸 website screenshots;

*   🎬 animated scrolling screenshots and videos;

*   📊 visual reports and dashboards;

*   🔥 and more…

[Check out their launch blog post](https://viasocket.com/blog/automated-website-screenshot-monitoring-using-screenshotone-and-viasocket/), [our launch blog post](/blog/screenshotone-and-viasocket-integration/) and [our viaSocket integration page](/integrations/viasocket/) for more details.

If you have any questions or need any assistance, please, reach out at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Fail rendering if the content is missing a string](/changelog/fail-if-content-missing/)

There is a set of use cases when you want to fail screenshot rendering and retry it if the content of the page is missing a string.

Read more →

1 min read

#### [ScreenshotOne is now integrated into Summit](/changelog/summit-integration/)

The ScreenshotOne screenshot API is now natively integrated into Summit and you can perform anything on top of the powerful screenshot automation and Summit models—only the sky is the limit.

Read more →

1 min read

#### [Improved full page screenshot algorithm](/changelog/fixed-a-corner-case-for-full-page-screenshots/)

We fixed issues with full page screenshots when the viewport was overridden together with the device option.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/playwright-python-screenshots
----

How to Take Website Screenshots with Playwright in Python

=========================================================

A complete guide to taking website screenshots with Playwright in Python. Learn page.screenshot() parameters, async patterns, element screenshots, dark mode, and device emulation.

[Blog post](/blog/) 5 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jan 16, 2026

#### Tags

[Screenshot rendering](/blog/tags/screenshot-rendering/) [Playwright guides](/blog/tags/playwright-guides/)

While building [ScreenshotOne (one of the best screenshot APIs)](https://screenshotone.com/), I spent a lot of time playing with different libraries and approaches to take website screenshots.

In Python, I tried [Selenium](/blog/selenium-python-screenshots/), [pyppeteer](/blog/pyppeteer-python-screenshots/), and finally landed on [Playwright](/blog/playwright/). After working with all three, I can confidently say Playwright is the best choice for Python developers today. Not only it is actively maintained and developed, but it also has a lot of features that are very useful for taking website screenshots.

In this guide, I’ll walk you through everything you need to know about taking screenshots with Playwright in Python—from basic usage to advanced techniques like device emulation and dark mode captures.

I wrote a lot and initially included details about full page screenshots, too. But later I realized that this is such a huge topic that it deserves a separate guide, [check it out if you want full page screenshots with Playwright in Python](/blog/playwright-python-full-page-website-screenshots/).

Quick Start

-----------

First, install Playwright:

Terminal window

    1pip install playwright2playwright install chromium

Here’s the simplest way to take a screenshot:

    1from playwright.sync_api import sync_playwright2

    3with sync_playwright() as p:4    browser = p.chromium.launch()5    page = browser.new_page()6    page.goto('https://github.com')7    page.screenshot(path='screenshot.png')8    browser.close()

That’s it:

But there’s so much more you can do.

Understanding page.screenshot() Parameters

------------------------------------------

The `page.screenshot()` method accepts several parameters that give you fine-grained control:

    1page.screenshot(2    path='screenshot.png',      # File path to save3    type='png',                 # 'png' or 'jpeg'4    quality=80,                 # JPEG quality (0-100), ignored for PNG5    full_page=True,             # Capture full scrollable page6    clip={                      # Capture specific region7        'x': 0,8        'y': 0,9        'width': 800,10        'height': 60011    },12    omit_background=True,       # Transparent background for PNG13    animations='disabled',      # Disable CSS animations14    scale='css'                 # 'css' or 'device' pixel scale15)

Let me break down when to use each:

*   **`full_page=True`**: Essential for capturing entire landing pages or long articles

*   **`omit_background=True`**: Perfect for screenshots with transparent backgrounds

*   **`clip`**: When you only need a specific portion of the page

*   **`animations='disabled'`**: Prevents half-rendered animations in your screenshots

Full page screenshots are unfortunately extremely hard to render right, so you might want to check out [the guide about the full page screenshots](/blog/playwright-python-full-page-website-screenshots/) for more details.

Sync vs Async: When to Use Each

-------------------------------

Playwright offers both synchronous and asynchronous APIs. Here’s when to use each:

### Synchronous API

Use for simple, one-off screenshots:

    1from playwright.sync_api import sync_playwright2

    3def take_screenshot(url, output_path):4    with sync_playwright() as p:5        browser = p.chromium.launch(headless=True)6        page = browser.new_page()7        page.goto(url)8        page.screenshot(path=output_path, full_page=True)9        browser.close()10

    11take_screenshot('https://example.com', 'example.png')

### Asynchronous API

Use for batch processing or when you need concurrency:

    1import asyncio2from playwright.async_api import async_playwright3

    4async def take_screenshot(url, output_path):5    async with async_playwright() as p:6        browser = await p.chromium.launch(headless=True)7        page = await browser.new_page()8        await page.goto(url)9        await page.screenshot(path=output_path, full_page=True)10        await browser.close()11

    12async def main():13    urls = [14        ('https://example.com', 'example.png'),15        ('https://github.com', 'github.png'),16    ]17    await asyncio.gather(*[18        take_screenshot(url, path) for url, path in urls19    ])20

    21asyncio.run(main())

The async version can process multiple URLs concurrently, significantly speeding up batch operations.

Waiting for Dynamic Content

---------------------------

Modern websites load content dynamically. Taking a screenshot too early means missing content. Here’s how to handle it:

### Wait for Network Idle

    1page.goto('https://example.com')2page.wait_for_load_state('networkidle')3page.screenshot(path='screenshot.png')

### Wait for Specific Elements

    1page.goto('https://example.com')2page.wait_for_selector('.main-content', state='visible')3page.screenshot(path='screenshot.png')

### Wait with Timeout

    1page.goto('https://example.com')2page.wait_for_selector('.lazy-loaded-image', timeout=10000)3page.screenshot(path='screenshot.png')

I typically combine these approaches for reliability:

    1page.goto('https://example.com', wait_until='domcontentloaded')2page.wait_for_load_state('networkidle')3page.wait_for_timeout(500)  # Extra buffer for animations4page.screenshot(path='screenshot.png')

Element-Specific Screenshots

----------------------------

Sometimes you only need a screenshot of a specific element:

    1from playwright.sync_api import sync_playwright2

    3with sync_playwright() as p:4    browser = p.chromium.launch()5    page = browser.new_page()6    page.goto('https://example.com')7

    8    # Screenshot a specific element9    element = page.locator('.hero-section')10    element.screenshot(path='hero.png')11

    12    browser.close()

This is particularly useful for:

*   Capturing product cards

*   Taking screenshots of charts or graphs

*   Isolating specific UI components

Device Emulation

----------------

Playwright makes it easy to emulate different devices:

    1from playwright.sync_api import sync_playwright2

    3with sync_playwright() as p:4    # Use a predefined device5    iphone = p.devices['iPhone 14 Pro Max']6

    7    browser = p.chromium.launch()8    context = browser.new_context(**iphone)9    page = context.new_page()10

    11    page.goto('https://example.com')12    page.screenshot(path='mobile.png')13

    14    browser.close()

Or set custom viewport dimensions:

    1context = browser.new_context(2    viewport={'width': 1920, 'height': 1080},3    device_scale_factor=2  # Retina display4)

Dark Mode Screenshots

---------------------

Many websites support dark mode. Here’s how to capture them:

    1from playwright.sync_api import sync_playwright2

    3with sync_playwright() as p:4    browser = p.chromium.launch()5    context = browser.new_context(6        color_scheme='dark'7    )8    page = context.new_page()9

    10    page.goto('https://github.com')11    page.screenshot(path='github-dark.png')12

    13    browser.close()

For websites that don’t natively support dark mode, you can force it with Chrome flags:

    1browser = p.chromium.launch(2    args=['--enable-features=WebContentsForceDark:inversion_method/cielab_based']3)

Handling Cookie Banners

-----------------------

Cookie consent banners can ruin screenshots. Here’s how to handle them:

### Option 1: Set a Cookie Before Navigation

    1context = browser.new_context()2context.add_cookies([{3    'name': 'cookiesAccepted',4    'value': 'true',5    'domain': 'example.com',6    'path': '/'7}])8page = context.new_page()9page.goto('https://example.com')

### Option 2: Hide the Banner with CSS

    1page.goto('https://example.com')2page.add_style_tag(content='''3    .cookie-banner,4    #cookie-consent,5    [class*="cookie"] {6        display: none !important;7    }8''')9page.screenshot(path='screenshot.png')

Cropping Screenshots

--------------------

Need to capture a specific region? Use the `clip` parameter:

    1page.screenshot(2    path='cropped.png',3    clip={4        'x': 100,5        'y': 100,6        'width': 500,7        'height': 3008    }9)

Or programmatically get element coordinates:

    1element = page.locator('.target-element')2box = element.bounding_box()3

    4page.screenshot(5    path='element-region.png',6    clip={7        'x': box['x'],8        'y': box['y'],9        'width': box['width'],10        'height': box['height']11    }12)

Headless Mode

-------------

For server environments, run in headless mode:

    1browser = p.chromium.launch(headless=True)

This is the default, but you can disable it for debugging:

    1browser = p.chromium.launch(headless=False)  # Opens visible browser

Error Handling

--------------

Always handle potential errors:

    1from playwright.sync_api import sync_playwright, TimeoutError2

    3def safe_screenshot(url, output_path):4    try:5        with sync_playwright() as p:6            browser = p.chromium.launch()7            page = browser.new_page()8

    9            page.goto(url, timeout=30000)10            page.wait_for_load_state('networkidle', timeout=10000)11            page.screenshot(path=output_path)12

    13            browser.close()14            return True15

    16    except TimeoutError:17        print(f"Timeout loading {url}")18        return False19    except Exception as e:20        print(f"Error: {e}")21        return False

When to Use a Screenshot API Instead

------------------------------------

While Playwright is powerful, managing browser infrastructure at scale has challenges:

*   Memory leaks with long-running processes

*   Browser crashes under heavy load

*   Keeping browsers updated

*   Handling anti-bot protections

For production workloads, consider using a [screenshot API (for Python) like ScreenshotOne](/screenshot-api/python/). It handles the infrastructure so you can focus on your application. Check out the [main guide on taking website screenshots in Python](/blog/how-to-take-website-screenshots-in-python/) for a comparison of all options.

Summary

-------

Playwright is an excellent choice for taking website screenshots in Python. Key takeaways:

1.  Use `full_page=True` for complete page captures

2.  Choose async API for batch processing

3.  Always wait for content with `wait_for_load_state` or `wait_for_selector`

4.  Use `color_scheme='dark'` for dark mode screenshots

5.  Handle cookie banners with cookies or CSS injection

Frequently Asked Questions

--------------------------

If you read the article, but still have questions. Please, check the most frequently asked. And if you still have questions, feel free reach out at [support@screenshotone.com](mailto:support@screenshotone.com).

### How to take a full page screenshot with Playwright Python?

Use the full\_page=True parameter: page.screenshot(path='screenshot.png', full\_page=True). This captures the entire scrollable page, not just the visible viewport.

### What is the difference between sync and async Playwright in Python?

Sync Playwright uses sync\_playwright() and blocks execution, while async Playwright uses async\_playwright() with asyncio for concurrent operations. Use async for batch processing multiple screenshots.

### How to wait for page to load before taking screenshot in Playwright?

Use page.wait\_for\_load\_state('networkidle') to wait until network is idle, or page.wait\_for\_selector('selector') to wait for specific elements to appear before taking the screenshot.

Read more Screenshot rendering

------------------------------

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

[View all posts](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots in Ruby](/blog/how-to-take-website-screenshots-in-ruby/)

Let's examine what Ruby proposes for us to render HTML or URL as a screenshot dynamically.

Read more

#### [How to take bulk screenshots with Puppeteer](/blog/bulk-screenshots-with-puppeteer/)

Learn how to take screenshots of multiple URLs with Puppeteer, including concurrency management, error handling, retries, and proxy support.

Read more

#### [How to take website screenshots with C# (.NET)](/blog/how-to-take-website-screenshots-with-csharp-dotnet/)

The article examines how you can take screenshots of any URL with C# (.NET) by using PuppeteerSharp, or screenshot API as a service.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/integrations/rapidapi
----

Integrations

1 min read

RapidAPI

========

Integrate ScreenshotOne through RapidAPI to automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

No-Code Code API

Resources

---------

*   [ScreenshotOne on RapidAPI](https://rapidapi.com/screenshotone-api-screenshotone-api-default/api/screenshotone1)

Capturing screenshots sounds easy until you try to do it yourself and run into N number of cases.

Dmytro has done a wonderful job in all 3 aspects: The product, The documentation, The wonderful human behind this!

Nabil Kazi

Co-Founder, [BugSmash](https://screenshotone.com/blog/bugsmash-story/)

Check more Integrations

-----------------------

No-code tools, AI, code libraries, and more.

[Check more Integrations](/integrations/)

No-Code Automation

### Clay

Generate website screenshots inside Clay to qualify leads, assess content, and enrich rows with visual context automatically.

[Read more →](/integrations/clay/)

Code API

### SDK and Code Examples

Use the SDKs and code examples to take screenshots in your own code.

[Read more →](/integrations/code/)

No-Code Automation

### Make

Use ScreenshotOne with Make to automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

[Read more →](/integrations/make/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/dxcam-python-screenshots
----

How to Capture Desktop Screen with DXcam in Python

==================================================

Complete guide to DXcam, the fastest Python screen capture library. Learn high-FPS capture, video mode, region capture, and DXcam vs Python MSS performance comparison.

[Blog post](/blog/) 4 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jan 14, 2026

#### Tags

[Desktop screen capture](/blog/tags/desktop-screen-capture/)

[DXcam](https://github.com/ra1nty/DXcam) is built specifically for high-performance screen capture on Windows. It uses the DirectX Desktop Duplication API to achieve capture speeds that other libraries can’t match. If you search for a cross-platform alternative, it is [Python MSS](/blog/mss-python-screen-capture/).

[](/blog/dxcam-python-screenshots/dxcam.png)

**At the moment of publishing the guide, the library was last updated in 2023.** In case you are going to use desktop screen capture for production-ready projects, check out our guide on [Python MSS](/blog/mss-python-screen-capture/), it is still actively maintained.

If because of any reason you decide to use DXcam or because of its specific features, continue reading the guide.

Installation and Basic Usage

----------------------------

Install the library using `pip`:

Terminal window

    1pip install dxcam

Then run the following code to capture a single frame to test the library works:

    1import dxcam2

    3# Create a camera4camera = dxcam.create()5

    6# Capture a single frame7frame = camera.grab()8

    9if frame is not None:10    print(f"Captured frame: {frame.shape}")

The returned frame is a NumPy array ready for processing.

Saving Screenshots

------------------

    1import dxcam2import cv23

    4camera = dxcam.create(output_color="BGR")  # BGR for OpenCV5frame = camera.grab()6

    7if frame is not None:8    cv2.imwrite('screenshot.png', frame)

Or with PIL:

    1import dxcam2from PIL import Image3

    4camera = dxcam.create(output_color="RGB")5frame = camera.grab()6

    7if frame is not None:8    img = Image.fromarray(frame)9    img.save('screenshot.png')

Video Mode (Continuous Capture)

-------------------------------

For high-FPS continuous capture:

    1import dxcam2import time3

    4camera = dxcam.create()5camera.start(target_fps=60)6

    7# Capture for 5 seconds8frames = []9start = time.time()10

    11while time.time() - start < 5:12    frame = camera.get_latest_frame()13    if frame is not None:14        frames.append(frame.copy())15

    16camera.stop()17

    18print(f"Captured {len(frames)} frames in 5 seconds")19print(f"Effective FPS: {len(frames) / 5:.1f}")

Capture Specific Region

-----------------------

    1import dxcam2

    3camera = dxcam.create()4

    5# Region: (left, top, right, bottom)6frame = camera.grab(region=(0, 0, 500, 500))7

    8if frame is not None:9    print(f"Region shape: {frame.shape}")

Capture Specific Monitor

------------------------

    1import dxcam2

    3# List available devices4devices = dxcam.device_info()5print("Available devices:", devices)6

    7# Create camera for specific output (monitor)8camera = dxcam.create(output_idx=0)  # First monitor9# camera = dxcam.create(output_idx=1)  # Second monitor

Lower Resolution Capture

------------------------

For faster processing, capture at lower resolution:

    1import dxcam2

    3# Standard capture4camera = dxcam.create()5frame = camera.grab()6print(f"Full resolution: {frame.shape}")7

    8# Capture region at lower resolution9region = (0, 0, 960, 540)  # Half of 1920x108010frame = camera.grab(region=region)11print(f"Lower resolution: {frame.shape}")

Output Color Formats

--------------------

    1import dxcam2

    3# RGB format (default)4camera_rgb = dxcam.create(output_color="RGB")5

    6# BGR format (for OpenCV)7camera_bgr = dxcam.create(output_color="BGR")8

    9# BGRA format (with alpha channel)10camera_bgra = dxcam.create(output_color="BGRA")

Performance Benchmarking

------------------------

    1import dxcam2import time3

    4camera = dxcam.create()5

    6# Single frame benchmark7start = time.time()8for _ in range(100):9    camera.grab()10elapsed = time.time() - start11print(f"Single grab FPS: {100 / elapsed:.1f}")12

    13# Video mode benchmark14camera.start(target_fps=240)15time.sleep(2)16

    17frames_captured = 018start = time.time()19while time.time() - start < 5:20    frame = camera.get_latest_frame()21    if frame is not None:22        frames_captured += 123

    24camera.stop()25print(f"Video mode FPS: {frames_captured / 5:.1f}")

Typical results on a modern system: 240+ FPS

Full Screen Recording Example

-----------------------------

    1import dxcam2import cv23import time4from collections import deque5

    6def record_screen(duration=5, fps=30, output='recording.mp4'):7    camera = dxcam.create(output_color="BGR")8

    9    # Get first frame to determine dimensions10    first_frame = camera.grab()11    height, width = first_frame.shape[:2]12

    13    # Set up video writer14    fourcc = cv2.VideoWriter_fourcc(*'mp4v')15    out = cv2.VideoWriter(output, fourcc, fps, (width, height))16

    17    # Start capture18    camera.start(target_fps=fps)19

    20    start = time.time()21    frames_written = 022

    23    while time.time() - start < duration:24        frame = camera.get_latest_frame()25        if frame is not None:26            out.write(frame)27            frames_written += 128

    29    camera.stop()30    out.release()31

    32    print(f"Recorded {frames_written} frames to {output}")33

    34record_screen(duration=5, fps=30)

Real-Time Processing Example

----------------------------

    1import dxcam2import cv23

    4def live_preview():5    """Display live screen capture with FPS counter."""6    camera = dxcam.create(output_color="BGR")7    camera.start(target_fps=60)8

    9    frame_count = 010    start_time = cv2.getTickCount()11

    12    while True:13        frame = camera.get_latest_frame()14        if frame is None:15            continue16

    17        # Calculate FPS18        frame_count += 119        elapsed = (cv2.getTickCount() - start_time) / cv2.getTickFrequency()20        fps = frame_count / elapsed21

    22        # Add FPS text23        cv2.putText(frame, f'FPS: {fps:.1f}', (10, 30),24                    cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)25

    26        # Display (resize for preview)27        preview = cv2.resize(frame, (960, 540))28        cv2.imshow('Screen Capture', preview)29

    30        if cv2.waitKey(1) & 0xFF == ord('q'):31            break32

    33    camera.stop()34    cv2.destroyAllWindows()35

    36live_preview()

Common Issues

-------------

### No Frame Returned

    1import dxcam2

    3camera = dxcam.create()4frame = camera.grab()5

    6if frame is None:7    print("No frame captured - screen might not have changed")8    # dxcam only captures when screen changes9    # Use video mode for continuous capture

### Multiple Cameras

    1import dxcam2

    3# Only one camera per output at a time4camera1 = dxcam.create(output_idx=0)5

    6# This will fail:7# camera2 = dxcam.create(output_idx=0)  # Error!8

    9# Delete first camera before creating another for same output10del camera111camera2 = dxcam.create(output_idx=0)  # OK

When to Use DXcam

-----------------

**Use DXcam when**:

*   You need maximum FPS (gaming, streaming).

*   You’re on Windows.

*   Real-time processing is required.

*   You don’t need cross-platform support and don’t care about the maintenance of the library.

**Use [Python MSS](/blog/mss-python-screen-capture/) when**:

*   You need cross-platform support.

*   30-60 FPS is sufficient.

*   Simpler API is preferred.

*   And you want to rely on a maintained library.

In case you need to render website screenshots, check out [our guide on websites screenshots with Python](/blog/how-to-take-website-screenshots-in-python/). The guide only consider website screenshot automation.

DXcam vs Python MSS Performance

-------------------------------

In general:

Metric

DXcam

Python MSS

Max FPS (1080p)

240+

30-60

Platform

Windows only

Cross-platform

API

NumPy native

Custom format

Best for

Gaming/streaming

General purpose

[Kyle Fu also confirms in his performance comparison that DXcam is faster than Python MSS](https://kylefu.me/2023/02/18/python-fast-screen-capture.html):

Summary

-------

`DXcam` might be the fastest screen capture option for Python on Windows, but it is not actively maintained at the moment of writing the guide, however:

1.  It might achieve 240+ FPS capture using DirectX.

2.  Supports Video mode for continuous capture.

3.  Native NumPy output.

4.  Region and multi-monitor support.

For cross-platform needs, use [Python MSS](/blog/mss-python-screen-capture/). For website screenshots, check out [our website screenshot automation guide with Python](/blog/how-to-take-website-screenshots-in-python/).

Frequently Asked Questions

--------------------------

If you read the article, but still have questions. Please, check the most frequently asked. And if you still have questions, feel free reach out at [support@screenshotone.com](mailto:support@screenshotone.com).

### Is DXcam fast for screen capture?

Yes, DXcam is the fastest Python screen capture library, achieving 240+ FPS on modern systems. It uses DirectX Desktop Duplication API for maximum performance.

### What is the difference between DXcam and Python MSS?

DXcam is faster (240+ FPS vs 30-60 FPS) but only works on Windows. Python MSS is cross-platform but slower. Use DXcam for gaming/streaming on Windows, Python MSS for cross-platform needs.

### Is Windows Graphics Capture faster than DXcam?

They're comparable in performance. DXcam uses Desktop Duplication API and is easier to use in Python. Windows.Graphics.Capture requires more setup but offers some additional features.

Read more Desktop screen capture

--------------------------------

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

[View all posts](/blog/tags/desktop-screen-capture/)

#### [How to Take Screenshots with PyAutoGUI in Python](/blog/pyautogui-python-screenshots/)

Complete guide to taking screenshots with PyAutoGUI in Python. Learn screenshot(), region parameters, locateOnScreen(), and common errors with ImageNotFoundException.

Read more

#### [How to Take Screenshots with Python MSS](/blog/mss-python-screen-capture/)

Complete guide to the MSS Python screen capture library. Learn installation, capturing monitors, regions, performance optimization, and common errors like xgetimage() failed.

Read more

#### [How to Capture Desktop Screenshots in Python](/blog/python-screen-capture/)

Complete guide to desktop screen capture in Python. Compare Python MSS, DXcam, PyAutoGUI for capturing monitors, windows, and screen regions.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/openclaw-alternative-by-nvidia
----

NemoClaw an enterprise alternative to OpenClaw by NVIDIA

========================================================

A practical look at what NemoClaw appears to be, what OpenClaw already is, and the main differences between them as of March 11, 2026.

[Blog post](/blog/) 5 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Mar 11, 2026

If you searched for `Nemoclaw`, the name currently appears publicly as **NemoClaw**.

The short version is simple:

*   **OpenClaw** is real, documented, installable, and aimed at developers and power users who want a self-hosted personal AI assistant.

*   **NemoClaw** appears to be NVIDIA’s reported answer for enterprise AI agents, but as of **March 11, 2026**, public information is still limited and much less concrete.

That distinction matters. A lot of posts make them sound like direct, equally mature competitors. They are not, at least not yet.

If you want the simpler overview of OpenClaw itself, read [What is OpenClaw and how can it help?](/blog/openclaw/). This post is more about the comparison angle and where NemoClaw appears to fit.

What is OpenClaw?

-----------------

[OpenClaw](https://openclaw.ai/) describes itself as “the AI that actually does things.”

The official site and docs position it as a **personal AI assistant** that you can message through tools you already use, such as WhatsApp, Telegram, Discord, and iMessage. Under the hood, the docs describe OpenClaw as a **self-hosted gateway** that runs on your own machine or server and connects those messaging channels to AI agents.

In practical terms, OpenClaw is about:

*   running the assistant on your own hardware;

*   keeping sessions, context, and workflows close to you;

*   reaching the agent from chat interfaces you already use;

*   supporting tools, memory, routing, and multi-agent setups.

The OpenClaw docs are unusually clear about the architecture. They describe a single Gateway process as the source of truth for sessions, routing, and channel connections. They also document onboarding, configuration, remote access, nodes, multi-agent routing, and a browser control UI.

So OpenClaw is not just an idea or an announcement. It is a real product with docs, installation steps, and an active community around a local-first assistant model.

What is NemoClaw?

-----------------

This is where things get more speculative.

As of **March 11, 2026**, NemoClaw appears in recent reporting as an **NVIDIA platform for enterprise AI agents**. The clearest reporting I found says NVIDIA is preparing an open-source agent platform for companies and pitching it to large software vendors ahead of GTC.

What I could verify publicly is this:

*   WIRED reported on **March 10, 2026** that NVIDIA plans to launch an open-source AI agent platform called NemoClaw and pitch it to enterprise software companies.

*   The reported positioning is enterprise-oriented: companies would use it to deploy agents for internal work tasks.

*   The same reporting says NVIDIA wants to include stronger privacy and security tooling than what fast-moving consumer agent projects usually ship with.

What I could **not** verify as of March 11, 2026:

*   a public NemoClaw product site;

*   public NemoClaw documentation;

*   a public install guide;

*   a stable public repository comparable to OpenClaw’s public docs experience.

That means the safest description is: **NemoClaw is a reported NVIDIA enterprise agent platform, not yet a publicly documented product in the same sense that OpenClaw is.**

Why the name makes sense

------------------------

The “Nemo” part likely points to NVIDIA’s existing **NeMo** ecosystem.

NVIDIA’s official [NeMo Agent Toolkit documentation](https://docs.nvidia.com/nemo/agent-toolkit/latest/index.html) describes NeMo Agent Toolkit as a flexible, lightweight library that connects existing enterprise agents to tools and data sources across frameworks. It emphasizes framework-agnostic workflows, observability, evaluation, profiling, MCP support, and A2A support.

So even without official NemoClaw docs, it is reasonable to infer that:

*   OpenClaw likely influenced the naming;

*   NVIDIA is likely building on top of its broader NeMo agent stack;

*   the product direction is probably more enterprise workflow infrastructure than personal assistant software.

That last point is an inference from the available sources, not something NVIDIA has fully documented publicly yet.

NemoClaw vs OpenClaw

--------------------

Here is the clearest way to think about the difference.

### 1\. Personal assistant vs enterprise platform

OpenClaw is built around the idea of a **personal or team assistant** you can reach from messaging apps.

NemoClaw, based on current reporting, appears aimed at **enterprise software teams** that want to deploy and manage agents for employees inside business workflows.

If OpenClaw feels like “message your AI coworker from Telegram,” NemoClaw sounds more like “give enterprises a secure framework for agentic work.”

### 2\. Local-first vs enterprise-first

OpenClaw strongly emphasizes:

*   self-hosting;

*   your hardware;

*   your data;

*   your channels;

*   your control.

NemoClaw appears to emphasize:

*   enterprise adoption;

*   integration into corporate software;

*   privacy controls;

*   security layers;

*   broad deployability across infrastructure.

Those are not the same priorities.

### 3\. Documented product vs reported roadmap

This is the most important difference today.

OpenClaw has:

*   a public website;

*   public docs;

*   install commands;

*   architecture docs;

*   FAQs;

*   setup flows.

NemoClaw, as of March 11, 2026, mostly has:

*   reporting;

*   strategic interpretation;

*   educated guesses based on NVIDIA’s NeMo stack.

That does not make NemoClaw unimportant. It just means you should not evaluate the two projects as if both are equally available.

### 4\. Messaging surface vs orchestration stack

OpenClaw’s identity is tightly connected to messaging surfaces like WhatsApp, Telegram, Discord, and iMessage.

NemoClaw, from what is publicly reported, looks less like a messaging-first product and more like an orchestration and deployment layer for enterprise agents.

In other words:

*   OpenClaw starts from the user experience;

*   NemoClaw likely starts from the enterprise systems layer.

### 5\. Speed vs governance

OpenClaw is community-driven and moves like an open-source internet-native project.

NemoClaw, if NVIDIA launches it as reported, will almost certainly move more like enterprise infrastructure software: more opinionated around compliance, observability, security, and partner ecosystems.

That difference alone will shape who each product is really for.

Which one should you care about?

--------------------------------

If you are a developer, builder, or operator who wants a personal agent running on your own machine and reachable from messaging apps, **OpenClaw is the concrete thing you can evaluate today**.

If you are trying to understand where enterprise agent infrastructure might go next, **NemoClaw is worth watching**, especially because NVIDIA already has real building blocks in the NeMo Agent Toolkit.

But there is a category error in many discussions:

*   OpenClaw is a present-tense product.

*   NemoClaw is mostly a future-tense platform story, at least publicly, on March 11, 2026.

Where ScreenshotOne fits

------------------------

Whether you use a personal assistant like OpenClaw or a more enterprise-style agent stack, one practical need shows up quickly: **visual verification**.

If an agent opens a website, submits a form, checks a dashboard, or completes a browser task, it is often useful to store a screenshot of the final state for:

*   debugging;

*   human review;

*   audit trails;

*   status updates;

*   customer-facing reports.

That is exactly where [ScreenshotOne](https://screenshotone.com/nemoclaw/) can help. Instead of building your own screenshot rendering pipeline around autonomous agents, you can generate clean screenshots, remove cookie banners or chat widgets, and keep a visual record of what the agent actually saw.

Summary

-------

OpenClaw and NemoClaw may sound similar, but they currently live in different stages and solve slightly different problems.

*   **OpenClaw** is a self-hosted personal AI assistant and gateway you can use now.

*   **NemoClaw** appears to be a reported NVIDIA enterprise agent platform that may build on the broader NeMo ecosystem.

*   The biggest difference today is not just audience. It is **maturity and availability**.

If you need something concrete today, look at OpenClaw.

If you are tracking where enterprise agent infrastructure is heading next, keep an eye on NemoClaw.

Sources

-------

*   [OpenClaw website](https://openclaw.ai/)

*   [OpenClaw documentation](https://docs.openclaw.ai/)

*   [OpenClaw FAQ](https://docs.openclaw.ai/start/faq/)

*   [NVIDIA NeMo Agent Toolkit docs](https://docs.nvidia.com/nemo/agent-toolkit/latest/index.html)

*   [WIRED report on NVIDIA and NemoClaw, March 10, 2026](https://es.wired.com/articulos/nvidia-lanzara-una-plataforma-de-agentes-de-ia-de-codigo-abierto)

Frequently Asked Questions

--------------------------

If you read the article, but still have questions. Please, check the most frequently asked. And if you still have questions, feel free reach out at [support@screenshotone.com](mailto:support@screenshotone.com).

### Is NemoClaw available today?

As of March 11, 2026, NemoClaw appears in reporting about NVIDIA's plans, but I could not verify public product documentation comparable to OpenClaw's docs.

### What is OpenClaw in one sentence?

OpenClaw is a self-hosted, local-first gateway that connects messaging apps like WhatsApp, Telegram, Discord, and iMessage to an always-on AI assistant.

Read more posts

---------------

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

[View all posts](/blog/)

#### [How to take a screenshot of a webpage in Haskell](/blog/how-to-take-a-screenshot-of-a-webpage-in-haskell/)

It's very a common need to take a screenshot of a live website. On a project I worked on recently, we had a legal requirement to take screenshots of forms which our users filled, as at the time they filled the forms, for consent documentation purposes.

Read more

#### [A Chrome Extension by ScreenshotOne for rendering full-page screenshots](/blog/full-page-chrome-extension/)

We just launched a new full-page screenshot Chrome extension that allows you to take full page screenshots of any websites and annotate them in a few clicks.

Read more

#### [How to build a Programmatic SEO site with automated website screenshots using ScreenshotOne, Airtable, and Launchman](/blog/how-to-build-a-programmatic-seo-site-with-automated-website-screenshots-using-screenshotone-airtable-and-launchman/)

Programmatic SEO is a great growth hacking strategy where you create a large number of content pages that rank for long-tailed keywords on Google.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/tags/pdf-rendering
----

PDF Rendering

-------------

Tips for rendering PDFs from HTML and web pages.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

[PDF rendering](/blog/tags/pdf-rendering/) [Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [How to generate PDFs with Puppeteer](/blog/how-to-generate-pdf-with-puppeteer/)

A practical and working guide on how to generate PDFs with Puppeteer.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

May 2, 2025

•

2 min read

[PDF rendering](/blog/tags/pdf-rendering/)

#### [How to convert HTML to PDF in JavaScript](/blog/how-to-convert-html-to-pdf-in-javascript/)

Nowadays, you have various options to generate PDFs from HTML or any given URL: generating PDF in the browser, on the server-side (Node.js), or even using a modern and friendly API to generate PDF.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

May 2, 2025

•

3 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/above-the-fold-checker
----

Added an Above-the-Fold Checker Tool

====================================

A new ScreenshotOne tool to capture what users see before the first scroll.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Mar 10, 2026

We have launched a new [above-the-fold checker](/tools/above-the-fold/).

“Above the fold” is the part of a webpage that is visible immediately after the page loads, before the visitor scrolls. In practice, it is the first impression: the headline, navigation, primary call to action, hero image, and sometimes cookie banners or popups competing for attention.

That area matters because it often decides whether a visitor keeps reading or leaves. If the message is unclear, the layout breaks on mobile, or a banner hides the key content, the page loses a lot of its value in the first few seconds.

The new tool helps you quickly check that first viewport on both desktop and mobile and see exactly what renders above the fold without extra setup.

[](/tools/above-the-fold/)

[Open the above-the-fold checker](/tools/above-the-fold/) and let us know what else you want to see in the tools section at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Better Markdown output](/changelog/better-markdown-output/)

Markdown output is now cleaner by removing non-content HTML blocks during conversion.

Read more →

1 min read

#### [Add ScreenshotOne to Clay](/changelog/clay-integration/)

Generate website screenshots inside Clay to qualify leads, assess content, and enrich rows with visual context automatically.

Read more →

1 min read

#### [Rendering Google Documents and Slides is now available](/changelog/google-docs-and-slides/)

You can now easily render Google Documents and Slides with ScreenshotOne.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/how-to-hide-chat-widgets-when-taking-a-screenshot-with-puppeteer
----

How to hide chat widgets when taking a screenshot with Puppeteer

================================================================

When you want to take chat widgets, there are annoying chat widgets that you would love to hide. It is easy to do.

[Blog post](/blog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jul 28, 2022

#### Tags

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

All you need is to detect the selector of the chat container and then apply `display: none !important` to it.

Let’s look, for example, with [Crisp chat](https://crisp.chat/en/) on [ScreenshotOne main page](/):

To hide it, find the selector of the main container of the chat. You can do it by using Chrome DevTools:

And then add the hiding styling before taking a screenshot:

    1const puppeteer = require('puppeteer');2

    3(async () => {4    const browser = await puppeteer.launch({ headless: true });5    try {6        const page = await browser.newPage();7

    8        await page.setViewport({ width: 1280, height: 1024 });9

    10        await page.goto('https://screenshotone.com/', { waitUntil: ['load', 'domcontentloaded', 'networkidle0'] });11

    12        await page.addStyleTag({13            content: '.crisp-client { display: none !important; }',14        });15

    16        await page.screenshot({ type: 'png', path: 'screenshot.png' });17    } catch (e) {18        console.log(e)19    } finally {20        await browser.close();21    }22})();

And voila:

If you take screenshots at scale, you need to do this for every chat widget. Or you can use \[ScreenshotOne API\] that knows how to [hide Facebook Messenger, Tawk, Crisp, Intercom, Drift, and many more](/docs/options/#block_chats).

Have a nice day 👋 and you also might find helpful:

*   [the complete guide on how to take a screenshot with Puppeteer](/blog/how-take-a-screenshot-with-puppeteer);

*   [how to hide cookie banners when taking a screenshot with Puppeteer](/blog/how-to-hide-cookie-banners-when-taking-a-screenshot-with-puppeteer).

Read more Puppeteer guides

--------------------------

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

[View all posts](/blog/tags/puppeteer-guides/)

#### [Puppeteer waitUntil: how to wait for page load](/blog/puppeteer-wait-until-the-page-is-ready/)

Join me in exploring how to find the ideal wait time or event of when to take the page screenshot with Puppeteer.

Read more

#### [Website Screenshots with Selenium in Python](/blog/selenium-python-screenshots/)

Complete guide to taking screenshots with Selenium in Python. Learn save\_screenshot(), element screenshots, full page workarounds, and headless mode setup.

Read more

#### [Puppeteer Performance Monitoring with Inspector](/blog/puppeteer-performance-monitoring-with-inspector/)

In this article I'll show you how to monitor performance and errors of a browser automation script written with Puppeteer.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/getting-started
----

[Skip to content](#_top)

Getting Started

===============

Copy page

You can use the API to generate invoices in PDF format for any given URL or HTML. Or make hundreds of screenshots of your site with different options to check that the site looks as expected.

Whatever use case you have, I get you covered. If there is a feature missing, please, contact me, and I will try to help you as fast as possible.

First Touch

-----------

ScreenshotOne API is straightforward to use. There is an example of an actual request to an API:

    1GET https://api.screenshotone.com/take?url=https://apple.com&access_key=<access key>

The result is:

[Sign up](https://dash.screenshotone.com/sign-up) to get the access key and start taking screenshots.

Requests

--------

ScreenshotOne API supports both GET and POST HTTP requests.

All requests are sent over HTTPS. HTTPS is a non-negotiable requirement to protect your privacy.

To take a screenshot of the site with GET HTTP request, send a request to:

    1https://api.screenshotone.com/take?[options]

Takes and returns a screenshot of the given site with specified [options](/docs/options).

If you send a POST HTTP request to take a screenshot, you should specify options as JSON in the body of the request:

    1POST https://api.screenshotone.com/take2Content-Type: application/json3{4    ...[options]5}

### Access key

You can specify the access key as part of `GET` parameters, `POST` `JSON` body, or as a header `X-Access-Key`.

Responses

---------

The response format depends on the given options. You might request API to return an image of PNG type or raw HTML instead of rendering it.

API returns the `Content-Type` header set according to the relevant MIME type for the requested format in options.

Since API returns binary in the data, you can safely put the request URL to ScreenshotOne API directly into the and  tags:

    1<img2  src="https://api.screenshotone.com/take?url=apple.com&access_key=<your access key>"3  alt="A screenshot of apple.com"4/>

Errors

------

The request might return an error due to an internal error, invalid options or when the limit is reached. ScreenshotOne API follows the HTTP status code semantic and returns JSON in case of an error:

    1GET https://api.screenshotone.com/?[options]2

    3Content-Type: application/json4{5    "error": {6        "code": "an_error_code",7        "message": "An error message"8    }9}

The API will always return [a human-readable error message, error code, and suitable HTTP status code](/docs/errors).

----
url: https://screenshotone.com/use-cases/screenshot-user-generated-content
----

Automate Website Screenshots

1 min read

Seize Live User-Contributed Content

===================================

Streamline the capture of lively user interactions and modifications.

Accurately showcasing lively user-contributed content is essential for maintaining the freshness and pertinence of website content. ScreenshotOne API delivers a proficient solution for seizing these real-time content alterations, permitting websites to store and scrutinize user interactions.

How ScreenshotOne API Helps

---------------------------

The website screenshot API excels in recording snapshots of active content, encapsulating the core of user interactions and adjustments promptly. This functionality is crucial for content supervisors and developers aiming to record and examine user engagement with their platforms.

Value and Time Savings

----------------------

Automating the recording of live user-contributed content, ScreenshotOne markedly diminishes the labor involved in content recording and analysis. This efficiency not only conserves time but also affords a more detailed and exhaustive insight into user engagement, bolstering content strategies and web design choices.

Working with Dmytro from ScreenshotOne has been an overwhelmingly positive and refreshing experience. He’s incredibly responsive, quick to act, and genuinely committed to making his service work for our needs.

Barnabás Ürmössy

Development Manager, [Kinsta](https://screenshotone.com/blog/kinsta/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/openai-4o-marketing-opportunities
----

OpenAI 4o image generation and marketing opportunities

======================================================

OpenAI 4o image generation is a really good model that can change the way you automate marketing

[Blog post](/blog/) 2 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Mar 30, 2025

A few days ago [OpenAI introduced 4o image generation](https://openai.com/index/introducing-4o-image-generation/). The model is really good at generating images in any possible styles and editing them, too.

I can’t image a better time to experiment with it and automate your marketing.

Marketing Opportunities

-----------------------

There is a lot of dimensions in marketing where you can apply new image generation opportunities.

### Generate ad creatives

You can now:

*   Create high-quality, unique ad variations for A/B testing without hiring a designer. And maybe then hire a designer to make them look even better.

*   Generate decent banners with different styles, backgrounds, and brand themes instantly.

*   Create a basic template with a professional designer and then use 4o image generation to adapt creatives dynamically based on audience segments (e.g., different visuals for different demographics).

And many more.

### Generate social media cards

Also you can:

*   Automatically create branded Twitter, LinkedIn, and Instagram cards featuring quotes, testimonials, or announcements.

*   Generate promotions or sales posts with dynamic text and images.

*   Quickly iterate and personalize posts based on trends or audience engagement.

And many more.

### Generate product images

Create realistic product mockups with different backgrounds, lighting, and perspectives. Generate lifestyle images showcasing products in various settings without expensive photoshoots. Quickly create high-quality images for e-commerce listings, social ads, and email campaigns.

### Generate marketing images with embedded website screenshots

Of course, one of my favorite opportunities is to use [ScreenshotOne (the best Screenshot API)](https://screenshotone.com) to automate marketing image generation and embed website screenshots into them.

Examples

--------

I want to share a few examples of how to use OpenAI 4o image generation to generate images with website screenshots embedded into them.

### 1\. UserJot

[UserJot](https://userjot.com/) is a feedback collection tool.

[](https://userjot.com/)

With a simple prompt, like: “Please, generate an image of people discussing customer feedback with the attached screenshot of UserJot.”

We get a creative like:

### 2\. TailScan

[TailScan](https://tailscan.com/) is the best devtool for Tailwind CSS.

[](https://tailscan.com/)

With a simple prompt, like: “Please, generate an image of a developer with the attached screenshot of TailScan on their screen.”

We get a creative like:

### 3\. Senja

[Senja](https://senja.io/) is the best testimonial collection tool in the market.

[](https://senja.io/)

With a simple prompt, like: “Please, generate an image of an open-air scene with a big screen and the attached screenshot of Senja.”

We get a creative like:

### 4\. Homestra

[Homestra](https://homestra.com/) is a platform for housing in Europe.

[](https://homestra.com/)

With a simple prompt, like: “Please, generate an image of a bus on a street with the attached screenshot of Homestra.”

We get a creative like:

Summary

-------

I shared just a few examples of how to use OpenAI 4o image generation and what is possible to do with it, but you can do so much more.

Now, it the best time to experiment, automate your marketing, use the new emerging opportunities.

Let me know if you would love to integrate ScreenshotOne and use it with OpenAI 4o image generation. Feel free to reach out to me at `support@screenshotone.com`.

Read more posts

---------------

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

[View all posts](/blog/)

#### [Monitoring website changes](/blog/monitoring-website-changes/)

I tried many ways to monitor and detect website changes. But I was always disappointed by the results. I want to share a few tips that might help you to get better results, if you plan to do the same.

Read more

#### [ScreenshotOne November 2025 updates](/blog/screenshotone-november-2025-updates/)

Error metrics in the dashboard, Postman Public API Network, and Landing Gallery customer story.

Read more

#### [NemoClaw an enterprise alternative to OpenClaw by NVIDIA](/blog/openclaw-alternative-by-nvidia/)

A practical look at what NemoClaw appears to be, what OpenClaw already is, and the main differences between them as of March 11, 2026.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/website-to-markdown-format
----

Convert any website to Markdown format with ScreenshotOne API

=============================================================

Now you can convert any website to Markdown format with ScreenshotOne API in just one simple API call.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Mar 17, 2025

Yes, it is as simple as that.

Use `format=markdown` option to get the markdown version of the website:

    1https://api.screenshotone.com/take?format=markdown&url=https://example.com/&access_key=<access key>

The result will be returned in Markdown format:

    1# Example Domain2

    3This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.4

    5[More information...](https://www.iana.org/domains/example)

It might include CSS styles, images, and other resources.

As always, if you have any questions, please, reach out at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Improved design of the authentication pages](/changelog/updated-design-of-authentication-pages/)

We updated the design of the authentication pages to make them more user-friendly and consistent.

Read more →

1 min read

#### [Choose the full page screenshot algorithm](/changelog/full-page-algorithm/)

Now, you can choose the full page screenshot algorithm.

Read more →

1 min read

#### [Failed payment alerts in the dashboard](/changelog/failed-payment-alerts/)

Starting today, you will see an alert in the dashboard when a payment fails.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/improved-blocking-of-cookie-banners
----

Improved blocking of cookie banners

===================================

We just released an updated version of our algorithm to block cookie banners by heuristics.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Mar 10, 2024

Blocking cookie banners is a hard problem and partially why many companies prefer using our API to invent and build their internal solution.

There are many methods to block cookie banners. One of them is to traverse all the buttons and elements on the website and try to click them if their text matches “Accept all cookies” or something similar.

We use such an approach with a combination of other methods. But it gave false positives by sometimes opening a and navigating to a new webpage on the website.

Today, we added a few checks and improved the algorithm to reduce false positives and yet make sure that the cookie banners are still blocked and you can render clear screenshots.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Screenshot URLs are now available in the response](/changelog/screenshot-url/)

You can now get a screenshot URL in the response of the API call.

Read more →

1 min read

#### [Choose the full page screenshot algorithm](/changelog/full-page-algorithm/)

Now, you can choose the full page screenshot algorithm.

Read more →

1 min read

#### [Improved errors](/changelog/improved-errors/)

Now, errors will have relevant documentation links. It will be also possible to see why some requests failed in the dashboard and get recommendations on how to address the issue.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/openclaw-playwright-puppeteer
----

OpenClaw with Playwright or Puppeteer: how to install browser support

=====================================================================

A practical guide to OpenClaw browser automation, why Playwright is the documented path, where Puppeteer fits, how to make screenshots, and when ScreenshotOne is the better choice for screenshot-only flows.

[Blog post](/blog/) 6 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Mar 12, 2026

If you want the broader introduction first, read [What is OpenClaw and how can it help?](/blog/openclaw/). This post is narrower: it focuses on browser automation, screenshots, and what to install if you want that part to work reliably.

The short answer is:

*   if you want browser automation inside OpenClaw, treat **Playwright** as the supported path;

*   if you were searching for **Puppeteer + OpenClaw**, you are probably really looking for browser control and screenshots, and OpenClaw’s official docs point to Playwright for that;

*   if your workflow is **screenshot only**, using [ScreenshotOne](/openclaw/) can be simpler than running browser infrastructure inside your agent stack.

What OpenClaw can do with the browser

-------------------------------------

As of **March 12, 2026**, the official OpenClaw docs describe a browser tool that gives your Claw an isolated browser profile and lets it:

*   open tabs and navigate pages;

*   read page content and make AI-readable snapshots;

*   click, type, select, drag, and scroll;

*   take screenshots of the full page or specific elements;

*   save PDFs;

*   work with a local browser or a remote CDP browser.

That matters because screenshots are only one part of the story. OpenClaw can use the browser to inspect a site, log in, click through a flow, verify the result, and then send back a screenshot as evidence.

So the browser is useful for:

*   monitoring dashboards or status pages;

*   checking competitor pages or pricing pages;

*   opening internal tools and confirming state changes;

*   collecting visual proof after a workflow runs;

*   building chat-first assistants that can browse and report back.

Playwright vs Puppeteer in OpenClaw

-----------------------------------

This is the part that is easy to misunderstand.

OpenClaw does not position Puppeteer as the main browser layer in its docs. The browser documentation instead describes a **CDP-backed setup with Playwright used for advanced browser actions**.

The docs also explicitly mention a Playwright requirement:

*   if Playwright is missing from the Gateway build, advanced actions return a `501` error;

*   OpenClaw recommends installing the **full `playwright` package**, not `playwright-core`;

*   or reinstalling OpenClaw with browser support enabled.

So if your goal is “make browser tasks and screenshots work in OpenClaw,” the practical answer is:

*   use OpenClaw’s browser tool;

*   make sure the deployment includes Playwright;

*   treat Puppeteer as a separate browser automation preference, not as the documented OpenClaw integration path.

That does not mean Puppeteer is a bad tool. It just means that if you want the least-friction setup inside OpenClaw, **follow the Playwright path the product documents today**.

Install OpenClaw first

----------------------

If you are starting from scratch, install OpenClaw with the official installer:

Terminal window

    1curl -fsSL https://install.openclaw.ai | bash

Then run onboarding and verify the Gateway:

Terminal window

    1openclaw2openclaw doctor3openclaw status4openclaw dashboard

The browser feature is controlled by the Gateway configuration. The docs show it under `browser.enabled`, and the browser profile is intentionally separate from your personal daily browser.

Install the browser support the right way

-----------------------------------------

### Standard local install

If you installed OpenClaw through the recommended installer, browser support may already be present. If browser actions fail with a message that Playwright is unavailable, the docs point you to the fix:

*   install the full `playwright` package in the same environment as the Gateway;

*   do not use `playwright-core` for this;

*   restart the Gateway after installation;

*   if needed, reinstall OpenClaw with browser support.

For a Node-based install, that usually means:

Terminal window

    1npm install playwright

The important detail is not the package manager syntax. The important detail is that **OpenClaw expects the full Playwright package in the Gateway environment**.

### Docker install

The docs are more explicit for Docker-based deployments. They show this command for adding Playwright support inside the OpenClaw container:

Terminal window

    1docker exec openclaw npm install playwright

Then restart the container or Gateway so OpenClaw can pick it up.

How to make screenshots in OpenClaw

-----------------------------------

Once browser support is working, you have a few options.

### 1\. Use the browser CLI

OpenClaw documents browser commands like these:

Terminal window

    1openclaw browser --browser-profile openclaw start2openclaw browser --browser-profile openclaw open https://example.com3openclaw browser --browser-profile openclaw screenshot --full-page

That is the simplest way to prove the browser is alive and can capture a page.

If you want an element-level screenshot, first create a page snapshot so you can reference a specific node, then capture that element:

Terminal window

    1openclaw browser --browser-profile openclaw snapshot2openclaw browser --browser-profile openclaw screenshot --ref "<element-ref>"

The same tool can also generate PDFs:

Terminal window

    1openclaw browser --browser-profile openclaw pdf

### 2\. Use the OpenClaw UI

The docs also show a browser control UI in the dashboard. That is useful when you want to:

*   inspect the current page manually;

*   see what the browser session is doing;

*   log in to sites that are easier to authenticate interactively;

*   test a screenshot flow before turning it into an automated skill.

### 3\. Use it from the agent

This is where OpenClaw gets interesting. Because the browser is part of the assistant environment, you can ask the Claw to:

*   open a website;

*   check whether something changed;

*   click through a flow;

*   take a screenshot;

*   send the screenshot back to you in chat.

That is much more useful than a raw screenshot script when the screenshot is just the final output of a broader workflow.

Where Puppeteer still fits

--------------------------

If you personally prefer Puppeteer, you can still use it in your own application stack outside OpenClaw. But that is different from asking, “What should I install so OpenClaw browser actions work?”

For that question, the official answer is effectively Playwright.

So the practical split is:

*   use **OpenClaw + Playwright** when the screenshot is one step inside a bigger agent workflow;

*   use **Puppeteer** if you are building your own browser automation separately from OpenClaw;

*   use **ScreenshotOne** if you only need reliable screenshots and do not want to manage browsers at all.

Why ScreenshotOne can be the better choice for screenshot-only flows

--------------------------------------------------------------------

OpenClaw’s browser is valuable when you want a real assistant that can browse, click, think, and report back.

But if the whole job is just:

1.  open a URL;

2.  render it correctly;

3.  return a clean screenshot;

then running a browser stack inside your agent platform can be more moving parts than you need.

That is where ScreenshotOne has a clear advantage.

With ScreenshotOne, you do not need to worry about:

*   browser lifecycle management;

*   Playwright provisioning;

*   long-lived browser sessions;

*   headless browser crashes or memory spikes;

*   tuning screenshot rendering edge cases by hand.

And because ScreenshotOne is focused specifically on screenshots, you get screenshot-first features that are often useful in production:

*   blocking cookie banners;

*   blocking chat widgets;

*   consistent capture at scale;

*   simple API-based integration;

*   cleaner output for reports, monitoring, or archival.

So the decision is not “which product is better?” It is “where is the complexity worth carrying?”

*   If you need a **browser-capable assistant**, OpenClaw is the right layer.

*   If you need a **screenshot service**, ScreenshotOne is the simpler layer.

In many teams, the best setup is both:

*   let OpenClaw decide **when** and **why** to capture something;

*   let ScreenshotOne handle **rendering the screenshot itself**.

If that is your use case, also read [Screenshots for OpenClaw Workflows](/use-cases/openclaw-workflows/).

Summary

-------

If you searched for how to install Puppeteer or Playwright with OpenClaw, the main thing to know is that **OpenClaw documents Playwright, not Puppeteer, as the browser dependency that matters for advanced actions**.

Use OpenClaw’s browser when you want the assistant to navigate, click, inspect, and verify. Use ScreenshotOne when the workflow is really about screenshot delivery, not browser orchestration.

That split will save you time and keep your setup simpler.

Sources

-------

*   [OpenClaw website](https://openclaw.ai/)

*   [OpenClaw installation docs](https://docs.openclaw.ai/start/install/)

*   [OpenClaw browser docs](https://docs.openclaw.ai/core/browser/)

Frequently Asked Questions

--------------------------

If you read the article, but still have questions. Please, check the most frequently asked. And if you still have questions, feel free reach out at [support@screenshotone.com](mailto:support@screenshotone.com).

### Does OpenClaw use Puppeteer or Playwright?

As of March 12, 2026, OpenClaw's browser docs describe a CDP-backed browser layer with Playwright used for advanced actions. The docs do not describe Puppeteer as the primary integration path.

### Can OpenClaw take screenshots of websites?

Yes. OpenClaw's browser tool can take page screenshots, element screenshots, and PDFs, either through the UI, the CLI, or agent workflows.

Read more posts

---------------

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

[View all posts](/blog/)

#### [How to take a screenshot of the element with Puppeteer](/blog/how-to-take-a-screenshot-of-the-element-with-puppeteer/)

Puppeteer allows you to automate everything you can do in the browser manually and even more. You can take screenshots of the entire page and the specific elements.

Read more

#### [Cloudflare Browser Rendering](/blog/cloudflare-browser-rendering/)

Cloudflare recently launched a new Browser Rendering platform. I decided to dive into it and quickly check if I could use it in ScreenshotOne to provide a faster and better customer experience.

Read more

#### [ScreenshotOne on LaunchDay!](/blog/itslaunchday/)

ScreenshotOne participated in the first launch batch of the LaunchDay platform

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/tools
----

The Screenshot API

Automate Website Screenshots

----------------------------

ScreenshotOne is developed to support a huge variety of use cases and to be the best assistant for developers in website screenshot automation.

### Website Screenshotter

Render screenshots website online for free and without registration.

[Render website screenshots →](/tools/website-screenshot/)

### Entire Webpage Screenshots

Render screenshots of entire webpages online for free and without signing up.

[Render full page screenshots →](/tools/full-page-website-screenshot/)

### Scrolling Screenshots

Render scrolling screenshots of webpages online for free and without signing up.

[Render scrolling screenshots →](/tools/scrolling-website-screenshot/)

### Above the Fold Checker

Capture the first visible viewport of a webpage and compare above-the-fold layouts.

[Check above the fold →](/tools/above-the-fold/)

### URL to Markdown

Convert any public webpage URL into clean Markdown.

[Convert URL to Markdown →](/tools/url-to-markdown/)

### Full-page Screenshot Chrome Extension

Take full page screenshots of website and annotate them in a few clicks.

[Check out the extension →](/tools/full-page-screenshot-chrome-extension/)

Bohdan Shulha

Founder, [Make a Directory](https://makeadir.com/)

> Being non-VC backed has it's own challenges, but as Dmytro's hands are not tied by investors, he's able to deliver excellent product development performance and support.

> 

> I will recommend ScreenshotOne to anyone who needs to complete similar tasks.

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/improved-metadata-icon-detection
----

Improved favicon detection for metadata\_icon

=============================================

Improved \`metadata\_icon\` to check common favicon link variants more reliably.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Feb 28, 2026

We fixed an issue where fallback favicon selectors were not tried if `link[rel="icon"]` was missing.

Now, when `metadata_icon=true`, ScreenshotOne checks these selectors in order:

*   `link[rel="icon"]`

*   `link[rel="shortcut icon"]`

*   `link[rel="icon shortcut"]`

This improves favicon extraction reliability for websites that use different `rel` conventions.

Use it as usual:

    1https://api.screenshotone.com/take?metadata_icon=true&url=https://example.com/&access_key=<access key>

If you have any questions or feedback, please let us know at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Async, Webhooks, and Extra Limits](/changelog/async-webhooks-and-extra-limits/)

May was a great month and full of new and exciting updates. Let's check them out quickly.

Read more →

1 min read

#### [A Simple Website Screenshot Tool by ScreenshotOne](/changelog/website-screenshot/)

A few words about why to launch yet another website screenshotting tool.

Read more →

1 min read

#### [An improved screenshot history page](/changelog/an-improved-screenshot-history-page/)

Daily, I work as hard as I can to ensure that ScreeenshotOne is the best screenshot API out there possible. But I rarely share updates but trust me, a ton of them might go unnoticed. Let's fix this situation.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/errors/signature-is-invalid
----

[Skip to content](#_top)

Signature Invalid

=================

Copy page

It is an API error returned when the provided signature parameter is not valid.

    1{2    "is_successful": false,3    "error_code": "signature_is_not_valid",4    "error_message": "You provided the `signature` parameter, but it is not valid. Make sure you use the correct signing algorithm—https://screenshotone.com/docs/signed-requests/.",5    "documentation_url": "https://screenshotone.com/docs/errors/signature-is-invalid/"6}

Reasons and how to fix

----------------------

### Incorrect Signing Algorithm

The most common reason for the “signature\_is\_not\_valid” error is using an incorrect signing algorithm to generate the signature.

To fix this, you can:

1.  **Verify signing algorithm**: Ensure you are using the correct signing algorithm as specified in the [signed requests documentation](https://screenshotone.com/docs/signed-requests/).

2.  **Check signature generation code**: Review your code that generates the signature to ensure it follows the correct algorithm and procedure.

### Mismatched Signature

The signature provided in the request might not match the expected signature due to data mismatches or incorrect key usage.

To fix this, consider:

1.  **Verify request data**: Ensure that all data used to generate the signature matches the data sent in the request.

2.  **Use correct secret key**: Ensure that the correct secret key is used to generate the signature.

### Signature Formatting Issues

Formatting issues, such as encoding problems or extra characters, can lead to an invalid signature.

To fix this, verify that the signature is correctly formatted and encoded as required by the API.

### Debugging Signature Issues

If you are still encountering issues, you can use debugging tools or logging to trace the signature generation process and identify where it might be going wrong.

Reach out to support

--------------------

If you continue to face issues or need further assistance, please reach out to `support@screenshotone.com`, and we will assist you as soon as possible.

----
url: https://screenshotone.com/screenshot-api/php
----

[What's new API error insights API error insights in the dashboard](/changelog/error-metrics/)

PHP Screenshot API

==================

Capture pixel-perfect website screenshots in PHP with a simple API call. No browser management, no complex setup—just clean, reliable screenshots.

----------------------

----------------------------

------------------------------------

Take screenshots with PHP

-------------------------

Use our official PHP SDK or send simple HTTP requests to capture screenshots.

    1<?php2

    3// composer require screenshotone/sdk:^1.04

    5use ScreenshotOneSdkClient;6use ScreenshotOneSdkTakeOptions;7

    8$client = new Client("<access key>", "<secret key>");9

    10$options = TakeOptions::url("https://example.com")11    ->fullPage(true)12    ->delay(2)13    ->geolocationLatitude(48.857648)14    ->geolocationLongitude(2.294677)15    ->geolocationAccuracy(50);16

    17$url = $client->generateTakeUrl($options);18echo $url.PHP_EOL;19// expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com...20

    21$image = $client->take($options);22file_put_contents('example.png', $image);23// the screenshot is stored in the example.png file

Mike Roberts

Founder, [SpyFu](https://www.spyfu.com/)

> ScreenshotOne is the best product on the market - and that's before you take into account how responsive and easy Dmytro is to work with.

> 

> Any time we've found a rare edge case, it's been resolved in hours.

> 

> Great company, great founder - can't say enough!

Without writing a line of code

No-code integrations

--------------------

Quickly render website screenshots with Zapier, Airtable, Make and other popular no-code platforms of your choice.

[](/integrations/zapier/)[](/integrations/airtable/)[](/integrations/make/)[](/integrations/bubble/)[](/integrations/n8n/)

Read

Lessons from running screenshot rendering infrastructure

--------------------------------------------------------

Practical guides and real updates based on our experience operating rendering infrastructure at production scale.

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots with PHP](/blog/how-to-take-website-screenshots-with-php/)

The article examines how you can take screenshots of any URL with PHP by using Selenium, Puppeteer alternatives, or screenshot API as a service.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jun 14, 2022

•

3 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Taking care of WordPress Sites with ScreenshotOne](/blog/kinsta/)

How Kinsta uses ScreenshotOne to deliver reliable automatic updates.

Written by

[Roger Williams](/contributors/roger-williams/), [Barnabás Ürmössy](/contributors/barnabs-rmssy/)

Published on

Apr 29, 2025

•

2 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Typeshare uses ScreenshotOne for image generation](/blog/how-typeshare-uses-screenshotone/)

Typeshare is a digital writing platform designed to enhance the writing experience by offering a suite of tools aimed at reducing common barriers writers face.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Apr 14, 2024

•

2 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/page-waitfortimeout-is-not-a-function-in-puppeteer
----

page.waitForTimeout is not a function in Puppeteer

==================================================

Puppeteer removed page.waitForTimeout(). Learn why the error happens and which modern alternatives to use instead.

[Blog post](/blog/) 2 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Mar 13, 2026

#### Tags

[Puppeteer guides](/blog/tags/puppeteer-guides/)

Why this error happens

----------------------

If you see an error like:

    1TypeError: page.waitForTimeout is not a function

your code is probably running on the old version of Puppeteer.

`page.waitForTimeout()` was removed, so older examples and blog posts that still use it will fail after an upgrade.

What to use instead

-------------------

In most cases, the correct replacement is not another sleep function. It is an explicit wait for the thing you actually need.

Use:

*   `page.waitForSelector()` when you need an element to appear;

*   `page.waitForNavigation()` when a click or submit triggers navigation;

*   `page.waitForResponse()` when you need a specific API call to finish;

*   `page.waitForFunction()` when you need a client-side condition to become true;

*   `page.waitForNetworkIdle()` when you want the page to become quiet after navigation.

If you are looking for `page.goto(..., { waitUntil: ... })` guidance, read [Puppeteer waitUntil: how to wait for page load](/blog/puppeteer-wait-until-the-page-is-ready/).

Replacements for common cases

-----------------------------

### Wait for a selector instead of sleeping

    1await page.goto(url, { waitUntil: "domcontentloaded", timeout: 30_000 });2await page.waitForSelector(".price", {3    visible: true,4    timeout: 10_000,5});

### Wait after a click that navigates

    1const [response] = await Promise.all([2    page.waitForNavigation({3        waitUntil: ["domcontentloaded", "networkidle2"],4        timeout: 30_000,5    }),6    page.click("a.next-page"),7]);

### Wait for a specific API response

    1await page.click("button.refresh");2

    3await page.waitForResponse((response) => {4    return response.url().includes("/api/data") && response.ok();5});

### Wait for a client-side condition

    1await page.waitForFunction(() => {2    return document.querySelectorAll(".result-card").length >= 10;3});

### Wait for the network to calm down

    1await page.goto(url, { waitUntil: "domcontentloaded", timeout: 30_000 });2

    3await page.waitForNetworkIdle({4    idleTime: 500,5    timeout: 10_000,6});

If you still need a fixed delay

-------------------------------

Sometimes a short delay is still the simplest fallback, especially for one-off scripts.

Use a standard JavaScript promise:

    1await new Promise((resolve) => setTimeout(resolve, 2000));

That is the closest drop-in replacement for `page.waitForTimeout(2000)`, but it is usually the weakest solution:

*   it can still be too short on slow pages;

*   it can waste time on fast pages;

*   it does not describe what the code is actually waiting for.

Migration example

-----------------

Old code:

    1await page.goto(url);2await page.waitForTimeout(5000);3await page.screenshot({ path: "page.png" });

Better modern version:

    1await page.goto(url, {2    waitUntil: "domcontentloaded",3    timeout: 30_000,4});5

    6await page.waitForNetworkIdle({7    idleTime: 500,8    timeout: 10_000,9});10

    11await page.screenshot({ path: "page.png" });

Best version, when you know the exact ready signal:

    1await page.goto(url, {2    waitUntil: "domcontentloaded",3    timeout: 30_000,4});5

    6await page.waitForSelector(".chart-container", {7    visible: true,8    timeout: 10_000,9});10

    11await page.screenshot({ path: "page.png" });

Summary

-------

`page.waitForTimeout()` is gone in Puppeteer.

You can replace it with:

*   an explicit Puppeteer wait method for the event you care about;

*   `new Promise((resolve) => setTimeout(resolve, ms))` if you really need a plain delay.

For navigation readiness and `waitUntil` options, see [Puppeteer waitUntil: how to wait for page load](/blog/puppeteer-wait-until-the-page-is-ready/).

Read more Puppeteer guides

--------------------------

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

[View all posts](/blog/tags/puppeteer-guides/)

#### [Puppeteer Performance Monitoring with Inspector](/blog/puppeteer-performance-monitoring-with-inspector/)

In this article I'll show you how to monitor performance and errors of a browser automation script written with Puppeteer.

Read more

#### [How to create a site thumbnail with Puppeteer](/blog/how-to-create-a-site-thumbnail-with-puppeteer/)

We can consider the screenshot of URL or HTML as a thumbnail, but I write about the thumbnail of a screenshot. How do you take a screenshot within the defined viewport but with different image width and height? Resize!

Read more

#### [Comparing Puppeteer versus Selenium for rendering website screenshots](/blog/comparing-puppeteer-versus-selenium-for-rendering-website-screenshots/)

When comparing Puppeteer, Selenium, and ScreenshotOne for rendering screenshots, it's crucial to understand the distinct capabilities and use cases of each tool.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/contributors/matthias-neumayer
----

Matthias Neumayer

-----------------

View all Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [How Branding 5 uses ScreenshotOne for competitor analysis](/blog/how-branding5-uses-screenshotone/)

If you are interested in diving deeper into the Branding 5 use case and discover if ScreenshotOne might be useful for you, too, keep reading.

Written by

[Matthias Neumayer](/contributors/matthias-neumayer/), [Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Oct 4, 2024

•

2 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/contributors/andy-hooke
----

Andy Hooke

----------

View all Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [How and why Saaspo uses ScreenshotOne to automate screenshot generation](/blog/saaspo/)

Saaspo chose ScreenshotOne to automate tedious and boring work to generate pixel-perfect screenshots for their platform. Why?

Written by

[Andy Hooke](/contributors/andy-hooke/), [Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Nov 4, 2025

•

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/4
----

Changes and updates

-------------------

Stay updated with the latest information about new features, bug fixes, and optimizations at ScreenshotOne

### Product updates in the last 12 months

Sep 22, 2025

#### [Available in Context7](/changelog/available-in-context7/)

ScreenshotOne documentation is now available in Context7.

Read more →

1 min read

Sep 16, 2025

#### [Failed payment alerts in the dashboard](/changelog/failed-payment-alerts/)

Starting today, you will see an alert in the dashboard when a payment fails.

Read more →

1 min read

Sep 2, 2025

#### [Improved blocking of banners for specific websites](/changelog/improved-banner-blocking-for-specific-websites/)

We just released an updated version of our algorithm to block banners for specific websites by heuristics.

Read more →

1 min read

Aug 28, 2025

#### [Playground Presets](/changelog/playground-presets/)

You can now create and save presets in the ScreenshotOne Playground!

Read more →

1 min read

Aug 27, 2025

#### [Screenshot URL in webhooks](/changelog/screenshot-url-in-webhooks/)

Now, you can get the screenshot URL in the webhook response.

Read more →

1 min read

Aug 26, 2025

#### [Improved full-page screenshot rendering](/changelog/improved-full-page-rendering/)

Fixed a few issues related to full-page screenshots rendering.

Read more →

1 min read

Aug 16, 2025

#### [Change organization owner for already subscribed customers](/changelog/change-ownership-for-subscribed/)

Starting today, you can change organization owner for already subscribed customers.

Read more →

1 min read

Jul 14, 2025

#### [Screenshot URLs are now available in the response](/changelog/screenshot-url/)

You can now get a screenshot URL in the response of the API call.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/enrich-content-with-screenshots
----

Automate Website Screenshots

1 min read

Enrich Blog Posts for SEO

=========================

Automatically capture and embed screenshots of websites mentioned in SEO content to enhance engagement and credibility.

Since [SEOBot started to add website thumbnails to blog posts](/blog/seobot-automates-screenshot-generation-for-articles/), we have realized there is one more interesting use case for using ScreenshotOne and happy to share it.

Basically, we propose to generate screenshots for any website mentioned in your blog posts.

Adding screenshots to blog posts makes them easier to understand and more interesting. Screenshots show readers exactly what you’re talking about, like how a website looks or how to do something step-by-step. This makes your post more engaging and helps people trust what you’re saying because they can see it for themselves.

Also, using screenshots can help more people find your blog. When you add pictures and use the right words to describe them, your blog can show up in image searches. This can bring more visitors to your site. Plus, posts with pictures are shared more on social media, making your blog more popular.

So, adding screenshots is a simple way to make your posts better and reach more readers.

We thought making a screenshot tool for our AI agents would be simple. But we faced countless unexpected problems.

So, we ditched the idea and chose ScreenshotOne API instead. It saved us lots of time and it just works!

John Rush

Founder, [Unicorn Platform](https://unicornplatform.com)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/integrations/zapier
----

Integrations

1 min read

Zapier

======

Automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos in Zapier.

No-Code Automation

Resources

---------

*   [ScreenshotOne on Zapier](https://zapier.com/apps/screenshotone/integrations)

Capturing screenshots sounds easy until you try to do it yourself and run into N number of cases.

Dmytro has done a wonderful job in all 3 aspects: The product, The documentation, The wonderful human behind this!

Nabil Kazi

Co-Founder, [BugSmash](https://screenshotone.com/blog/bugsmash-story/)

Check more Integrations

-----------------------

No-code tools, AI, code libraries, and more.

[Check more Integrations](/integrations/)

No-Code Automation

### Clay

Generate website screenshots inside Clay to qualify leads, assess content, and enrich rows with visual context automatically.

[Read more →](/integrations/clay/)

Code API

### SDK and Code Examples

Use the SDKs and code examples to take screenshots in your own code.

[Read more →](/integrations/code/)

No-Code Automation

### Make

Use ScreenshotOne with Make to automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

[Read more →](/integrations/make/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/bulk-screenshots
----

[Skip to content](#_top)

Bulk Screenshots

================

Copy page

Tip

Our bulk screenshots API endpoint is a simple wrapper endpoint around the regular screenshot API endpoints like (`/take`, `/animate`, and similar). But since it is a simple wrapper, you might find it much better to implement your own bulk screenshot solution. Check out our guide on [how to take screenshots of multiple URLs](/docs/guides/bulk-screenshots/) with ScreenshotOne API.

Request

-------

You can use a bulk screenshot-taking feature to take many screenshots in one request. Send a simple POST HTTP request to `/bulk` path with the list of URLs (HTML or Markdown):

    1POST https://api.screenshotone.com/bulk2

    3{4    "access_key": "<your access key>"5    "execute": false,6    "optimize": false,7    "options": {"url": "https://example.com", "viewport_width": 1280, "viewport_height": 1024, "block_ads": true},8    "requests": [9        {"viewport_width": 360, "viewport_height": 640}, // a screenshot of example.com with a different viewport10        {"url": "https://example.com"},11        {"url": "https://finance.yahoo.com", "block_cookie_banners": true},12        {"html": "<h1>Hello, world!</h1>", "block_ads": false},13        {"markdown": "**Yes!**"}14    ]15}

The options property contains default options that will be applied to every request. And for every request, you can specify options to override the default values. You can specify all [the regular options you use to take a single screenshot](/docs/options).

You can specify the access key as a query parameter `access_key=<your access key>`, an HTTP header `X-Access-Key: <your access key>`, or in the request’s body.

Response

--------

The response contains an array of screenshot URLs you can use to download the screenshots:

    1{2    "responses": [3        {"url": "https://api.screenshotone.com/take?url=http://example.com&viewport_width=1280&viewport_height=1024&block_ads=true"},4        {"url": "https://api.screenshotone.com/take?url=https://finance.yahoo.com&viewport_width=1280&viewport_height=1024&block_ads=true&block_cookie_banners=true"},5        {"url": "https://api.screenshotone.com/take?html=<h1>Hello, world!</h1>&viewport_width=1280&viewport_height=1024&block_ads=false&block_cookie_banners=true"}6    ]7}

But if you requested to [execute requests](#execute-requests), the result will also contain a summary execution response for each request:

    1[2    {3        "url": "https://api.screenshotone.com/take?url=http://example.com&viewport_width=1280&viewport_height=1024&block_ads=true",4        "response": {5            "is_successful": true,6            "status": 200,7            "statusText": "OK"8        }9    },10    {11        "url": "https://api.screenshotone.com/take?url=https://finance.yahoo.com&viewport_width=1280&viewport_height=1024&block_ads=true&block_cookie_banners=true",12        "response": {13            "is_successful": true,14            "status": 200,15            "statusText": "OK"16        }17    },18    {19        "url": "https://api.screenshotone.com/take?html=<h1>Hello, world!</h1>&viewport_width=1280&viewport_height=1024&block_ads=false&block_cookie_banners=true",20        "response": {21            "is_successful": true,22            "status": 200,23            "statusText": "OK"24        }25    },26    {27        "url": "https://api.screenshotone.com/take?markdown=**Yes!**&viewport_width=1280&viewport_height=1024&block_ads=false&block_cookie_banners=true",28        "response": {29            "is_successful": true,30            "status": 200,31            "statusText": "OK"32        }33    }34]

As you noticed, images are not returned, but in case of an error, the `is_successful` property will be `false`, and you can expect the `body` property to explore the error:

    1[2    {3        "url": "https://api.screenshotone.com/take?url=http://example.com&viewport_width=1280&viewport_height=1024&block_ads=true",4        "response": {5            "is_successful": false,6            "status": 400,7            "statusText": "Bad request",8            body: {9                "error_code": "concurrency_limit_reached"10                "error_message": "Concurrency limit is reached"11            }12        }13    }14]

Execute requests

----------------

Bulk screenshots are implemented in a lazy loading way. It means that the screenshot is literally taken when you tried to download it, not when you sent a bulk request. If you want to execute each request before you get a response, set the parameter `execute` to `true`:

    1POST https://api.screenshotone.com/bulk2

    3{4    "access_key": "<your access key>"5    "execute": true,6    // ...7}

But make sure to wait enough time until all the screenshots are done.

Optimizations

-------------

To take bulk screenshots faster, you can use the optimization feature if you want to take bulk screenshots for the same URLs (HTML or Markdown) but with a different set of parameters:

    1POST https://api.screenshotone.com/bulk2

    3{4    "access_key": "<your access key>"5    "execute": true,6    "optimize": true,7    "options": {"url": "https://example.com", "viewport_width": 1280, "viewport_height": 1024},8    "requests": [9        {"viewport_width": 360, "viewport_height": 640}, // a screenshot of example.com with a different viewport10        {"viewport_width": 736, "viewport_height": 414}11    ]12}

The feature only works when `execute` is set to `true`.

The optimization is not guaranteed since many sites can reload and take the same time to render in case the viewport is changed. And some options, like blocking and not blocking ads, do require a page reload, which takes the same time as not using optimization at all.

The best approach is to test if it works for your use case.

Use cases

---------

### Upload bulk screenshots to S3-compatible storage

In the example, I want to take screenshots for one site but for different devices and upload them to [S3-compatible storage](https://screenshotone.com/docs/options/#storing):

    1POST https://api.screenshotone.com/bulk2

    3{4    "access_key": "<your access key>"5    "execute": true,6    "options": {"url": "https://example.com", "store": true, "response_type": "empty"},7    "requests": [8        {"viewport_device": "pixel_4a_5g_landscape", "storage_path": "pixel_4a_5g_landscape"},9        {"viewport_device": "iphone_13_pro", "storage_path": "iphone_13_pro"},10        {"viewport_device": "iphone_13", "storage_path": "iphone_13"}11    ]12}

In this example, I upload screenshots taken from different devices and save the files with the names of the devices.

Limitations

-----------

Currently, only up to 20 requests are supported in the one bulk request.

----
url: https://screenshotone.com/docs/upload-to-s3
----

[Skip to content](#_top)

Upload to S3

============

Copy page

You can use [ScreenshotOne screenshot API](https://screenshotone.com/) to take website screenshots and upload them directly to Amazon S3 and any other S3-compatible storage like [Cloudflare R2](https://www.cloudflare.com/products/r2/), [Backblaze](https://www.backblaze.com/), and others.

I will guide through a few simple steps of how you can do it.

Today’s UI for Amazon AWS console or ScreenshotOne might be a bit different, and things can change after a while, but you should sense the overall approach from the post you need to apply to make it work.

If you are familiar with AWS, you can go straight away to [configure access to S3 in ScreenshotOne](#configure-access-to-s3-in-screenshotone).

Prepare the bucket and credentials

----------------------------------

Open the [S3 console](https://console.aws.amazon.com/s3/) and click on the “Create bucket” button:

Type the bucket name, choose a region, and other important for you settings:

Now, let’s create access keys to upload to the S3 bucket.

Danger

Never, ever, don’t share the access key to your main account with ScreenshotOne or another service. Create an IAM user with as narrow access as possible and share its keys.

> [AWS Identity and Access Management (IAM) user](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users.html) is an entity that you create in AWS to represent the person or application that uses it to interact with AWS. A user in AWS consists of a name and credentials.

Before creating a user, we will create a narrow policy to restrict access to the bucket we created and only for putting objects into it.

> You manage access in AWS by creating [policies](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html) and attaching them to IAM identities (users, groups of users, or roles) or AWS resources. A policy is an object in AWS that, when associated with an identity or resource, defines their permissions. AWS evaluates these policies when an IAM principal (user or role) makes a request. Permissions in the policies determine whether the request is allowed or denied.

Open [the IAM management console](https://console.aws.amazon.com/iam/), navigate to “Policies”, then click on the “Create policy” button. And one the following screen, select `S3` as a service, then allow only `PutObject` operation for the bucket with the name `screenshotone`:

After clicking on the “Create policy” button and entering the policy name:

I gave a clear name to the policy as an example. You can provide whatever you like.

Then open [the IAM management console](https://console.aws.amazon.com/iam/) again and navigate to users. Once you are here, click on the “Add users” button:

After that, type username and select “Access key - Programmatic access”:

We need to select and attach the policy we created earlier to the user:

The user is primarily ready, so we can skip the following steps and get to the end, where we can see credentials:

Copy the credentials and store them in safe place like password manager. We will need them in the next step to configure ScreenshotOne to upload screenshots.

I will save the credentials for our example to use in the next section:

    1Access key ID: AKIAURGNZP6VM5HASWIF2Secret access key: wVd8OgAnGIEdlQaWxDwzVcOQNO03G1dgFiDyHLPT

Configure access to S3 in ScreenshotOne

---------------------------------------

Caution

If you haven’t created the bucket in the `us-east-1` AWS region, please, specify your bucket region through an endpoint in a format like `https://s3.<your-region>.amazonaws.com`.

You can set credentials ([Access Key ID](https://screenshotone.com/docs/options/#storage_access_key_id) and [Secret Access Key](https://screenshotone.com/docs/options/#storage_secret_access_key)) when sending an API request or you cat to go to the [access page](https://dash.screenshotone.com/access). And put all the credentials you got from Amazon AWS for S3 into the “S3 access” configuration form:

I specified the default bucket, but you can use many buckets to upload screenshots and then override the target bucket with [the storage\_bucket option](https://screenshotone.com/docs/options/#storage_bucket) when using API. But for example, I use only one bucket—it is enough.

Take a website screenshot through API with `storing` options

------------------------------------------------------------

ScreenshotOne API has [a bunch of options related to uploading screenshots to S3 storage](https://screenshotone.com/docs/options/#storing):

*   [store](https://screenshotone.com/docs/options/#store) triggers upload of the taken screenshot, rendered HTML or PDF to the configured S3 bucket.

*   [storage\_path](https://screenshotone.com/docs/options/#storage_path)—specifies the key for the file, but not an extension. The extension will be added automatically based on the specified [format](https://screenshotone.com/docs/options/#format).

*   [storage\_bucket](https://screenshotone.com/docs/options/#storage_bucket)—overrides the default bucket configured in the [access page](https://dash.screenshotone.com/access).

*   [storage\_class](https://screenshotone.com/docs/options/#storage_class)—allows to specify [the object storage class](https://aws.amazon.com/s3/storage-classes/).

Let’s take a screenshot and upload it to S3:

    1https://api.screenshotone.com/take?access_key=0MpjJxw8Vk7ZAw&url=https://nextjs.org&store=true&storage_path=nextjs.org

The result is:

And let’s check S3:

In case you don’t need to return the resulting image and speed up uploading, add `response_type=empty` to the request:

    1https://api.screenshotone.com/take?access_key=0MpjJxw8Vk7ZAw&url=https://example.com&store=true&storage_path=example.com&response_type=empty

The result is a white screen—zero bytes sent from the ScrenshotOne API in response. And let’s again check that the screenshot is uploaded:

That’s it. But if you want to do it asynchronously?

Async and Webhooks

------------------

ScreenshotOne supports [asynchronous screenshot rendering and webhooks](/docs/async-and-webhooks/). You can upload your screenshots to S3 asynchronously without waiting and then receive the resulting upload URL to your server.

To do that, specify additional parameters `async`, `webhook_url`, `storage_return_location`. And only JSON response type is supported.

So the full request might look like:

    1https://api.screenshotone.com/take?access_key=0MpjJxw8Vk7ZAw&url=https://example.com&store=true&storage_path=example.com&response_type=json&async=true&webhook_url=https://example.com&storage_return_location=true

Read more about [asynchronous screenshot rendering and webhooks](/docs/async-and-webhooks/).

Why upload to S3

----------------

I don’t know your use case and would be happy to know it, but there are a few reasons why customers of ScreenshotOne upload website screenshots to S3.

One is to use CDN that pulls images from S3 storage, and the other is to archive screenshots, process them later, or even compare them.

Instead of summary

------------------

It makes me happy to help people solve their problems. And even happier when people pay for that. I hope today I solved yours. Have a good day or even night, and be happy 👌

----
url: https://screenshotone.com/docs/guides/how-to-customize-any-website-before-screenshotting
----

[Skip to content](#_top)

Customize websites before screenshotting

========================================

Copy page

ScreenshotOne supports a few options that can help you add any customizations to any website before rendering screenshots of it.

Hide any element by CSS selectors

---------------------------------

If you just need to quickly hide a few elements on the website, just use [the hide\_selectors](https://screenshotone.com/docs/options/#hide_selectors) option and specify as many CSS selectors as you wish.

For example, let’s hide the main header on the example.com website with:

    1https://api.screenshotone.com/take?url=https://example.com&hide_selectors=h1&access_key=<your API key>

Before hiding:

After hiding:

You can specify as many selectors as you wish, e.g.:

    1https://api.screenshotone.com/take?url=https://example.com&hide_selectors[]=h1&hide_selectors[]=p&access_key=<your API key>

Add custom CSS styles

---------------------

But often you want to do more than just hide a few elements. Maybe you want to change some colors of the elements, or font size, or whatever. Then you can simply add custom CSS styles with [the styles option](https://screenshotone.com/docs/options/#styles).

Don’t forget to encode the code. And often, you must add a `!important` attribute to every property you use.

Let’s try it with the example.com website:

    1https://api.screenshotone.com/take?url=https://example.com&styles=h1%20%7Bcolor%3A%20red%20%21important%3B%7D&access_key=<your API key>

Notice, that the styles parameter is URL-encoded. Let’s look at the result:

Execute custom JavaScript code

------------------------------

But what if hiding elements and adding styles is not enough? We got you covered! You can any custom JavaScript code you want.

You can check out a more complex example of using scripting for integrating [Google Translate API when screenshotting websites](/docs/guides/how-to-translate-and-render-a-website-as-a-screenshot/).

Caution

If your script causes navigation and makes the page reload, make sure to specify [the scripts\_wait\_until option](/docs/options/#scripts_wait_until) if you want to wait or large enough [delay](/docs/options/#delay).

Let’s execute an extreme example and just override the page content with:

    1scripts = document.body.innerHTML = "Hello, world!";

The URL would look like:

    1https://api.screenshotone.com/take?scripts=document.body.innerHTML="Hello,%20world!"&url=https://example.com/&access_key=<your access key>

And the result is:

Click

-----

If you use scripting to only click on some element by selector, there is a popular shortcut for that [the click option](/docs/options/#click).

    1https://api.screenshotone.com/take?click=.a-some-button-class-selector&url=https://example.com&access_key=<your access key>

Just specify any selector of any element and it will be clicked.

----
url: https://screenshotone.com/use-cases/automate-personalized-videos
----

Automate Website Screenshots

1 min read

Automate Personalized Videos at Scale

=====================================

Using email marketing with dynamic, scrolling, or animated screenshots for personalized videos.

Creating personalized video content for email marketing campaigns can be a game-changer for small businesses, especially in industries where engagement rates directly correlate to conversion rates.

One simple approach involves the use of a website screenshot API, like ScreenshotOne, to automate the creation of dynamic, [scrolling, or animated screenshots](/scrolling-screenshots/) that can be integrated into videos.

This method offers a personalized touch that can significantly increase the effectiveness of email marketing efforts.

Shoutout to Dmytro Krasun and his product ScrenshotOne, an excellently built product covering almost all of our use cases.

Most importantly and the reason I'm writing this is he provides a crazy good level of support through his support chat, thanks!

Zawwad Ul Sami

Founder, [MailToon](https://mailtoon.io/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/integrations/s3
----

Integrations

1 min read

S3

==

Upload screenshots to Amazon S3 or any other S3-compatible storage.

Code API

Resources

---------

*   [Guide](https://screenshotone.com/docs/guides/upload-to-s3/)

ScreenshotOne is a terrific Screenshot API. We're taking screenshots at scale at landing.gallery and ScreenshotOne is handling it like an absolute champ.

The founder is incredibly responsive and the docs are outstanding and get you going within minutes.

Chris Jayden

Maker, [Landing Gallery](https://screenshotone.com/blog/landing-gallery/)

Check more Integrations

-----------------------

No-code tools, AI, code libraries, and more.

[Check more Integrations](/integrations/)

No-Code Automation

### Make

Use ScreenshotOne with Make to automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

[Read more →](/integrations/make/)

No-Code Automation

### Clay

Generate website screenshots inside Clay to qualify leads, assess content, and enrich rows with visual context automatically.

[Read more →](/integrations/clay/)

Code API

### SDK and Code Examples

Use the SDKs and code examples to take screenshots in your own code.

[Read more →](/integrations/code/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/how-to-set-a-time-zone-in-puppeteer-for-page
----

How to set a time zone in Puppeteer for page

============================================

Puppeteer allows changing the time zone on a per-page basis. In automation testing, you can use it to test how the website behaves for different time zones. Or you can use it for scrapping to imitate the user from the expected time zone by the site.

[Blog post](/blog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Jun 23, 2022

By the way, in our [screenshot API](/), you can take the screenshot of the element by specifying [the time zone parameter](/docs/options/#time_zone).

Puppeteer allows changing the time zone on a per-page basis. In automation testing, you can test how the website behaves for different time zones. Or you can use it for scrapping to imitate the user from the expected time zone by the site.

It is reasonably simple to do by using [page.emulateTimezone(timezoneId)](https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#pageemulatetimezonetimezoneid):

    1const puppeteer = require('puppeteer');2

    3(async () => {4    const browser = await puppeteer.launch({});5    try {6        const page = await browser.newPage();7

    8        await page.emulateTimezone('Europe/London');9

    10        await page.goto('https://screenshotone.com/');11    } catch (e) {12        console.log(e)13    } finally {14        await browser.close();15    }16})();

The list of available time zones you can find at [Chromium source code](https://source.chromium.org/chromium/chromium/src/+/main:third_party/icu/source/data/misc/metaZones.txt), these are the most popular ones:

*   America/Santiago

*   Asia/Shanghai

*   Europe/Berlin

*   America/Guayaquil

*   Europe/Madrid

*   Pacific/Majuro

*   Asia/Kuala\_Lumpur

*   Pacific/Auckland

*   Europe/Lisbon

*   Europe/Kiev

*   Asia/Tashkent

*   Europe/London

I hope I have helped solve the issue and I wish you a nice day!

Read more posts

---------------

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

[View all posts](/blog/)

#### [Building a website directory with Next.js, Tailwind CSS, and Prisma](/blog/building-a-website-directory-with-nextjs-tailwind-css-and-prisma/)

See how easy it is to build a website directory with screenshots with Next.js, Tailwind CSS, and Prisma.

Read more

#### [ScreenshotOne reached $200K ARR with 400+ paying customers](/blog/200000-arr-and-400-paying-customers/)

It is a good milestone to make a compact snapshot of the insights that (maybe?) led to it.

Read more

#### [A complete guide on how to take full page screenshots with Puppeteer, Playwright or Selenium](/blog/a-complete-guide-on-how-to-take-full-page-screenshots-with-puppeteer-playwright-or-selenium/)

You can take a full page screenshot with Pupeeter by specifying the \`fullPage\` parameter as true when taking a screenshot. But there is a caveat. If a site has lazy-loaded images, they won't be rendered. Let's examine how to fix the issue and trigger lazy image loading with Puppeteer.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/tags/puppeteer-guides/3
----

Puppeteer Guides

----------------

How-to posts and troubleshooting guides for Puppeteer-based automation.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Puppeteer waitUntil: how to wait for page load](/blog/puppeteer-wait-until-the-page-is-ready/)

Join me in exploring how to find the ideal wait time or event of when to take the page screenshot with Puppeteer.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Mar 13, 2026

•

8 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Uploading website screenshots to any S3-compatible storage](/blog/uploading-website-screenshots-to-any-s3-compatible-storage/)

In this note, I share how I take website screenshots or render HTML and upload the resulted images or PDF to any S3-compatible storage like Amazon S3, Cloudflare R2, or Backblaze B2.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jul 12, 2022

•

2 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to render HTML with Puppeteer](/blog/how-to-render-html-with-puppeteer/)

Use Puppeteer or screenshot API to generate the Open Graph protocol images, bills, receipts, or invoices PDF or PNG files from the HTML templates.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Mar 13, 2026

•

3 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to add custom scripts to a page in Puppeteer](/blog/how-to-add-custom-scripts-to-a-page-in-puppeteer/)

How to add custom scripts to a page in Puppeteer. Let's discover how it works quickly."

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jun 24, 2022

•

2 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to add custom styles to a page in Puppeteer](/blog/how-to-add-custom-styles-to-a-page-in-puppeteer/)

To add custom styles to any page use Puppeteer's page method \`page.addStyleTag(options)\`. Let's discover how it works quickly.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jun 24, 2022

•

2 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [How to block requests with Puppeteer](/blog/how-to-block-requests-with-puppeteer/)

Puppeteer allows blocking any outgoing requests while loading the page. Whether you want to block ads, tracking scripts, or different types of resources, it is relatively easy to do with Puppeteer.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jul 14, 2022

•

3 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [How to use proxy per page with Puppeteer](/blog/how-to-use-proxy-per-page-with-puppeteer/)

It is easy to use proxy globally for the puppeteer instance, but there is a trick to use proxy on a per-page basis.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Apr 29, 2025

•

2 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take screenshots with Puppeteer](/blog/how-to-take-a-screenshot-with-puppeteer/)

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

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Apr 29, 2025

•

11 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/12
----

Changes and updates

-------------------

Stay updated with the latest information about new features, bug fixes, and optimizations at ScreenshotOne

### Product updates in the last 12 months

May 25, 2023

#### [Async, Webhooks, and Extra Limits](/changelog/async-webhooks-and-extra-limits/)

May was a great month and full of new and exciting updates. Let's check them out quickly.

Read more →

1 min read

May 13, 2023

#### [ScreenshotOne is available as a ChatGPT plugin](/changelog/screenshotone-is-available-as-a-chatgpt-plugin/)

From today, you can render screenshots of any website or even raw HTML in ChatGPT—ScreenshotOne is available as a plugin. But at the moment of writing not available yet, in the official store, but it can be available when you read it.

Read more →

2 min read

Apr 7, 2023

#### [An improved screenshot history page](/changelog/an-improved-screenshot-history-page/)

Daily, I work as hard as I can to ensure that ScreeenshotOne is the best screenshot API out there possible. But I rarely share updates but trust me, a ton of them might go unnoticed. Let's fix this situation.

Read more →

1 min read

Sep 14, 2022

#### [I migrated to Google Cloud](/changelog/i-migrated-to-google-cloud/)

Google Cloud gives $300 in credits for 3 months for experimenting. And I decided to give it a try, but not because of the free credits.

Read more →

4 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/language-and-locale
----

Set locale and language of the browser

======================================

A new version of the ScreenshotOne API has been just deployed. It allows you to set both locale and language of the browser when rendering screenshots with one simple option.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Oct 15, 2024

In order to set locale and language of the browser, you only need to specify the `Accept-Language` header in the request, like this:

    1https://api.screenshotone.com/take?headers=accept-language:de-DE&url...&access_key=...

The API is smart enough to understand that the `Accept-Language` header is a locale and language header and will set the locale and language of the browser accordingly:

1.  It will send the `Accept-Language` header to the website.

2.  It will set the locale and language of the browser.

All dates, numbers, and currencies will be displayed in the specified locale and language.

If you are curious about how it works under the hood, you can check out [the Puppeteer guide with working examples on how to set the locale and language of the browser](https://puppeteer.guide/posts/language-and-locale/). The solution is based on the same approach.

In case you encounter any issues, or have any questions, please feel free to reach out to us at [support@screenshotone.com](mailto:support@screenshotone.com).

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Trigger screenshot download](/changelog/attachment-name/)

Now you can set attachment filename to trigger screenshot download in the browser.

Read more →

1 min read

#### [Added an Above-the-Fold Checker Tool](/changelog/above-the-fold-checker/)

A new ScreenshotOne tool to capture what users see before the first scroll.

Read more →

1 min read

#### [Detect any website fonts with a ScreenshotOne API](/changelog/detect-any-website-fonts-with-a-screenshotone-api/)

Now you can detect fonts used by any website with ScreenshotOne API in just one simple API call.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/n8n-integration
----

n8n integration for ScreenshotOne

=================================

You can now use ScreenshotOne in n8n workflows to render website screenshots, PDFs, scrolling screenshots and videos.

[Blog post](/blog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jun 26, 2025

As ScreenshotOne customers requested, we have built and published [n8n integration for ScreenshotOne](/docs/no-code/n8n/) 🥳

[](https://www.npmjs.com/package/n8n-nodes-screenshotone)

In a few clicks in n8n, you can:

*   📸 render website screenshots (full page and regular above the fold);

*   📄 PDFs from HTML or URLs;

*   🎬 [scrolling screenshots](/scrolling-screenshots/) and videos;

*   🔥 and more…

All as part of your workflows in your favorite automation platform.

n8n

---

[n8n](https://n8n.io/) is a workflow automation platform that allows you to connect your favorite applications and services to automate your work.

[](https://n8n.io/)

With a simple UI, in a few clicks, you can build your own complex workflows with data passing between nodes (applications/services).

You should also build your own n8n integration

----------------------------------------------

According to Google Trends, n8n has been exploding in popularity recently:

[](https://trends.google.com/trends/explore?q=n8n)

If you have a product that can be used in n8n workflows, you should definitely build your own n8n integration:

1.  It will allow your customers to use your product in their workflows.

2.  It will bring you new customers.

3.  It will help you to build your brand and awareness around it in no-code space.

Support

-------

If you have any questions or need any assistance, please, reach out at `support@screenshotone.com`.

Read more posts

---------------

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

[View all posts](/blog/)

#### [OpenClaw with Playwright or Puppeteer: how to install browser support](/blog/openclaw-playwright-puppeteer/)

A practical guide to OpenClaw browser automation, why Playwright is the documented path, where Puppeteer fits, how to make screenshots, and when ScreenshotOne is the better choice for screenshot-only flows.

Read more

#### [Cloudflare Browser Rendering](/blog/cloudflare-browser-rendering/)

Cloudflare recently launched a new Browser Rendering platform. I decided to dive into it and quickly check if I could use it in ScreenshotOne to provide a faster and better customer experience.

Read more

#### [A Chrome Extension by ScreenshotOne for rendering full-page screenshots](/blog/full-page-chrome-extension/)

We just launched a new full-page screenshot Chrome extension that allows you to take full page screenshots of any websites and annotate them in a few clicks.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/how-to-take-a-screenshot-with-puppeteer
----

How to take screenshots with Puppeteer

======================================

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

[Blog post](/blog/) 11 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Apr 29, 2025

#### Tags

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

Making screenshots of the websites with [Puppeteer](/blog/puppeteer/) is tricky. And I write that as somebody who has been working with Puppeteer for years.

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

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

Meet Puppeteer

--------------

It is a Node library that interacts with browsers that support [Chrome DevTools Protocol (CDP)](https://chromedevtools.github.io/devtools-protocol/). It is not only Chrome and Chromium, but [Firefox also has partial support of CDP](https://firefox-source-docs.mozilla.org/remote/index.html#remote-protocol-cdp).

The Chrome DevTools Protocol was developed to manage, debug and inspect Chromium and Chrome at the low level.

So, think of Puppeteer high-level API over Chrome DevTools Protocol which allows you to do everything in the browser that you can do manually:

1.  Extract data from a SPA, submit a form, type text, perform end-to-end UI testing and other automation-related tasks.

2.  [Debug performance issues](https://developer.chrome.com/docs/devtools/evaluate-performance/reference/).

3.  Run, debug and test Chrome Extensions.

4.  Pre-render SPA to make a static site. But for Google SEO, it does not matter since [Google renders JavaScript for every page](https://developers.google.com/search/docs/advanced/javascript/javascript-seo-basics) nowadays.

5.  And guess what? Make screenshots and PDFs of pages.

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

Lightweight option of Puppeteer

-------------------------------

First of all, there are two versions of the library available: [puppeteer-core](https://www.npmjs.com/package/puppeteer-core) and [puppeteer](https://www.npmjs.com/package/puppeteer-core). You should use puppeteer-core when you are going to manage browser instances by yourself, or you do not need it, otherwise stick to puppeteer.

Three simple examples that come to my mind with puppeteer-core:

1.  You are using CDP from the extension, so you do not have to download Chrome or Chromium.

2.  You want to use a different Chrome, Chromium, or Firefox build.

3.  You have a running cluster of browsers or a separate browser instance on an other machine.

When you use puppeteer-core, you must ensure that you use a compatible browser version. But the puppeteer library downloads and runs a compatible version of Chromium instance for you, without any worries.

Practical Examples of using Puppeteer to take screenshots

---------------------------------------------------------

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

npm i puppeteer

### Simple screenshots with Puppeteer

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

    1"use strict";2

    3const puppeteer = require("puppeteer");4(async () => {5    const browser = await puppeteer.launch();6    try {7        const page = await browser.newPage();8        await page.goto("https://github.com");9        await page.screenshot({ path: "github.png" });10    } catch (e) {11        console.log(e);12    } finally {13        await browser.close();14    }15})();

The result is a screenshot of the GitHub website:

You use the parameter `path` in `Puppeteer` 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 `Puppeteer`.

### High-resolution and Retina Displays

To avoid blurred images on a high-resolution display like [Retina Display](https://en.wikipedia.org/wiki/Retina_display) you can change the viewport properties `width`, `height` and `deviceScaleFactor`:

    1"use strict";2

    3const puppeteer = require("puppeteer");4

    5(async () => {6    const browser = await puppeteer.launch();7

    8    try {9        const page = await browser.newPage();10

    11        await page.setViewport({12            width: 2880, // default: 80013            height: 1800, // default: 60014            deviceScaleFactor: 2, // default: 115        });16

    17        await page.goto("https://apple.com");18        await page.screenshot({ path: "apple.com.png" });19    } catch (e) {20        console.log(e);21    } finally {22        await browser.close();23    }24})();

That’s called pixel-perfect screenshots.

### Full-page screenshots

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

    1"use strict";2

    3const puppeteer = require("puppeteer");4

    5(async () => {6    const browser = await puppeteer.launch();7

    8    try {9        const page = await browser.newPage();10        await page.goto("https://apple.com");11        await page.screenshot({ path: "apple.com.png", fullPage: true });12    } catch (e) {13        console.log(e);14    } finally {15        await browser.close();16    }17})();

But it won’t work good with lazy-loaded images. I wrote a brief guide on [how to take full page screenshots with Puppeteer right](/blog/take-a-full-page-screenshot-with-puppeteer/).

### Wait until the page is completely loaded

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

    1"use strict";2

    3const puppeteer = require("puppeteer");4

    5(async () => {6    const browser = await puppeteer.launch({});7

    8    try {9        const page = await browser.newPage();10

    11        await page.goto("https://apple.com/", {12            waitUntil: "networkidle2",13        });14

    15        await page.screenshot({ path: "apple.com.png" });16    } catch (e) {17        console.log(e);18    } finally {19        await browser.close();20    }21})();

It is a little bit of magic, but `networkidle2` event is heuristic to determine page load state. It [works quite well for many real-world use cases](/blog/puppeteer-wait-until-the-page-is-ready/).

But if you need to wait until some element is rendered and visible, you need to add [Page.waitForSelector()](https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#pagewaitforselectorselector-options):

    1"use strict";2

    3const puppeteer = require("puppeteer");4

    5(async () => {6    const browser = await puppeteer.launch({});7

    8    try {9        const page = await browser.newPage();10

    11        await page.goto("https://example.com/", {12            waitUntil: "networkidle0",13        });14

    15        const selector = "div";16        await page.waitForSelector(selector, {17            visible: true,18        });19

    20        await page.screenshot({ path: "example.com.png" });21    } catch (e) {22        console.log(e);23    } finally {24        await browser.close();25    }26})();

You can also wait:

*   [for selector or function or timeout](https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#pagewaitforselectororfunctionortimeout-options-args);

*   [for file chooser](https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#pagewaitforfilechooseroptions);

*   [for frame](https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#pagewaitforframeurlorpredicate-options);

*   [for function](https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#pagewaitforfunctionpagefunction-options-args);

*   [for navigation](https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#pagewaitfornavigationoptions);

*   [for network idle](https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#pagewaitfornetworkidleoptions);

*   [for request](https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#pagewaitforrequesturlorpredicate-options);

*   [for response](https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#pagewaitforresponseurlorpredicate-options);

*   [for selector](https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#pagewaitforselectorselector-options);

*   [for timeout](https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#pagewaitfortimeoutmilliseconds);

*   and [for XPath](https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#pagewaitforxpathxpath-options).

### How to take a screenshot of the page area

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

    1"use strict";2

    3const puppeteer = require("puppeteer");4

    5(async () => {6    const browser = await puppeteer.launch();7

    8    try {9        const page = await browser.newPage();10        await page.goto("https://apple.com");11        await page.screenshot({12            path: "apple.com.png",13            clip: {14                x: 100,15                y: 100,16                width: 800,17                height: 800,18            },19        });20    } catch (e) {21        console.log(e);22    } finally {23        await browser.close();24    }25})();

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

### A screenshot of the specific element

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

    1"use strict";2

    3const puppeteer = require("puppeteer");4

    5(async () => {6    const browser = await puppeteer.launch();7

    8    try {9        const page = await browser.newPage();10        await page.goto("https://example.com");11

    12        const selector = "body > div:first-child";13        await page.waitForSelector(selector);14        const element = await page.$(selector);15

    16        await element.screenshot({17            path: "example.com.png",18        });19    } catch (e) {20        console.log(e);21    } finally {22        await browser.close();23    }24})();

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](/docs/options/#selector).

### Screenshots with transparent background

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

    1"use strict";2

    3const puppeteer = require("puppeteer");4

    5(async () => {6    const browser = await puppeteer.launch();7

    8    try {9        const page = await browser.newPage();10        await page.goto("https://example.com");11

    12        await page.screenshot({13            path: "example.com.png",14            omitBackground: true,15        });16    } catch (e) {17        console.log(e);18    } finally {19        await browser.close();20    }21})();

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:

    1"use strict";2

    3const puppeteer = require("puppeteer");4

    5(async () => {6    const browser = await puppeteer.launch();7

    8    try {9        const page = await browser.newPage();10        await page.goto("https://example.com");11

    12        await page.evaluate(() => {13            document.body.style.background = "transparent";14        });15

    16        await page.screenshot({17            path: "example.com.png",18            omitBackground: true,19        });20    } catch (e) {21        console.log(e);22    } finally {23        await browser.close();24    }25})();

### Screenshot as Base64

I also wrote about [rendering PNG, JPEG, and WebP in Base64 encoding with Puppeetter](/blog/taking-screenshots-with-puppeteer-in-gif-jp2-tiff-avif-heif-or-svg-format#base64).

You build Puppeteer as a service and do not want to store screenshot files. You can choose to return the screenshot in [Base64](https://en.wikipedia.org/wiki/Base64) encoding format:

    1"use strict";2

    3const puppeteer = require("puppeteer");4

    5(async () => {6    const browser = await puppeteer.launch({});7

    8    try {9        const page = await browser.newPage();10        await page.goto("https://example.com/");11

    12        const base64 = await page.screenshot({ encoding: "base64" });13        console.log(base64);14    } catch (e) {15        console.log(e);16    } finally {17        await browser.close();18    }19})();

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:

    1"use strict";2

    3const puppeteer = require("puppeteer");4(async () => {5    const browser = await puppeteer.launch();6    try {7        const page = await browser.newPage();8        await page.goto("https://example.com");9        await page.screenshot({10            path: "example.jpg",11            type: "jpeg",12            quality: 100,13        });14    } catch (e) {15        console.log(e);16    } finally {17        await browser.close();18    }19})();

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 Puppeetter](/blog/taking-screenshots-with-puppeteer-in-gif-jp2-tiff-avif-heif-or-svg-format).

### Blocking ads and trackers when using Puppeteer

In our [screenshot API](/), you can block ads by setting [blockAds=true](/docs/options/#block_ads).

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 `puppeteer-extra` and `puppeteer-extra-plugin-adblocker` in addition to `puppeteer` package:

npm i puppeteer-extra puppeteer-extra-plugin-adblocker

And then use it:

    1"use strict";2

    3const puppeteer = require("puppeteer-extra");4

    5const AdblockerPlugin = require("puppeteer-extra-plugin-adblocker");6puppeteer.use(AdblockerPlugin());7

    8(async () => {9    const browser = await puppeteer.launch();10

    11    try {12        const page = await browser.newPage(); // ads are blocked automatically13

    14        await page.goto("https://www.example.com");15

    16        await page.screenshot({17            path: "example.com.png",18            fullPage: true,19        });20    } catch (e) {21        console.log(e);22    } finally {23        await browser.close();24    }25})();

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:

    1puppeteer.use(2    AdblockerPlugin({3        blockTrackers: true, // default: false4    })5);

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

### Preventing Puppeteer detection

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

    1"use strict";2

    3const puppeteer = require("puppeteer");4

    5(async () => {6    const options = {7        args: [8            '--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"',9        ],10        headless: true,11    };12

    13    const browser = await puppeteer.launch(options);14    try {15        const page = await browser.newPage();16        await page.goto("https://www.example.com");17

    18        await page.screenshot({19            path: "example.com.png",20            fullPage: true,21        });22    } catch (e) {23        console.log(e);24    } finally {25        await browser.close();26    }27})();

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

npm i puppeteer-extra puppeteer-extra-plugin-stealth

And then use:

    1"use strict";2

    3const puppeteer = require("puppeteer-extra");4

    5const StealthPlugin = require("puppeteer-extra-plugin-stealth");6puppeteer.use(StealthPlugin());7

    8(async () => {9    const browser = await puppeteer.launch();10

    11    try {12        const page = await browser.newPage();13        await page.evaluateOnNewDocument(() => {14            const newProto = navigator.__proto__;15            delete newProto.webdriver;16            navigator.__proto__ = newProto;17        });18

    19        await page.goto("https://bot.sannysoft.com");20        await page.waitForTimeout(5000);21        await page.screenshot({ path: "stealth.png", fullPage: true });22    } catch (e) {23        console.log(e);24    } finally {25        await browser.close();26    }27})();

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

### Using basic access authentication with Puppeteer

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:

    1"use strict";2

    3const puppeteer = require("puppeteer");4

    5(async () => {6    const browser = await puppeteer.launch();7

    8    try {9        const page = await browser.newPage();10

    11        await page.authenticate({12            username: "YOUR_BASIC_AUTH_USERNAME",13            password: "YOUR_BASIC_AUTH_PASSWORD",14        });15

    16        await page.goto("https://example.com");17        await page.screenshot({ path: "example.png" });18    } catch (e) {19        console.log(e);20    } finally {21        await browser.close();22    }23})();

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

Our [screenshot API](/) supports emojis out of the box.

If you run Puppeteer 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 Puppeteer to render emojis, you can use [Noto Fonts](https://github.com/googlefonts/noto-fonts) published under [SIL Open Font License (OFL) v1.1](http://scripts.sil.org/OFL).

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

More recipes on using Puppeteer

-------------------------------

You also might find useful:

*   [How to generate PDFs with Puppeteer](/blog/how-to-generate-pdf-with-puppeteer/).

*   [How to block cookie banners, GDPR overlay windows and other privacy-related notices when taking a screenshot with Puppeteer](/blog/how-to-hide-cookie-banners-when-taking-a-screenshot-with-puppeteer/).

*   [How to use proxy with Puppeteer](https://puppeteer.guide/posts/proxies/).

*   [How to handle navigation errors in Puppeteer](https://puppeteer.guide/posts/handling-navigation-errors/).

*   [How to use proxy per page with Puppeteer](/blog/how-to-use-proxy-per-page-with-puppeteer/).

*   [How to add custom scripts to a page in Puppeteer](/blog/how-to-add-custom-scripts-to-a-page-in-puppeteer/).

*   [How to add custom styles to a page in Puppeteer](/blog/how-to-add-custom-styles-to-a-page-in-puppeteer/).

*   [How to configure language and locale in Puppeteer](/blog/how-to-set-language-and-locale-in-puppeteer/).

*   [How to render HTML with Puppeteer](/blog/how-to-render-html-with-puppeteer).

*   [How to upload screenshots to any S3-compatible storage](/blog/uploading-website-screenshots-to-any-S3-compatible-storage/).

Puppeteer Alternatives

----------------------

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

1.  The oldest alternative to make screenshots is using the [Selenium WebDriver](https://www.selenium.dev/documentation/webdriver/browser/windows/#takescreenshot) protocol.

2.  The second one is [to render screenshots with Playwright](/blog/how-to-render-screenshots-with-playwright/), and it is a good one. It is the competitor to the Puppeteer.

3.  If you consider only rendering screenshots, [ScreenshotOne is the best Puppeteer alternative](/comparisons/puppeteer-alternative-for-screenshots).

Playwright and Puppeteer 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. But the library is still considered new.

Conclusion

----------

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

As you see you can go really far with Puppeteer. But if only need to take screenshots, consider using one of the best [Puppeteer alternatives](/comparisons/puppeteer-alternative-for-screenshots)—[our screenshot API](/).

Thank you for reading! And have a nice day 👋

Read more Puppeteer guides

--------------------------

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

[View all posts](/blog/tags/puppeteer-guides/)

#### [Puppeteer Performance Monitoring with Inspector](/blog/puppeteer-performance-monitoring-with-inspector/)

In this article I'll show you how to monitor performance and errors of a browser automation script written with Puppeteer.

Read more

#### [Capture beyond viewport in Puppeteer and Chrome DevTools Protocol](/blog/capture-beyond-viewport-in-puppeteer-and-chrome-devtools-protocol/)

Let's talk about the captureBeyondViewport parameter introduced in Chrome DevTools Protocol which will soon be supported by Puppeteer or even supported now at the time when you are reading the post.

Read more

#### [Taking screenshots with Puppeteer in GIF, JP2, TIFF, AVIF, HEIF, or SVG format](/blog/taking-screenshots-with-puppeteer-in-gif-jp2-tiff-avif-heif-or-svg-format/)

Puppeteer, by default, supports only four formats for taking screenshots or rendering HTML: PNG, JPEG, WebP, and PDF. But what if you want it to take it in a different format like GIF, JP2, TIFF, AVIF, HEIF, or SVG?

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/integrations/pipedream
----

Integrations

1 min read

Pipedream

=========

Automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos in Pipedream.

No-Code Automation

Resources

---------

*   [ScreenshotOne on Pipedream](https://pipedream.com/apps/screenshotone/integrations)

Shout out to ScreenshotOne (by Dmytro Krasun) for being one of those services that just quietly runs in the background doing the thing you want it to do perfectly!

Been using it to generate screenshots for lead demo sites when I'm not able to embed the site in an iframe (which you shouldn't let your site allow btw). Works so well.

Herman Schutte

Founder, [SiteSpeakAI](https://sitespeak.ai)

Check more Integrations

-----------------------

No-code tools, AI, code libraries, and more.

[Check more Integrations](/integrations/)

No-Code Automation

### Clay

Generate website screenshots inside Clay to qualify leads, assess content, and enrich rows with visual context automatically.

[Read more →](/integrations/clay/)

Code API

### SDK and Code Examples

Use the SDKs and code examples to take screenshots in your own code.

[Read more →](/integrations/code/)

No-Code Automation

### Zapier

Automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos in Zapier.

[Read more →](/integrations/zapier/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/ravenala
----

ScreenshotOne is available on Ravenala

======================================

ScreenshotOne is available on Ravenala, a new AI-powered platform for creating and managing content.

[Blog post](/blog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Aug 3, 2025

[](https://ravenala.ai/)

Ravenala

--------

ScreenshotOne is now available on [Ravenala](https://ravenala.ai/), a AI platform that help you with a wide range of tasks and questions:

1.  Answer questions: provide facts, explain concepts, or give detailed information on many topics (science, history, language, etc.).

2.  Weather updates: give you current or forecasted weather for any location.

3.  Writing and content creation: help you write articles, emails, stories, or even generate code.

4.  Travel and local info: offer recommendations, directions, and local insights for various cities.

5.  Productivity tools: help you create to-do lists, plan schedules, or manage documents.

6.  Learning and study help: assist with explanations, summaries, and practice questions.

7.  And more…

ScreenshotOne on Ravenala

-------------------------

Ravenala has [a marketplace of apps](https://www.ravenala.ai/apps/marketplace) that can be used in their chat, and ScreenshotOne is one of them. It allows you to take screenshots of any website and analyze them, integrate them into your content or just screenshot websites as part of your flows.

Read more posts

---------------

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

[View all posts](/blog/)

#### [Optimize for speed when rendering screenshots in Puppeteer and Chrome DevTools Protocol](/blog/optimize-for-speed-when-rendering-screenshots-in-puppeteer-and-chrome-devtools-protocol/)

Let's talk about the optimizeForSpeed parameter introduced in Chrome DevTools Protocol which will soon be supported by Puppeteer or even supported now at the time when you are reading the post.

Read more

#### [ScreenshotOne reached $200K ARR with 400+ paying customers](/blog/200000-arr-and-400-paying-customers/)

It is a good milestone to make a compact snapshot of the insights that (maybe?) led to it.

Read more

#### [A Chrome Extension by ScreenshotOne for rendering full-page screenshots](/blog/full-page-chrome-extension/)

We just launched a new full-page screenshot Chrome extension that allows you to take full page screenshots of any websites and annotate them in a few clicks.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/contributors/sergey-karakhanyan
----

Sergey Karakhanyan

------------------

View all Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [Automating screenshots for directory websites with ScreenshotOne](/blog/directify-feedback/)

How and why "Directify" used ScreenshotOne to automate screenshots for directory websites.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Sergey Karakhanyan](/contributors/sergey-karakhanyan/)

Published on

Dec 15, 2024

•

2 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/scrolling-screenshots
----

[What's new API error insights API error insights in the dashboard](/changelog/error-metrics/)

Generate Scrolling Screenshots via API

======================================

Render scrollable screenshots with ScreenshotOne in one simple API call, be it GIF animation or MP4 video.

[Start rendering for free →](https://dash.screenshotone.com/sign-up)

No credit card required.

 Sorry, your browser doesn't support embedded videos.

https://api.screenshotone.com/animate? scenario=scroll&url=https://tailwindcss.com

"Great support."

**Guillaume Barillot,** CTO at Deepidoo

"Great company, great founder!"

**Mike Roberts,** Founder at SpyFu

"ScreenshotOne is the way to go."

**Lukas Hermann,** Co-Founder of Stagetimer

Looks great

Take clean screenshots

----------------------

----------------------------

------------------------------------

-------------------------

Send simple HTTP requests or use native libraries for your language of choice.

Java Go Node.js PHP Python Ruby C# (.NET)

    1// add com.screenshotone.jsdk:screenshotone-api-jsdk:[1.0.0,2.0.0)2// to your `pom.xml` or `build.gradle`3

    4import com.screenshotone.jsdk.Client;5import com.screenshotone.jsdk.TakeOptions;6

    7import java.io.File;8import java.nio.file.Files;9

    10public class App {11    public static void main(String[] args) throws Exception {12        final Client client = Client.withKeys("<access key>", "<secret key>");13        TakeOptions takeOptions = TakeOptions.url("https://example.com")14                .fullPage(true)15                .deviceScaleFactor(1)16                .viewportHeight(1200)17                .viewportWidth(1200)18                .format("png")19                .omitBackground(true);20        final String url = client.generateTakeUrl(takeOptions);21

    22        System.out.println(url);23        // Output: https://api.screenshotone.com/take?url=...24

    25        // or download the screenshot26        final byte[] image = client.take(takeOptions);27

    28        Files.write(new File("./example.png").toPath(), image);29        // the screenshot is stored in the example.png file30    }31}

    1// go get github.com/screenshotone/gosdk2

    3import screenshots "github.com/screenshotone/gosdk"4

    5client, err := screenshots.NewClient("<access key>", "<secret key>")6// check err7

    8options := screenshots.NewTakeOptions("https://example.com").9    Format("png").10    FullPage(true).11    DeviceScaleFactor(2).12    BlockAds(true).13    BlockTrackers(true)14

    15u, err := client.GenerateTakeURL(options)16// check err17

    18fmt.Println(u.String())19// Output: https://api.screenshotone.com/take?url=...20

    21// or download the screenshot22image, err := client.Take(context.TODO(), options)23// check err24

    25defer image.Close()26out, err := os.Create("example.png")27// check err28

    29defer out.Close()30io.Copy(out, image)31// the screenshot is stored in the example.png file

    1// $ npm install screenshotone-api-sdk --save2

    3import * as fs from 'fs';4import * as screenshotone from 'screenshotone-api-sdk';5

    6// create API client7const client = new screenshotone.Client("<access key>", "<secret key>");8

    9// set up options10const options = screenshotone.TakeOptions11    .url("https://example.com")12    .delay(3)13    .blockAds(true);14

    15// generate URL16const url = client.generateTakeURL(options);17console.log(url);18// expected output: https://api.screenshotone.com/take?url=...19

    20// or download the screenshot21const imageBlob = await client.take(options);22const buffer = Buffer.from(await imageBlob.arrayBuffer());23fs.writeFileSync("example.png", buffer)24// the screenshot is stored in the example.png file

    1<?php2

    3// composer require screenshotone/sdk:^1.04

    5use ScreenshotOneSdkClient;6use ScreenshotOneSdkTakeOptions;7

    8$client = new Client("<access key>", "<secret key>");9

    10$options = TakeOptions::url("https://example.com")11    ->fullPage(true)12    ->delay(2)13    ->geolocationLatitude(48.857648)14    ->geolocationLongitude(2.294677)15    ->geolocationAccuracy(50);16

    17$url = $client->generateTakeUrl($options);18echo $url.PHP_EOL;19// expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com...20

    21$image = $client->take($options);22file_put_contents('example.png', $image);23// the screenshot is stored in the example.png file

    1# pip install screenshotone2

    3import shutil4from screenshotone import Client, TakeOptions5

    6# create API client7client = Client('<access key>', '<secret key>')8

    9# set up options10options = (TakeOptions.url('https://screenshotone.com')11    .format("png")12    .viewport_width(1024)13    .viewport_height(768)14    .block_cookie_banners(True)15    .block_chats(True))16

    17# generate the screenshot URL and share it with a user18url = client.generate_take_url(options)19# expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fscreenshotone.com&viewport_width=1024&viewport_height=768&block_cookie_banners=True&block_chats=True&access_key=&signature=6afc9417a523788580fa01a9f668ea82c78a9d2b41441d2a696010bf2743170f20

    21# or render a screenshot and download the image as stream22image = client.take(options)23

    24# store the screenshot the example.png file25with open('example.png', 'wb') as result_file:26    shutil.copyfileobj(image, result_file)

    1# Add this gem to your Gemfile:2# gem 'screenshotone'3

    4# If you don't need to add a signature5client = ScreenshotOne::Client.new('<access key>')6

    7# Or ff you do need to add a signature8client = ScreenshotOne::Client.new('<access key>', '<secret key>')9

    10# You can set any available option, in a camel_case format, for example:11options = ScreenshotOne::TakeOptions.new(url: 'https://example.com').12            full_page(true).13            delay(2).14            geolocation_latitude(48.857648).15            geolocation_longitude(2.294677).16            geolocation_accuracy(50)17

    18# Verify all the parameters are valid (we will validate the parameters that should be19# numeric, booleans or that accept only certain values)20options.valid?21=> true22

    23# To simply get the final url:24client.generate_take_url(options)25=> "https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com..."26

    27# To actually get the image (the response body of a request to the previous url)28client.take(options)29=> "\xFF\xD8\xFF\xE0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xFF\..."

    1// Add the library via nuget using the package manager console: PM> Install-Package ScreenshotOne.dotnetsdk2// Or from the .NET CLI as: dotnet add package ScreenshotOne.dotnetsdk3

    4// And generate a screenshot URL without executing request:5var client = new Client("<access key>", "<secret key>");6var options = TakeOptions.Url("https://www.amazon.com")7  .FullPage(true)8  .Format(Format.PNG)9  .BlockCookieBanners(true);10

    11var url = client.GenerateTakeUrl(options);12// url = https://api.screenshotone.com/take?url=https%3A%2F%2Fwww.amazon.com&full_page=true&format=png&block_cookie_banners=true&access_key=_OzqMIjpCw-ARQ&signature=8a08e62d13a5c3490fda0734b6707791d3decc9ab9ba41e8cc045288a39db50213

    14// Or take a screenshot and save the image in the file:15var client = new Client("<access key>", "<secret key>");16var options = TakeOptions.Url("https://www.google.com")17  .FullPage(true)18  .Format(Format.PNG)19  .BlockCookieBanners(true);20

    21var bytes = await client.Take(options);22

    23File.WriteAllBytes(@"c:\temp\example.png", bytes);

Mike Roberts

Founder, [SpyFu](https://www.spyfu.com/)

> ScreenshotOne is the best product on the market - and that's before you take into account how responsive and easy Dmytro is to work with.

> 

> Any time we've found a rare edge case, it's been resolved in hours.

> 

> Great company, great founder - can't say enough!

Without writing a line of code

No-code Scrolling Screenshots

-----------------------------

Quickly render scrollable website screenshots with Zapier, Airtable, Make and other popular no-code platforms of your choice.

[](/integrations/zapier/)[](/integrations/airtable/)[](/integrations/make/)[](/integrations/bubble/)[](/integrations/n8n/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/15
----

Automate Website Screenshots

----------------------------

Guides, Product Updates, and Helpful Resources from ScreenshotOne.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

#### [How to set a time zone in Puppeteer for page](/blog/how-to-set-a-time-zone-in-puppeteer-for-page/)

Puppeteer allows changing the time zone on a per-page basis. In automation testing, you can use it to test how the website behaves for different time zones. Or you can use it for scrapping to imitate the user from the expected time zone by the site.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jun 23, 2022

•

1 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [How to block requests with Puppeteer](/blog/how-to-block-requests-with-puppeteer/)

Puppeteer allows blocking any outgoing requests while loading the page. Whether you want to block ads, tracking scripts, or different types of resources, it is relatively easy to do with Puppeteer.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jul 14, 2022

•

3 min read

#### [How to take a screenshot of the element with Puppeteer](/blog/how-to-take-a-screenshot-of-the-element-with-puppeteer/)

Puppeteer allows you to automate everything you can do in the browser manually and even more. You can take screenshots of the entire page and the specific elements.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jun 18, 2022

•

1 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [How to use proxy per page with Puppeteer](/blog/how-to-use-proxy-per-page-with-puppeteer/)

It is easy to use proxy globally for the puppeteer instance, but there is a trick to use proxy on a per-page basis.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Apr 29, 2025

•

2 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take screenshots with Puppeteer](/blog/how-to-take-a-screenshot-with-puppeteer/)

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

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Apr 29, 2025

•

11 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/11
----

Changes and updates

-------------------

Stay updated with the latest information about new features, bug fixes, and optimizations at ScreenshotOne

### Product updates in the last 12 months

Feb 11, 2024

#### [ScreenshotOne moves to a different affiliate program provider](/changelog/screenshotone-moves-to-a-different-affiliate-program-provider/)

I am really sorry but we moved our affiliate program to Tolt because Reflio is not in active maintenance anymore—it is a forced move.

Read more →

1 min read

Feb 2, 2024

#### [Better and more extensible PDF rendering](/changelog/better-and-more-extensible-pdf-rendering/)

ScreenshotOne supports PDF rendering for a long time but it was used till recently by a small group of customers. Growing demand in PDF rendering required updating the API. And today, we introduce new options for PDF customization.

Read more →

1 min read

Dec 23, 2023

#### [The new ScreenshotOne dashboard is out](/changelog/the-new-screenshotone-dashboard-is-out/)

It is a long-term move and rebuilding the ScreenshotOne dashboard was a decision to continue improving customer experience. The previous version of the dashboard was outdated and didn't serve new arising customer needs well.

Read more →

1 min read

Dec 8, 2023

#### [ScreenshotOne can now return screenshots and HTML in one request](/changelog/screenshotone-can-now-return-screenshots-and-html-in-one-request/)

Starting from today ScreenshotOne can return both a website screenshot and the content in one simple API request.

Read more →

1 min read

Nov 26, 2023

#### [Detect any website fonts with a ScreenshotOne API](/changelog/detect-any-website-fonts-with-a-screenshotone-api/)

Now you can detect fonts used by any website with ScreenshotOne API in just one simple API call.

Read more →

1 min read

Nov 25, 2023

#### [Support of the OpenAI GPT Vision API in ScreenshotOne](/changelog/support-of-the-openai-gpt-vision-api-in-screenshotone/)

From today, you can use our screenshot API together with the OpenAI Vision API. It allows you to send screenshots directly to the Vision API without building all the infrastructure yourself.

Read more →

2 min read

Nov 21, 2023

#### [ScreenshotOne API supports GPU Rendering](/changelog/screenshotone-api-supports-gpu-rendering/)

From today ScreenshotOne supports GPU rendering for both regular and animated website screenshots. The API now leverages the latest in graphics processing technology to bring your screenshot needs to a whole new level.

Read more →

2 min read

Jul 30, 2023

#### [Improving performance and stability by consolidating validation and access check logic in the API gateway](/changelog/improving-performance-and-stability-by-consolidating-validation-and-access-check-logic-in-the-api-gateway/)

For the past few days, I have been working on improving the stability and performance of the ScreenshotOne API. I started from low-hanging fruits—moving validations and access key management from rendering services to ScreenshotOne's API gateway. The API will be more stable and performant as a result. If you are curious why, please continue reading.

Read more →

2 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/3
----

Automate Website Screenshots

----------------------------

Guides, Product Updates, and Helpful Resources from ScreenshotOne.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

[Desktop screen capture](/blog/tags/desktop-screen-capture/)

#### [How to Take Screenshots with PyAutoGUI in Python](/blog/pyautogui-python-screenshots/)

Complete guide to taking screenshots with PyAutoGUI in Python. Learn screenshot(), region parameters, locateOnScreen(), and common errors with ImageNotFoundException.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 13, 2026

•

3 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to Take Screenshots with pyppeteer in Python](/blog/pyppeteer-python-screenshots/)

Guide to taking screenshots with pyppeteer in Python. Learn the basics, full page captures, and why you should migrate to Playwright.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jan 19, 2026

•

2 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Website Screenshots with Selenium in Python](/blog/selenium-python-screenshots/)

Complete guide to taking screenshots with Selenium in Python. Learn save\_screenshot(), element screenshots, full page workarounds, and headless mode setup.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 11, 2026

•

5 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take bulk screenshots with Puppeteer](/blog/bulk-screenshots-with-puppeteer/)

Learn how to take screenshots of multiple URLs with Puppeteer, including concurrency management, error handling, retries, and proxy support.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Dec 16, 2025

•

8 min read

#### [ScreenshotOne November 2025 updates](/blog/screenshotone-november-2025-updates/)

Error metrics in the dashboard, Postman Public API Network, and Landing Gallery customer story.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Dec 2, 2025

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [ScreenshotOne took away one major complexity off the Supawrite plate](/blog/supawrite/)

A short story about how ScreenshotOne helps a content marketing platform automate their screenshot workflow.

Written by

[Daniel Kempe](/contributors/daniel-kempe/)

Published on

Dec 2, 2025

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Landing Gallery uses ScreenshotOne to automate screenshot generation](/blog/landing-gallery/)

How and why "Landing Gallery" uses ScreenshotOne to automate screenshot generation for their landing page inspiration platform.

Written by

[Chris Jayden](/contributors/chris-jayden/)

Published on

Nov 30, 2025

•

3 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How RankPill uses ScreenshotOne](/blog/rankpill/)

Sharing how RankPill uses ScreenshotOne to automate website screenshot generation for SEO and GEO automation.

Written by

[Modest Mitkus](/contributors/modest-mitkus/), [Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Nov 6, 2025

•

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/signed-requests
----

[Skip to content](#_top)

Signed Links

============

Copy page

When you share links to the screenshots with your access key in public, there is a problem that everybody can take your API access key and reuse it to take screenshots on their own and exhaust your screenshot quota.

To prevent others from using your API key, you need to:

1.  [Sign every request](https://screenshotone.com/docs/signed-requests/#signing-requests) you are going to share publicly.

2.  [Require signing](https://screenshotone.com/docs/signed-requests/#require-signing) for every request.

Then even if the potential unscrupulous person sees or steals your access key, they can’t reuse it until they also steal your secret key (signing key).

You generally don’t need to sign requests if you will not share screenshot links publicly and will use screenshot API only on the server-side.

Signing requests

----------------

Singed links do not work with HTTP “POST” requests. The feature is intended to be used for sharing links in public.

To sign the request, like `https://api.screenshotone.com/take?access_key=0Ij4LFMtFnGUrA&url=https://apple.com`, you need to follow the simple algorithm:

1.  Use your secret to hash the query string `access_key=0Ij4LFMtFnGUrA&url=https://apple.com` with the HMAC SHA256 algorithm.

2.  **Append** the signature parameter with the hash: `https://api.screenshotone.com/?access_key=0Ij4LFMtFnGUrA&url=https://apple.com&signature=70bea3e52efc43834129ecbea236f38bf9bb4a7cd7c2e1951017435defd4dbaf`.

**Do not sort the parameters. Or if you sort them, send them sorted, too.**

To hash the query string with your secret key and HMAC SHA256 algorithm in the CLI, you can run the following command:

Terminal window

    1$ echo -n "access_key=0Ij4LFMtFnGUrA&url=https://apple.com" | openssl sha256 -hmac "m9ajW9br9hTw2A"                     130 ↵2

    370bea3e52efc43834129ecbea236f38bf9bb4a7cd7c2e1951017435defd4dbaf

Code examples

-------------

You can need to apply the same algorithm in the language of your choice.

### Python

For example, in Python:

    1import urllib.parse2import hmac3import hashlib4

    5def generate_signature(params: dict, secret_key: str) -> str:6    """7    Generate a signature for the given parameters using HMAC-SHA256.8

    9    Args:10        params (dict): Dictionary of parameters to sign11        secret_key (str): Secret key used for signing12

    13    Returns:14        str: The hexadecimal signature15    """16    # convert parameters to URL-encoded query string17    query_string = urllib.parse.urlencode(params, doseq=True)18

    19    signature = hmac.new(20        bytes(secret_key, "utf-8"),21        msg=bytes(query_string, "utf-8"),22        digestmod=hashlib.sha256,23    ).hexdigest()24

    25    return signature26

    27# Example usage28if __name__ == "__main__":29    # options30    params = {31        "access_key": "your_access_key",32        "url": "https://example.com",33        "format": "jpeg",34        "viewport_width": 1920,35        "viewport_height": 108036    }37

    38    secret_key = "your_secret_key"39

    40    # generate signature41    signature = generate_signature(params, secret_key)42

    43    print("Parameters:", params)44    print("Query string:", urllib.parse.urlencode(params, doseq=True))45    print("Signature:", signature)46

    47    query_string = urllib.parse.urlencode(params, doseq=True)48    final_url = f"https://api.screenshotone.com/take?{query_string}&signature={signature}"49    print("\nAPI URL:", final_url)

### JavaScript

Or in JavaScript:

    1// npm install @peculiar/webcrypto2import { Crypto } from "@peculiar/webcrypto";3

    4const encoder = new TextEncoder();5

    6export async function signQueryString(queryString: string, secretKey: string) {7    const webCrypto =8        typeof globalThis.crypto !== "undefined"9            ? globalThis.crypto10            : new Crypto();11

    12    let algorithm = { name: "HMAC", hash: "SHA-256" };13    let key = await webCrypto.subtle.importKey(14        "raw",15        encoder.encode(secretKey),16        algorithm,17        false,18        ["sign", "verify"]19    );20    const digest = await webCrypto.subtle.sign(21        algorithm.name,22        key,23        encoder.encode(queryString)24    );25

    26    const signature = Array.from(new Uint8Array(digest))27        .map((b) => b.toString(16).padStart(2, "0"))28        .join("");29

    30    return signature;31}32

    33// example usage34const query = new URLSearchParams({35    access_key: "your_access_key",36    url: "https://example.com"37});38let queryString = query.toString();39

    40const signature = await signQueryString(queryString, "your_secret_key");41queryString += "&signature=" + signature;42

    43console.log(queryString);

Require signing

---------------

After you start signing requests and make sure that the API accepts your requests, you can require signing every request. Go to [the access configuration page](https://dash.screenshotone.com/access) and enforce signing every request. The change will be applied immediately, but cached screenshots might not be impacted. That’s it. After this step, unsigned requests with your API access key are not accepted.

Animated screenshots

--------------------

[Animated screenshots](/docs/animated-screenshots/) also support signed links. There is no difference in the underlying mechanism besides that the URL prefix should be `/animate`.

----
url: https://screenshotone.com/use-cases/font-marketplace-enhancement
----

Automate Website Screenshots

1 min read

Better Font Marketplaces

========================

Show how fonts look on live websites to improve conversion rates.

Use [ScreenshotOne font detection API](/font-detection-api/) to integrate into font libraries or marketplaces to show how different fonts look on live websites, giving customers a real-time preview and enhancing their purchasing experience.

Showcase fonts on live websites

-------------------------------

For that ask users to submit their websites, crawl them and then use the font detection API to verify the fonts from your marketplace.

And once verified, you can share these examples with your customers to try to improve conversion rates.

Check out [our guide on how to detect website fonts](/docs/guides/how-to-detect-website-fonts/) for more details.

Competitive Advantage

---------------------

Font marketplaces that offer this capability stand out from competitors by providing a unique value proposition. Rather than building complex web scraping and font detection systems, marketplaces can integrate ScreenshotOne API to deliver this feature quickly and reliably, focusing their resources on curating and selling fonts.

I’ve been using ScreenshotOne for 3 years and couldn’t run Saaspo without it.

You can tell Dmytro really cares about the product as it keeps getting better.

Highly recommend to anyone looking for a screenshot tool!

Andy Hooke

Founder, [Saaspo](https://screenshotone.com/blog/saaspo/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/puppeteer
----

What is Puppeteer

=================

What is Puppeteer and what you can use it for.

[Blog post](/blog/) 4 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

May 6, 2024

#### Tags

[Puppeteer guides](/blog/tags/puppeteer-guides/)

[Puppeteer](https://pptr.dev) is a Node.js library that provides a high-level API to control Chrome or Chromium browsers.

It allows developers to automate browser actions, such as navigating to web pages, interacting with elements, taking screenshots, and generating PDFs.

Puppeteer runs the browser in headless mode by default, which means the browser runs in the background without a visible user interface. However, it can also be configured to run in “headful” mode, where the browser window is visible. Puppeteer’s API makes it easy to write end-to-end tests, scrape websites, generate screenshots and PDFs, and more.

It is a powerful tool for automating browser-based tasks and is widely used in the web development community.

Puppeteer Use Cases

-------------------

There is a lot of use cases supported by Puppeteer.

### Web Scraping

Puppeteer can be used to extract data from websites by programmatically navigating through them, which is particularly useful for websites that require JavaScript rendering.

For example:

    1import puppeteer from "puppeteer";2

    3(async () => {4    const browser = await puppeteer.launch();5    const page = await browser.newPage();6

    7    await page.goto("https://developer.chrome.com/");8

    9    await page.setViewport({ width: 1080, height: 1024 });10

    11    await page.type(".devsite-search-field", "automate beyond recorder");12

    13    const searchResultSelector = ".devsite-result-item-link";14    await page.waitForSelector(searchResultSelector);15    await page.click(searchResultSelector);16

    17    const textSelector = await page.waitForSelector(18        "text/Customize and automate"19    );20    const fullTitle = await textSelector?.evaluate((el) => el.textContent);21

    22    console.log('The title of this blog post is "%s".', fullTitle);23

    24    await browser.close();25})();

### Automated Testing

It is commonly used to automate testing of web applications, including end-to-end testing and performance testing. It can simulate user interactions like clicking, scrolling, form submissions, and more.

### Generating Screenshots and PDFs

Puppeteer can capture screenshots of web pages or generate PDF files from them, useful for creating reports, archiving snapshots, or generating receipts and invoices dynamically.

It is that simple:

    1const browser = await puppeteer.launch();2const page = await browser.newPage();3await page.goto("https://news.ycombinator.com", {4    waitUntil: "networkidle2",5});6await page.screenshot({7    path: "hn.pdf",8});9

    10await browser.close();

If you need more, you can always check out [the best screenshot APIs](https://screenshotone.com/blog/best-screenshot-apis-2024/).

### Rendering Pre-Rendered Content for SEO

Since JavaScript-heavy apps might not be fully crawlable by search engines, Puppeteer can be used to render these applications on the server-side, thus making them SEO-friendly.

### Automating Form Submissions

Puppeteer can fill and submit forms, which is useful for testing or for automating the entry of data into systems through their web interfaces.

### Performance Monitoring

You can use Puppeteer to monitor the performance of web pages, measure loading times, and track other performance metrics.

[](https://pagespeed.web.dev/)

Yes, [PageSpeed Insights](https://pagespeed.web.dev/) is built on top of Puppeteer and it can be automated if you need.

### UI Testing

It helps in ensuring that the visual aspects of a web application display correctly across different browsers and resolutions.

### Network Requests Interception

Puppeteer allows developers to intercept and modify the network requests made by a page, which can be used to mock backend responses or to add/modify headers.

Puppeteer versus Playwright

---------------------------

[Playwright](/blog/playwright/) offers robust and flexible web automation across multiple browsers and supports several programming languages, making it ideal for complex, multi-browser testing scenarios.

But [Puppeteer](/blog/puppeteer/) is tailored for Chrome/Chromium browsers and benefits from a strong community and extensive documentation, making it suitable for projects with these specific needs.

The choice between Playwright and Puppeteer depends on the browser requirements and the programming environment of the project, with Playwright providing more advanced features like parallel test execution and multi-context browsing.

If you are curious, you can read about [the difference between Puppeteer and Playwright in more details](/blog/puppeteer-versus-playwright/).

Summary

-------

By the way, when choosing between Puppeteer and APIs or other libraries, consider the specific needs of your task. Puppeteer excels in scenarios where browser-based interaction is crucial, such as web scraping dynamic content, automating user interactions, and performing end-to-end testing of web applications.

Puppeteer can also generate screenshots and PDFs of web pages, offering a high degree of control over browser context and rendered elements.

On the other hand, APIs are the optimal choice for direct, stable, and efficient data access. If the data you need is available through an API, it is typically quicker and more reliable than using a web scraping tool like Puppeteer. APIs are specifically designed for data exchange and can handle large volumes of requests with better performance and less risk of disruption from changes on the data provider’s website.

For simpler data retrieval tasks that don’t require simulating a full browser environment, other libraries such as HTTP clients (like axios or requests) or HTML parsing libraries (like [Cheerio](https://cheerio.js.org/)) might be more appropriate. These tools are lighter on resources and better suited for static content extraction or when interacting with straightforward server-side APIs. They allow for quick data processing without the overhead of a full browser, making them ideal for many backend applications.

Read more Puppeteer guides

--------------------------

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

[View all posts](/blog/tags/puppeteer-guides/)

#### [page.waitForTimeout is not a function in Puppeteer](/blog/page-waitfortimeout-is-not-a-function-in-puppeteer/)

Puppeteer removed page.waitForTimeout(). Learn why the error happens and which modern alternatives to use instead.

Read more

#### [Puppeteer waitUntil: how to wait for page load](/blog/puppeteer-wait-until-the-page-is-ready/)

Join me in exploring how to find the ideal wait time or event of when to take the page screenshot with Puppeteer.

Read more

#### [Puppeteer Performance Monitoring with Inspector](/blog/puppeteer-performance-monitoring-with-inspector/)

In this article I'll show you how to monitor performance and errors of a browser automation script written with Puppeteer.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/10
----

Changes and updates

-------------------

Stay updated with the latest information about new features, bug fixes, and optimizations at ScreenshotOne

### Product updates in the last 12 months

May 31, 2024

#### [Extract Open Graph metadata while rendering screenshots](/changelog/open-graph-metadata/)

From today, you can get parsed Open Graph metadata and screenshots in one API request.

Read more →

1 min read

May 16, 2024

#### [Navigate Pages when recording Scrolling Screenshots](/changelog/scrolling-screenshots-navigation/)

You can record a page navigation when recording scrolling screenshot video. It allows render less boring and more engaging videos.

Read more →

1 min read

May 6, 2024

#### [A Simple Website Screenshot Tool by ScreenshotOne](/changelog/website-screenshot/)

A few words about why to launch yet another website screenshotting tool.

Read more →

1 min read

May 1, 2024

#### [Improved errors](/changelog/improved-errors/)

Now, errors will have relevant documentation links. It will be also possible to see why some requests failed in the dashboard and get recommendations on how to address the issue.

Read more →

1 min read

Apr 8, 2024

#### [Use cases in the ScreenshotOne playground](/changelog/improved-playground/)

Having documentation and code examples is great, but not enough to allow developers to quickly integrate the API and assess all available features of the ScreenshotOne API.

Read more →

1 min read

Mar 17, 2024

#### [Fail rendering if the content contains a string](/changelog/fail-if-content-contains/)

There is a set of use cases when you want to fail screenshot rendering and retry it if the content of the page contains a string.

Read more →

1 min read

Mar 10, 2024

#### [Improved blocking of cookie banners](/changelog/improved-blocking-of-cookie-banners/)

We just released an updated version of our algorithm to block cookie banners by heuristics.

Read more →

1 min read

Feb 28, 2024

#### [Improved uploading and error handling to S3-compatible storage](/changelog/improved-storage-upload/)

Today, the new version of ScreenshotOne API was deployed to production that enables a retries mechanism when uploading to an S3 storage and more granular error handling.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/tools/url-to-markdown
----

Convert a URL to Markdown

-------------------------

Turn any public webpage into Markdown online for free.

[Tools](/tools/) Free URL to Markdown Tool

Your website URL

Convert any public webpage into Markdown.

Convert to Markdown

Markdown output

Copy and reuse the converted page content anywhere.

Copy

Markdown output

If you need to automate website screenshot rendering or integrate screenshotting into your application or SaaS, please, check out [the best screenshot API—ScreenshotOne](/).  

Check out more [screenshot tools](/tools/).

Frequently Asked Questions

--------------------------

Discover quick and comprehensive answers to common questions about our platform, services, and features.

What does the URL to Markdown tool do?

It fetches a public webpage and converts its content into Markdown so you can reuse it in notes, docs, and AI workflows.

Why would I convert a webpage to Markdown?

Markdown is easier to copy, edit, summarize, store, and feed into LLMs than raw HTML or visually rendered pages.

What is ScreenshotOne?

ScreenshotOne is a website rendering API that can capture screenshots, generate PDFs, and convert page content into formats like Markdown.

Integrate today

Automate screenshot rendering with the language you love

--------------------------------------------------------

Send simple HTTP requests or use native libraries for your language of choice.

Java Go Node.js PHP Python Ruby C# (.NET)

    1// add com.screenshotone.jsdk:screenshotone-api-jsdk:[1.0.0,2.0.0)2// to your `pom.xml` or `build.gradle`3

    4import com.screenshotone.jsdk.Client;5import com.screenshotone.jsdk.TakeOptions;6

    7import java.io.File;8import java.nio.file.Files;9

    10public class App {11    public static void main(String[] args) throws Exception {12        final Client client = Client.withKeys("<access key>", "<secret key>");13        TakeOptions takeOptions = TakeOptions.url("https://example.com")14                .fullPage(true)15                .deviceScaleFactor(1)16                .viewportHeight(1200)17                .viewportWidth(1200)18                .format("png")19                .omitBackground(true);20        final String url = client.generateTakeUrl(takeOptions);21

    22        System.out.println(url);23        // Output: https://api.screenshotone.com/take?url=...24

    25        // or download the screenshot26        final byte[] image = client.take(takeOptions);27

    28        Files.write(new File("./example.png").toPath(), image);29        // the screenshot is stored in the example.png file30    }31}

    1// go get github.com/screenshotone/gosdk2

    3import screenshots "github.com/screenshotone/gosdk"4

    5client, err := screenshots.NewClient("<access key>", "<secret key>")6// check err7

    8options := screenshots.NewTakeOptions("https://example.com").9    Format("png").10    FullPage(true).11    DeviceScaleFactor(2).12    BlockAds(true).13    BlockTrackers(true)14

    15u, err := client.GenerateTakeURL(options)16// check err17

    18fmt.Println(u.String())19// Output: https://api.screenshotone.com/take?url=...20

    21// or download the screenshot22image, err := client.Take(context.TODO(), options)23// check err24

    25defer image.Close()26out, err := os.Create("example.png")27// check err28

    29defer out.Close()30io.Copy(out, image)31// the screenshot is stored in the example.png file

    1// $ npm install screenshotone-api-sdk --save2

    3import * as fs from 'fs';4import * as screenshotone from 'screenshotone-api-sdk';5

    6// create API client7const client = new screenshotone.Client("<access key>", "<secret key>");8

    9// set up options10const options = screenshotone.TakeOptions11    .url("https://example.com")12    .delay(3)13    .blockAds(true);14

    15// generate URL16const url = client.generateTakeURL(options);17console.log(url);18// expected output: https://api.screenshotone.com/take?url=...19

    20// or download the screenshot21const imageBlob = await client.take(options);22const buffer = Buffer.from(await imageBlob.arrayBuffer());23fs.writeFileSync("example.png", buffer)24// the screenshot is stored in the example.png file

    1<?php2

    3// composer require screenshotone/sdk:^1.04

    5use ScreenshotOneSdkClient;6use ScreenshotOneSdkTakeOptions;7

    8$client = new Client("<access key>", "<secret key>");9

    10$options = TakeOptions::url("https://example.com")11    ->fullPage(true)12    ->delay(2)13    ->geolocationLatitude(48.857648)14    ->geolocationLongitude(2.294677)15    ->geolocationAccuracy(50);16

    17$url = $client->generateTakeUrl($options);18echo $url.PHP_EOL;19// expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com...20

    21$image = $client->take($options);22file_put_contents('example.png', $image);23// the screenshot is stored in the example.png file

    1# pip install screenshotone2

    3import shutil4from screenshotone import Client, TakeOptions5

    6# create API client7client = Client('<access key>', '<secret key>')8

    9# set up options10options = (TakeOptions.url('https://screenshotone.com')11    .format("png")12    .viewport_width(1024)13    .viewport_height(768)14    .block_cookie_banners(True)15    .block_chats(True))16

    17# generate the screenshot URL and share it with a user18url = client.generate_take_url(options)19# expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fscreenshotone.com&viewport_width=1024&viewport_height=768&block_cookie_banners=True&block_chats=True&access_key=&signature=6afc9417a523788580fa01a9f668ea82c78a9d2b41441d2a696010bf2743170f20

    21# or render a screenshot and download the image as stream22image = client.take(options)23

    24# store the screenshot the example.png file25with open('example.png', 'wb') as result_file:26    shutil.copyfileobj(image, result_file)

    1# Add this gem to your Gemfile:2# gem 'screenshotone'3

    4# If you don't need to add a signature5client = ScreenshotOne::Client.new('<access key>')6

    7# Or ff you do need to add a signature8client = ScreenshotOne::Client.new('<access key>', '<secret key>')9

    10# You can set any available option, in a camel_case format, for example:11options = ScreenshotOne::TakeOptions.new(url: 'https://example.com').12            full_page(true).13            delay(2).14            geolocation_latitude(48.857648).15            geolocation_longitude(2.294677).16            geolocation_accuracy(50)17

    18# Verify all the parameters are valid (we will validate the parameters that should be19# numeric, booleans or that accept only certain values)20options.valid?21=> true22

    23# To simply get the final url:24client.generate_take_url(options)25=> "https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com..."26

    27# To actually get the image (the response body of a request to the previous url)28client.take(options)29=> "\xFF\xD8\xFF\xE0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xFF\..."

    1// Add the library via nuget using the package manager console: PM> Install-Package ScreenshotOne.dotnetsdk2// Or from the .NET CLI as: dotnet add package ScreenshotOne.dotnetsdk3

    4// And generate a screenshot URL without executing request:5var client = new Client("<access key>", "<secret key>");6var options = TakeOptions.Url("https://www.amazon.com")7  .FullPage(true)8  .Format(Format.PNG)9  .BlockCookieBanners(true);10

    11var url = client.GenerateTakeUrl(options);12// url = https://api.screenshotone.com/take?url=https%3A%2F%2Fwww.amazon.com&full_page=true&format=png&block_cookie_banners=true&access_key=_OzqMIjpCw-ARQ&signature=8a08e62d13a5c3490fda0734b6707791d3decc9ab9ba41e8cc045288a39db50213

    14// Or take a screenshot and save the image in the file:15var client = new Client("<access key>", "<secret key>");16var options = TakeOptions.Url("https://www.google.com")17  .FullPage(true)18  .Format(Format.PNG)19  .BlockCookieBanners(true);20

    21var bytes = await client.Take(options);22

    23File.WriteAllBytes(@"c:\temp\example.png", bytes);

Mike Roberts

Founder, [SpyFu](https://www.spyfu.com/)

> ScreenshotOne is the best product on the market - and that's before you take into account how responsive and easy Dmytro is to work with.

> 

> Any time we've found a rare edge case, it's been resolved in hours.

> 

> Great company, great founder - can't say enough!

Without writing a line of code

No-code integrations

--------------------

Quickly render website screenshots with Zapier, Airtable, Make and other popular no-code platforms of your choice.

[](/integrations/zapier/)[](/integrations/airtable/)[](/integrations/make/)[](/integrations/bubble/)[](/integrations/n8n/)

Read

Lessons from running screenshot rendering infrastructure

--------------------------------------------------------

Practical guides and real updates based on our experience operating rendering infrastructure at production scale.

[Playwright guides](/blog/tags/playwright-guides/)

#### [Playwright "Execution context was destroyed": how to fix navigation and page.evaluate errors](/blog/playwright-execution-context-was-destroyed-most-likely-because-of-a-navigation/)

Fix the Playwright "Execution context was destroyed, most likely because of a navigation" error after click, form submit, redirect, reload, or page.evaluate.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 13, 2026

•

4 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [page.waitForTimeout is not a function in Puppeteer](/blog/page-waitfortimeout-is-not-a-function-in-puppeteer/)

Puppeteer removed page.waitForTimeout(). Learn why the error happens and which modern alternatives to use instead.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 13, 2026

•

2 min read

#### [OpenClaw with Playwright or Puppeteer: how to install browser support](/blog/openclaw-playwright-puppeteer/)

A practical guide to OpenClaw browser automation, why Playwright is the documented path, where Puppeteer fits, how to make screenshots, and when ScreenshotOne is the better choice for screenshot-only flows.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 12, 2026

•

6 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/social-media-content-compliance
----

Automate Website Screenshots

1 min read

Social Media Content Compliance

===============================

Ensure compliance with regulations and brand standards on social media.

For small companies, managing brand reputation and ensuring content compliance on social media platforms is critical. The ScreenshotOne API offers a solution for automating the monitoring of social media content against regulatory and brand standards.

How ScreenshotOne API Helps

---------------------------

Through the website screenshot API, businesses can automate the capture of their social media posts and ads, providing a record for compliance verification. This facilitates easy review and auditing of content, ensuring it meets all regulatory requirements and brand guidelines.

Value and Time Savings

----------------------

The automation provided by ScreenshotOne significantly reduces the manual effort involved in monitoring social media for compliance. It offers a reliable, time-saving solution that helps protect the company’s brand integrity and ensures adherence to regulations, allowing businesses to focus on growth and engagement strategies.

I’ve been using ScreenshotOne for 3 years and couldn’t run Saaspo without it.

You can tell Dmytro really cares about the product as it keeps getting better.

Highly recommend to anyone looking for a screenshot tool!

Andy Hooke

Founder, [Saaspo](https://screenshotone.com/blog/saaspo/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/export-to-image
----

Automate Website Screenshots

1 min read

Website Feature Enhancement

===========================

Incorporate 'export to PNG' and 'export to PDF' options on your blog or website.

Augmenting a website with functionalities such as ‘export to PNG’ or ‘export to PDF’ significantly elevates the user experience. ScreenshotOne API can be integrated to provide these options, enabling visitors to save web content in their preferred format effortlessly.

Facilitation by ScreenshotOne API

---------------------------------

The screenshot API offers a straightforward method to embed these exporting capabilities into a website. It allows users to transform web pages into images or documents for personal use, sharing, or storage, directly improving the site’s functionality and accessibility.

Development Time and Cost Efficiency

------------------------------------

Embedding ScreenshotOne for these features conserves development time and resources, eliminating the necessity for bespoke coding and verification. It presents a rapid and effective strategy to enhance website capabilities, boosting user satisfaction and engagement.

An example by Typeshare

-----------------------

[Typeshare](https://typeshare.co/) uses ScreenshotOne to automate image generation and export essays in different formats for social media networks.

ScreenshotOne allows TypeShare’s team to focus on their core business and spend less time on boring screenshot automation.

If you are curious, read more about [how Typeshare uses ScreenshotOne for image generation](/blog/how-typeshare-uses-screenshotone/).

We have lots of SaaS subscriptions with Typeshare but by far the best value is ScreenshotOne.

For a small monthly fee, we basically get a full-time developer who handles all our image generation.

We've spent thousands on building this in-house and it was nowhere near as good as what Dmytro Krasun has built.

Can't recommend ScreenshotOne enough!

Sam Shore

Founder, [Typeshare](https://screenshotone.com/blog/how-typeshare-uses-screenshotone/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/screenshot-api/python
----

[What's new API error insights API error insights in the dashboard](/changelog/error-metrics/)

Python Screenshot API

=====================

Capture pixel-perfect website screenshots in Python with a simple API call. No browser management, no Selenium setup—just clean, reliable screenshots.

----------------------

----------------------------

------------------------------------

Take screenshots with Python

----------------------------

Use our official Python SDK or send simple HTTP requests to capture screenshots.

    1# pip install screenshotone2

    3import shutil4from screenshotone import Client, TakeOptions5

    6# create API client7client = Client('<access key>', '<secret key>')8

    9# set up options10options = (TakeOptions.url('https://screenshotone.com')11    .format("png")12    .viewport_width(1024)13    .viewport_height(768)14    .block_cookie_banners(True)15    .block_chats(True))16

    17# generate the screenshot URL and share it with a user18url = client.generate_take_url(options)19# expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fscreenshotone.com&viewport_width=1024&viewport_height=768&block_cookie_banners=True&block_chats=True&access_key=&signature=6afc9417a523788580fa01a9f668ea82c78a9d2b41441d2a696010bf2743170f20

    21# or render a screenshot and download the image as stream22image = client.take(options)23

    24# store the screenshot the example.png file25with open('example.png', 'wb') as result_file:26    shutil.copyfileobj(image, result_file)

Mike Roberts

Founder, [SpyFu](https://www.spyfu.com/)

> ScreenshotOne is the best product on the market - and that's before you take into account how responsive and easy Dmytro is to work with.

> 

> Any time we've found a rare edge case, it's been resolved in hours.

> 

> Great company, great founder - can't say enough!

Without writing a line of code

No-code integrations

--------------------

Quickly render website screenshots with Zapier, Airtable, Make and other popular no-code platforms of your choice.

[](/integrations/zapier/)[](/integrations/airtable/)[](/integrations/make/)[](/integrations/bubble/)[](/integrations/n8n/)

Read

Lessons from running screenshot rendering infrastructure

--------------------------------------------------------

Practical guides and real updates based on our experience operating rendering infrastructure at production scale.

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots in Python](/blog/how-to-take-website-screenshots-in-python/)

With Python, you can take website screenshots in multiple ways. But the best way to do it depends solely on your needs and your use case. Let's quickly examine all the options.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Mar 18, 2024

•

8 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Taking care of WordPress Sites with ScreenshotOne](/blog/kinsta/)

How Kinsta uses ScreenshotOne to deliver reliable automatic updates.

Written by

[Roger Williams](/contributors/roger-williams/), [Barnabás Ürmössy](/contributors/barnabs-rmssy/)

Published on

Apr 29, 2025

•

2 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Typeshare uses ScreenshotOne for image generation](/blog/how-typeshare-uses-screenshotone/)

Typeshare is a digital writing platform designed to enhance the writing experience by offering a suite of tools aimed at reducing common barriers writers face.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Apr 14, 2024

•

2 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/how-branding5-uses-screenshotone
----

How Branding 5 uses ScreenshotOne for competitor analysis

=========================================================

If you are interested in diving deeper into the Branding 5 use case and discover if ScreenshotOne might be useful for you, too, keep reading.

[Customer story](/blog/tags/customer-stories/) 2 min read

#### Written by

[Matthias Neumayer](/contributors/matthias-neumayer/), [Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Oct 4, 2024

[Branding 5](https://www.branding5.com/) is a one-stop solution for creating sophisticated competitor analysis or finding your brand positioning with our AI powered solutions.

They use ScreenshotOne to render screenshots of competitor websites for a target business and analyze them using AI.

Branding 5 and ScreenshotOne

----------------------------

Here is what Matthias Neumayer a co-founder shared with us about their integration with ScreenshotOne:

### How did you discover ScreenshotOne?

> I first discovered ScreenshotOne through Twitter/X, where I noticed a lot of positive discussions and endorsements from users praising its functionality and ease of use.

### Did you consider any alternatives?

> Yes, I explored several alternatives to ScreenshotOne, but I found that none of them offered the same level of comprehensive documentation and user-friendly playground experience. Many other screenshot tools fell short in terms of reliability and ease of integration. What really sets ScreenshotOne apart is its ability to automatically block cookie banners and streamline the entire process, allowing me to focus on my core tasks without getting bogged down by tedious details.

> “Many other screenshot tools fell short in terms of reliability and ease of integration”

### How does it help your business?

> ScreenshotOne plays a crucial role in our competitor analysis tool. We rely on high-quality screenshots to provide our clients with valuable insights. The screenshots are later analyzed using AI, and ScreenshotOne ensures we have the best possible image quality, which is essential for accurate analysis and reporting. This capability not only enhances our deliverables but also elevates the overall client experience.

### How satisfied are you with the solution?

> I am extremely satisfied with ScreenshotOne. Its reliability, performance, and ease of use make it a standout solution in the market. I often find myself wishing that every API could match the seamless experience that ScreenshotOne provides. Especially the playground really helps with integrating the API fast.

More Examples and Use Cases

---------------------------

You might be also interested in how [SpyFu uses ScreenshotOne for RivalFlowAI for competitive content analysis with AI](/blog/rivalflowai-by-spyfu/).

ScreenshotOne supports a huge variety of uses including but not only:

*   [Automating Open Graph image generation](/use-cases/open-graph-images/).

*   [Generating personalized videos](/use-cases/automate-personalized-videos/).

*   [Rendering site thumbnails for search previews](/use-cases/preview-search-results/)

And [many more](/use-cases/).

Read more customer stories

--------------------------

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

[View all posts](/blog/tags/customer-stories/)

#### [How BugSmash automates website screenshot rendering](/blog/bugsmash-story/)

How and why BugSmash uses ScreenshotOne for critical screenshot rendering tasks.

Read more

#### [How AdKit automated onboarding](/blog/adkit/)

A short story by the founder of AdKit about how they use ScreenshotOne for onboarding automation.

Read more

#### [SEOBot uses ScreenshotOne API to generate screenshots for articles](/blog/seobot-automates-screenshot-generation-for-articles/)

Customers can your product in unpredictable and surprising ways. SEOBot now uses ScreenshotOne API to enhance its articles with screenshots, making content more engaging and visually appealing.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/playground-presets
----

Playground Presets

==================

You can now create and save presets in the ScreenshotOne Playground!

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Aug 28, 2025

Presets

-------

Presets let you capture your favorite API configurations and share them across your team or the whole organization.

Use cases

---------

### Collaboration and consistency

Share presets with colleagues so everyone works with the same setup.

To ensure your team uses the same screenshot settings (e.g., full-page, mobile view, transparent background).

### Save time

Quickly apply a preset instead of tweaking parameters every time.

### Experimentation

Save multiple variations (e.g., “Marketing banners,” “Docs screenshots”) and switch between them instantly.

Summary

-------

This makes it easier to standardize workflows, avoid mistakes, and speed up repetitive tasks when capturing or testing screenshots.

Your feedback is appreciated

----------------------------

If you have any questions, suggestions, or need any assistance, please, reach out at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [ScreenshotOne is available as a ChatGPT plugin](/changelog/screenshotone-is-available-as-a-chatgpt-plugin/)

From today, you can render screenshots of any website or even raw HTML in ChatGPT—ScreenshotOne is available as a plugin. But at the moment of writing not available yet, in the official store, but it can be available when you read it.

Read more →

2 min read

#### [Better Markdown output](/changelog/better-markdown-output/)

Markdown output is now cleaner by removing non-content HTML blocks during conversion.

Read more →

1 min read

#### [ScreenshotOne is available on viaSocket](/changelog/viasocket-integration/)

Automate website screenshots, animated scrolling captures, and visual documentation workflows with ScreenshotOne and viaSocket.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/contributors/anatoly-pashias
----

Anatoly Pashias

---------------

View all Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [Why FrameKit chose ScreenshotOne for their business](/blog/framekit/)

A short story about how and why FrameKit chose ScreenshotOne for their use case.

Written by

[Anatoly Pashias](/contributors/anatoly-pashias/)

Published on

Mar 2, 2026

•

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/errors/storage-returned-transient-error
----

[Skip to content](#_top)

Storage Returned Transient Error

================================

Copy page

It is an API error returned when the storage server returns a transient error and retries have been exhausted.

    1{2    "is_successful": false,3    "error_code": "storage_returned_transient_error",4    "error_message": "The storage returned an HTTP status code between 500 and 599 and we exhausted retries. You can likely retry the request again.",5    "documentation_url": "https://screenshotone.com/docs/errors/storage-returned-transient-error/"6}

Reasons and how to fix

----------------------

### Transient Storage Server Error

The most common reason for the “storage\_returned\_transient\_error” is that the S3 storage returned an HTTP status code between 500 and 599, indicating a transient error.

To fix this, you can:

1.  **Retry the request**: Since the error is transient, retrying the request after a short wait is often effective.

2.  **Check storage service status**: Verify the status of the storage service you are using to see if there are any ongoing issues or maintenance that might be causing the error.

### Exhausted Retries

The API has attempted to retry the request multiple times but has exhausted its retry limit.

To fix this, consider implementing additional retries on your end, with exponential backoff to avoid overwhelming the storage server.

### Temporary Network Issues

Temporary network issues can also cause transient errors from the storage server.

To fix this, ensure that your network connection is stable and retry the request.

Reach out to support

--------------------

If you continue to face issues or need further assistance, please reach out to `support@screenshotone.com`, and we will assist you as soon as possible.

----
url: https://screenshotone.com/blog/screenshotone-october-2025-updates
----

ScreenshotOne October 2025 updates

==================================

Metadata content format, upgraded dashboard, improved webhooks, updated Go SDK, Make conference, and AWS disruption lessons.

[Blog post](/blog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Nov 1, 2025

A short summary of the product updates, company news and learnings in October 2025:

Product Updates

---------------

### Metadata content format

[Choose the format of page content](/changelog/metadata-content-format/): Control how the API returns page content with the new `metadata_content_format` option—choose between HTML or Markdown format.

### Better dashboard performance

[Dashboard performance improved](/changelog/upgraded-dashboard-underlying-framework/): The ScreenshotOne Dashboard has been upgraded to Next.js 16, delivering better performance and user experience.

### Better webhooks documentation and playground

[Improved webhooks documentation and playground](/changelog/improved-webhooks-documentation-and-playground/): All webhook options are now available in Playground with enhanced documentation.

[](/changelog/improved-webhooks-documentation-and-playground/)

### Updated Go SDK

[The official Go SDK now supports the latest API features with fixes for asynchronous requests](/changelog/updated-gosdk/)).

[](/changelog/updated-gosdk/)

Company News and Learnings

--------------------------

### ScreenshotOne at Make conference

ScreenshotOne was featured at the official Make conference, with Shubham Sharma demonstrating how to automate screenshots with Make for complex workflows. [Read more](/blog/make-conference/).

### Lessons from the AWS us-east-1 disruption

We shared insights from the AWS us-east-1 disruption on October 19-20, including how ScreenshotOne’s multi-cloud infrastructure kept the API unaffected, and lessons learned about resilience and backup providers. [Read the full post](/blog/lessons-from-the-aws-us-east-1-disruption/).

Summary

-------

It was a great month for ScreenshotOne with a lot of updates and news.

Questions or feedback? Reach out at `support@screenshotone.com`.

Read more posts

---------------

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

[View all posts](/blog/)

#### [ScreenshotOne on LaunchDay!](/blog/itslaunchday/)

ScreenshotOne participated in the first launch batch of the LaunchDay platform

Read more

#### [OpenClaw with Playwright or Puppeteer: how to install browser support](/blog/openclaw-playwright-puppeteer/)

A practical guide to OpenClaw browser automation, why Playwright is the documented path, where Puppeteer fits, how to make screenshots, and when ScreenshotOne is the better choice for screenshot-only flows.

Read more

#### [Blast Banners with ScreenshotOne](/blog/blast-banners/)

A funny game built on top of ScreenshotOne API.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/how-to-add-custom-scripts-to-a-page-in-puppeteer
----

How to add custom scripts to a page in Puppeteer

================================================

How to add custom scripts to a page in Puppeteer. Let's discover how it works quickly."

[Blog post](/blog/) 2 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jun 24, 2022

#### Tags

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

To add custom scripts to any page use Puppeteer’s page method `page.addScriptTag(options)`.

You can inject:

*   script by providing URL;

*   script from the machine where the Puppeteer instance is running;

*   raw script.

We are going to add a custom script to an [example](https://example.com) site:

We will change it with `document.querySelector('h1').innerHTML = "Hello, world!";`:

Let’s go!

Adding custom script by URL

---------------------------

To add custom script in Puppeteer by URL, use `page.addScriptTag({url: 'https://example.com/custom.js'})`:

As an example:

    1const puppeteer = require('puppeteer');2

    3(async () => {4    const browser = await puppeteer.launch({});5    try {6        const page = await browser.newPage();7

    8        await page.goto('https://example.com/');9

    10        await page.addScriptTag({ url: 'https://example.com/custom.js' });11

    12        await page.screenshot({ path: 'example.com.png' });13    } catch (e) {14        console.log(e)15    } finally {16        await browser.close();17    }18})();19```

No need to worry and wait until the script file is included, because the promise for `page.addScriptTag` will resolve only when the added tag when the script’s `onload` event is fired.

Adding custom script by path

----------------------------

You also can add a custom stylesheet by specifying the path, use

`page.addScriptTag({path: 'custom.js'})`. If the path is relative, it is relative to the working directory.

As an example, I created `custom.js`:

    1h1 {2  color: red;3}

And then:

    1const puppeteer = require("puppeteer");2

    3(async () => {4  const browser = await puppeteer.launch({});5  try {6    const page = await browser.newPage();7

    8    await page.goto("https://example.com/");9

    10    await page.addScriptTag({ path: "custom.js" });11

    12    await page.screenshot({ path: "example.com.png" });13  } catch (e) {14    console.log(e);15  } finally {16    await browser.close();17  }18})();

Adding raw script content

-------------------------

In our [screenshot API](/), you can easily add custom scripts by specifying [the scripts parameter](/docs/options/#scripts).

And the simplest way to add CSS custom style is just add raw CSS content by using `page.addStyleTag({content: '<selector> { <property>: <value>; }'})`:

    1const puppeteer = require('puppeteer');2

    3(async () => {4    const browser = await puppeteer.launch({});5    try {6        const page = await browser.newPage();7

    8        await page.goto('https://example.com/');9

    10        await page.addScriptTag({ content: 'document.querySelector('h1').innerHTML = "Hello, world!"'});11

    12        await page.screenshot({ path: 'example.com.png' });13    } catch (e) {14        console.log(e)15    } finally {16        await browser.close();17    }18})();

I hope I helped you today to solve your problem and have a nice day 👋

You also might find helpful:

*   [the complete guide on how to take a screenshot with Puppeteer](/blog/how-take-a-screenshot-with-puppeteer)

*   [how to add custom styles to a page in Puppeteer](/blog/how-to-add-custom-styles-to-a-page-in-puppeteer)

*   [how to render HTML with Puppeteer](/blog/how-to-render-html-with-puppeteer)

Read more Puppeteer guides

--------------------------

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

[View all posts](/blog/tags/puppeteer-guides/)

#### [How to render HTML with Puppeteer](/blog/how-to-render-html-with-puppeteer/)

Use Puppeteer or screenshot API to generate the Open Graph protocol images, bills, receipts, or invoices PDF or PNG files from the HTML templates.

Read more

#### [How to take website screenshots with Java](/blog/how-to-take-website-screenshots-with-java/)

The article examines how you can take screenshots of any URL with Java by using Selenium, Puppeteer alternatives, Playwright, or screenshot API as a service.

Read more

#### [How to Take Bulk Screenshots with Playwright in Python](/blog/bulk-screenshots-playwright-python/)

Learn how to automate bulk website screenshots with Playwright in Python. Master async batch processing, concurrent screenshots, rate limiting, and error handling for large-scale screenshot automation.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/integrations/sanity
----

Integrations

1 min read

Sanity

======

Add website screenshots to your Sanity content with a plugin.

Low-Code CMS

Resources

---------

*   [Check the plugin on Sanity](https://www.sanity.io/plugins/sanity-plugin-asset-source-screenshotone)

ScreenshotOne helps us easily make instant OG images for all our clients at our [SEO agency](http://magicspace.agency), it's the easiest way to make quick screenshots fast and they look amazing.

Ilias Ism

Founder, [ogimage.org](https://ogimage.org/)

Check more Integrations

-----------------------

No-code tools, AI, code libraries, and more.

[Check more Integrations](/integrations/)

No-Code Automation

### Zapier

Automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos in Zapier.

[Read more →](/integrations/zapier/)

No-Code Automation

### n8n

Use ScreenshotOne in n8n workflows to render website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

[Read more →](/integrations/n8n/)

No-Code Automation

### Clay

Generate website screenshots inside Clay to qualify leads, assess content, and enrich rows with visual context automatically.

[Read more →](/integrations/clay/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/capture-beyond-viewport-in-puppeteer-and-chrome-devtools-protocol
----

Capture beyond viewport in Puppeteer and Chrome DevTools Protocol

=================================================================

Let's talk about the captureBeyondViewport parameter introduced in Chrome DevTools Protocol which will soon be supported by Puppeteer or even supported now at the time when you are reading the post.

[Blog post](/blog/) 3 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jan 1, 2023

#### Tags

[Puppeteer guides](/blog/tags/puppeteer-guides/)

The option `captureBeyondViewport` was introduced to solve the problem in Chrome DevTools when you take a screenshot of the node and the part of the node is hidden from the viewport. If `captureBeyondViewport` is set to true, the hidden part of the node will be screenshotted too.

Showcasing captureBeyondViewport

--------------------------------

That’s the example that we are going to test:

    1<!DOCTYPE html>2<html>3    <body>4        <div5            class="beyond-viewport-element"6            style="height: 110vh; background-color: blue; border: 10px solid red"7        ></div>8        <div9            class="next-element"10            style="height: 100px; background-color: green; border: 10px solid yellow"11        ></div>12    </body>13</html>

And that’s how it looks like from my browser:

Since the height of the `.beyond-viewport-element` element is defined as `110vh`, we can’t see the bottom of the element. It is hidden behind the viewport, including the next element.

Let’s see how it works in the example and compare results with different values for `captureBeyondViewport`.

Don’t forget to install `puppeteer`:

Terminal window

    1npm i puppeteer --save

Then let’s set up a viewport with a small height to hide the part of the page by intent:

    1"use strict";2

    3const example = `<!DOCTYPE html>4<html>5    <body>6        <div7            class="beyond-viewport-element"8            style="height: 110vh; background-color: blue; border: 10px solid red"></div>9        <div10            class="next-element"11            style="height: 100px; background-color: green; border: 10px solid yellow"></div>12    </body>13</html>`;14

    15const puppeteer = require("puppeteer");16(async () => {17    const browser = await puppeteer.launch();18    try {19        const page = await browser.newPage();20

    21        await page.setContent(example);22

    23        const node = await page.$(".beyond-viewport-element");24

    25        await node.screenshot({26            path: "node_screenshot_within_viewport.png",27            captureBeyondViewport: false,28        });29    } catch (e) {30        console.log(e);31    } finally {32        await browser.close();33    }34})();

That’s the result with `captureBeyondViewport=false`:

Let’s change `captureBeyondViewport` to true, which is the default value, by the way:

    1// ...2await node.screenshot({3    path: "node_screenshot_beyond_viewport.png",4    captureBeyondViewport: true,5});6// ...

And that’s the result with `captureBeyondViewport=true`:

The difference is apparent.

The difference between fullPage and captureBeyondViewport

---------------------------------------------------------

Now, let’s chat about the nuances of full-page screenshots and capturing beyond the viewport. When `Puppeteer` takes the full-page screenshot, it changes the viewport height to match the computed layout height. And if the page contains elements relative to viewport height, they won’t be taken into account since their height will be changed.

Let’s see how it works in practice:

    1"use strict";2

    3const example = `<!DOCTYPE html>4<html>5    <body>6        <div7            class="beyond-viewport-element"8            style="height: 110vh; background-color: blue; border: 10px solid red"></div>9        <div10            class="next-element"11            style="height: 100px; background-color: green; border: 10px solid yellow"></div>12    </body>13</html>`;14

    15const puppeteer = require("puppeteer");16(async () => {17    const browser = await puppeteer.launch();18    try {19        const page = await browser.newPage();20

    21        await page.setContent(example);22

    23        await page.screenshot({24            path: "full_page_within_viewport.png",25            fullPage: true,26            captureBeyondViewport: false,27        });28    } catch (e) {29        console.log(e);30    } finally {31        await browser.close();32    }33})();

The result is:

But if we change `captureBeyondViewport` to `true`, the result looks like as we would expect for the full page screenshot:

[ScreenshotOne (URL/HTML to image/PDF) API](https://screenshotone.com/) supports capturing beyond and within the viewport.

A few related articles you might be interested in:

--------------------------------------------------

1.  [Take a screenshot “from the surface” in Puppeteer and Chrome DevTools Protocol](/blog/take-a-screenshot-from-the-surface-in-puppeteer-and-chrome-devtools-protocol).

2.  [Optimize for speed when rendering screenshots in Puppeteer and Chrome DevTools Protocol](/blog/optimize-for-speed-when-rendering-screenshots-in-puppeteer-and-chrome-devtools-protocol).

3.  [A complete guide on how to take full page screenshots with Puppeteer, Playwright or Selenium](/blog/puppeteer-full-page-screenshot).

Read more Puppeteer guides

--------------------------

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

[View all posts](/blog/tags/puppeteer-guides/)

#### [How to use proxy per page with Puppeteer](/blog/how-to-use-proxy-per-page-with-puppeteer/)

It is easy to use proxy globally for the puppeteer instance, but there is a trick to use proxy on a per-page basis.

Read more

#### [Taking screenshots with Puppeteer in GIF, JP2, TIFF, AVIF, HEIF, or SVG format](/blog/taking-screenshots-with-puppeteer-in-gif-jp2-tiff-avif-heif-or-svg-format/)

Puppeteer, by default, supports only four formats for taking screenshots or rendering HTML: PNG, JPEG, WebP, and PDF. But what if you want it to take it in a different format like GIF, JP2, TIFF, AVIF, HEIF, or SVG?

Read more

#### [How to fix the "Execution context was destroyed" error when using Puppeteer](/blog/puppeteer-execution-context-was-destroyed-most-likely-because-of-a-navigation/)

Fix the Puppeteer "Execution context was destroyed, most likely because of a navigation" error after click, form submit, redirect, reload, or page.evaluate.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/improved-full-page-scrolling-for-lazy-loaded-content
----

Improved full-page scrolling for lazy-loaded content

====================================================

Better scrolling routine to load content reliably on long pages.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Dec 3, 2024

We improved the scrolling routine used for full-page screenshots to make lazy-loaded content appear more reliably before capturing:

*   Tuned scrolling cadence and guards to account for deferred rendering and wrappers.

*   Reduced timeouts for pages that previously stalled during full-page renders.

As a result, more pages with infinite scroll or heavy lazy-loading now render fully without missing sections.

If you still see missing parts on a specific URL, send it to `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Improved errors](/changelog/improved-errors/)

Now, errors will have relevant documentation links. It will be also possible to see why some requests failed in the dashboard and get recommendations on how to address the issue.

Read more →

1 min read

#### [Better and more extensible PDF rendering](/changelog/better-and-more-extensible-pdf-rendering/)

ScreenshotOne supports PDF rendering for a long time but it was used till recently by a small group of customers. Growing demand in PDF rendering required updating the API. And today, we introduce new options for PDF customization.

Read more →

1 min read

#### [Choose the full page screenshot algorithm](/changelog/full-page-algorithm/)

Now, you can choose the full page screenshot algorithm.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/metadata-content-format
----

Choose the format of the page content returned by the ScreenshotOne API

=======================================================================

Now you can choose the format of the page content returned by ScreenshotOne API with the metadata\_content\_format option.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Oct 30, 2025

You can now control the format of the page content when using the `metadata_content` option.

Use `metadata_content_format` to specify how you want the page content returned. Available formats:

*   `html` - returns the HTML content of the page (default)

*   `markdown` - returns the page content converted to Markdown format

    1https://api.screenshotone.com/take?metadata_content=true&metadata_content_format=markdown&url=https://example.com/&access_key=<access key>

If you use JSON response type, you will get:

    1{2    "content": {3        "url": "https://example.com/.../....md",4        "expires": "Wed, 21 Oct 2015 07:28:00 GMT",5    }6}

The content will be uploaded to the ScreenshotOne CDN and you will receive the URL of the content file.

It is also available in the [playground](https://dash.screenshotone.com/playground).

As always, if you have any questions, please, reach out at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Get favicon used by a website with ScreenshotOne API](/changelog/metadata-icon/)

Now you can get favicon used by a website with ScreenshotOne API in just one simple API call.

Read more →

1 min read

#### [ScreenshotOne can now return screenshots and HTML in one request](/changelog/screenshotone-can-now-return-screenshots-and-html-in-one-request/)

Starting from today ScreenshotOne can return both a website screenshot and the content in one simple API request.

Read more →

1 min read

#### [New organization role](/changelog/new-organization-role/)

Allow other members to manage your organization without transferring ownership.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/fail-if-request-failed
----

Fail ScreenshotOne API requests on purpose

==========================================

Use a new option to fail ScreenshotOne API requests on purpose.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Mar 17, 2025

Use `fail_if_request_failed` option to fail the API request if any matched request failed:

    1https://api.screenshotone.com/take?fail_if_request_failed=*images.example.com*&url=https://example.com/&access_key=<access key>

In the example above, the API request will fail if the request to `*images.example.com*` fails or any other request that matches the pattern.

It is useful if you in specific cases you want to ensure that all resources are loaded. Also, notice that failed requests are not counted towards your rendering quota.

As always, if you have any questions, please, reach out at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [I migrated to Google Cloud](/changelog/i-migrated-to-google-cloud/)

Google Cloud gives $300 in credits for 3 months for experimenting. And I decided to give it a try, but not because of the free credits.

Read more →

4 min read

#### [Using AI to block banners](/changelog/using-ai-to-block-banners/)

First successful attempts to block banners on websites using AI before rendering screenshots.

Read more →

1 min read

#### [Better Markdown output](/changelog/better-markdown-output/)

Markdown output is now cleaner by removing non-content HTML blocks during conversion.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/screenshots-on-macos
----

How to make beautiful screenshots on macOS

==========================================

I do write a lot about how to automate website screenshots, but I rarely share about what tools I use to make beautiful screenshots on the daily basis.

[Blog post](/blog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Apr 7, 2024

A free and simple way to take a screenshot on macOS

---------------------------------------------------

I assume that every Apple user already knows how to take screenshots on macOS.

But if not, you can open Spotlight and search for the “screenshot” application. It is a native application that has basic features to take a screenshot.

Once you open it, the application allows you to shoot the full screen or only some area of the screen, it is up to you.

You can also use a shortcut like `Command + Shift + 4` to open it and screenshot only the part of your screen. Or `Command + Shift + 3` to screenshot the full screen.

It is a basic tool that I use when I need to share screenshots with my friends. But when I share my screenshots in public, I have a strong urge to make them pretty.

Beautiful screenshots with Xnapper on macOS

-------------------------------------------

When I post on X or any other public place, I prefer to beautify my screenshots:

[](https://twitter.com/DmytroKrasun/status/1766093414091628827)

Usually, posts with beautiful screenshots get more attention.

I bought one [Xnapper](https://xnapper.com/) license for that. It is well worth it. In a few clicks, Xnapper allows me to take a screenshot on macOS, then quickly select a beautiful background and export it precisely in the size I need it:

It seems that not only I but [many others love Xnapper, too](https://xnapper.com/love).

A screenshot API?

-----------------

How could I not mention [my lovely screenshot API](https://screenshotone.com)? I use it when I need to automate website screenshots for [a landing page gallery](https://landinghunt) or to automate the rendering of open graph images and many more [use cases](https://screenshotone.com/use-cases/).

Read more posts

---------------

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

[View all posts](/blog/)

#### [ScreenshotOne and viaSocket integration](/blog/screenshotone-and-viasocket-integration/)

Use viaSocket with ScreenshotOne to build workflows that include website screenshot automation.

Read more

#### [Embracing the Future of Web Archiving with ScreenshotOne API](/blog/embracing-the-future-of-web-archiving-with-screenshotone-api/)

Enter the ScreenshotOne API – a revolutionary tool designed to change the face of web archiving.

Read more

#### [OpenClaw with Playwright or Puppeteer: how to install browser support](/blog/openclaw-playwright-puppeteer/)

A practical guide to OpenClaw browser automation, why Playwright is the documented path, where Puppeteer fits, how to make screenshots, and when ScreenshotOne is the better choice for screenshot-only flows.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/how-typeshare-uses-screenshotone
----

How Typeshare uses ScreenshotOne for image generation

=====================================================

Typeshare is a digital writing platform designed to enhance the writing experience by offering a suite of tools aimed at reducing common barriers writers face.

[Customer story](/blog/tags/customer-stories/) 2 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Apr 14, 2024

A few words about Typeshare

---------------------------

[Typeshare](https://typeshare.co) integrates advanced features like idea generation, content optimization, and structured writing to support both novice and experienced writers.

The platform provides an “Idea Generator” that tailors suggestions to the writer’s style and interests, offering a continuous stream of creative prompts. Additionally, Typeshare includes hundreds of writing templates for various types of content, facilitating quick and efficient content creation.

[](https://typeshare.co)

One of the standout features of [Typeshare](https://typeshare.co) is its user-friendly interface that encourages writing and collaboration. The platform is structured to help writers avoid the dreaded blank page syndrome by using predefined templates that can be easily customized.

[](https://typeshare.co)

This feature is particularly valuable for creating content quickly and efficiently, which is crucial for maintaining a consistent writing schedule. Furthermore, Typeshare offers tools for content planning and scheduling, allowing users to manage their publication timelines effectively.

Typeshare also emphasizes social sharing and connectivity among users. It supports direct publishing to major social media platforms like Twitter, LinkedIn, and Medium, making it easier for writers to share their content with a broader audience.

[](https://typeshare.co)

This integration improves the process from creation to publication, enabling writers to focus more on content creation and less on the logistics of content distribution. The platform’s community-oriented features, including feedback mechanisms and collaborative options, foster a supportive writing environment that encourages growth and improvement through user interaction.

How Typeshare uses ScreenshotOne

--------------------------------

[Typeshare](https://typeshare.co) generates and exports images for writing and then share them on social media and other places.

[](https://typeshare.co)

ScreenshotOne processes a high volume of screenshots. Taking all the boring and scaling work and allowing Typeshare to focus on its core business and provide the best possible experience for writers.

Testimonials

------------

Sam Shore, a founder of [Typeshare](https://typeshare.co/) recently [tweeted](https://twitter.com/samjshore/status/1779574376611893347) (edited with the permission of the author):

> We have lots of SaaS subscriptions with Typeshare but by far the best value is ScreenshotOne.

> 

> For a small monthly fee we basically get a full-time developer who handles all our image generation.

> 

> We’ve spent thousands on building this in-house and it was nowhere near as good as what Dmytro Krasun has built.

> 

> Can’t recommend ScreenshotOne enough!

More Examples and Use Cases

---------------------------

You might be also interested in how [SpyFu uses ScreenshotOne for RivalFlowAI for competitive content analysis with AI](/blog/rivalflowai-by-spyfu/).

ScreenshotOne supports a huge variety of uses including but not only:

*   [Automating Open Graph image generation](/use-cases/open-graph-images/).

*   [Generating personalized videos](/use-cases/automate-personalized-videos/).

*   [Rendering site thumbnails for search previews](/use-cases/preview-search-results/)

And [many more](/use-cases/).

Read more customer stories

--------------------------

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

[View all posts](/blog/tags/customer-stories/)

#### [Integrating ScreenshotOne into the directory management platform](/blog/makeadir-feedback/)

How and why "Make a Directory" used ScreenshotOne to automate screenshots for directory websites.

Read more

#### [How BugSmash automates website screenshot rendering](/blog/bugsmash-story/)

How and why BugSmash uses ScreenshotOne for critical screenshot rendering tasks.

Read more

#### [Boosting email CTR for "Bridesmaid For Hire" with ScreenshotOne](/blog/braidsmade-for-hire-case-study/)

How and why "Bridesmaid for Hire" used ScreenshotOne to boost their email campaign CTR.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/privacy-policy
----

Privacy Policy

==============

Thank you for choosing to be a customer (or a user) of ScreenshotOne (“ScreenshotOne”, “we”, “us”, or “our”).

We are committed to protecting your personal information and your right to privacy. If you have any questions or concerns about our policy, or our practices with regards to your personal information, please contact us at [support@screenshotone.com](mailto:support@screenshotone.com).

**ScreenshotOne collects personal data from its users. The user’s acceptance of this privacy policy occurs upon the first interaction with the service via the website screenshotone.com or any of its subdomains.**

ScreenshotOne’s goal is to ensure that the privacy of your company and that of your customers is protected at the highest level when you use the ScreenshotOne service for rendering screenshots, videos, documents, and more.

Data collection

---------------

We collect the following data:

1.  Your email address, IP address, and browser information for authentication purposes.

2.  Your email and associated product usage data for product analytics and improving the service.

3.  Your history of screenshot requests except for cookies and proxy parameters specified in the requests.

4.  Your payment transactions summary (amount and payment method, not the credit card details).

5.  Your company name if you change the ScreenshotOne organization name and it reflects your company name.

Storing generated content

-------------------------

ScreenshotOne doesn’t store the generated content persistently (screenshots, videos, PDFs, HTML, Markdown, and more):

1.  **If you don’t use caching.** When you set `cache=true` in your API request, the rendered content is cached for the duration specified by `cache_ttl` (default 4 hours, maximum 30 days). [Learn more about caching](/docs/caching/). Do not set `cache=true` if you do not want to store the generated content.

2.  **If you don’t use any permanent storage.** When you set `store=true` in your API request or similar storage options, the rendered content is uploaded to your configured S3-compatible storage. [Learn more about storage](/docs/options/#storing). Do not set `store=true` if you do not want to store the generated content.

3.  **When you use the default `response_type=by_format` without caching or storage options**: 3.1. The screenshot is rendered and returned directly to the requestor without being stored persistently on the ScreenshotOne servers. 3.2. No copy is stored persistently on the ScreenshotOne servers. 3.3. Only the request metadata (URL, parameters excluding cookies and proxy details) is logged for analytics, service improvement, and debugging and your needs.

**Important note:** During processing, rendered content may be temporarily stored to pass through internal system components (such as queues, message brokers, or temporary buffers).

This approach ensures that your rendered content and if it contains your users data remain private by default.

Third-party providers

---------------------

A list of third-party providers used by ScreenshotOne, links to their privacy policies, and why and how they are integrated into the ScreenshotOne service and used:

### Crisp

[Crisp](https://crisp.chat/en/) is used to answering questions instantly and allows you to message me immediately. When you sign in to the site, I share your email with the Crisp widget to send you replies if I amn’t available.

[Crisp: Privacy Policy](https://crisp.chat/en/privacy/)

### DigitalOcean

[DigitalOcean](https://www.digitalocean.com/) is for hosting internal API management software, dashboard application, and database. Also for rendering screenshots. All the data is stored in the managed database on DigitalOcean servers.

The servers are located in the United States.

[DigitalOcean: Privacy Policy](https://www.digitalocean.com/legal/privacy-policy).

### Google Cloud

[Google Cloud](https://cloud.google.com/) for running headless browsers at scale.

The servers are located in the United States.

[Google Cloud: Privacy Policy](https://cloud.google.com/terms/cloud-privacy-notice)

### Pirsch Analytics

[Pirsch Analytics](https://pirsch.io/) is used for basic website analytics. It is cookie-free, GDPR-compliant analytics product that doesn’t require a consent form.

[Pirsch Analytics: Privacy Policy](https://pirsch.io/privacy)

The servers are located in the United States.

### Cloudflare

[Cloudflare](https://www.cloudflare.com/) for proxying all requests to API, caching, and storage for rendered images.

The servers are located in the United States.

[Cloudflare: Privacy Policy](https://www.cloudflare.com/privacypolicy/)

### PostHog

[PostHog](https://posthog.com/) is used for product analytics.

The servers are located in the European Union.

[PostHog: Privacy Policy](https://posthog.com/privacy)

### Grafana Cloud

[Grafana Cloud](https://grafana.com/products/cloud/) is used for storing the ScreenshotOne logs and metrics.

Cookies and proxy parameters you send are exempted from the logs—they are removed before even logging.

[Grafana Cloud: Privacy Policy](https://grafana.com/privacy-policy/https://grafana.com/legal/privacy-policy/)

### Tolt

[Tolt](https://tolt.com/) is used for the ScreenshotOne referral program.

Your email and payments are sent to Tolt if you subscribed through one of the ScreenshotOne affiliate partners. It is done to track affiliate commissions only.

[Tolt: Privacy Policy](https://tolt.io/privacy-policy)

### Better Stack

[Better Stack](https://betterstack.com/) is used for monitoring the status of the ScreenshotOne services. No data is shared at all with them.

[Better Stack: Privacy Policy](https://betterstack.com/privacy)

### Hetzner

[Hetzner](https://www.hetzner.com/) is used for hosting the ScreenshotOne services.

The servers are located within the European Union.

[Hetzner: Privacy Policy](https://www.hetzner.com/legal/privacy-policy)

### Paddle

[Paddle](https://paddle.com/) is used for processing payments.

Your credit card information is not stored, nor logged on our servers. It is all processed by Paddle.

[Paddle: Privacy Policy](https://paddle.com/privacy)

GDPR compliance

---------------

Under the General Data Protection Regulation (GDPR), you have certain rights with respect to your data, including the right to request access, rectification, erasure, restriction of processing, data portability, and the right to object to processing.

You may exercise these rights by contacting me using the contact information provided below.

ScreenshotOne is not yet compliant with the GDPR.

Security

--------

Check out our [security compliance](/security-compliance/) more details.

Updates to the policy

---------------------

From time to time, the policy might be updated. The latest version is always at [https://screenshotone.com/privacy-policy/](https://screenshotone.com/privacy-policy/).

This policy was last updated on November 15, 2025.

Contact

-------

[Contact us](/contact/) if you have any questions, issues, or specific requests.

----
url: https://screenshotone.com/blog/playwright-python-full-page-website-screenshots
----

How to Take Full Page Screenshots with Playwright in Python

===========================================================

Learn how to capture full page screenshots with Playwright in Python. Master the full\_page parameter, handle infinite scroll pages, lazy-loaded images, and maximum size limits.

[Blog post](/blog/) 4 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jan 17, 2026

#### Tags

[Screenshot rendering](/blog/tags/screenshot-rendering/) [Playwright guides](/blog/tags/playwright-guides/)

To get familiar with Playwright in Python, you can check out [our guide on how to take website screenshots with Playwright in Python](/blog/playwright-python-screenshots/). The following guide is fully focused on full page screenshots only.

The `full_page=True` parameter in Playwright is one of its best features. Unlike Selenium, which requires complicated scrolling and stitching, Playwright handles it natively. But there are nuances you need to understand.

The Basics

----------

Here’s the simplest full page screenshot:

    1from playwright.sync_api import sync_playwright2

    3with sync_playwright() as p:4    browser = p.chromium.launch()5    page = browser.new_page()6    page.goto('https://example.com')7    page.screenshot(path='fullpage.png', full_page=True)8    browser.close()

That’s it for static pages. But most modern websites aren’t static.

Understanding Viewport vs Full Page

-----------------------------------

It’s important to understand the difference:

*   **Viewport**: The visible area of the browser window (e.g., 1920x1080)

*   **Full Page**: The entire scrollable content (could be 1920x5000 or more)

    1# Viewport only (default)2page.screenshot(path='viewport.png')3

    4# Full scrollable page5page.screenshot(path='fullpage.png', full_page=True)

The viewport setting still matters for full page screenshots—it determines the width:

    1context = browser.new_context(2    viewport={'width': 1440, 'height': 900}3)4page = context.new_page()5page.goto('https://example.com')6# Screenshot will be 1440px wide, but full height7page.screenshot(path='fullpage.png', full_page=True)

Handling Lazy-Loaded Images

---------------------------

Modern websites lazy-load images to improve performance. If you take a screenshot immediately, you’ll see placeholder images or blank spaces.

### Solution: Scroll First, Screenshot Later

    1from playwright.sync_api import sync_playwright2

    3def scroll_page(page):4    """Scroll through the page to trigger lazy loading."""5    page.evaluate('''6        async () => {7            await new Promise((resolve) => {8                let totalHeight = 0;9                const distance = 300;10                const timer = setInterval(() => {11                    const scrollHeight = document.body.scrollHeight;12                    window.scrollBy(0, distance);13                    totalHeight += distance;14

    15                    if (totalHeight >= scrollHeight) {16                        clearInterval(timer);17                        window.scrollTo(0, 0);  // Scroll back to top18                        resolve();19                    }20                }, 100);21            });22        }23    ''')24

    25with sync_playwright() as p:26    browser = p.chromium.launch()27    page = browser.new_page()28    page.goto('https://example.com')29

    30    # Scroll to trigger lazy loading31    scroll_page(page)32

    33    # Wait for images to load34    page.wait_for_load_state('networkidle')35

    36    # Now take the screenshot37    page.screenshot(path='fullpage.png', full_page=True)38    browser.close()

Handling Infinite Scroll Pages

------------------------------

Some pages load more content as you scroll (like social media feeds). Here’s how to handle them:

    1from playwright.sync_api import sync_playwright2

    3def scroll_infinite_page(page, max_scrolls=10):4    """Scroll an infinite page until no new content loads."""5    prev_height = -16    scroll_count = 07

    8    while scroll_count < max_scrolls:9        # Scroll to bottom10        page.evaluate('window.scrollTo(0, document.body.scrollHeight)')11        page.wait_for_timeout(1000)  # Wait for content to load12

    13        # Check if new content was loaded14        new_height = page.evaluate('document.body.scrollHeight')15        if new_height == prev_height:16            break  # No new content17

    18        prev_height = new_height19        scroll_count += 120

    21    # Scroll back to top22    page.evaluate('window.scrollTo(0, 0)')23

    24with sync_playwright() as p:25    browser = p.chromium.launch()26    page = browser.new_page()27    page.goto('https://news.ycombinator.com')28

    29    scroll_infinite_page(page, max_scrolls=5)30    page.wait_for_timeout(500)31

    32    page.screenshot(path='fullpage.png', full_page=True)33    browser.close()

Fixed Headers and Footers

-------------------------

Fixed (sticky) elements can cause issues in full page screenshots—they appear multiple times as the page renders. Here’s how to handle them:

    1page.goto('https://example.com')2

    3# Hide fixed elements before screenshot4page.add_style_tag(content='''5    * {6        position: static !important;7    }8    .sticky-header,9    .fixed-footer,10    [style*="position: fixed"],11    [style*="position: sticky"] {12        position: relative !important;13    }14''')15

    16page.screenshot(path='fullpage.png', full_page=True)

Or more targeted:

    1# Hide specific fixed elements2page.evaluate('''3    document.querySelectorAll('.sticky-header, .fixed-nav').forEach(el => {4        el.style.position = 'relative';5    });6''')

Maximum Size Considerations

---------------------------

Very long pages can cause issues:

1.  **Memory**: Large screenshots consume significant memory

2.  **File Size**: PNG files can become huge

3.  **Rendering**: Some systems limit image dimensions

### Solution: Use JPEG for Large Screenshots

    1page.screenshot(2    path='fullpage.jpg',3    full_page=True,4    type='jpeg',5    quality=856)

### Solution: Capture in Sections

For extremely long pages, capture in sections:

    1from playwright.sync_api import sync_playwright2from PIL import Image3import io4

    5def capture_in_sections(page, section_height=2000):6    """Capture a long page in sections and stitch together."""7    total_height = page.evaluate('document.body.scrollHeight')8    viewport_width = page.evaluate('window.innerWidth')9

    10    images = []11    offset = 012

    13    while offset < total_height:14        # Scroll to position15        page.evaluate(f'window.scrollTo(0, {offset})')16        page.wait_for_timeout(100)17

    18        # Capture viewport19        screenshot_bytes = page.screenshot()20        images.append(Image.open(io.BytesIO(screenshot_bytes)))21

    22        offset += section_height23

    24    # Stitch images together25    total_height = sum(img.height for img in images)26    result = Image.new('RGB', (viewport_width, total_height))27

    28    y_offset = 029    for img in images:30        result.paste(img, (0, y_offset))31        y_offset += img.height32

    33    return result

Async Version for Better Performance

------------------------------------

    1import asyncio2from playwright.async_api import async_playwright3

    4async def full_page_screenshot(url, output_path):5    async with async_playwright() as p:6        browser = await p.chromium.launch()7        page = await browser.new_page()8        await page.goto(url)9

    10        # Scroll to load lazy content11        await page.evaluate('''12            async () => {13                await new Promise(resolve => {14                    let totalHeight = 0;15                    const distance = 300;16                    const timer = setInterval(() => {17                        window.scrollBy(0, distance);18                        totalHeight += distance;19                        if (totalHeight >= document.body.scrollHeight) {20                            clearInterval(timer);21                            window.scrollTo(0, 0);22                            resolve();23                        }24                    }, 100);25                });26            }27        ''')28

    29        await page.wait_for_load_state('networkidle')30        await page.screenshot(path=output_path, full_page=True)31        await browser.close()32

    33asyncio.run(full_page_screenshot('https://example.com', 'fullpage.png'))

Comparison: Playwright vs Selenium Full Page

--------------------------------------------

Feature

Playwright

Selenium

Native full page

`full_page=True`

Not supported

Workaround needed

No

Yes (scroll + stitch)

Quality

Excellent

Depends on implementation

Speed

Fast

Slow

This is one of the main reasons I recommend Playwright over Selenium for screenshot tasks.

When Screenshots Aren’t Enough

------------------------------

For production systems handling thousands of screenshots, consider:

*   Memory management becomes critical

*   Browser crashes can lose progress

*   Rate limiting and retries add complexity

A [screenshot API like ScreenshotOne](/) handles these challenges. See the [main Python screenshot guide](/blog/how-to-take-website-screenshots-in-python/) for when to use each approach.

Summary

-------

Full page screenshots with Playwright are straightforward, but remember:

1.  Use `full_page=True` for complete captures

2.  Scroll first to trigger lazy-loaded content

3.  Handle infinite scroll with max scroll limits

4.  Remove fixed positioning for clean results

5.  Use JPEG for very long pages to manage file size

Frequently Asked Questions

--------------------------

If you read the article, but still have questions. Please, check the most frequently asked. And if you still have questions, feel free reach out at [support@screenshotone.com](mailto:support@screenshotone.com).

### How to take full page screenshot with Playwright Python?

Use page.screenshot(path='screenshot.png', full\_page=True). The full\_page parameter captures the entire scrollable page height, not just the visible viewport.

### What is the maximum screenshot size in Playwright?

Playwright doesn't have a hard limit, but very long pages (over 16,384 pixels) may cause memory issues. For extremely long pages, consider capturing in sections or using a screenshot API.

### How to handle lazy-loaded images in full page screenshots?

Scroll through the page first to trigger lazy loading, then wait for images to load before taking the screenshot. Use page.evaluate() to scroll and page.wait\_for\_load\_state('networkidle') to wait.

Read more Screenshot rendering

------------------------------

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

[View all posts](/blog/tags/screenshot-rendering/)

#### [What is Playwright](/blog/playwright/)

What is Playwright and what you can use it for.

Read more

#### [How to take screenshots with Puppeteer](/blog/how-to-take-a-screenshot-with-puppeteer/)

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

Read more

#### [How to Take Screenshots with pyppeteer in Python](/blog/pyppeteer-python-screenshots/)

Guide to taking screenshots with pyppeteer in Python. Learn the basics, full page captures, and why you should migrate to Playwright.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/200000-arr-and-400-paying-customers
----

ScreenshotOne reached $200K ARR with 400+ paying customers

==========================================================

It is a good milestone to make a compact snapshot of the insights that (maybe?) led to it.

[Blog post](/blog/) 7 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Apr 10, 2025

I want to share my journey and appreciation I have for it with all of you, my customers, my supporters, my friends and my family.

ScreenshotOne has been launched almost 3 years ago. And now, it reaches $200,000 in annual recurring revenue with 400+ paying customers.

It feels like I just shared [the lessons learned from the first marketing month](https://dmytrokrasun.com/posts/lessons-learned-from-the-first-marketing-month/) a few days ago. Time flies.

I don’t believe it. It is crazy!

A blog post instead of social media

-----------------------------------

A lot of ScreenshotOne customers come from Google and they might not now know it, but I actively share everything about building and growing ScreenshotOne on X, LinkedIn, Bluesky and Threads.

[](https://x.com/dmytrokrasun/status/1896121242559930828)

But I have never shared all these numbers, thoughts and ideas in the ScreenshotOne blog. I think that for this particular case, the blog format fits better than sharing on X or LinkedIn.

I will consider using this format in the future, too. I can write a post once including all the details and graphics the way I want it and then distribute it on social media and other platforms.

And I am sure that the link will be saved, while on social I might be blocked and not everyone has access to it. I want to be able to share it with my friends, too.

Reaching $200K ARR

------------------

Fully bootstrapped and funded by lovely [ScreenshotOne customers](/customers/).

It feels unbelievable. And I am proud of the work that has been done and led ScreenshotOne to this milestone.

But it wouldn’t be possible without ScreenshotOne customers who value the product and share feedback with me, without the community of builders and makers I am part of, my friends and my family.

[](/blog/how-typeshare-uses-screenshotone/)

I am incredibly lucky to experience all that and appreciate a lot. But there is a lot of work ahead. And I am excited about it as never before.

Top 3 Insights

--------------

I can write forever about all the lessons I learned why building and growing ScreenshotOne. But! I don’t know precisely what worked and what not.

Even when backed with data, I still believe I am operating in the fog and guessing it.

However, somehow I managed to navigate to the current point even through the fog. How? I have a few guesses.

### 1\. Market, marketing and positioning

**The market you are in is everything.** It is banal, but it doesn’t make it less true.

If your market is growing, you will be growing too. It will literally pull you, especially if you managed to beat your competitors.

In my case, I managed to achieve the first positions on many marketing channels. But screenshotting is still a niche business and it is impossible to squeeze additional $5 million ARR in one year. There is no capacity for that.

**Positioning is how you resonate with your customers.** Without understanding whom you sell to, you can’t resonate with them. And can’t build a good product for them.

Ironically, it is counterintuitive, but [focusing on one specific customer persona won’t make you lose customers, but might bring even more](https://longform.asmartbear.com/icp-ideal-customer-persona/).

If you don’t have any idea whom you are going to sell your product, don’t build it. Either do more research, or do build it an still do research, or bet on something else. But a have a picture in your mind of your ideal customer profile. I don’t believe you can progress without it.

Positioning determines your blog posts, channels, tweets, features, pricing… It is everything.

**Marketing** is both your product, your positioning and how you distribute it. But I want to emphasize one thing, which is unpopular, but a good product might sell!

I often see launches by people and go and try their product. And even I wanted to buy it, I can’t. Cause many products just don’t work. [Make it work, make it simple and make it lovable](https://longform.asmartbear.com/slc/).

I can’t emphasize enough how much easier it is to sell a working and good product.

### 2\. Focus, obsession and stubbornness

> “Get rich by focus. Stay rich by diversification.”

Launched a product in the niche that is validated and already has many products and money. Stick with it. Keep improving the product. Make everything possible but find your first users.

If the market is validated, there is zero reason to fail. You can’t fail literally.

By the way, Screenshot APIs is a bad example. Cause there is not a lot of money, but harsh competition.

### 3\. Do not stop experimenting

The opposite to what I write above, yes? But it is good for your soul. And what is good for your mental health, is good for your business.

No matter how focused you are, but anyway!

Launch side projects, go on hikes, meet new people, take vacations… All that compounds and might reveal new insights for your main product.

For, example, I launched a new product for tracking brand visible in LLMs and optimizing marketing for LLMs. While building it and checking ScreenshotOne’s presence in AI, I realized how much more work I need to do it to improve its visibility.

And I tried a new technology—PostgreSQL, and assessed if it could fit ScreenshotOne better than current one—MySQL. And the short answer is “maybe”.

But now I am refreshed and feel that I can double-down on ScreenshotOne long-term.

Future

------

The same as with insights, I could dump my whole backlog and you would see how many things I want to build.

### 1\. Hiring?

I don’t plan to hire anybody for full-time role, anytime soon. Since I have enough time to keep up with all the customer demand.

However, one of the things I didn’t have time on is to redesign the marketing website and adjust it for my growing marketing needs.

But I was lucky to order a redesign from [Alex Szhzurek from uncoverLAB](https://uncoverlab.co/) and the current marketing website version while still in progress is her work.

And part-time front-end developer to help implement all her ideas—[Piotr Kulpinski](https://kulpinski.dev/). I can’t stress enough how skilled are these people and how I am impressed by their work.

They are both the top professionals in their fields and it is the level of work you will rarely see.

### 2\. Product Quality

Obsessing over delivering the best product for my customers is that the thing that I will keep doing daily.

Whatever ScreenshotOne customers asks in the support chat and whatever features they request, I try to solve all their needs as fast as possible.

That means also updating documentation, updating our playground, crafting SDKs and everything that leads to better UI/UX/DX of using and integrating ScreenshotOne.

However, product quality is never done. I want to render screenshots faster, have lower error rate and less bugs. Nobody needs to tell me this, I know that happens.

### 3\. More features?

I managed to keep only 2 major features in ScreenshotOne: regular screenshots and videos. And almost haven’t added any new significant parameters and API methods for the past 2 years. It allowed me to polish the product and make it laser-focused on solving one simple task, but solve it well.

However, my customers ask more and more about other features for the screenshot API:

1.  Scheduled screenshots.

2.  Long-term archival of screenshots.

3.  Comparing screenshot differences.

4.  More native integrations with Make and other no-code tools.

Also, we need to improve the dashboard:

1.  Managing organizations.

2.  More granularity and configuration of API keys.

3.  Better onboarding.

And more. I think, it is time to give up and start adding more features that people ask me.

### 4\. Money

Do you think there is still value sharing my MRR for somebody except for my competitors?

I share it now as a habit, partially as marketing, partially I like seeing others learning from what I do, building and succeeding, too.

But money is not a huge focus for me anymore, why then talking about something that I don’t care? It is an open question for me. It also does attract copycats. People reach out even and ask questions about how I implement some features, I try to answer and help everybody. But I feel it becomes dumber and dumber idea. And it plays against me. Which doesn’t make any sense.

My personal goals

-----------------

There is a human behind ScreenshotOne. And as many other humans, this one wants to take a real vacation, at least once in the past 3 years. Real vacation means something hiking 7 days without the Internet and keep ScreenshotOne operational.

How I will achieve that is another question. But that one of the goals that seems important to me. I keep working daily, but it is not sustainable long-term.

I must automate more and more processes, and if needed hire people to help me. Maybe even as a backup for myself.

That seems like a real next challenge for me, personally.

A last few words

----------------

Thank you for reading! And I really really wish more people experienced what it feels to serve customers by building a product they love.

Read more posts

---------------

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

[View all posts](/blog/)

#### [Unveil the Power of Automation with ScreenshotOne and Zapier](/blog/unveil-the-power-of-automation-with-screenshotone-and-zapier/)

I am thrilled to announce an exciting update for the ScreenshotOne users – the much-anticipated integration of ScreenshotOne with Zapier. This powerful combination is here to enhance your automation journey and expand your workflow capabilities to new heights.

Read more

#### [ScreenshotOne made it to the official Make conference](/blog/make-conference/)

One of our friends noticed ScreenshotOne at the official Make conference

Read more

#### [Building a website directory with Next.js, Tailwind CSS, and Prisma](/blog/building-a-website-directory-with-nextjs-tailwind-css-and-prisma/)

See how easy it is to build a website directory with screenshots with Next.js, Tailwind CSS, and Prisma.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/code-examples/javascript-and-typescript-nodejs
----

[Skip to content](#_top)

JavaScript and TypeScript (Node.js) SDK and Code Examples

=========================================================

Copy page

Note

If you have any questions, please, reach out at `support@screenshotone.com`.

### Installation

Run the next command to install the JavaScript and TypeScript Node.js SDK to take screenshots:

Terminal window

    1npm install screenshotone-api-sdk --save

### Usage

Don’t forget to [sign up](https://dash.screenshotone.com/sign-up) to get access and secret keys.

Danger

By default, the generated URL by SDK is not signed, and you can’t share it, because the API key will be leaked.

Use the method designated to generate a signed URL specifically—`generateSignedTakeURL()`.

Notice, in the recent versions of the SDK, all methods are asynchronous.

Generate a screenshot URL without executing the request. Or download the screenshot. It is up to you:

    1import * as fs from "fs";2import * as screenshotone from "screenshotone-api-sdk";3

    4// create API client5const client = new screenshotone.Client("<access key>", "<secret key>");6

    7// set up options8const options = screenshotone.TakeOptions.url("https://example.com")9    .delay(3)10    .blockAds(true);11

    12// generate URL13const url = client.generateTakeURL(options); // or generateSignedTakeURL(options) for signed URLs14console.log(url);15// expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com&delay=3&block_ads=true&access_key=%3Caccess+key%3E16

    17// or download the screenshot18const imageBlob = await client.take(options);19const buffer = Buffer.from(await imageBlob.arrayBuffer());20fs.writeFileSync("example.png", buffer);21// the screenshot is store in the example.png file

Check out [other SDKs and code examples](/docs/code-examples/).

----
url: https://screenshotone.com/blog/how-to-render-html-with-puppeteer
----

How to render HTML with Puppeteer

=================================

Use Puppeteer or screenshot API to generate the Open Graph protocol images, bills, receipts, or invoices PDF or PNG files from the HTML templates.

[Blog post](/blog/) 3 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Mar 13, 2026

#### Tags

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

Use cases for rendering HTML

----------------------------

There are many use cases when rendering HTML is proper:

*   generate bills, receipts, or invoices PDF or PNG files from the HTML templates;

*   dynamically create images for the Open Graph protocol;

*   generate marketing images at scale from templates;

*   create images for essays and writings to share on social networks;

*   make images for ads from the HTML templates;

*   and many more.

And it is super easy to do with Puppeteer.

Render HTML with Puppeteer

--------------------------

Puppeteer has a method `page.setContent(html, options)` to render HTML, it is easy and convenient to use. But don’t forget to install the Puppeteer library:

Terminal window

    1npm i puppeteer

And then, try it:

    1const puppeteer = require("puppeteer");2

    3(async () => {4    const browser = await puppeteer.launch({});5    try {6        const page = await browser.newPage();7        await page.setContent("<h1>Hello, world!</h1>");8

    9        await page.screenshot({ path: "hello_world.png" });10    } catch (e) {11        console.error(e);12    } finally {13        await browser.close();14    }15})();

The result is predictable:

In case if your HTML contains links to externals resources like styles, scripts, fonts, or other kind of external resources, you can specify timeout and wain until “event”:

    1const puppeteer = require("puppeteer");2

    3(async () => {4    const browser = await puppeteer.launch({});5    try {6        const page = await browser.newPage();7        await page.setContent("...", {8            timeout: 30000,9            waitUntil: "load", // or one of 'domcontentloaded' | 'networkidle0' | 'networkidle2'10        });11

    12        await page.screenshot({ path: "hello_world.png" });13    } catch (e) {14        console.error(e);15    } finally {16        await browser.close();17    }18})();

Always specify a timeout to make sure that the request does not hang. And you can specify the `waitUntil` option:

*   `load` — consider navigation to be finished when the load event is fired;

*   `domcontentloaded` — consider navigation to be finished when the DOMContentLoaded event is fired.

*   `networkidle0` — think navigation to be finished when there are no more than 0 network connections for at least 500 ms.

*   `networkidle2` — think navigation to be finished when there are no more than 2 network connections for at least 500 ms.

Check out our guide on [how to wait for page load](/blog/puppeteer-wait-until-the-page-is-ready/) for more details.

Using html2canvas library

-------------------------

In case you need to render HTML or to take screenshots right at the client-side, in the browser, there is a magic library html2canvas. The library traverses the given HTML and renders in the canvas.

It is very easy to use. Install it:

Terminal window

    1npm install html2canvas

And then use:

    1import html2canvas from "html2canvas";2

    3html2canvas(document.body).then(function (canvas) {4    document.body.appendChild(canvas);5});

The beauty of the library is that you can take a screenshot of the page or render HTML to canvas and then images right in the browser. The downside is that library output might differ from the actual output. And it might miss the latest CSS features. So, you use it at your own risk. But for simple HTML, it should be enough.

Using API to render HTML

------------------------

Using API is better when you have large volumes to take screenshots. In this case, you don’t need to be afraid that you can handle them and tweak Puppeteer. Or you want to make sure that you always render with the latest version of the browser.

If you don’t want to set up and manage Puppeteer, you can use our [scalable and reliable API to render PDF or images from HTML](https://screenshotone.com). It supports [native libraries to take screenshots](/docs/code-examples) for many languages

And now look how simple it is to render HTML:

    1GET https://api.screenshotone.com/take?html=<h1>Hello,%20world!</h1>&access_key=<your access key>

The result is the same as using Puppeteer:

I hope I helped you and have a nice day 👋

You also might find helpful:

*   [the complete guide on how to take a screenshot with Puppeteer](/blog/how-take-a-screenshot-with-puppeteer)

*   [how to add custom styles to a page in Puppeteer](/blog/how-to-add-custom-styles-to-a-page-in-puppeteer)

*   [how to add custom scripts to a page in Puppeteer](/blog/how-to-add-custom-scripts-to-a-page-in-puppeteer)

Read more Puppeteer guides

--------------------------

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

[View all posts](/blog/tags/puppeteer-guides/)

#### [How to render screenshots with Playwright](/blog/how-to-render-screenshots-with-playwright/)

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

Read more

#### [Let's build a screenshot API](/blog/building-screenshot-api/)

Two years have passed since the launch of ScreenshotOne, and I want to do a fun coding exercise and build a tiny subset of what the API is today, but from scratch.

Read more

#### [How to take website screenshots with Go](/blog/how-to-take-website-screenshots-with-go/)

The article examines how you can take screenshots of any URL with Go (a.k.a. Golang) by using Selenium, Puppeteer alternatives, Playwright, or screenshot API as a service.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/terms-of-service
----

Terms of Service

================

Introduction

------------

These terms of use (the “Terms”) apply to your access and use of our subscription-based API service (the “Service”). By accessing or using the Service, you agree to be bound by these Terms. If you do not agree to these Terms, do not use the Service.

Privacy

-------

We are committed to protecting your privacy and personal data. We will only use your personal data in accordance with our privacy policy, which is available on our website. Please review our [Privacy Policy](/privacy-policy/) carefully before using the Service.

License

-------

Subject to your compliance with these Terms, we grant you a limited, non-exclusive, non-transferable, non-sublicensable license to access and use the Service.

Restrictions

------------

You agree not to (a) access the Service in a manner that could damage, disable, overburden, or impair the Service or interfere with any other party’s use of the Service; or (b) use the Service for any illegal or unauthorized purpose.

Termination

-----------

We reserve the right to terminate or suspend your access to the Service at any time, for any reason, and without notice.

Disclaimer of Warranties

------------------------

The Service is provided “as is” and “as available” without warranties of any kind. We do not guarantee that the Service will be available at all times or that it will be error-free.

Limitation of Liability

-----------------------

In no event shall we be liable for any damages arising out of or in connection with the use of the Service.

Changes to These Terms

----------------------

We reserve the right to modify these Terms at any time. We will post any changes on this page and encourage you to review the Terms regularly. Your continued use of the Service after any changes have been made will constitute your acceptance of the revised Terms.

Entire Agreement

----------------

These Terms constitute the entire agreement between you and us regarding the use of the Service and supersede any prior agreements.

ChatGPT plugin

--------------

ScreenshotOne can be used as [a ChatGPT plugin for rendering HTML or websites as images](/blog/screenshotone-is-available-as-a-chatgpt-plugin/). All terms and conditions stay the same for the plugin since the plugin is not publicly available but is used on a per-user basis by specifying your private access key.

Contact

-------

[Contact](/contact/) if you have any questions, objections, or requests.

----
url: https://screenshotone.com/use-cases/nemoclaw-agents
----

Automate Website Screenshots

3 min read

Screenshots for NemoClaw Agents

===============================

Use ScreenshotOne with NemoClaw to capture website screenshots for enterprise AI agents, browser verification, secure reporting, and visual audit trails.

NemoClaw is positioned around enterprise AI agents, privacy-aware deployment, open-source flexibility, and integrations for teams that need more control over how agents run in production.

That changes what screenshots are used for. The need is less about simple chat updates and more about giving an agent reliable visual evidence it can attach to a workflow, escalation, review, or internal report.

If you want a more assistant-like workflow that lives inside chat apps and sends proactive updates, see [Screenshots for OpenClaw Workflows](/use-cases/openclaw-workflows/). OpenClaw leans more toward personal assistant behavior across messaging channels, while NemoClaw is the better fit for enterprise control, internal operations, and auditability.

[ScreenshotOne fits naturally here](/nemoclaw/). Let NemoClaw handle agent orchestration, deployment choices, and enterprise workflow logic. Let ScreenshotOne handle the hard part of rendering modern websites reliably and returning clean screenshots your agents can inspect, store, or forward.

Where ScreenshotOne fits in a NemoClaw stack

--------------------------------------------

If NemoClaw is coordinating browser-capable agents, screenshots become a practical checkpoint between action and decision. Instead of trusting only extracted text or DOM output, the agent can capture what the page actually looked like at the moment the workflow finished.

That keeps the flow simple:

1.  A NemoClaw agent receives a browser or monitoring task.

2.  It sends the target URL to ScreenshotOne.

3.  It gets a reliable screenshot back.

4.  It attaches that image to the next step, report, or escalation.

NemoClaw workflows that benefit from screenshots

------------------------------------------------

### Browser task verification

If an agent logs into a dashboard, checks a back office page, publishes something, or completes a browser step, a screenshot gives you a clear final-state record. That makes reviews easier and helps operators confirm that the agent reached the expected page.

This is useful for:

*   verifying post-action page state

*   confirming that a workflow reached the right confirmation screen

*   attaching visual context to failed runs

*   giving human reviewers evidence before approving the next step

### Secure internal reporting

Enterprise agent workflows often end in internal reporting, not public messages. Screenshots make those reports easier to trust. Instead of a summary that says a page changed or a task completed, NemoClaw can attach the visual result for analysts, operators, or compliance teams.

### Scheduled monitoring with audit trails

If NemoClaw is used for recurring checks, ScreenshotOne can capture landing pages, product pages, help centers, partner portals, or status pages on a schedule. That gives your team a visual trail over time instead of only text diffs or event logs.

### Research, compliance, and escalation

When agents gather information from the web, screenshots make handoffs cleaner. A report with links and extracted notes is useful, but a report with visual evidence is easier to validate, archive, and share internally.

Why use ScreenshotOne with NemoClaw instead of building it in-house?

--------------------------------------------------------------------

Even in an enterprise AI stack, browser rendering is still its own infrastructure problem. Timing issues, lazy-loaded interfaces, modern frontend frameworks, anti-bot protections, and output consistency all make screenshots harder than they look.

ScreenshotOne gives NemoClaw a focused service for that layer, so your team can keep agent logic, deployment boundaries, and review workflows separate from the operational burden of running screenshot infrastructure.

If you are building NemoClaw workflows that touch the web, ScreenshotOne is a straightforward way to add visual context, stronger auditability, and more dependable reporting.

ScreenshotOne is a really helpful service provider. All that I need for my work is combined here.

Service is comfortable, fast, and consistent. It has a nice support service that always stays active to problems of users and has an immediate response time.

I really appreciate and recommend ScreenshotOne to everyone.

Alexandr Bezhan

Chief Product Officer, [AMS Pilot](https://www.amspilot.com/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

### Screenshots for OpenClaw Workflows

Use ScreenshotOne to automate website screenshots inside OpenClaw workflows for visual checks, proactive monitoring, and image-based reporting.

[Read more →](/use-cases/openclaw-workflows/)

### Landing Page Evaluation with AI

Automate landing page roasting for your customers or yourself with modern technologies like OpenAI Vision.

[Read more →](/use-cases/ai-landing-page-roasting/)

### AI Agents With Browser Observation

Give AI agents reliable screenshots of web pages so they can inspect, compare, and act with visual context.

[Read more →](/use-cases/ai-agents/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/errors/selector-not-found
----

[Skip to content](#_top)

Selector Not Found

==================

Copy page

It is an API error returned when the specified selector is not found or not visible within the given timeout period.

    1{2    "is_successful": false,3    "error_code": "selector_not_found",4    "error_message": "If `selector` is specified and `error_on_selector_not_found`=true, or `click` is specified and `error_on_click_selector_not_found`=true, the error will be returned if the element by selector is not visible or it took more than timeout seconds to render it, but not more than 30 seconds.",5    "documentation_url": "https://screenshotone.com/docs/errors/selector-not-found/"6}

Reasons and how to fix

----------------------

### Selector Not Visible

The most common reason for the “selector\_not\_found” error is that the element specified by the selector is not visible on the page within the given timeout period.

To fix this, you can:

1.  **Check the selector**: Ensure that the selector you are using is correct and matches an element on the page.

2.  **Increase timeout**: If the element takes longer to load, increase the timeout value to give the element more time to become visible.

### Element is visible but has zero height

If there is an empty element on the page, the API will not be able to take a screenshot of it. In that case you will still get the “selector\_not\_found” error.

One of the ways to still get a screenshot is to make sure that [`error_on_selector_not_found`](https://screenshotone.com/docs/options/#error_on_selector_not_found) is set to `false` (and it is `false` by default).

You will get then the screenshot of the page instead of the error.

### Incorrect Selector

An incorrect or invalid selector can lead to this error, as the API cannot find the element on the page.

To fix this, verify that the selector is correctly specified and matches the element you want to target.

### Element Not Rendered

If the element is not rendered within the timeout period (not more than 30 seconds), the error will be triggered.

To fix this, ensure that the element is being rendered properly and within the expected time frame. You might need to investigate any delays in rendering the element.

### Conditional Visibility

If the element’s visibility is conditional (e.g., depends on user interaction or specific page states), it might not be visible when the API checks for it.

To fix this, ensure that the conditions for the element’s visibility are met before making the API request.

### Page Load Issues

Page load issues or JavaScript errors on the page can prevent the element from becoming visible.

To fix this, check for any page load issues or JavaScript errors that might be interfering with the rendering of the element.

Reach out to support

--------------------

If you continue to face issues or need further assistance, please reach out to `support@screenshotone.com`, and we will assist you as soon as possible.

----
url: https://screenshotone.com/docs/errors/request-aborted
----

[Skip to content](#_top)

Request Aborted

===============

Copy page

It is an API error returned when the request was aborted either by the user or the intermediate proxies and can’t be fulfilled.

    1{2    "is_successful": false,3    "error_code": "request_aborted",4    "error_message": "The request was aborted either by the user or the intermediate proxies and can't be fulfilled. If the error persists, please, reach out to `support@screenshotone.com`.",5    "documentation_url": "https://screenshotone.com/docs/request-aborted/"6}

Reasons and how to fix

----------------------

### HTTP Client Timeouts

One common reason for the “request\_aborted” error is HTTP client timeouts. This occurs when the client (e.g., a web browser or a server making a request) has a timeout setting that is shorter than the time it takes for the request to be processed.

To fix this, you can increase the timeout setting in your HTTP client configuration.

### Local Development Live Reloading

During local development, live reloading tools (such as those used in web development environments) may cause requests to be aborted if the server restarts or if the code is recompiled. This can lead to the “request\_aborted” error.

To avoid this, ensure that you have a stable development environment and minimize the frequency of live reloads while making API requests.

### Edge Function Timeouts

If you are using edge functions or serverless functions (e.g., AWS Lambda, Vercel Edge Functions), they might have their own timeout settings. When these timeouts are exceeded, the request will be aborted, resulting in the “request\_aborted” error.

To fix this, you should increase the timeout settings for your edge functions.

Reach out to support

--------------------

If nothing helps you, please, reach out to `support@screenshotone.com` and we will try to help you as fast as possible.

----
url: https://screenshotone.com/blog/9
----

Automate Website Screenshots

----------------------------

Guides, Product Updates, and Helpful Resources from ScreenshotOne.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

#### [ScreenshotOne is featured on MicroLaunch](/blog/featured-on-microlaunch/)

ScreenshotOne is featured on MicroLaunch

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Apr 7, 2024

•

1 min read

#### [How to make beautiful screenshots on macOS](/blog/screenshots-on-macos/)

I do write a lot about how to automate website screenshots, but I rarely share about what tools I use to make beautiful screenshots on the daily basis.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Apr 7, 2024

•

1 min read

[Engineering](/blog/tags/engineering/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Let's build a screenshot API](/blog/building-screenshot-api/)

Two years have passed since the launch of ScreenshotOne, and I want to do a fun coding exercise and build a tiny subset of what the API is today, but from scratch.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

May 26, 2024

•

16 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Why and how to choose a screenshot API](/blog/why-and-how-to-choose-a-screenshot-api/)

You don't need a screenshot API if it is a one-off task for you and you can use some library for screenshotting.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 20, 2024

•

6 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [3 best screenshot APIs in 2026](/blog/best-screenshot-apis/)

The truth is, that there is no single best screenshot API that fits everyone. But some APIs stand out and shine when compared to others. Also, it depends on your use case and needs which must be included in considering what API to use.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jan 6, 2026

•

7 min read

#### [Rendering screenshot with Browserless](/blog/browserless/)

A few words about what is Browserless, when to use it, and if it is suitable for screenshots or not.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

May 6, 2024

•

4 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Stagetimer automates Open Graph image generation](/blog/how-stagetimer-automates-og-image-generation/)

We would love to share a quick review of ScreenshotOne by Lukas Hermann, a co-founder of Stagetimer on how he uses the API daily to generate screenshots and automate regular tasks associated with screenshots.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Lukas Hermann](/contributors/lukas-hermann/)

Published on

Mar 5, 2024

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Elias Stråvik uses GPT-4 Vision and Zapier for landing page feedback automation](/blog/generating-landing-page-feedback-with-vision/)

A quick review of ScreenshotOne by Elias Stråvik, a founder of Roast as A Service on how he uses the ScreenshotOne daily to automate regular tasks associated with screenshots.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Elias Stravik](/contributors/elias-stravik/)

Updated on

Mar 4, 2024

•

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/tags/playwright-guides
----

Playwright Guides

-----------------

How-to posts and troubleshooting guides for Playwright-based automation.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

[Playwright guides](/blog/tags/playwright-guides/)

#### [Playwright "Execution context was destroyed": how to fix navigation and page.evaluate errors](/blog/playwright-execution-context-was-destroyed-most-likely-because-of-a-navigation/)

Fix the Playwright "Execution context was destroyed, most likely because of a navigation" error after click, form submit, redirect, reload, or page.evaluate.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 13, 2026

•

4 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/) [Playwright guides](/blog/tags/playwright-guides/)

#### [How to Take Full Page Screenshots with Playwright in Python](/blog/playwright-python-full-page-website-screenshots/)

Learn how to capture full page screenshots with Playwright in Python. Master the full\_page parameter, handle infinite scroll pages, lazy-loaded images, and maximum size limits.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 17, 2026

•

4 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/) [Playwright guides](/blog/tags/playwright-guides/)

#### [How to Take Website Screenshots with Playwright in Python](/blog/playwright-python-screenshots/)

A complete guide to taking website screenshots with Playwright in Python. Learn page.screenshot() parameters, async patterns, element screenshots, dark mode, and device emulation.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 16, 2026

•

5 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/) [Playwright guides](/blog/tags/playwright-guides/)

#### [How to Take Bulk Screenshots with Playwright in Python](/blog/bulk-screenshots-playwright-python/)

Learn how to automate bulk website screenshots with Playwright in Python. Master async batch processing, concurrent screenshots, rate limiting, and error handling for large-scale screenshot automation.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 14, 2026

•

7 min read

[Playwright guides](/blog/tags/playwright-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to render screenshots with Playwright](/blog/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](/contributors/dmytro-krasun/)

Published on

Apr 29, 2025

•

10 min read

[Playwright guides](/blog/tags/playwright-guides/)

#### [What is Playwright](/blog/playwright/)

What is Playwright and what you can use it for.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

May 6, 2024

•

2 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Playwright guides](/blog/tags/playwright-guides/)

#### [Puppeteer versus Playwright](/blog/puppeteer-versus-playwright/)

When to use Playwright and when to use Puppeteer.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

May 6, 2024

•

2 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/options
----

[Skip to content](#_top)

Screenshot Options

==================

Copy page

This document lists all available request options to take screenshots of websites, render HTML, or Markdown.

Credentials

-----------

### access\_key

Each request must have an access key to authenticate the API user. You can find it on the [access page](https://dash.screenshotone.com/access).

An example of the request URL with `access_key`:

    1https://api.screenshotone.com/take?url=https://apple.com&access_key=<your access key>

### signature

A signature is optional. It is used for [the signed requests](/docs/signed-requests).

Do not use the secret (signing) key as a signature. A signature is a complex parameter that is [a hash of all screenshot parameters with a signing key](/docs/signed-requests).

You can force signing all requests [access page](https://dash.screenshotone.com/access).

Essentials

----------

### url

URL of the site to take a screenshot of. One of the [Markdown](#markdown), [HTML](#html) or [URL](#url) parameters is required.

An example of the request URL with `url=https://www.youtube.com/feed/explore`:

    1https://api.screenshotone.com/take?url=https://www.youtube.com/feed/explore&access_key=<your access key>

### html

HTML you want to render. One of the [Markdown](#markdown), [HTML](#html) or [URL](#url) parameters is required.

An example of the request URL with `html=<h1>Hello, world!</h1>`:

    1https://api.screenshotone.com/take?html=<h1>Hello,%20world!</h1>&access_key=<your access key>

### markdown

Markdown you want to render. One of the [Markdown](#markdown), [HTML](#html) or [URL](#url) parameters is required.

An example of the request URL with `markdown=# Hello, world!` (encoded to `markdown=%23%20Hello%2C%20world!`):

    1https://api.screenshotone.com/take?html=%23%20Hello%2C%20world!&access_key=<your access key>

### format

You can get the HTML content of the page and image in one request by using the [metadata\_content](#metadata_content) parameter.

Available response formats:

*   `png`

*   `jpeg` or `jpg`

*   `webp`

*   `gif`

*   `jp2`

*   `tiff`

*   `avif`

*   `heif`

*   `pdf` (see [PDF options](#pdf-rendering))

*   `html` (text representation)

*   `markdown` (text representation)

Default value is `jpg`.

An example of the request URL with `format=jpeg` (an alias for `format=jpg`):

    1https://api.screenshotone.com/take?format=jpeg&url=https://apple.com&access_key=<your access key>

For the HTML format (`format=html`), consider including the shadow DOM elements with the [`include_shadow_dom`](#include_shadow_dom) option.

### response\_type

Available response types:

*   `by_format` — return exactly the response defined in the [format option](#format). If `format=png`, the response will be the binary representation of the `png` with the content type header `image/png`. **With this option (default), screenshots are not stored on ScreenshotOne servers** unless you explicitly enable [caching](#caching), [storage](#storing) options or similar.

*   `empty` — return only status or error. It is suitable when you want to [upload the screenshot to storage](#storing) and don’t care about the results. It also speeds up the response since there are no networking costs involved.

*   `json` — A method returns the response in the JSON format, but it is only suitable if you use options that are effective for JSON. By default, the JSON response will be empty. But for example, when you use [caching](#caching), the JSON will be populated with additional data. (This option might temporarily store the rendered content on ScreenshotOne servers to serve the screenshot or other content URLs for you.)

ScreenshotOne API doesn’t support the `base64` encoding format. But you can get the screenshot in the binary format and convert it to the `base64` encoding with your language of choice.

The default value is `by_format`.

An example of the request URL:

    1https://api.screenshotone.com/take?response_type=empty&url=https://example.com&access_key=<your access key>

### selector

A CSS-like selector of the element to take a screenshot of. It is optional.

If the selector is specified and `error_on_selector_not_found=true`, the error will be returned if the element by selector is not visible or it took more than `timeout` seconds to render it, but not more than 30 seconds.

For HTML or Markdown formats, the selector returns the outer rendered HTML of the provided input.

Supports `shadow/` selectors which will traverse the shadow DOM elements. It will be slower, and if many elements have the same selectors, the first one will be chosen.

An example of the request URL with `selector=.content`:

    1https://api.screenshotone.com/take?selector=.content&url=https://scalabledeveloper.com/posts/context-in-go/&access_key=<your access key>

The same page without selector:

    1https://api.screenshotone.com/take?url=https://scalabledeveloper.com/posts/context-in-go/&access_key=<your access key>

Setting the [selector](#selector) option changes the behavior of the [capture\_beyond\_viewport](#capture_beyond_viewport) option, and sets it to `true` by default.

### selector\_algorithm

The default algorithm is `default` which means to use the browser tools to screenshot the element by selector. But the new algorithm `clip` allows more flexibility and better results for some cases.

E.g. if you need to screenshot the element by selector and the element is not fully visible, or it requires scrolling to screenshot the element, the `clip` algorithm will be more suitable.

An example of the API request URL with `selector_algorithm=clip`:

    1https://api.screenshotone.com/take?selector_algorithm=clip&selector=h1&url=https://example.com&access_key=<your access key>

### selector\_scroll\_into\_view

When you take a screenshot of an element by [selector](#selector), there is a rare case where the page or the part of the element might not be visible on the viewport or the element might contain lazy loaded images or elements that are not visible on the viewport.

With the `selector_scroll_into_view` option, you control if you want to scroll the page to the element or not and to trigger lazy loaded images and elements.

The option is set to `true` by default.

### capture\_beyond\_viewport

When you take [a full page screenshot](#full_page) or a screenshot of an element by [selector](#selector), there is a rare case where the page or the part of the element might not be visible on the viewport.

With the `capture_beyond_viewport` option, you control if you want to take the screenshot of the full page or the element (`capture_beyond_viewport=true`) or if you are OK with taking a screenshot of the part of the page or the element (`capture_beyond_viewport=false`).

When you take [full page screenshot](#full_page) or you take screenshot of an element by [selector](#selector).

The option is set to `true` by default for the full-page screenshots, when [full\_page](#full_page) is `true`.

You might find it useful to check out [the examples of how the captureBeyondViewport option works](/blog/capture-beyond-viewport-in-puppeteer-and-chrome-devtools-protocol) “examples of how the captureBeyondViewport option works”).

The option is `true` by default for the screenshots by the [selector](#selector), too.

### scroll\_into\_view

It scrolls the page if needed and ensures that the given selector is present in the view when taking a screenshot.

If more than one element matches the selector, the first visible element in DOM is selected.

The element will be positioned at the top of the viewport. To adjust the position a bit before taking a screenshot, use the [scroll\_into\_view\_adjust\_top](#scroll_into_view_adjust_top) option.

In case, if the selector is not found, it will render the viewport at the top of the page. To change this behavior, use the [error\_on\_selector\_not\_found](#error_on_selector_not_found) option, set it to `true` to return an error if the selector is not found.

An example of the request URL:

    1https://api.screenshotone.com/take?scroll_into_view=%23faq&url=https://screenshotone.com&access_key=<your access key>

### scroll\_into\_view\_adjust\_top

After the given element appears in the viewport and its top coordinate is aligned with the viewport’s top, you can adjust the position a bit before taking a screenshot by specifying the `scroll_into_view_adjust_top` parameter.

By default, it is `0`. But you can use negative and positive integers.

An example of the request URL:

    1https://api.screenshotone.com/take?scroll_into_view_adjust_top=-100&scroll_into_view=%23faq&url=https://screenshotone.com&access_key=<your access key>

### request\_gpu\_rendering

By default is disabled and currently available only for the top-tier paid plans.

Setting `request_gpu_rendering` to `true` hints API to route requests to servers with supported hardware rendering acceleration.

It is not 100% guaranteed to satisfied and software acceleration might be used as a fallaback, but most of the time the ScreenshotOne API will do its best to render screenshots with GPU support if the option is set to `true`.

However, you can use the `fail_if_gpu_rendering_fails` option to force the request to fail if GPU rendering fails.

### include\_shadow\_dom

By default is disabled and equals to `false`.

Setting `include_shadow_dom` to `true` will use a different method of content extraction for requests that has `format=html` or request `metadata_content=true`. The API will try to include all open and closed shadow DOM roots in the content. By default, they are not included.

### attachment\_name

The option allows you to specify the name of the attachment. The format will be added as a suffix to the name.

    1https://api.screenshotone.com/take?attachment_name=screenshot&url=https://example.com&access_key=<your access key>&format=jpg

It will trigger the browser to download the screenshot with the name `screenshot.jpg`

### external\_identifier

You can set `external_identifier` parameter to any alphanumeric value. It will be included in the webhook request headers:

*   `x-screenshotone-external-identifier`—external identifier. It is helpful for error and successful request tracking.

PDF Rendering

-------------

If you want resulting PDF reflects a full page screenshot as close as possible, use the combination of next options:

    1format=pdf&media_type=screen&pdf_print_background=true&pdf_fit_one_page=true

### pdf\_print\_background

Set to `true` to print background graphics. The default value is `false`.

### pdf\_fit\_one\_page

The default value is `false`.

When the option is set to \`true“, the API will try to fit the website on one page. It is the closest equivalent to a full-page screenshot as a PDF without splitting into pages.

### pdf\_landscape

Set to `true` to set PDF orientation to landscape. It is `false` by default.

### pdf\_paper\_format

Specifies the paper format for the PDF output. Available options are:

*   “a0”: ISO A0 paper size (841 x 1189 mm)

*   “a1”: ISO A1 paper size (594 x 841 mm)

*   “a2”: ISO A2 paper size (420 x 594 mm)

*   “a3”: ISO A3 paper size (297 x 420 mm)

*   “a4”: ISO A4 paper size (210 x 297 mm)

*   “a5”: ISO A5 paper size (148 x 210 mm)

*   “a6”: ISO A6 paper size (105 x 148 mm)

*   “legal”: Legal paper size (8.5 x 14 inches)

*   **“letter”: Letter paper size (8.5 x 11 inches)—default.**

*   “tabloid”: Tabloid paper size (11 x 17 inches)

If not specified, the default paper format is “a4”.

### pdf\_margin

Specifies the margin for the PDF file. By default, the margin is `0`.

But you can set it to any value in string format, e.g. `pdf_margin=20px` or other supported units.

You can then override the margin for each side separately:

    1pdf_margin=20px&pdf_margin_top=0px

This will set the margin for all sides to `20px` except the top, which will be `0px`.

### pdf\_margin\_top

The top margin for the resulting PDF.

### pdf\_margin\_right

The top margin for the resulting PDF.

### pdf\_margin\_bottom

The top margin for the resulting PDF.

### pdf\_margin\_left

The top margin for the resulting PDF.

OpenAI Vision Integration

-------------------------

ScreenshotOne supports direct integration with [OpenAI vision](https://platform.openai.com/docs/guides/vision), so you can get a screenshot and generate vision prompt completion in one simple API call with no additional cost.

You will get the result either as a `X-ScreenshotOne-Vision-Completion` header in the reponse or as:

    1{2

    3    "vision": {4        "completion": "..."5    }6}

If you use `response_type=json`.

### openai\_api\_key

Use your OpenAI API key to send requests to the OpenAI API key. It is not stored in the ScreenshotOne database.

### vision\_prompt

Specify the prompt you want to use along with the screenshot of the site.

### vision\_max\_tokens

Specify how many tokens at max the GPT vision must return as a response.

Clip

----

There is a guide on [how to screenshot an area of a site](/docs/guides/how-to-screenshot-an-area-of-a-site/) with examples of how to use clip options.

### clip\_x

You can use clip options ([clip\_x](#clip_x), [clip\_y](#clip_y), [clip\_width](#clip_width), [clip\_height](#clip_height)) to clip only the part of the screen.

The `clip_x` option specifies only the top coordinate (x) of the area to clip.

### clip\_y

You can use clip options ([clip\_x](#clip_x), [clip\_y](#clip_y), [clip\_width](#clip_width), [clip\_height](#clip_height)) to clip only the part of the screen.

The `clip_y` option specifies only the left coordinate (y) of the area to clip.

### clip\_width

You can use clip options ([clip\_x](#clip_x), [clip\_y](#clip_y), [clip\_width](#clip_width), [clip\_height](#clip_height)) to clip only the part of the screen.

The `clip_width` option specifies only the width of the area to clip.

### clip\_height

You can use clip options ([clip\_x](#clip_x), [clip\_y](#clip_y), [clip\_width](#clip_width), [clip\_height](#clip_height)) to clip only the part of the screen.

The `clip_height` option specifies only the width of the area to clip.

Full page

---------

Read more suggestions on [how to take better full-page screenshots](/docs/guides/full-page-screenshots/).

### full\_page

To take the screenshot of the full page, set `full_page=true`.

Default value is `false`.

When `full_page` is set to `true`, [full\_page\_scroll](#full_page_scroll) is automatically set to `true`, until you override it. It is done to make sure that all lazy loaded images are requested and rendered.

An example of the request URL:

    1https://api.screenshotone.com/take?full_page=true&url=https://netflix.com&access_key=<your access key>

### full\_page\_scroll

If set to `true`, scrolls to the bottom of the page and back to the top. Default value is `false`.

When `full_page` is set to `true`, `full_page_scroll` is automatically set to `true`, until you override it. It is done to make sure that all lazy loaded images are requested and rendered.

An example of the request URL:

    1https://api.screenshotone.com/take?full_page_scroll=true&full_page=true&url=https://netflix.com&access_key=<your access key>

### full\_page\_scroll\_delay

The default value is `400` microseconds. Use it to specify how fast you want to scroll the page to the bottom.

Some sites require larger values than `400` microseconds to trigger the loading of lazy-load images.

Use it in combination with [full\_page\_scroll\_delay](#full_page_scroll_by) to find optimal solution.

An example of the request URL:

    1https://api.screenshotone.com/take?full_page_scroll_delay=1000&full_page_scroll=true&full_page=true&url=https://netflix.com&access_key=<your access key>

### full\_page\_scroll\_by

The default value is the height of the viewport. Use it to specify how fast you want to scroll the page to the bottom.

Some sites require values less than viewport height to trigger the loading of lazy-load images. Try to play with values between `100` and `500`. However, don’t hesitate to try out any value that might work for you.

Use it in combination with [full\_page\_scroll\_delay](#full_page_scroll_delay) to find optimal solution.

An example of the request URL:

    1https://api.screenshotone.com/take?full_page_scroll_by=400&full_page_scroll=true&full_page=true&url=https://netflix.com&access_key=<your access key>

### full\_page\_max\_height

The default value is not set. Use it to limit the height of the full page screenshot. Also allows to handle and fix problems related to infinite scrolling.

An example of the request URL:

    1https://api.screenshotone.com/take?full_page_max_height=10000&full_page_scroll=true&full_page=true&url=https://netflix.com&access_key=<your access key>

### full\_page\_algorithm

The default value is `default`.

The `default` algorithm is the same as the one used in the Chrome DevTools Protocol, with some tuning and for some websites with different optimizations.

But if you set `full_page_algorithm=by_sections`, the API will take a screenshot section by section and then combine them into one image. It allows more complex pages with animations to be rendered correctly.

The `by_sections` will scroll the website automatically regardless of the [full\_page\_scroll](#full_page_scroll) option value.

Viewport

--------

When rendering a full-page screenshot, the viewport dimensions play an important role and affect the quality of the screenshot, please, check out [the guide on how to take better full-page screenshots](/docs/guides/full-page-screenshots/) for more details.

### viewport\_device

**The default value is not set.**

Instead of manually specifying viewport parameters like width and height, you can specify a device to use for emulation. In addition, other parameters of the viewport, including the user agent, will be set automatically.

The `viewport_device` option sets the next options for you: [viewport\_width](#viewport_width), [viewport\_height](#viewport_height), [device\_scale\_factor](#device_scale_factor), [viewport\_mobile](#viewport_mobile), [viewport\_has\_touch](#viewport_has_touch), [viewport\_landscape](#viewport_landscape). You can change these options and override the ones set by the `viewport_device` option.

Use [the list of devices](/docs/viewport-devices/) for available values. Use the `id` property of the device as `viewport_device`, e.g. `viewport_device=galaxy_s9+_landscape`.

API does not use an actual device to take a screenshot. It is emulation that works in most cases.

An example of the request URL with `viewport_device=iphone_13_pro_max_landscape`:

    1https://api.screenshotone.com/take?viewport_device=iphone_13_pro_max_landscape&url=https://tailwindcss.com&access_key=<your access key>

### viewport\_width

If the [viewport\_device](#viewport_device) option is set, the parameter overrides it!

The width of the browser viewport (pixels).

The browser’s viewport is the window area where you can see the web content.

Default value is `1280`.

An example of the request URL with `viewport_width=1920` and `viewport_height=1080`:

    1https://api.screenshotone.com/take?viewport_width=1920&viewport_height=1080&url=https://apple.com&access_key=<your access key>

### viewport\_height

If the [viewport\_device](#viewport_device) option is set, the parameter overrides it!

The height of the browser viewport (pixels).

The browser’s viewport is the window area where you can see the web content.

Default value is `1024`.

An example of the request URL with `viewport_width=1920` and `viewport_height=1080`:

    1https://api.screenshotone.com/take?viewport_width=1920&viewport_height=1080&url=https://apple.com&access_key=<your access key>

### device\_scale\_factor

If the [viewport\_device](#viewport_device) option is set, the parameter overrides it!

Set the device scale factor, think of it as DPR (Device Pixel Ratio). The acceptable value is between the range of 1 and 5, including real numbers, like 2.25.

Set 2 if you need to render a screenshot with a higher pixel density like Apple’s Retina Display.

The parameter can override the value set by [viewport\_device](#viewport_device) option.

An example of the request URL with `device_scale_factor=1`:

    1https://api.screenshotone.com/take?device_scale_factor=1&url=https://apple.com&access_key=<your access key>

An example of the request URL with `device_scale_factor=2`:

    1https://api.screenshotone.com/take?device_scale_factor=2&url=https://apple.com&access_key=<your access key>

### viewport\_mobile

If the [viewport\_device](#viewport_device) option is set, the parameter overrides it!

Whether the [meta viewport](https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag) tag is taken into account. Defaults to `false`.

An example of the request URL with `viewport_mobile=true`:

    1https://api.screenshotone.com/take?viewport_mobile=true&url=https://example.com&access_key=<your access key>

### viewport\_has\_touch

If the [viewport\_device](#viewport_device) option is set, the parameter overrides it!

The default value is `false`. Set to `true` if the viewport supports touch events.

The parameter can override the value set by [viewport\_device](#viewport_device) option.

An example of the request URL with `viewport_has_touch=true`:

    1https://api.screenshotone.com/take?viewport_has_touch=true&url=https://example.com&access_key=<your access key>

### viewport\_landscape

If the [viewport\_device](#viewport_device) option is set, the parameter overrides it!

The default value is `false`. Set to `true` if the viewport is in landscape mode.

The parameter can override the value set by [viewport\_device](#viewport_device) option.

An example of the request URL with `viewport_landscape=true`:

    1https://api.screenshotone.com/take?viewport_landscape=true&url=https://example.com&access_key=<your access key>

Image

-----

### image\_quality

Render image with specified quality. Available for the next formats:

*   `jpeg` (`jpg`)

*   `webp`

*   `png`

*   `tiff`

*   `jp2`

*   `avif`

*   `hei`

Allowed range is between 0 and 100. Default value is `80`.

An example of the request URL with `image_quality=10`:

    1https://api.screenshotone.com/take?format=webp&image_quality=10&url=https://apple.com&access_key=<your access key>

### image\_width

The `image_width` and `image_height` parameters allow you to create a thumbnail of the screenshot.

By default `image_width` = [viewport\_width](#viewport_width) and `image_height` = [viewport\_height](#viewport_height).

If you specify image width and height parameters, the API will resize a screenshot, preserving the aspect ratio. The image will be resized to be as large as possible while ensuring its dimensions are less than or equal to the image width and height specified.

If you omit one of the parameters, the other is computed automatically, preserving the aspect ratio.

An example of the request with `image_width=500`:

    1https://api.screenshotone.com/take?image_width=500&url=https://example.com/&access_key=<access key>

### image\_height

The `image_width` and `image_height` parameters allow you to create a thumbnail of the screenshot.

By default `image_width` = [viewport\_width](#viewport_width) and `image_height` = [viewport\_height](#viewport_height).

If you specify image width and height parameters, the API will resize a screenshot, preserving the aspect ratio. The image will be resized to be as large as possible while ensuring its dimensions are less than or equal to the image width and height specified.

If you omit one of the parameters, the other is computed automatically, preserving the aspect ratio.

An example of the request with `image_width=500&image_height=400`:

    1https://api.screenshotone.com/take?image_width=500&image_height=400&url=https://example.com/&access_key=<access key>

### omit\_background

Render a transparent background for the image. Works only if the site has not defined background color. Available for the following response formats:

*   `png`

*   `webp`

Default value is \`false.

Set `omit_background=true` to take a screenshot with the transparent background.

Emulations

----------

### dark\_mode

The default value is not set.

Set `true` to request site rendering, if supported, in the dark mode. Set `false` to request site rendering in the light mode if supported. If you don’t set the parameter. The site is rendered in the default mode.

An example of the request URL with `dark_mode=true`:

    1https://api.screenshotone.com/take?dark_mode=true&url=https://tailwindcss.com/&access_key=<your access key>

### reduced\_motion

When `reduced_motion` set to `true`, the API will request the site to minimize the amount of non-essential motion it uses. When the site supports it, it should use animations as least as possible.

An example of the request URL with `reduced_motion=true`:

    1https://api.screenshotone.com/take?reduced_motion=true&url=https://tailwindcss.com/&access_key=<your access key>

### media\_type

If you want to request the page and it is supported to be rendered for printers, specify `print`. If the page is by default rendered for printers and you want it to be rendered for screens, use `screen`.

An example of the request URL with `media_type=print`:

    1https://api.screenshotone.com/take?media_type=print&url=https://example.com/&access_key=<your access key>

Customization

-------------

### hide\_selectors

The `hide_selectors` option allows hiding elements before taking a screenshot. You can specify as many selectors as you wish. **All** elements that match each selector will be hidden by setting the `display` style property to `none !important`.

An example of the request URL with `hide_selectors=.a&hide_selectors=.b`:

    1https://api.screenshotone.com/take?hide_selectors=.a&hide_selectors=.b&url=https://example.com/&access_key=<your access key>

### scripts

`scripts` parameter allows to inject custom JavaScript and customize the page behavior.

An example of the request URL with `scripts=document.body.innerHTML="Hello, world!"`:

If the script might trigger a redirect by using window.location functions or something similar, it is required to set [the “scripts\_wait\_until” option](#scripts_wait_until).

    1https://api.screenshotone.com/take?scripts=document.body.innerHTML="Hello,%20world!"&url=https://example.com/&access_key=<your access key>

">

### scripts\_wait\_until

The default value of `scripts_wait_until` is `[]` — nothing, no wait at all.

The `scripts_wait_until` option allows you to wait until a given set of events after the [scripts](#scripts) were executed. You need to use in case, if your script might trigger page reloading, like:

    1window.location = "https://example.com";

It accepts the same values as [wait\_until](#wait_until) and can have multiple values:

*   `load`: the navigation is successful when the load even is fired;

*   `domcontentloaded`: the navigation is finished when the DOMContentLoaded even is fired;

*   `networkidle0`: the navigation is finished when there are no more than 0 network connections for at least 500 ms;

*   `networkidle2`: consider navigation to be finished when there are no more than 2 network connections for at least 500 ms.

The parameter accepts many values. It means that screenshots will be taken after all events occur altogether.

An example of the request with `scripts_wait_until=networkidle2&scripts_wait_until=domcontentloaded`:

    1https://api.screenshotone.com/take?scripts_wait_until=networkidle2&scripts_wait_until=domcontentloaded&url=https://example.com/&access_key=<access key>

### styles

`styles` parameter allows to inject custom styles and customize the page. It might help generate beautiful images for the Open Graph protocol.

An example of the request URL with `styles=h1{color: red;}`:

    1https://api.screenshotone.com/take?styles=h1{color:%20red;}&url=https://example.com/&access_key=<your access key>

A screenshot without styles for comparison:

### click

Specify the CSS selector of an element to click on before taking the screenshot. It could be anything, including a button, link, or even a regular `div` element.

Supports `shadow/` selectors which will traverse the shadow DOM elements. It will be slower, and if many elements have the same selectors, the first one will be chosen.

An example of the request URL with `click=.a-some-button-class-selector`:

    1https://api.screenshotone.com/take?click=.a-some-button-class-selector&url=https://example.com&access_key=<your access key>

### hover

Specify the CSS selector of an element to hover on before taking the screenshot. It could be anything, including a button, link, or even a regular `div` element.

Supports `shadow/` selectors which will traverse the shadow DOM elements. It will be slower, and if many elements have the same selectors, the first one will be chosen.

An example of the request URL with `hover=.a-some-button-class-selector`:

    1https://api.screenshotone.com/take?hover=.a-some-button-class-selector&url=https://example.com&access_key=<your access key>

### error\_on\_click\_selector\_not\_found

If the element by selector to click is not visible or it took more than timeout seconds to render it, the error will be returned. Default value is `true`.

Set `error_on_click_selector_not_found=false` to do not throw an error if the element by selector is not found.

### error\_on\_hover\_selector\_not\_found

If the element by selector to hover is not visible or it took more than timeout seconds to render it, the error will be returned. Default value is `true`.

Set `error_on_hover_selector_not_found=false` to do not throw an error if the element by selector is not found.

Blocking

--------

### block\_cookie\_banners

Blocks cookie banners, GDPR overlay windows, and other privacy-related notices. Default value is `false` when the `url` option is set.

It is useful when you want to take “clean” screenshots.

An example of the request URL with `block_cookie_banners=true`:

    1https://api.screenshotone.com/take?block_cookie_banners=true&url=https://stackoverflow.com&access_key=<your access key>

An example of the request URL with `block_cookie_banners=false`:

    1https://api.screenshotone.com/take?block_ads=false&url=https://stackoverflow.com&access_key=<your access key>

### block\_banners\_by\_heuristics

The option might be helpful if the regular [block\_cookie\_banners](#block_cookie_banners) option doesn’t work. This parameter uses a different set of techniques and heuristics to block banners. But use it at your own risk. The site screenshot might not be precise with it.

Blocks cookie banners, GDPR overlay windows, and other privacy-related notices. Default value is `false`.

It is useful when you want to take “clean” screenshots, but the [block\_cookie\_banners](#block_cookie_banners) option doesn’t work.

An example of the request URL with `block_banners_by_heuristics=true`:

    1https://api.screenshotone.com/take?block_banners_by_heuristics=true&url=https://example.com&access_key=<your access key>

### block\_chats

Blocks chats like Crisp, Facebook Messenger, Intercom, Drift, Tawk, User.com, Zoho SalesIQ and many others. Default value is `false` when the `url` option is set..

It is useful when you want to take “clean” screenshots.

An example of the request URL with `block_chats=true`:

    1https://api.screenshotone.com/take?block_chats=true&url=https://screenshotone.com&access_key=<your access key>

An example of the request URL with `block_chats=false`:

    1https://api.screenshotone.com/take?block_chats=false&url=https://screenshotone.com&access_key=<your access key>

### block\_ads

Blocks ads. Default value is `false` when the `url` option is set..

It is useful when you want to take “clean” screenshots or don’t want to generate a loss for advertisers.

An example of the request URL with `block_ads=true`:

    1https://api.screenshotone.com/take?block_ads=true&url=https://scalabledeveloper.com/posts/linux-kernel-coding-style/&access_key=<your access key>

An example of the request URL with `block_ads=false`:

    1https://api.screenshotone.com/take?block_ads=false&url=https://scalabledeveloper.com/posts/linux-kernel-coding-style/&access_key=<your access key>

### block\_trackers

Block trackers. Default value is `false` when the `url` option is set.

It is useful when you don’t want to count screenshots as client visits in your analytics app.

Set `block_trackers=true` to disable all trackers.

### block\_requests

Block requests by specifying URL, domain, or even a simple pattern like `block_requests=*.example.com/*`. You can specify the parameter multiple times like `block_requests=example.com&block_requests=http://*`.

Blocking requests by URL or domain can be used to test how the site responds when resources are not available. Or it might be used to speed up page loading.

Or, as an example, another way of blocking ads and trackers with `block_requests=*.carbonads.com&block_requests=*.google-analytics.com`:

    1https://api.screenshotone.com/take?block_requests=*.carbonads.com&url=https://scalabledeveloper.com/posts/linux-kernel-coding-style/&access_key=<access key>

### block\_resources

Blocks loading resources by type. Available resource types are:

Blocking resources might be helpful when you need to optimize page loading speed before taking a screenshot.

You can specify multiple values as `block_resources=stylesheet&block_resources=image`:

    1https://api.screenshotone.com/take?block_resources=stylesheet&block_resources=image&url=https://screenshotone.com&access_key=<access key>

Geolocation

-----------

### geolocation\_latitude

Set geolocation latitude for the request. Both latitude and longitude are required if one of them is set.

Take a screenshot from Eiffel Tower with accuracy in 50 meters `geolocation_latitude=48.858184&geolocation_longitude=2.294720&geolocation_accuracy=50`:

    1https://api.screenshotone.com/take?geolocation_latitude=48.858184&geolocation_longitude=2.294720&geolocation_accuracy=50&url=https://www.infobyip.com/browsergeolocation.php&access_key=<access key>

### geolocation\_longitude

Set geolocation longitude for the request. Both latitude and longitude are required if one of them is set.

Take a screenshot from Eiffel Tower with accuracy in 50 meters `geolocation_latitude=48.858184&geolocation_longitude=2.294720&geolocation_accuracy=50`:

    1https://api.screenshotone.com/take?geolocation_latitude=48.858184&geolocation_longitude=2.294720&geolocation_accuracy=50&url=https://www.infobyip.com/browsergeolocation.php&access_key=<access key>

### geolocation\_accuracy

Set the geolocation accuracy in meters.

Take a screenshot from Eiffel Tower with accuracy in 50 meters `geolocation_latitude=48.858184&geolocation_longitude=2.294720&geolocation_accuracy=50`:

    1https://api.screenshotone.com/take?geolocation_latitude=48.858184&geolocation_longitude=2.294720&geolocation_accuracy=50&url=https://www.infobyip.com/browsergeolocation.php&access_key=<access key>

Request

-------

### ip\_country\_code

If `proxy` is set, it overrides the `ip_country_code` option.

You can use data center proxies provided by ScreenshotOne to take screenshots from different countries. Set parameter `ip_country_code`to the desired country, and you are ready to go, e.g., `ip_country_code=gb`.

The parameter is not supposed to be used for stealth screenshots. These are not residential proxies. If you have such a case, please, feel free to send the request to [support@screenshotone.com](mailto:support@screenshotone.com).

While ScreenshotOne uses premium, highly available data center proxies, routing requests through them is slower than without a proxy. Try to avoid using the feature if you don’t need it.

The list of supported countries:

*   `us` (United States) **default**

*   `gb` (Great Britain)

*   `de` (Germany)

*   `it` (Italy)

*   `fr` (France)

*   `cn` (China)

*   `ca` (Canada)

*   `es` (Spain)

*   `jp` (Japan)

*   `kr` (South Korea)

*   `in` (India)

*   `au` (Australia)

*   `br` (Brazil)

*   `mx` (Mexico)

*   `nz` (New Zealand)

*   `pe` (Peru)

*   `is` (Iceland)

*   `ie` (Ireland).

Feel free to request any additional country at [support@screenshotone.com](mailto:support@screenshotone.com).

### proxy

If `proxy` is set, it overrides the `ip_country_code` option.

You can use your custom proxy to take screenshots or render HTML with the `proxy` option.

It is suitable in many cases. For example, you might want to render a screenshot from the given location and check how the site renders for this location.

Only the `HTTP` proxies are supported.

If you need to specify username and password, use the usual URL format like: [http://myuser:mypassword@example.com/](http://myuser:mypassword@example.com/).

Example of the request:

    1https://api.screenshotone.com/take?proxy=http://127.0.0.1:1080&url=https://example.com/&access_key=<access key>

### user\_agent

ScreenshotOne takes care of the browser user agent, if you change the user agent, you might break stealth mode capabilities. Change the user agent only when you absolutely need that and know what you are doing.

If the [viewport\_device](#viewport_device) option is set, the parameter overrides it!

A user agent for the request. The default value is the latest version of the browser that `Puppeteer` uses.

An example with default user agent:

    1https://api.screenshotone.com/take?url=https://www.whatsmyua.info/&access_key=<access key>

An example with specified user agent `user_agent=screenshoter`:

    1https://api.screenshotone.com/take?user_agent=screenshoter&url=https://www.whatsmyua.info/&access_key=<access key>

### authorization

Set the `Authorization` header for the request.

Setting the authorization header is proper when you want to take a screenshot of the protected page by basic authentication or token.

For example, if use basic authentication with credentials like `username:password`, encode it to Base64 format `dXNlcm5hbWU6cGFzc3dvcmQ=` and then use set the value of the authorization header like `authorization=Basic+dXNlcm5hbWU6cGFzc3dvcmQ=`.

Also, check our guide about [how to screenshot authenticated pages](/docs/guides/authenticated-pages/).

### cookies

Set cookies for the request in format `<cookie-name>=<cookie-value>; Domain=<domain-value>; Secure; HttpOnly`. You can specify multiple cookies.

An escaped query string might look like: `cookies=name1=val1;+Domain=example.com;+Secure;+HttpOnly&cookies=name2=val2;+Domain=example.com;+Secure;+HttpOnly`

### headers

Set extra headers for the request in the format of `Header-Name:Header-Value`

Headers can override all other previously implicitly set headers by options like `cookies` or `authorization`.

You can specify multiple headers at once `headers=X-Header-1:Value-1&headers=X-Header-2:Value-2`:

    1https://api.screenshotone.com/take?headers=X-Header-1:Value-1&headers=X-Header-2:Value-2&url=http://myhttpheader.com/&access_key=<access key>

### time\_zone

Sets time zone for the request. Available time zones are:

*   `America/Belize`

*   `America/Cayman`

*   `America/Chicago`

*   `America/Costa_Rica`

*   `America/Denver`

*   `America/Edmonton`

*   `America/El_Salvador`

*   `America/Guatemala`

*   `America/Guayaquil`

*   `America/Hermosillo`

*   `America/Jamaica`

*   `America/Los_Angeles`

*   `America/Mexico_City`

*   `America/Nassau`

*   `America/New_York`

*   `America/Panama`

*   `America/Port-au-Prince`

*   `America/Santiago`

*   `America/Tegucigalpa`

*   `America/Tijuana`

*   `America/Toronto`

*   `America/Vancouver`

*   `America/Winnipeg`

*   `Asia/Kuala_Lumpur`

*   `Asia/Shanghai`

*   `Asia/Tashkent`

*   `Europe/Berlin`

*   `Europe/Kiev`

*   `Europe/Lisbon`

*   `Europe/London`

*   `Europe/Madrid`

*   `Pacific/Auckland`

*   `Pacific/Majuro`

Default time zone is `GMT +/- 00:00`.

An example with `time_zone=Europe/Madrid`:

    1https://api.screenshotone.com/take?time_zone=Europe/Madrid&url=https://whatismytimezone.com/&access_key=<access key>

### bypass\_csp

In rare cases, especially when you trying to add \[custom scripts\] to a website, you need to bypass the content security policies of the website. You need to simplify the set `bypass_csp` to `true`, by default it is `false`.

Wait

----

These are one of the most tricky parameters when rendering screenshots of a site. Read on [how to wait until the page is ready](/blog/puppeteer-wait-until-the-page-is-ready/) if you are curious. Or use these `wait` options directly.

### wait\_until

Use `wait_until` to wait until an event occurred before taking a screenshot or rendering HTML or PDF.

The default value of `wait_until` is `['load']`. Allowed values are:

*   `load`: the navigation is successful when the load even is fired;

*   `domcontentloaded`: the navigation is finished when the DOMContentLoaded even is fired;

*   `networkidle0`: the navigation is finished when there are no more than 0 network connections for at least 500 ms;

*   `networkidle2`: consider navigation to be finished when there are no more than 2 network connections for at least 500 ms.

The parameter accepts many values. It means that screenshots will be taken after all events occur altogether.

An example of the request with `wait_until=networkidle2&wait_until=domcontentloaded`:

    1https://api.screenshotone.com/take?wait_until=networkidle2&wait_until=domcontentloaded&url=https://example.com/&access_key=<access key>

### delay

Specify the `delay` option in seconds to wait before taking a screenshot or rendering HTML or PDF.

It is suitable when the [wait\_until](#wait_until) option does not work well for you, and you want to ensure that everything is ready.

The default value is 0.

The delay value can be more than 30 seconds, only if [the timeout option](#timeout) is larger than 300 seconds which is only allowed for asynchronous requests.

An example of the request with `delay=5`:

    1https://api.screenshotone.com/take?delay=5&url=https://example.com/&access_key=<access key>

### timeout

Specify `timeout` (in seconds) of when to abort the request if screenshot or rendering is still impossible. The default value is `60` seconds and the max value is `90`.

An example of the request with `timeout=20`:

    1https://api.screenshotone.com/take?timeout=20&url=https://example.com/&access_key=<access key>

### navigation\_timeout

Specify `navigation_timeout` (in seconds) of when to abort the request if the target site doesn’t respond. The default and max value is `30`.

An example of the request with `navigation_timeout=20`:

    1https://api.screenshotone.com/take?navigation_timeout=20&url=https://example.com/&access_key=<access key>

### wait\_for\_selector

If you are already screenshotting an element by the same selector, waiting for a selector is not effective and won’t be used.

Specify `wait_for_selector` to wait until the element appears in DOM, which is not necessarily visible.

If you specify a few selectors separated by commas, it will be enough to wait for only one. To change the behavior and wait for all selectors, check out the [wait\_for\_selector\_algorithm](#wait_for_selector_algorithm) option.

An example of the request with `wait_for_selector=.dynamically-loaded-element`:

    1https://api.screenshotone.com/take?wait_for_selector=.dynamically-loaded-element&url=https://example.com/&access_key=<access key>

### wait\_for\_selector\_algorithm

The default value is `at_least_one` that means to wait for at least one selector matched.

You can set it to `at_least_by_count` to wait for all selectors matched at least. But it doesn’t mean all elements matched.

E.g. if you specify ‘.class1,.class2’ and there are 2 elements in the DOM that match this selector, it will be enough to stop waiting. It can also mean that there are 2 elements of `.class1`.

Caching

-------

There is [a dedicated page about caching](/docs/caching/) and how to use it.

Note

**Screenshots are not cached by default and not stored on ScreenshotOne servers, unless storage or similar options are used and JSON response type is requested.**

**During processing**, rendered content may be temporarily stored to pass through internal system components (such as queues, message brokers, or temporary buffers).

Screenshots are cached by the combination of all specified request options. And the [cache\_key](#cache_key) option allows having different cached versions of the same screenshot.

Cached screenshots are not counted by quota and are not logged anywhere. They are served directly from the cache. Screenshots are cached in a combination of Cloudflare CDN and R2 storage (like Amazon S3).

There is a header `x-screenshotone-cache-url` that provides a direct link to the cached image, PDF or video. The file exist as long as it was defined in the [cache\_ttl](#cache_ttl) parameter when API request was performed with `cache=true`.

And if the `response_type` option is specified as `json`, you can find a cache URL in the JSON response too:

    1{2    "cache_url": "https://cache.screenshotone.com/..."3}

What is the benefits of using the cache URL?

1.  You don’t share API keys and don’t complicate your code with [signed links](/docs/signed-requests/).

2.  You control when to regenerate the cache, but a user with a link to the screenshot can’t regenerate it. Because if you shared a link to an API request, once the cache is expired, it would be regenerated.

### cache

The `cache` option enables or disables caching of a screenshot, rendering HTML, or PDF. The default value is `false`.

The `false` option forces disabling caching and always generate a free screenshot or render HTML or PDF without caching.

An example of the request with `cache=false`:

    1https://api.screenshotone.com/take?cache=false&url=https://example.com/&access_key=<access key>

### cache\_ttl

The `cache` option must be set to `true` to use the `cache_ttl` parameter.

The `cache_ttl` option (in seconds) hints at how long the cached screenshot should be stored. The minimum value is `14400` seconds (4 hours), and the maximum value is `2592000` seconds (one month).

An example of the request with `cache_ttl=20000`:

    1https://api.screenshotone.com/take?cache=true&cache_ttl=20000&url=https://example.com/&access_key=<access key>

### cache\_key

The `cache` option must be set to `true` to use the `cache_key` parameter.

Screenshots are cached by the combination of all specified request options. The [cache\_key](#cache_key) option allows having different cached versions of the same screenshot.

An example of the request with `cache_key=abc123`:

    1https://api.screenshotone.com/take?cache=true&cache_key=abc123&url=https://example.com/&access_key=<access key>

Storing

-------

When the [cache option](#cache) is set to true, the upload will be triggered only on the cache miss. It means that if you want to upload screenshots anytime, you take them, please set the [cache option](#cache) to false.

You can use any S3-compatible storage to store screenshots, rendered HTML or PDF to the configured S3 bucket.

Note

ScreenshotOne **does not** store the generated content anywhere (except if you specify other storage options, caching or requesting JSON response type). Using `storage_*` and similar options, you can store screenshots, rendered HTML or PDF to your S3 storage.

**During processing**, rendered content may be temporarily stored to pass through internal system components (such as queues, message brokers, or temporary buffers).

This ensures your rendered content remains private unless you choose to store it.

In case you don’t care about getting the actual but only want to upload the rendering result to storage, specify [response\_type=empty](#response_type).

An example of the request with `response_type=empty`:

    1https://api.screenshotone.com/take?response_type=empty&url=https://example.com/&access_key=<access key>

### store

Default value is `false`. Use `store=true` to trigger upload of the taken screenshot, rendered HTML or PDF to the configured S3 bucket. Make sure you configured [access to S3](https://dash.screenshotone.com/access).

An example of the request with `store=true`:

    1https://api.screenshotone.com/take?store=true&url=https://example.com/&access_key=<access key>

### storage\_path

The parameter is required if you set `store=true`. You must specify the key for the file, but don’t specify an extension, it will be added automatically based on the [format](#format) you specified.

You can also specify “subdirectories” in the path part.

An example of the request with `storage_path=latest/example`:

    1https://api.screenshotone.com/take?store=true&storage_path=latest/example&url=https://example.com/&access_key=<access key>

### storage\_endpoint

Leave empty for Amazon S3, specify only when needed. Any S3-compatible storage is supported, e.g. `"https://<accountId>.r2.cloudflarestorage.com"` for Cloudlfare R2 storage.

### storage\_access\_key\_id

Access key ID. It overrides the one specified in the dashboard configuration.

### storage\_secret\_access\_key

Secret access key. It overrides the one specified in the dashboard configuration.

### storage\_bucket

You can override the default bucket you configured with `storage_bucket=<bucket name>`.

An example of the request with `storage_bucket=temporary`:

    1https://api.screenshotone.com/take?storage_bucket=temporary&store=true&storage_path=latest/example&url=https://example.com/&access_key=<access key>

### storage\_class

The default value is `standard`.

Storage class allows you to specify [the object storage class](https://aws.amazon.com/s3/storage-classes/).

Allowed values:

*   `standard`;

*   `reduced_redundancy`;

*   `standard_ia`;

*   `onezone_ia`;

*   `intelligent_tiering`;

*   `glacier`;

*   `deep_archive`;

*   `outposts`;

*   `glacier_ir`.

An example of the request with `storage_class=glacier_ir`:

    1https://api.screenshotone.com/take?storage_class=glacier_ir&store=true&storage_path=latest/example&url=https://example.com/&access_key=<access key>

### storage\_acl

The default value is not set.

Specify [the ACL value](https://docs.aws.amazon.com/AmazonS3/latest/userguide/acl-overview.html#canned-acl) when uploading the file.

Allowed values:

*   (not set) (**default**);

*   `public-read`.

An example of the request with `storage_acl=public-read`:

    1https://api.screenshotone.com/take?storage_acl=public-read&store=true&storage_path=latest/example&url=https://example.com/&access_key=<access key>

### storage\_return\_location

You can require to return the file location returned by S3.

An example of the request with `storage_return_location=true`:

    1https://api.screenshotone.com/take?storage_return_location=true&store=true&storage_path=latest/example&url=https://example.com/&access_key=<access key>

You will receive the location as a header `X-ScreenshotOne-Store-Location` or if you set `response_type=json` as a property of JSON `store.location`.

Metadata

--------

You can extract different properties of the site or a screenshot on demand. They might impact performance, and that’s why they are disabled by default.

### metadata\_image\_size

The default value is `false`.

Set to `true` to get the screenshot’s actual image width and height. If response\_type is set to `json`, you can get it from `metadata.image_size{width,height}` property. Otherwise, read from response headers such as `X-ScreenshotOne-Image-Width` and `X-ScreenshotOne-Image-Height`.

### metadata\_fonts

The default value is `false`.

Get the fonts used by a website.

Check out [our guide on how to detect website fonts](/docs/guides/how-to-detect-website-fonts/) for more details.

### metadata\_icon

Get the favicon used by a website.

The default value is `false`.

    1https://api.screenshotone.com/take?metadata_icon=true&url=https://screenshotone.com/&access_key=<access key>

As headers:

    1X-ScreenshotOne-Icon: {"url":"https://screenshotone.com/favicon-32x32.png","type":"image/png"}

As JSON:

    1{2    "metadata": {3        "icon": {4            "url": "https://screenshotone.com/favicon-32x32.png",5            "type": "image/png"6        }7    }8}

Danger

Do not render the icon from the URL directly in your web application, it might be used to attack your site, always check and sanitize it.

Also, sometimes, it can return data URLs for the icon URL, like: `data:image/svg+xml,<svg...`.

### metadata\_open\_graph

The default value is `false`.

If you set it to `true`, you can get the parsed Open Graph metadata either in the `x-screenshotone-open-graph` header, or in the JSON as the `metadata.open_graph` property.

    1{2    "metadata": {3        "open_graph": {4            "title": "The Screenshot API for developers",5            "description": "ScreenshotOne is the best screenshot rendering platform for developers.",6            "image": "https://screenshotone.com/og.png"7        }8    }9}

### metadata\_page\_title

The default value is `false`.

Get the title of the page.

Either in the `x-screenshotone-page-title` header, or in the JSON as the `metadata.page_title` property.

### metadata\_content

You can request the content (HTML) of the page in addition to the screenshot. It will be uploaded to the ScreenshotOne CDN/public storage and you will receive the URL of the content and the date when it expires and is not available anymore.

If you don’t use caching, then the API will use the minimum available [cache TTL](https://screenshotone.com/docs/options/#cache_ttl). Don’t expect content URLs to be permanent and download the content as early and as fast as you can.

If the content is successfully extracted and uploaded, you will get the URL of the file in the header as `X-ScreenshotOne-Content-URL`. Also `X-ScreenshotOne-Content-Expires` header with the value when the content won’t be available. The format of the expires header is the same as for the regular [Expires HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expires).

If you use JSON response type, then you will get it as:

    1{2    // ...3    "content": {4        "url": "https://example.com/...",5        "expires": "Wed, 21 Oct 2015 07:28:00 GMT"6    }7    // ...8}

On rare occasions if there is an error or some problem of fetching HTML content of the page, you won’t get that data, then it is recommended to perform one more request but use [an HTML format instead](https://screenshotone.com/docs/options/#format).

The default value is `false`.

Consider including the shadow DOM elements with the [`include_shadow_dom`](#include_shadow_dom) option.

### metadata\_content\_format

You can specify the format of the page content when using the [`metadata_content`](#metadata_content) option.

Available formats:

*   `html` - returns the HTML content of the page (default);

*   `markdown` - returns the page content converted to `Markdown` format.

    1https://api.screenshotone.com/take?response_type=json&metadata_content=true&metadata_content_format=markdown&url=https://example.com/&access_key=<your access key>

If you use JSON response type, you will get:

    1{2    "content": {3        "url": "https://example.com/...",4        "expires": "Wed, 21 Oct 2015 07:28:00 GMT",5        "format": "markdown"6    }7}

The default value is `html`.

### metadata\_http\_response\_status\_code

Set to `true` to get the host HTTP response headers.

If you render a binary screenshot, not JSON, you can get that data from the API response headers as `X-ScreenshotOne-HTTP-Response-Status-Code`.

In JSON, it will look like:

    1https://api.screenshotone.com/take?2&url=https://example.com/3...4&metadata_http_response_headers=true5&metadata_http_response_status_code=true6

    7{8    ...9    "http_response": {10      "status_code": 200,11      "headers": {12        "accept-ranges": "bytes",13        "age": "56658",14        "cache-control": "max-age=604800",15        "content-encoding": "gzip",16        "content-length": "648",17        "content-type": "text/html; charset=UTF-8",18        "date": "Fri, 02 Aug 2024 10:26:35 GMT",19        "etag": "\"3147526947\"",20        "expires": "Fri, 09 Aug 2024 10:26:35 GMT",21        "last-modified": "Thu, 17 Oct 2019 07:18:26 GMT",22        "server": "ECAcc (nyd/D13E)",23        "vary": "Accept-Encoding",24        "x-cache": "HIT"25      }26    }27    ...28}

### metadata\_http\_response\_status\_headers

Set to `true` to get the host HTTP response status code.

If you render a binary screenshot, not JSON, you can get that data from the API response headers as `X-ScreenshotOne-HTTP-Response-Headers`.

In JSON, it will look like:

    1https://api.screenshotone.com/take?2&url=https://example.com/3...4&metadata_http_response_headers=true5&metadata_http_response_status_code=true6

    7{8    ...9    "http_response": {10      "status_code": 200,11      "headers": {12        "accept-ranges": "bytes",13        "age": "56658",14        "cache-control": "max-age=604800",15        "content-encoding": "gzip",16        "content-length": "648",17        "content-type": "text/html; charset=UTF-8",18        "date": "Fri, 02 Aug 2024 10:26:35 GMT",19        "etag": "\"3147526947\"",20        "expires": "Fri, 09 Aug 2024 10:26:35 GMT",21        "last-modified": "Thu, 17 Oct 2019 07:18:26 GMT",22        "server": "ECAcc (nyd/D13E)",23        "vary": "Accept-Encoding",24        "x-cache": "HIT"25      }26    }27    ...28}

Async and Webhooks

------------------

There is a [complete guide about asynchronous requests and webhooks](/docs/async-and-webhooks/).

### async

You can execute any request asynchronously by setting the `async` option to `true`. The API will return an empty response immediately. It is `false` by default.

Usually, it is in [combination with webhooks](/docs/async-and-webhooks/) to [upload rendered screenshots or PDFs to S3](/docs/upload-to-s3/).

### webhook\_url

You can receive the result of the screenshot execution at your desired URL. To do it, specify the `webhook_url` parameter. E.g. `webhook_url=https://example.com`.

Usually, it is in [combination with async](/docs/async-and-webhooks/) to [upload rendered screenshots or PDFs to S3](/docs/upload-to-s3/).

### webhook\_sign

Signing webhook request body takes time. If you are sure that your webhooks are unique and secret, you might want to disable signing to improve performance by using `webhook_sign=false`.

It is `true` by default.

### webhook\_errors

Set to `true` to get the error details in the webhook request body (if JSON response type is used) or headers.

It is `false` by default.

Error options

-------------

### ignore\_host\_errors

When the site responds within the range of 200-299 status code, you can ignore errors and take a screenshot of the error page anyway. To do that, set the option `ignore_host_errors` to true. It is `false` by default.

It is helpful when you want to create a gallery of error pages or, for some reason, you need to render error pages.

### error\_on\_selector\_not\_found

If [a selector](#selector) or a [scroll\_into\_view option](#scroll_into_view) is specified and `error_on_selector_not_found=true`, the error will be returned if the element by selector is not visible or it took more than `timeout` seconds to render it, but not more than 30 seconds.

Default value is `false`.

### fail\_if\_request\_failed

The option forces the request to fail if any network request fails during page loading. By default, it is not specified, which means the screenshot will be taken even if some resources (like images, scripts, or stylesheets) fail to load.

Setting `fail_if_request_failed` is useful when you need to ensure that all resources are properly loaded before taking a screenshot. This can help identify issues with missing assets or network problems.

An example of the API request that will fail if any request URL that matches _example.com_ fails:

    1https://api.screenshotone.com/take?access_key=<access key>&fail_if_request_failed=*example.com*&url=https://example.com/

Failed requests are not counted against your rendering quota.

### fail\_if\_content\_missing

The option forces the request to fail if the specified text is missing on the page content. Case insensitive.

It can be specified multiple times. And the request will fail if any of the specified strings is missing on the page content.

Failed requests are not counted against your rendering quota.

### fail\_if\_content\_contains

The option forces the request to fail if the specified text is matched on the page content. Case insensitive.

It can be specified multiple times. And the request will fail if any of the specified strings is matched on the page content.

Check out the guide on [how to fail rendering if the content contains a string](/docs/guides/fail-if-content-contains/) for more details.

Failed requests are not counted against your rendering quota.

### fail\_if\_gpu\_rendering\_fails

The options forces the request to fail if GPU rendering fails. Otherwise, the request will be retried. Or sent to the CPU-based rendering services.

----
url: https://screenshotone.com/docs/guides/how-to-handle-api-errors
----

[Skip to content](#_top)

How to handle API errors

========================

Copy page

Error handling is an essential part of any high-quality application. Make sure you handle all errors returned by the ScreenshotOne API correctly and provide informative explanations to your customers or react to them accordingly.

Following HTTP standards

------------------------

The ScreenshotOne API is on-purpose built using HTTP protocol and follows HTTP standards as much as possible. To make sure the API will be stable and can support customers for years to come.

In general, if the resulting status code is in the range of 400-599, then we are dealing with errors.

    1GET https://api.screenshotone.com/?[options]2

    3Content-Type: application/json4

    5{6    "is_successful":false,7    "error_code": "an_error_code",8    "error_message": "An error message"9}

Errors caused by API consumers

------------------------------

All errors caused by invalid requests, absent credentials, or any reasons caused by you, an API consumer, are marked with status codes 400-499. It means, that until you find a way to fix them, the request won’t be executed successfully.

API internal errors

-------------------

Errors with status codes in the range 500-599 are caused by the API internal reasons and you have almost little influence over that.

But you can safely retry them. Except in a few cases. When you get a network error (`network_error`), it might be because the site blocks the API, and there is no sense in retrying the request. Or if the site returned an error (`host_returned_error`) and it is an error within the range 400-499, it means that the API is either blocked, or you need to change the request to the site.

You still might want to try to retry errors like `network_error` and `host_returned_error` (if the host’s error is `403` in the `returned_status_code` property of the response), but try to add a residential rotating proxy to that API request. Maybe the second time you can succeed and the request will work for you.

An example of the code that retries the request with a residential rotating proxy:

    1const response = await fetch(2    "https://api.screenshotone.com/take?url=https://example.com&access_key=..."3);4if (!response.ok) {5    const error = await response.json();6    if (7        // add more error codes8        error.error_code === "network_error" ||9        (error.error_code === "host_returned_error" && error.returned_status_code == 403)10    ) {11        const proxy = "http://...";12        const proxyResponse = await fetch(13            `https://api.screenshotone.com/take?url=https://example.com&access_key=...&proxy=${proxy}`14        );15        if (!proxyResponse.ok) {16            const proxyError = await proxyResponse.json();17            // you can try to retry again18        }19

    20        // the retry was sucessful21        const screenshot = await proxyResponse.blob();22    }23}

Showing errors to your end users

--------------------------------

In general, you can try to just return the error message provided by the API, but if you want to show a more user-friendly message, you can use the following code:

    1const response = await fetch("https://api.screenshotone.com/...");2

    3// after retries and other processing, once you decide to show an error to your end user4if (!response.ok) {5    const errorData = await response.json();6

    7    const errorMessage = generateUserFriendlyErrorMessage(errorData);8

    9    // show the error to your end user in your UI, CLI or any other way10    showErrorToUser(errorMessage);11}12

    13function generateUserFriendlyErrorMessage(error) {14    // these are error messages for your public users, not for you15    switch (error.error_code) {16        case "screenshots_limit_reached":17            return "The screenshot rendering is not available. Please, retry later.";18        case "concurrency_limit_reached":19        case "temporary_unavailable":20            return "Please try again in a moment.";21        case "request_not_valid":22            return "Please, make sure your request is valid and try again.";23        case "selector_not_found":24            return "The target element was not found on the page";25        case "name_not_resolved":26            return "Unable to resolve the domain name. Check that there is no typo in the URL. If this is a new site, please wait for DNS propagation.";27        case "network_error":28            return "Unable to connect to the requested URL. The site may be blocking access or temporarily down.";29        case "host_returned_error":30            if ([401, 403, 429].includes(error.returned_status_code)) {31                return "The target website blocks automated screenshot rendering.";32            }33            if (error.returned_status_code >= 500) {34                return "The target website is temporarily down. Please, retry later.";35            }36            if (error.returned_status_code == 404) {37                return "The target website returned a 404 HTTP error—the page not found.";38            }39

    40            return `The target website returned a ${error.returned_status_code} HTTP error.`;41        case "timeout_error":42            return "The screenshot rendering timed out. Please, try again.";43        case "storage_returned_transient_error":44        case "internal_application_error":45        case "request_aborted":46            return "Failed to render the screenshot. Please try your request again";47        case "access_key_required":48        case "access_key_invalid":49        case "signature_is_required":50        case "signature_is_not_valid":51        case "invalid_storage_configuration":52        case "script_triggers_redirect":53        case "storage_access_denied":54        case "content_contains_specified_string":55        case "invalid_cookie_parameter":56        case "resulting_image_too_large":57            // these are errors that often are not caused by the end user action,58            // and they need to be fixed on your or our side59            return "The screenshot rendering failed. Please, reach out to support.";60        default:61            // return a generic error message62            // or the message provided by the API error.error_message63            return "The screenshot rendering failed. Please, reach out to support.";64    }65}

These are the most common errors often caused by end users. If you want to process more codes, check out [all our errors](/docs/errors/).

Reporting errors

----------------

All ScreenshotOne API errors are logged and we are acknowledged by them. And will react to them as fast as possible.

In general, you don’t need to report to us any errors. But if it blocks your work or you want us to prioritize fixing them, please, feel free to report an error at `support@screenshotone.com`.

Error reference

---------------

All API errors are listed in [the error reference](/docs/errors/).

----
url: https://screenshotone.com/use-cases/brand-ip-monitoring
----

Automate Website Screenshots

1 min read

Brand Intellectual Property Surveillance

========================================

Track and store web content for unauthorized brand IP usage.

Ensuring intellectual property (IP) protection is critical for maintaining a brand’s integrity and market value. ScreenshotOne API facilitates the monitoring and storage of web pages to verify they do not misuse the brand’s IP unlawfully.

Utility of ScreenshotOne API

----------------------------

By employing the screenshot API, businesses can automate the process of capturing web pages and scrutinizing them for unauthorized displays of logos, trademarks, or copyrighted materials. This proactive stance aids in swiftly identifying and remedying IP violations.

Strategic and Time Efficiency

-----------------------------

The automated oversight and documentation offered by ScreenshotOne conserve considerable time and resources compared to conventional manual tracking. It provides an effective means to safeguard a brand’s intellectual assets, ensuring compliance and maintaining brand reputation.

ScreenshotOne is one of those rare tools that just does its job perfectly. It's simple to integrate, consistently delivers great results, and the support is excellent.

We tested a few alternatives and ScreenshotOne was the clear winner for both quality and ease of use. We'd love to see the option to capture different screen formats too, like tablet and mobile, to support a more complete analysis.

William Prud'homme

Founder, [Forge IQ](https://screenshotone.com/blog/forge-iq/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/errors/temporary-unavailable
----

[Skip to content](#_top)

Temporary Unavailable

=====================

Copy page

It is an API error returned when the API is temporarily unavailable due to an error or overload.

    1{2    "is_successful": false,3    "error_code": "temporary_unavailable",4    "error_message": "The API is temporarily unavailable due to an error or overload. Please wait a bit and then safely retry your request.",5    "documentation_url": "https://screenshotone.com/docs/errors/temporary-unavailable/"6}

Reasons and how to fix

----------------------

### API Overload

One common reason for the “temporary\_unavailable” error is that the API is overloaded with requests, causing temporary unavailability.

To fix this, you can:

1.  **Wait and retry**: Wait for a short period and then retry your request. The API should become available once the load decreases.

2.  **Rate limiting**: Implement rate limiting on your end to avoid overwhelming the API with too many requests in a short period.

### Temporary Errors

Temporary errors or issues within the API infrastructure can also cause this error.

To fix this, consider:

1.  **Retry the request**: Since the issue is temporary, retrying the request after a brief wait is often effective.

2.  **Monitor status page**: Check [the API status page](https://status.screenshotone.com/) to see if there are any ongoing issues.

### Scheduled Maintenance

The API might be undergoing scheduled maintenance, leading to temporary unavailability.

### Network Issues

Network issues between your system and the API server can also result in this error.

To fix this, ensure your network connection is stable and retry the request.

Implementing Retry Logic

------------------------

Implementing retry logic in your application can help handle temporary unavailability gracefully. Use exponential backoff strategy for retries to avoid overwhelming the API further.

Reach out to support

--------------------

If you continue to face issues or need further assistance, please reach out to `support@screenshotone.com`, and we will assist you as soon as possible.

----
url: https://screenshotone.com
----

[What's new API error insights API error insights in the dashboard](/changelog/error-metrics/)

The screenshot API for developers

=================================

Render screenshots in one simple API call, instead of managing browser clusters, and handling all the corner cases.

----------------------

----------------------------

------------------------------------

-------------------------

Send simple HTTP requests or use native libraries for your language of choice.

Java Go Node.js PHP Python Ruby C# (.NET)

    1// add com.screenshotone.jsdk:screenshotone-api-jsdk:[1.0.0,2.0.0)2// to your `pom.xml` or `build.gradle`3

    4import com.screenshotone.jsdk.Client;5import com.screenshotone.jsdk.TakeOptions;6

    7import java.io.File;8import java.nio.file.Files;9

    10public class App {11    public static void main(String[] args) throws Exception {12        final Client client = Client.withKeys("<access key>", "<secret key>");13        TakeOptions takeOptions = TakeOptions.url("https://example.com")14                .fullPage(true)15                .deviceScaleFactor(1)16                .viewportHeight(1200)17                .viewportWidth(1200)18                .format("png")19                .omitBackground(true);20        final String url = client.generateTakeUrl(takeOptions);21

    22        System.out.println(url);23        // Output: https://api.screenshotone.com/take?url=...24

    25        // or download the screenshot26        final byte[] image = client.take(takeOptions);27

    28        Files.write(new File("./example.png").toPath(), image);29        // the screenshot is stored in the example.png file30    }31}

    1// go get github.com/screenshotone/gosdk2

    3import screenshots "github.com/screenshotone/gosdk"4

    5client, err := screenshots.NewClient("<access key>", "<secret key>")6// check err7

    8options := screenshots.NewTakeOptions("https://example.com").9    Format("png").10    FullPage(true).11    DeviceScaleFactor(2).12    BlockAds(true).13    BlockTrackers(true)14

    15u, err := client.GenerateTakeURL(options)16// check err17

    18fmt.Println(u.String())19// Output: https://api.screenshotone.com/take?url=...20

    21// or download the screenshot22image, err := client.Take(context.TODO(), options)23// check err24

    25defer image.Close()26out, err := os.Create("example.png")27// check err28

    29defer out.Close()30io.Copy(out, image)31// the screenshot is stored in the example.png file

    1// $ npm install screenshotone-api-sdk --save2

    3import * as fs from 'fs';4import * as screenshotone from 'screenshotone-api-sdk';5

    6// create API client7const client = new screenshotone.Client("<access key>", "<secret key>");8

    9// set up options10const options = screenshotone.TakeOptions11    .url("https://example.com")12    .delay(3)13    .blockAds(true);14

    15// generate URL16const url = client.generateTakeURL(options);17console.log(url);18// expected output: https://api.screenshotone.com/take?url=...19

    20// or download the screenshot21const imageBlob = await client.take(options);22const buffer = Buffer.from(await imageBlob.arrayBuffer());23fs.writeFileSync("example.png", buffer)24// the screenshot is stored in the example.png file

    1<?php2

    3// composer require screenshotone/sdk:^1.04

    5use ScreenshotOneSdkClient;6use ScreenshotOneSdkTakeOptions;7

    8$client = new Client("<access key>", "<secret key>");9

    10$options = TakeOptions::url("https://example.com")11    ->fullPage(true)12    ->delay(2)13    ->geolocationLatitude(48.857648)14    ->geolocationLongitude(2.294677)15    ->geolocationAccuracy(50);16

    17$url = $client->generateTakeUrl($options);18echo $url.PHP_EOL;19// expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com...20

    21$image = $client->take($options);22file_put_contents('example.png', $image);23// the screenshot is stored in the example.png file

    1# pip install screenshotone2

    3import shutil4from screenshotone import Client, TakeOptions5

    6# create API client7client = Client('<access key>', '<secret key>')8

    9# set up options10options = (TakeOptions.url('https://screenshotone.com')11    .format("png")12    .viewport_width(1024)13    .viewport_height(768)14    .block_cookie_banners(True)15    .block_chats(True))16

    17# generate the screenshot URL and share it with a user18url = client.generate_take_url(options)19# expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fscreenshotone.com&viewport_width=1024&viewport_height=768&block_cookie_banners=True&block_chats=True&access_key=&signature=6afc9417a523788580fa01a9f668ea82c78a9d2b41441d2a696010bf2743170f20

    21# or render a screenshot and download the image as stream22image = client.take(options)23

    24# store the screenshot the example.png file25with open('example.png', 'wb') as result_file:26    shutil.copyfileobj(image, result_file)

    1# Add this gem to your Gemfile:2# gem 'screenshotone'3

    4# If you don't need to add a signature5client = ScreenshotOne::Client.new('<access key>')6

    7# Or ff you do need to add a signature8client = ScreenshotOne::Client.new('<access key>', '<secret key>')9

    10# You can set any available option, in a camel_case format, for example:11options = ScreenshotOne::TakeOptions.new(url: 'https://example.com').12            full_page(true).13            delay(2).14            geolocation_latitude(48.857648).15            geolocation_longitude(2.294677).16            geolocation_accuracy(50)17

    18# Verify all the parameters are valid (we will validate the parameters that should be19# numeric, booleans or that accept only certain values)20options.valid?21=> true22

    23# To simply get the final url:24client.generate_take_url(options)25=> "https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com..."26

    27# To actually get the image (the response body of a request to the previous url)28client.take(options)29=> "\xFF\xD8\xFF\xE0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xFF\..."

    1// Add the library via nuget using the package manager console: PM> Install-Package ScreenshotOne.dotnetsdk2// Or from the .NET CLI as: dotnet add package ScreenshotOne.dotnetsdk3

    4// And generate a screenshot URL without executing request:5var client = new Client("<access key>", "<secret key>");6var options = TakeOptions.Url("https://www.amazon.com")7  .FullPage(true)8  .Format(Format.PNG)9  .BlockCookieBanners(true);10

    11var url = client.GenerateTakeUrl(options);12// url = https://api.screenshotone.com/take?url=https%3A%2F%2Fwww.amazon.com&full_page=true&format=png&block_cookie_banners=true&access_key=_OzqMIjpCw-ARQ&signature=8a08e62d13a5c3490fda0734b6707791d3decc9ab9ba41e8cc045288a39db50213

    14// Or take a screenshot and save the image in the file:15var client = new Client("<access key>", "<secret key>");16var options = TakeOptions.Url("https://www.google.com")17  .FullPage(true)18  .Format(Format.PNG)19  .BlockCookieBanners(true);20

    21var bytes = await client.Take(options);22

    23File.WriteAllBytes(@"c:\temp\example.png", bytes);

Mike Roberts

Founder, [SpyFu](https://www.spyfu.com/)

> ScreenshotOne is the best product on the market - and that's before you take into account how responsive and easy Dmytro is to work with.

> 

> Any time we've found a rare edge case, it's been resolved in hours.

> 

> Great company, great founder - can't say enough!

Without writing a line of code

No-code integrations

--------------------

Quickly render website screenshots with Zapier, Airtable, Make and other popular no-code platforms of your choice.

[](/integrations/zapier/)[](/integrations/airtable/)[](/integrations/make/)[](/integrations/bubble/)[](/integrations/n8n/)

Read

Lessons from running screenshot rendering infrastructure

--------------------------------------------------------

Practical guides and real updates based on our experience operating rendering infrastructure at production scale.

[Customer stories](/blog/tags/customer-stories/)

#### [Taking care of WordPress Sites with ScreenshotOne](/blog/kinsta/)

How Kinsta uses ScreenshotOne to deliver reliable automatic updates.

Written by

[Roger Williams](/contributors/roger-williams/), [Barnabás Ürmössy](/contributors/barnabs-rmssy/)

Published on

Apr 29, 2025

•

2 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Typeshare uses ScreenshotOne for image generation](/blog/how-typeshare-uses-screenshotone/)

Typeshare is a digital writing platform designed to enhance the writing experience by offering a suite of tools aimed at reducing common barriers writers face.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Apr 14, 2024

•

2 min read

[Engineering](/blog/tags/engineering/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Let's build a screenshot API](/blog/building-screenshot-api/)

Two years have passed since the launch of ScreenshotOne, and I want to do a fun coding exercise and build a tiny subset of what the API is today, but from scratch.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

May 26, 2024

•

16 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/pyppeteer-python-screenshots
----

How to Take Screenshots with pyppeteer in Python

================================================

Guide to taking screenshots with pyppeteer in Python. Learn the basics, full page captures, and why you should migrate to Playwright.

[Blog post](/blog/) 2 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Jan 19, 2026

#### Tags

[Screenshot rendering](/blog/tags/screenshot-rendering/)

> **Important Note**: pyppeteer is no longer actively maintained. The last update was a few years ago. For new projects, I strongly recommend using [Playwright](/blog/playwright-python-screenshots/) instead. This guide is for those maintaining legacy code.

[pyppeteer](https://github.com/pyppeteer/pyppeteer) is a Python port of Puppeteer, the Node.js browser automation library. While it was groundbreaking when released, it hasn’t kept up with browser changes.

Installation and Basic Screenshot

---------------------------------

Install it as:

Terminal window

    1pip install pyppeteer

On first run, pyppeteer downloads Chromium automatically.

    1import asyncio2from pyppeteer import launch3

    4async def take_screenshot():5    browser = await launch()6    page = await browser.newPage()7    await page.goto('https://example.com')8    await page.screenshot({'path': 'screenshot.png'})9    await browser.close()10

    11asyncio.get_event_loop().run_until_complete(take_screenshot())

As you might expect, the result is a screenshot like that:

Full Page Screenshots

---------------------

    1import asyncio2from pyppeteer import launch3

    4async def full_page_screenshot():5    browser = await launch()6    page = await browser.newPage()7    await page.goto('https://example.com')8    await page.screenshot({9        'path': 'fullpage.png',10        'fullPage': True11    })12    await browser.close()13

    14asyncio.get_event_loop().run_until_complete(full_page_screenshot())

Viewport Settings

-----------------

    1async def screenshot_with_viewport():2    browser = await launch()3    page = await browser.newPage()4

    5    # Set viewport6    await page.setViewport({7        'width': 1920,8        'height': 10809    })10

    11    await page.goto('https://example.com')12    await page.screenshot({'path': 'screenshot.png'})13    await browser.close()

Element Screenshots

-------------------

    1async def element_screenshot():2    browser = await launch()3    page = await browser.newPage()4    await page.goto('https://example.com')5

    6    element = await page.querySelector('.hero-section')7    await element.screenshot({'path': 'element.png'})8

    9    await browser.close()

Waiting for Content

-------------------

    1async def screenshot_with_wait():2    browser = await launch()3    page = await browser.newPage()4    await page.goto('https://example.com')5

    6    # Wait for selector7    await page.waitForSelector('.main-content')8

    9    # Or wait for navigation10    await page.waitForNavigation()11

    12    await page.screenshot({'path': 'screenshot.png'})13    await browser.close()

Headless Mode

-------------

    1async def headless_screenshot():2    browser = await launch(headless=True)  # Default is True3    page = await browser.newPage()4    await page.goto('https://example.com')5    await page.screenshot({'path': 'screenshot.png'})6    await browser.close()

PDF Generation

--------------

One advantage pyppeteer shares with Playwright:

    1async def generate_pdf():2    browser = await launch()3    page = await browser.newPage()4    await page.goto('https://example.com')5    await page.pdf({6        'path': 'page.pdf',7        'format': 'A4'8    })9    await browser.close()

Why Migrate to Playwright?

--------------------------

Feature

pyppeteer

Playwright

Maintained

No (since a few years ago)

Yes (actively)

Browser support

Chromium only

Chrome, Firefox, Safari

Sync API

No

Yes

Auto-wait

Basic

Advanced

Documentation

Outdated

Excellent

Community

Small

Large

Migration Guide

---------------

Most pyppeteer code translates to Playwright with minor changes:

### pyppeteer

    1import asyncio2from pyppeteer import launch3

    4async def main():5    browser = await launch()6    page = await browser.newPage()7    await page.goto('https://example.com')8    await page.screenshot({'path': 'screenshot.png', 'fullPage': True})9    await browser.close()10

    11asyncio.get_event_loop().run_until_complete(main())

### Playwright

    1import asyncio2from playwright.async_api import async_playwright3

    4async def main():5    async with async_playwright() as p:6        browser = await p.chromium.launch()7        page = await browser.new_page()8        await page.goto('https://example.com')9        await page.screenshot(path='screenshot.png', full_page=True)10        await browser.close()11

    12asyncio.run(main())

Key differences:

*   `launch()` → `p.chromium.launch()`

*   `newPage()` → `new_page()`

*   `{'path': ...}` → `path=...` (keyword args)

*   `fullPage` → `full_page`

*   `asyncio.get_event_loop().run_until_complete()` → `asyncio.run()`

Common Issues with pyppeteer

----------------------------

### Chromium Version Mismatch

pyppeteer downloads an old Chromium version that may not work with modern websites:

    1# Workaround: specify executable path2browser = await launch(executablePath='/path/to/chrome')

### Connection Errors

    1# Increase timeout2browser = await launch(timeout=60000)

### Memory Leaks

Long-running pyppeteer processes often leak memory. Restart the browser periodically:

    1# Close and reopen browser every N screenshots2if screenshot_count % 100 == 0:3    await browser.close()4    browser = await launch()

Summary

-------

pyppeteer works for simple use cases but has significant limitations:

*   **Not actively maintained**

*   Uses outdated Chromium

*   Limited browser support

*   Basic async patterns

**Recommendation**: Migrate to [Playwright](/blog/playwright-python-screenshots/) for better features, active maintenance, and modern browser support. And check out [our best guide on how to take website screenshots in Python](/blog/how-to-take-website-screenshots-in-python/).

Frequently Asked Questions

--------------------------

If you read the article, but still have questions. Please, check the most frequently asked. And if you still have questions, feel free reach out at [support@screenshotone.com](mailto:support@screenshotone.com).

### Is pyppeteer still maintained?

No, pyppeteer is no longer actively maintained. The latest update was a few years ago. For new projects, use Playwright instead, which is actively developed and has better features.

### What is the difference between pyppeteer and Playwright?

Both are browser automation libraries, but Playwright is actively maintained, supports multiple browsers natively, has better async support, and includes more features. pyppeteer only supports Chromium and is outdated.

### How to migrate from pyppeteer to Playwright?

The APIs are similar. Replace 'from pyppeteer import launch' with 'from playwright.async api import async playwright', and adjust method names slightly. Most code translates directly.

Read more Screenshot rendering

------------------------------

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

[View all posts](/blog/tags/screenshot-rendering/)

#### [Let's build a screenshot API](/blog/building-screenshot-api/)

Two years have passed since the launch of ScreenshotOne, and I want to do a fun coding exercise and build a tiny subset of what the API is today, but from scratch.

Read more

#### [How to take website screenshots with JavaScript or TypeScript (Node.js)](/blog/how-to-take-website-screenshots-with-javascript-or-typescript-nodejs/)

The article examines how you can take screenshots of any URL with Javascript and TypeScript (Node.js) by using Selenium, Puppeteer alternatives, Playwright, or screenshot API as a service.

Read more

#### [How to take website screenshots in Python](/blog/how-to-take-website-screenshots-in-python/)

With Python, you can take website screenshots in multiple ways. But the best way to do it depends solely on your needs and your use case. Let's quickly examine all the options.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/comparing-puppeteer-versus-selenium-for-rendering-website-screenshots
----

Comparing Puppeteer versus Selenium for rendering website screenshots

=====================================================================

When comparing Puppeteer, Selenium, and ScreenshotOne for rendering screenshots, it's crucial to understand the distinct capabilities and use cases of each tool.

[Blog post](/blog/) 2 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Oct 5, 2023

#### Tags

[Puppeteer guides](/blog/tags/puppeteer-guides/)

Puppeteer

---------

**Puppeteer** is a Node library which provides a high-level API to control headless Chrome or Chromium over the DevTools Protocol. It’s primarily used for automating web browser tasks, including taking screenshots.

**Advantages:**

*   **Direct Control**: Puppeteer offers fine-grained control over Chrome, allowing for detailed manipulation of pages.

*   **Performance**: Being a lighter tool, it’s generally faster, especially for single-page applications.

*   **Headless Mode**: It can run headless, reducing resource consumption.

**Limitations:**

*   **Browser Specific**: It’s limited to Chrome or Chromium, which can be a drawback for cross-browser testing.

*   **Learning Curve**: Requires familiarity with JavaScript and Node.js environments.

Selenium

--------

**Selenium** is an open-source framework for testing web applications across different browsers and platforms. It’s not just limited to screenshots but can perform a vast array of browser automation tasks.

**Advantages:**

*   **Cross-Browser Compatibility**: Works with multiple browsers like Chrome, Firefox, Safari, etc.

*   **Language Flexibility**: Supports various programming languages like Java, C#, Python, etc.

**Limitations:**

*   **Complexity**: More complex to set up compared to Puppeteer.

*   **Performance**: Generally slower, especially for dynamic, JavaScript-heavy pages.

ScreenshotOne API

-----------------

**ScreenshotOne** is an API service that specializes in taking screenshots of web pages. It’s designed to streamline the screenshot capture process without the need for in-depth programming or browser automation expertise.

**Why ScreenshotOne is a Better Option:**

1.  **Ease of Use**: ScreenshotOne abstracts the complexities involved in setting up and managing Puppeteer or Selenium. It offers a simple API call to capture screenshots, making it accessible to users with minimal technical background.

2.  **Browser Compatibility**: Unlike Puppeteer, which is limited to Chrome, ScreenshotOne handles cross-browser compatibility internally, offering more flexibility.

3.  **Speed and Efficiency**: It’s optimized for quick and efficient screenshot capture, which can be more resource-intensive if managed through Selenium or Puppeteer.

4.  **Maintenance and Scalability**: ScreenshotOne takes care of maintenance and updates, reducing the overhead associated with keeping a browser automation setup current and scalable.

5.  **Quality and Reliability**: It provides consistent image quality and reliability, which can be challenging to achieve with self-managed tools, especially in varied and dynamic web environments.

In conclusion, while Puppeteer and Selenium are powerful tools for browser automation and can be used for capturing screenshots, they come with a certain level of complexity and maintenance overhead. ScreenshotOne, on the other hand, offers a hassle-free, efficient, and reliable solution for screenshot capture, making it a superior choice for users looking for simplicity and effectiveness without the need for in-depth technical setup.

Read more Puppeteer guides

--------------------------

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

[View all posts](/blog/tags/puppeteer-guides/)

#### [How to use proxy per page with Puppeteer](/blog/how-to-use-proxy-per-page-with-puppeteer/)

It is easy to use proxy globally for the puppeteer instance, but there is a trick to use proxy on a per-page basis.

Read more

#### [Puppeteer waitUntil: how to wait for page load](/blog/puppeteer-wait-until-the-page-is-ready/)

Join me in exploring how to find the ideal wait time or event of when to take the page screenshot with Puppeteer.

Read more

#### [How to block requests with Puppeteer](/blog/how-to-block-requests-with-puppeteer/)

Puppeteer allows blocking any outgoing requests while loading the page. Whether you want to block ads, tracking scripts, or different types of resources, it is relatively easy to do with Puppeteer.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/download-request-content
----

Download request content in the dashboard

=========================================

You can now download request content in the dashboard.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

May 5, 2025

When you send HTML or Markdown content to ScreenshotOne, we render it and save the request content.

Now, you can download the request content in the dashboard in case if you need it for debugging:

If you have any questions, suggestions, or feedback, please [contact us](mailto:support@screenshotone.com).

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [ScreenshotOne is available on viaSocket](/changelog/viasocket-integration/)

Automate website screenshots, animated scrolling captures, and visual documentation workflows with ScreenshotOne and viaSocket.

Read more →

1 min read

#### [Add ScreenshotOne to n8n workflows](/changelog/n8n-integration/)

You can now use ScreenshotOne in n8n workflows to render website screenshots, PDFs, scrolling screenshots and videos.

Read more →

1 min read

#### [Include shadow DOM when requesting the page content](/changelog/include-shadow-dom/)

A new version of the ScreenshotOne API has been just deployed. It allows you to include the shadow DOM contents when requesting the page content.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/docs-for-llms
----

Documentation for LLMs

======================

ScreenshotOne now supports documentation format specifically targeted for LLMs—llms.txt and llms-full.txt.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Nov 19, 2024

A few days ago, the head of Claude relations at Anthropic shared a new feature on X:

[](https://x.com/alexalbert__/status/1857457290917589509)

Since today, ScreenshotOne also supports it:

*   [llms.txt](https://screenshotone.com/docs/llms.txt)

*   [llms-full.txt](https://screenshotone.com/docs/llms-full.txt)

You can use it in your AI code editor, or feed it directly to any LLM or chat interface with LLMs like ChatGPT or Claude:

If you have any questions or suggestions, please let us know at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Download request content in the dashboard](/changelog/download-request-content/)

You can now download request content in the dashboard.

Read more →

1 min read

#### [Better Markdown output](/changelog/better-markdown-output/)

Markdown output is now cleaner by removing non-content HTML blocks during conversion.

Read more →

1 min read

#### [Better numbers formatting in the dashboard](/changelog/better-numbers-formatting-in-the-dashboard/)

We improve UI/UX of rendering numbers in the dashboard for better readability.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/failed-payment-alerts
----

Failed payment alerts in the dashboard

======================================

Starting today, you will see an alert in the dashboard when a payment fails.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Sep 16, 2025

In the dashboard, you will now see a new alert in case of failed payments:

In case if you have any suggestions or feedback, please, reach out at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Using AI to block banners](/changelog/using-ai-to-block-banners/)

First successful attempts to block banners on websites using AI before rendering screenshots.

Read more →

1 min read

#### [Added a URL to Markdown Tool](/changelog/url-to-markdown-tool/)

A new free ScreenshotOne tool to convert any public webpage URL into Markdown.

Read more →

1 min read

#### [Improved favicon detection for metadata\_icon](/changelog/improved-metadata-icon-detection/)

Improved \`metadata\_icon\` to check common favicon link variants more reliably.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/animated-scrolling-till-selector
----

Stop scrolling screenshots when a given selector is visible

===========================================================

New options were added to the ScreenshotOne API to stop scrolling screenshots when a given selector is reached.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Oct 13, 2024

ScreenshotOne has [a scrolling screenshot](/scrolling-screenshots/) feature. It allows you to record videos of a page being scrolled. There is [a variety of options](/docs/animated-screenshots/) to tune it and make it work for your case.

 Sorry, your browser doesn't support embedded videos.

But one of the ScreenshotOne customers requested a new option—to stop scrolling screenshots when a given selector is visible.

For example, you want to record a video of a page being scrolled till the “pricing section” is visible and stop there for some reason. Or like in the example below, you want to record a video of a page being scrolled till the “code example” section:

 Sorry, your browser doesn't support embedded videos.

Two new options have been added to the ScreenshotOne API to achieve that:

1.  `scroll_till_selector`—scroll till the selector is visible;

2.  And `scroll_till_selector_adjust_top`—adjust the top position of the selector in the viewport.

The resulting code for the example above will be:

    1https://api.screenshotone.com/animate?access_key=<YOUR API KEY>2    &url=https://screenshotone.com/scrolling-screenshots/3    &scenario=scroll4    &scroll_till_selector=body%20%3E%20div:nth-child(8)

If you have any feedback or suggestions, please let us know at [support@screenshotone.com](mailto:support@screenshotone.com).

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Detect any website fonts with a ScreenshotOne API](/changelog/detect-any-website-fonts-with-a-screenshotone-api/)

Now you can detect fonts used by any website with ScreenshotOne API in just one simple API call.

Read more →

1 min read

#### [Better and more extensible PDF rendering](/changelog/better-and-more-extensible-pdf-rendering/)

ScreenshotOne supports PDF rendering for a long time but it was used till recently by a small group of customers. Growing demand in PDF rendering required updating the API. And today, we introduce new options for PDF customization.

Read more →

1 min read

#### [Better authentication for ScreenshotOne dashboard](/changelog/improved-dashboard-authentication/)

Email and password authentication, email change flow, email verification, GitHub authentication, and improved UX/UI.

Read more →

6 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/available-in-context7
----

Available in Context7

=====================

ScreenshotOne documentation is now available in Context7.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Sep 22, 2025

ScreenshotOne documentation is now available in [Context7—an MCP server that fetches the latest documentation for developer tools and APIs](https://context7.com/).

[](https://context7.com/?q=ScreenshotOne)

If you have any questions or suggestions, please let us know at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Notifications when the usage reaches 50% of the limit](/changelog/half-quota-reached-notifications/)

You can now get notifications when the usage reaches 50% of the limit.

Read more →

1 min read

#### [Improved webhooks documentation and playground](/changelog/improved-webhooks-documentation-and-playground/)

We improved the webhooks documentation and playground.

Read more →

1 min read

#### [Fixed a validation issue in the playground](/changelog/fixed-a-playground-issue/)

We fixed a validation issue in the ScreenshotOne playground caused by selector scroll into view.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/screenshot-api/java
----

[What's new API error insights API error insights in the dashboard](/changelog/error-metrics/)

Java Screenshot API

===================

Capture pixel-perfect website screenshots in Java with a simple API call. No browser management, no Selenium setup, just clean, reliable screenshots.

----------------------

----------------------------

------------------------------------

Take screenshots with Java

--------------------------

Use our official Java SDK or send simple HTTP requests to capture screenshots.

    1// add com.screenshotone.jsdk:screenshotone-api-jsdk:[1.0.0,2.0.0)2// to your `pom.xml` or `build.gradle`3

    4import com.screenshotone.jsdk.Client;5import com.screenshotone.jsdk.TakeOptions;6

    7import java.io.File;8import java.nio.file.Files;9

    10public class App {11    public static void main(String[] args) throws Exception {12        final Client client = Client.withKeys("<access key>", "<secret key>");13        TakeOptions takeOptions = TakeOptions.url("https://example.com")14                .fullPage(true)15                .deviceScaleFactor(1)16                .viewportHeight(1200)17                .viewportWidth(1200)18                .format("png")19                .omitBackground(true);20        final String url = client.generateTakeUrl(takeOptions);21

    22        System.out.println(url);23        // Output: https://api.screenshotone.com/take?url=...24

    25        // or download the screenshot26        final byte[] image = client.take(takeOptions);27

    28        Files.write(new File("./example.png").toPath(), image);29        // the screenshot is stored in the example.png file30    }31}

Mike Roberts

Founder, [SpyFu](https://www.spyfu.com/)

> ScreenshotOne is the best product on the market - and that's before you take into account how responsive and easy Dmytro is to work with.

> 

> Any time we've found a rare edge case, it's been resolved in hours.

> 

> Great company, great founder - can't say enough!

Without writing a line of code

No-code integrations

--------------------

Quickly render website screenshots with Zapier, Airtable, Make and other popular no-code platforms of your choice.

[](/integrations/zapier/)[](/integrations/airtable/)[](/integrations/make/)[](/integrations/bubble/)[](/integrations/n8n/)

Read

Lessons from running screenshot rendering infrastructure

--------------------------------------------------------

Practical guides and real updates based on our experience operating rendering infrastructure at production scale.

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots with Java](/blog/how-to-take-website-screenshots-with-java/)

The article examines how you can take screenshots of any URL with Java by using Selenium, Puppeteer alternatives, Playwright, or screenshot API as a service.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jun 10, 2022

•

3 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Taking care of WordPress Sites with ScreenshotOne](/blog/kinsta/)

How Kinsta uses ScreenshotOne to deliver reliable automatic updates.

Written by

[Roger Williams](/contributors/roger-williams/), [Barnabás Ürmössy](/contributors/barnabs-rmssy/)

Published on

Apr 29, 2025

•

2 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Typeshare uses ScreenshotOne for image generation](/blog/how-typeshare-uses-screenshotone/)

Typeshare is a digital writing platform designed to enhance the writing experience by offering a suite of tools aimed at reducing common barriers writers face.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Apr 14, 2024

•

2 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/hover-option
----

New hover option

================

Use the new hover option to interact with elements before rendering, and choose whether to fail if the hover selector is not found.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Feb 7, 2026

ScreenshotOne API now has a `hover` option which allows you to hover over a specific element on a page before taking a screenshot.

You don’t pay for failed and cached screenshots with ScreenshotOne.

By default, the request fails when the selector is not found. If you want to continue rendering anyway, set `error_on_hover_selector_not_found=false`.

If you have any questions or feedback, please let us know at [support@screenshotone.com](mailto:support@screenshotone.com).

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Added an Above-the-Fold Checker Tool](/changelog/above-the-fold-checker/)

A new ScreenshotOne tool to capture what users see before the first scroll.

Read more →

1 min read

#### [Better and more extensible PDF rendering](/changelog/better-and-more-extensible-pdf-rendering/)

ScreenshotOne supports PDF rendering for a long time but it was used till recently by a small group of customers. Growing demand in PDF rendering required updating the API. And today, we introduce new options for PDF customization.

Read more →

1 min read

#### [Better authentication for ScreenshotOne dashboard](/changelog/improved-dashboard-authentication/)

Email and password authentication, email change flow, email verification, GitHub authentication, and improved UX/UI.

Read more →

6 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/browser-extension-font-detection
----

Automate Website Screenshots

1 min read

Browser Extension Font Detection

================================

Build browser extensions to allow users to identify and learn about fonts on any website with a single click.

Similar to the [design tools font detection](/use-cases/design-apps-font-detection/) use case, build **browser extensions to detect fonts** use case leverages the [ScreenshotOne font detection API](/font-detection-api/) to create browser extensions for design enthusiasts and professionals, allowing them to identify and learn about the fonts used on their favorite websites.

Instant Font Identification

---------------------------

Design enthusiasts and professionals often want to quickly identify fonts they see while browsing. A browser extension powered by ScreenshotOne’s font detection API provides instant typography information for any website with just a click.

Check out [our guide on how to detect website fonts](/docs/guides/how-to-detect-website-fonts/) for more details.

Designer-Friendly Features

--------------------------

Browser extensions can offer features like font history tracking, favorites lists, and the ability to export font information for use in design projects. This transforms casual browsing into a learning and research opportunity for designers.

Quick Development and Deployment

--------------------------------

Building font detection capabilities into a browser extension from scratch would require significant development effort. By integrating ScreenshotOne API, extension developers can quickly bring their product to market and focus on creating an excellent user experience rather than solving complex technical challenges around font detection and web scraping.

When OpenAI launched GPT-4 Vision I immediately thought that this would be great to give instant feedback to founders on their landing pages.

I wanted to launch an MVP in just a day or two to try it out and immediately ran into the problem of getting great screenshots of landing pages from a URL. It turned out that cookie banners, animations, and more often got in the way.

Then I found ScreenshotOne which had a fantastic integration with Zapier. It just immediately worked out of the box. Four weeks later, and hundreds of founders have had thousands of tests run on their landing pages. I couldn't be a happier user of ScreenshotOne!

Elias Stråvik

Founder, [Roast as a Service](https://www.roastasaservice.com/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

### Automated Web Audits with Font Analysis

With our font detection API generate comprehensive typography reports to optimize websites for aesthetics and performance.

[Read more →](/use-cases/automated-web-audits-fonts/)

### Brand Consistency Font Checks

Use ScreenshotOne font detection API to automatically verify font consistency across web pages to maintain brand integrity.

[Read more →](/use-cases/brand-consistency-font-checks/)

### Educational Font Detection Tool

Use our font detection API to enable students to explore and learn from typography used in real-world web applications.

[Read more →](/use-cases/educational-font-detection/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/integrations/mcp
----

Integrations

1 min read

MCP

===

Use ScreenshotOne with MCP Server to render website screenshots with any LLM that supports MCP.

Code API AI

Resources

---------

*   [ScreenshotOne MCP Server on GitHub](https://github.com/screenshotone/mcp)

That was a lot of work to get rendering screenshots work right (there's a lot of edge cases in my case) and I just opted for ScreenshotOne because of the pricing and great API.

Bjarn Bronsveld

Founder, [Spectate](https://spectate.net/)

Check more Integrations

-----------------------

No-code tools, AI, code libraries, and more.

[Check more Integrations](/integrations/)

Code API

### SDK and Code Examples

Use the SDKs and code examples to take screenshots in your own code.

[Read more →](/integrations/code/)

No-Code Automation

### n8n

Use ScreenshotOne in n8n workflows to render website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

[Read more →](/integrations/n8n/)

No-Code Automation

### Clay

Generate website screenshots inside Clay to qualify leads, assess content, and enrich rows with visual context automatically.

[Read more →](/integrations/clay/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/promptwatch
----

Why Promptwatch wins in the AI search space

===========================================

About how Promptwatch uses ScreenshotOne to automate website screenshots and why that matters.

[Customer story](/blog/tags/customer-stories/) 3 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Klaas Foppen](/contributors/klaas-foppen/)

#### Updated on

Feb 11, 2026

I chatted with Klaas Foppen, the CTO and Co-Founder of [Promptwatch](https://promptwatch.com/), to learn more about their use of [ScreenshotOne](/). During our conversation, I realized why they are winning in the AI search space and are already the best product in that category or will be.

But before sharing the core insight, I want to tell you a few words about their product first and how ScreenshotOne helps them. It will help to set things in the perspective.

Promptwatch

-----------

[Promptwatch](https://promptwatch.com/) tracks and optimizes your visibility in ChatGPT, Gemini, and other AI search engines—helping you drive high-converting traffic to your site.

[](https://promptwatch.com/)

At the moment of writing they are used by used by 5,800+ brands and agencies.

[](https://promptwatch.com/case-studies)

In addition to [prompt tracking](https://promptwatch.com/prompt-tracking), they have [crawler logs](https://promptwatch.com/crawler-logs), [content creation](https://promptwatch.com/content-creation) and many more features.

Use case

--------

Promptwatch has [a content creation tool](https://promptwatch.com/content-creation) that allows you to create content optimized to rank on Google and AI platforms.

[](https://promptwatch.com/content-creation)

That’s where [ScreenshotOne](/) comes in. Enriching generated content with screenshots makes it more engaging and appealing to readers. It can help collaterally to rank images on Google and adds more (visual) context to the content.

> “It is super simple, works very well and fast.”

However, one question still couldn’t leave my head…

Build versus buy

----------------

A long time ago, I wrote a guide on [how to build a screenshot API](/blog/building-screenshot-api/). I didn’t share everything, otherwise it would take a book to write, but you can check out that post and see how complex it was to build a reliable and scalable API.

However, with the latest AI coding tools, the task of building everything in-house might become seeming rational. And as the founder of a developer tooling company, I find myself increasingly thinking about building versus buying. So, I asked myself an uncomfortable question: **why not build your own solution in the age of AI?**

Klaas responded:

> Building a screenshot taking API is extremely difficult, it sounds easy but dealing with all the cookie banners and DOM loading events is just to much work!

And also he added on X (after I shared this post) for how long it might be still valuable to buy versus build:

[](https://x.com/forgebitz/status/2020811603482906629)

And that’s the core insight of this post. It also resonates with the feedback I get from most of our customers who are focused on their product and core features:

Of course, you can build everything in-house. But if you are in a competing space and can’t allow yourself spending time on the low ROI secondary tasks, why not to buy tested tools.

Today, at least, I find myself doing that, too. I pay for a lot of software, because I want to focus on my product first. And that’s one of the ways to win today.

Summary

-------

[Promptwatch](https://promptwatch.com) is winning in the AI search space because they are able to focus on their core business and solve their customers’ problems first and foremost.

It is not the only reason, of course, they have a great team, expertise and are customer-centric.

But it really helps to focus when you outsource secondary tasks with low ROI to existing polishing reliable solutions like [ScreenshotOne](/) (e.g. for screenshot automation).

Read more customer stories

--------------------------

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

[View all posts](/blog/tags/customer-stories/)

#### [Taking care of WordPress Sites with ScreenshotOne](/blog/kinsta/)

How Kinsta uses ScreenshotOne to deliver reliable automatic updates.

Read more

#### [How Landing Gallery uses ScreenshotOne to automate screenshot generation](/blog/landing-gallery/)

How and why "Landing Gallery" uses ScreenshotOne to automate screenshot generation for their landing page inspiration platform.

Read more

#### [Boosting email CTR for "Bridesmaid For Hire" with ScreenshotOne](/blog/braidsmade-for-hire-case-study/)

How and why "Bridesmaid for Hire" used ScreenshotOne to boost their email campaign CTR.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/improved-proxy-validation
----

Improved proxy validation

=========================

Stricter proxy option validation to prevent misconfiguration.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Dec 17, 2024

We refined validation for proxy settings to catch configuration issues earlier and provide clearer feedback:

*   Better checks for proxy format and supported schemes.

*   More actionable error messages when proxy configuration is invalid.

This helps avoid failed renders due to malformed or unsupported proxy values.

If you have a proxy that should work but does not, share details at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Trigger screenshot download](/changelog/attachment-name/)

Now you can set attachment filename to trigger screenshot download in the browser.

Read more →

1 min read

#### [Better Markdown output](/changelog/better-markdown-output/)

Markdown output is now cleaner by removing non-content HTML blocks during conversion.

Read more →

1 min read

#### [ScreenshotOne is now integrated into Summit](/changelog/summit-integration/)

The ScreenshotOne screenshot API is now natively integrated into Summit and you can perform anything on top of the powerful screenshot automation and Summit models—only the sky is the limit.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/user-experience-documentation
----

Automate Website Screenshots

1 min read

User Experience Documentation

=============================

Document and improve website user experience.

Enhancing user experience (UX) is a priority for companies looking to retain customers and increase conversions. The ScreenshotOne API can play a crucial role in documenting and analyzing the UX of a company’s website over time.

How ScreenshotOne API Helps

---------------------------

By using the screenshot API, UX designers and developers can capture and archive the look and functionality of a website at different stages of its design and development. This visual documentation assists in identifying areas for improvement and tracking changes that enhance the user experience.

Value and Time Savings

----------------------

Implementing an automated solution like ScreenshotOne for UX documentation saves significant time and resources. It eliminates the need for manual captures and comparisons, providing a streamlined process for monitoring and improving website design and functionality.

I appreciate the fast customer support. Building the product, doing marketing is hard enough. But Dmytro still manages to solve my problems fast. Thank you!

Dan Kulkov

Co-Founder, [FounderPal](https://founderpal.ai/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/updated-gosdk
----

Updated the official Go SDK

===========================

We updated the Go SDK to support the latest API features.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Oct 25, 2025

A quick reminder that you can use the official Go SDK to render screenshots with ScreenshotOne.

[](https://screenshotone.com/docs/code-examples/go/)

We updated the to support the latest API features and fixed the issues with the SDK, specifically, the issues with asynchronous requests.

On how to use the updated Go SDK, please refer to the [Go SDK documentation](https://screenshotone.com/docs/code-examples/go/) or go directly to the [GitHub repository](https://github.com/screenshotone/gosdk).

If you have any feedback, please reach out to us at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [ScreenshotOne is available on Pipedream](/changelog/pipedream-integration/)

Automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos in Pipedream.

Read more →

1 min read

#### [Get favicon used by a website with ScreenshotOne API](/changelog/metadata-icon/)

Now you can get favicon used by a website with ScreenshotOne API in just one simple API call.

Read more →

1 min read

#### [Transfer organization ownership](/changelog/organization-transfer-ownership/)

From today, you can transfer organization ownership to another user.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/async-and-webhooks
----

[Skip to content](#_top)

Async and Webhooks

==================

Copy page

ScreenshotOne supports asynchronous screenshot rendering and webhooks. The document describes both of them in one place since usually they are used together.

The main current supported use case is to render screenshots asynchronously, [upload them to S3](/docs/upload-to-s3/) and return the file location to the specified webhook. That’s what customers asked to implement first.

Async

-----

You can literally execute any request asynchronously by setting the `async` option to `true.` But not every request makes sense to execute asynchronously.

Once you set `async=true,` the API checks your access key and limits and returns the response immediately but continues to execute the request.

One of the top use cases for which it was requested is uploading files to S3 asynchronously without waiting for screenshots to be rendered.

An example of such a request could be:

    1https://api.screenshotone.com/take?access_key=0MpjJxw8Vk7ZAw&url=https://example.com&store=true&storage_path=example.com&response_type=json&async=true

You request rendering but don’t wait for the response. What if you want to get the result of uploading? You can do it by using webhooks.

Webhooks

--------

Using webhooks with ScreenshotOne allows you to deliver the results of the request execution to your URL as a POST body.

Currently, caching is not supported for webhooks since it doesn’t make much sense. If you need its support for other use cases, please, send a chat message or email to `support@screenshotone.com`.

You can use webhooks with both synchronous and asynchronous requests. But usually, it is used in combination with asynchronous requests.

An example of an asynchronous request that uploads rendered screenshot to S3 and sends a webhook might look like this:

    1https://api.screenshotone.com/take?access_key=<your api key>2  &url=https://example.com3  &store=true4  &storage_path=example.com5  &response_type=json6  &async=true7  &webhook_url=<your webhook URL>8  &storage_return_location=true

Not that, to get the location, you must specify the `storage_return_location` parameter as `true`.

An example of the webhook request body you will receive:

    1{2  "screenshot_url": "...",3  // ...4  "store": {5    // ...6    "location": "..."7  },8}

You also receive the `X-ScreenshotOne-Signature` (`x-screenshotone-signature`) header that you should use to validate the webhook request body and make sure that ScreenshotOne sent the request.

If you do not upload the screenshot to any S3-compatible storage, you will receive [the `screenshot_url`](/docs/screenshot-url/) in the response body if you set `response_type=json`:

    1{2  // ...3  "screenshot_url": "..."4}

If you don’t specify the `response_type` parameter as `json`, you will receive the screenshot in the binary format in the response body.

    1<binary data>

### Verifying Signature

To ensure that ScreenshotOne sent the request, you should get the signature from the `X-ScreenshotOne-Signature` header and verify it with your secret key from [the access page](https://dash.screenshotone.com/access) by applying the HMAC SHA-256 algorithm.

Never share your secret key with any party. In case it is leaked, you can quickly regenerate it on [the access page](https://dash.screenshotone.com/access).

A pseudo-code on TypeScript (Node.js) of how you can do it:

    1import * as crypto from "crypto";2

    3const receivedSignature = request.headers.get("x-screenshotone-signature");4const requestBody = await request.rawText();5

    6const calculatedSignature = crypto7    .createHmac("sha256", yourSecretKey)8    .update(requestBody, "utf-8")9    .digest("hex");10

    11if (calculatedSignature !== receivedSignature) {12    // the signature is not valid13    // you should not process this request and reject it immediately14    throw new Error("...");15}16

    17// it is safe to process the request18// you can do something with the webhook request body

### Disable Signing

Singing webhook request body takes time. If you are sure that your webhooks are unique and secret, you might want to disable signing to improve performance by using `webhook_sign=false`.

### Debugging and support headers

There are a few headers that are not part of the body and are not participating in the signing. They must not be used for any logic; it is just for debugging and support purposes:

*   `x-screenshotone-rendering-seconds`—screenshot rendering time in seconds with fractions, e.g. `2.56`;

*   `x-screenshotone-size-bytes`—screenshot size if available (not streaming), e.g. `30033`;

*   `x-screenshotone-trace-id`—unique request trace id when reaching out to the ScreenshotOne support;

*   `x-screenshotone-reference`—screenshot or video id (if available) that can be seen in the history or used when reaching out to the ScreenshotOne support.

### External identifier

You can set `external_identifier` parameter to any alphanumeric value. It will be included in the webhook request headers:

*   `x-screenshotone-external-identifier`—external identifier. It is helpful for error tracking and successful request tracking.

### Webhook errors

We currently don’t support a separate endpoint to send webhook errors. But you can still get them in the webhook request body or headers.

By default, errors are not sent to the webhook URL, at all. But if you want to get them, you can set `webhook_errors=true` parameter.

And you will get error details in the webhook request body if the JSON response type is used:

    1{2    // ...3    "error_code": "...",4    "error_message": "...",5    "documentation_url": "..."6}

Or always in the headers:

*   `x-screenshotone-error-code`—error code;

*   `x-screenshotone-error-message`—error message;

*   `x-screenshotone-documentation-url`—documentation URL about the error.

Check out all possible error codes in the [API error reference](/docs/errors/).

### Testing webhook errors

You can test it with an URL like this `https://example.com/404`. It will trigger an error.

In general, it is enough to check for the error code presence or absence of the screenshot URL/binary data to determine if the request was successful or not.

In the worst case scenario, you might assume if you haven’t been notified about any errors or successful requests, likely the request has been failed.

Summary

-------

That’s it. In case you have any questions or problems, feel free to write to `support@screenshotone.com`.

----
url: https://screenshotone.com/docs/code-examples/python
----

[Skip to content](#_top)

Python SDK and Code Examples

============================

Copy page

If you have any questions, please, reach out at `support@screenshotone.com`.

### Installation

Run the next command to install the Python SDK to take screenshots:

Terminal window

    1pip install screenshotone

### Usage

Don’t forget to [sign up](https://dash.screenshotone.com/sign-up) to get access and secret keys.

Generate a screenshot URL without executing the request. Or download the screenshot. It is up to you:

    1import shutil2from screenshotone import Client, TakeOptions3

    4# create API client5client = Client('<your access key>', '<your secret key>')6

    7# set up options8options = (TakeOptions.url('https://screenshotone.com')9    .format("png")10    .viewport_width(1024)11    .viewport_height(768)12    .block_cookie_banners(True)13    .block_chats(True))14

    15# generate the screenshot URL and share it with a user16url = client.generate_take_url(options)17# expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fscreenshotone.com&viewport_width=1024&viewport_height=768&block_cookie_banners=True&block_chats=True&access_key=<your access key>&signature=6afc9417a523788580fa01a9f668ea82c78a9d2b41441d2a696010bf2743170f18

    19# or render a screenshot and download the image as stream20image = client.take(options)21

    22# store the screenshot the example.png file23with open('example.png', 'wb') as result_file:24    shutil.copyfileobj(image, result_file)

Check out [other SDKs and code examples](/docs/code-examples/).

----
url: https://screenshotone.com/use-cases/seo-performance-tracking
----

Automate Website Screenshots

1 min read

SEO Performance Tracking

========================

Monitor SEO rankings and visibility for strategic insights.

For small businesses aiming to improve their online presence, monitoring SEO performance is essential. Using a website screenshot API like ScreenshotOne can provide critical insights into search engine rankings and visibility.

How ScreenshotOne API Helps

---------------------------

The screenshot API facilitates the tracking of SERP (Search Engine Results Page) positions for specific keywords by capturing snapshots of search results at regular intervals. This enables businesses to analyze their SEO strategies’ effectiveness over time and adjust tactics accordingly.

Value and Time Savings

----------------------

Automating SEO performance tracking with the ScreenshotOne API saves businesses from the time-consuming process of manual searches and documentation. It provides a scalable and efficient solution, allowing companies to focus on optimizing their SEO strategies rather than on technical implementation details.

Capturing screenshots sounds easy until you try to do it yourself and run into N number of cases.

Dmytro has done a wonderful job in all 3 aspects: The product, The documentation, The wonderful human behind this!

Nabil Kazi

Co-Founder, [BugSmash](https://screenshotone.com/blog/bugsmash-story/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/using-clobbr-to-quickly-load-test-the-screenshotone-api
----

Using Clobbr to quickly load test the ScreenshotOne API

=======================================================

Google Cloud gives $300 in credits for 3 months for experimenting. And I decided to give it a try, but not because of the free credits.

[Blog post](/blog/) 3 min read

#### Written by

[Dan Mindru](/contributors/dan-mindru/), [Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Sep 23, 2023

Historically, API load testing was viewed as an “enterprise” endeavour. The pedigree shows this clearly. jMeter, one of the most popular load testing tools is written in Java – a language that has powered enterprise servers for almost 3 decades.

As software development evolved, APIs have become critical parts of software small to big. Perhaps pushed by microservices and serverless, APIs are now not only an enterprise topic. However, tools regarding API load testing have yet to catch up. They are complicated, heavy, require a lot of configuration and above all – are priced for enterprise use cases.

Understanding Small Companies’ API Testing Needs

------------------------------------------------

Small companies and solo developers often operate with limited budgets and resources, which presents different challenges when it comes to API testing. For example:

*   Budget constraints

*   Simpler Use Cases

*   Ease of Use

*   Quick and Cost-Effective Results

The tools needed to check all these points are not the goliaths of load testing. Satisfying these requires a focused, ease-to-use and intuitive type of software. To move quickly, no code or servers should be necessary. Moreover, their use cases are a lot simpler. The traditional tools will throw them into terms, features and workflows they don’t need. Those extensive features get in the way and cost a pretty penny.

Lastly, smaller companies may have limited technical expertise or dedicated QA teams. Therefore, an API testing tool should be user-friendly and accessible to non-technical users.

Ease of use is crucial for smaller companies to efficiently set up and run API tests without the need for extensive training or technical know-how. You should be able to jump in and have your first test ready within minutes, without looking up documentation or guides.

Clobbr - Affordable API Testing for Small Companies & Solo Developers

---------------------------------------------------------------------

Here’s where Clobbr comes in. There are a few things that make this an indispensable tool.

### Pricing Model

Clobbr stands out as a unique tool for small companies primarily due to its straightforward and budget-friendly pricing model. Unlike many other API testing tools that follow a subscription-based approach, Clobbr adopts a one-time payment model. This single purchase grants users full access to the tool’s features without any ongoing financial commitment.

### Simplicity and good UX

Clobbr boasts an intuitive interface that minimizes the learning curve. Users can easily navigate the tool without the need for extensive training or technical expertise.

The tool streamlines the API testing workflow, allowing users to make requests to multiple endpoints effortlessly. Configuration options, such as setting request timeouts, headers, and payload, are straightforward and user-friendly.

### Privacy. No accounts. No servers.

Clobbr prioritizes data privacy and security, assuring users that all data is stored locally, and no sensitive information is shared with third parties. There is no account needed and no server setup.

Real-Life Benefits: Use Case for ScreenshotOne

----------------------------------------------

It helped me to quickly load test my API and potentially “close” a paying customer for my screenshot API.

They asked me if my API could process 100 requests per second in parallel. There are a lot of ways one can do it. From writing your script to using k6 from Grafana Labs. I needed something simple quickly and it should have had with charts. That’s where Clobbr shines.

Until I build a fully-fledged load-testing CI with an isolated production environment, Clobbr is my quick go-to solution to get a grasp of API performance.

Conclusion

----------

You don’t need to spend hours on a course or break the bank to test your API performance. With a few clicks you’ll get a pretty good idea on how your API is going to do under load.

The cool part about this is that Clobbr also has an open source CLI counterpart, so it’s actually possible to contribute, raise bugs and improve it together with the community.

Read more on [Clobbr.app](https://clobbr.app). Or try [Clobbr CLI on Github](https://github.com/parsecph/clobbr).

[](https://clobbr.app)

Read more posts

---------------

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

[View all posts](/blog/)

#### [ScreenshotOne August 2025 updates](/blog/screenshotone-august-2025-updates/)

Playground presets, screenshot URL in webhooks, improved full‑page rendering, and ownership change for subscribed orgs.

Read more

#### [Alexander Schnebel about how he uses ScreenshotOne in Productglowup](/blog/alexander-schnebel-about-how-he-uses-screenshotone-in-productglowup/)

I had a great chat with Alexander Schnebel, the fullstack software engineer behind Productglowup.

Read more

#### [A Chrome Extension by ScreenshotOne for rendering full-page screenshots](/blog/full-page-chrome-extension/)

We just launched a new full-page screenshot Chrome extension that allows you to take full page screenshots of any websites and annotate them in a few clicks.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/pdf-generation-api
----

[What's new API error insights API error insights in the dashboard](/changelog/error-metrics/)

Generate PDFs from URLs, HTML, or Markdown via API

==================================================

Render PDF documents with ScreenshotOne in one simple API call, be it URL to PDF, HTML to PDF, or Markdown to PDF.

[Start rendering for free →](https://dash.screenshotone.com/sign-up)

No credit card required.

 Sorry, your browser doesn't support embedded videos.

https://api.screenshotone.com/take? format=pdf&url=https://tailwindcss.com

"Great support."

**Guillaume Barillot,** CTO at Deepidoo

"Great company, great founder!"

**Mike Roberts,** Founder at SpyFu

"ScreenshotOne is the way to go."

**Lukas Hermann,** Co-Founder of Stagetimer

Looks great

Take clean screenshots

----------------------

----------------------------

------------------------------------

-------------------------

Send simple HTTP requests or use native libraries for your language of choice.

Java Go Node.js PHP Python Ruby C# (.NET)

    1// add com.screenshotone.jsdk:screenshotone-api-jsdk:[1.0.0,2.0.0)2// to your `pom.xml` or `build.gradle`3

    4import com.screenshotone.jsdk.Client;5import com.screenshotone.jsdk.TakeOptions;6

    7import java.io.File;8import java.nio.file.Files;9

    10public class App {11    public static void main(String[] args) throws Exception {12        final Client client = Client.withKeys("<access key>", "<secret key>");13        TakeOptions takeOptions = TakeOptions.url("https://example.com")14                .fullPage(true)15                .deviceScaleFactor(1)16                .viewportHeight(1200)17                .viewportWidth(1200)18                .format("png")19                .omitBackground(true);20        final String url = client.generateTakeUrl(takeOptions);21

    22        System.out.println(url);23        // Output: https://api.screenshotone.com/take?url=...24

    25        // or download the screenshot26        final byte[] image = client.take(takeOptions);27

    28        Files.write(new File("./example.png").toPath(), image);29        // the screenshot is stored in the example.png file30    }31}

    1// go get github.com/screenshotone/gosdk2

    3import screenshots "github.com/screenshotone/gosdk"4

    5client, err := screenshots.NewClient("<access key>", "<secret key>")6// check err7

    8options := screenshots.NewTakeOptions("https://example.com").9    Format("png").10    FullPage(true).11    DeviceScaleFactor(2).12    BlockAds(true).13    BlockTrackers(true)14

    15u, err := client.GenerateTakeURL(options)16// check err17

    18fmt.Println(u.String())19// Output: https://api.screenshotone.com/take?url=...20

    21// or download the screenshot22image, err := client.Take(context.TODO(), options)23// check err24

    25defer image.Close()26out, err := os.Create("example.png")27// check err28

    29defer out.Close()30io.Copy(out, image)31// the screenshot is stored in the example.png file

    1// $ npm install screenshotone-api-sdk --save2

    3import * as fs from 'fs';4import * as screenshotone from 'screenshotone-api-sdk';5

    6// create API client7const client = new screenshotone.Client("<access key>", "<secret key>");8

    9// set up options10const options = screenshotone.TakeOptions11    .url("https://example.com")12    .delay(3)13    .blockAds(true);14

    15// generate URL16const url = client.generateTakeURL(options);17console.log(url);18// expected output: https://api.screenshotone.com/take?url=...19

    20// or download the screenshot21const imageBlob = await client.take(options);22const buffer = Buffer.from(await imageBlob.arrayBuffer());23fs.writeFileSync("example.png", buffer)24// the screenshot is stored in the example.png file

    1<?php2

    3// composer require screenshotone/sdk:^1.04

    5use ScreenshotOneSdkClient;6use ScreenshotOneSdkTakeOptions;7

    8$client = new Client("<access key>", "<secret key>");9

    10$options = TakeOptions::url("https://example.com")11    ->fullPage(true)12    ->delay(2)13    ->geolocationLatitude(48.857648)14    ->geolocationLongitude(2.294677)15    ->geolocationAccuracy(50);16

    17$url = $client->generateTakeUrl($options);18echo $url.PHP_EOL;19// expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com...20

    21$image = $client->take($options);22file_put_contents('example.png', $image);23// the screenshot is stored in the example.png file

    1# pip install screenshotone2

    3import shutil4from screenshotone import Client, TakeOptions5

    6# create API client7client = Client('<access key>', '<secret key>')8

    9# set up options10options = (TakeOptions.url('https://screenshotone.com')11    .format("png")12    .viewport_width(1024)13    .viewport_height(768)14    .block_cookie_banners(True)15    .block_chats(True))16

    17# generate the screenshot URL and share it with a user18url = client.generate_take_url(options)19# expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fscreenshotone.com&viewport_width=1024&viewport_height=768&block_cookie_banners=True&block_chats=True&access_key=&signature=6afc9417a523788580fa01a9f668ea82c78a9d2b41441d2a696010bf2743170f20

    21# or render a screenshot and download the image as stream22image = client.take(options)23

    24# store the screenshot the example.png file25with open('example.png', 'wb') as result_file:26    shutil.copyfileobj(image, result_file)

    1# Add this gem to your Gemfile:2# gem 'screenshotone'3

    4# If you don't need to add a signature5client = ScreenshotOne::Client.new('<access key>')6

    7# Or ff you do need to add a signature8client = ScreenshotOne::Client.new('<access key>', '<secret key>')9

    10# You can set any available option, in a camel_case format, for example:11options = ScreenshotOne::TakeOptions.new(url: 'https://example.com').12            full_page(true).13            delay(2).14            geolocation_latitude(48.857648).15            geolocation_longitude(2.294677).16            geolocation_accuracy(50)17

    18# Verify all the parameters are valid (we will validate the parameters that should be19# numeric, booleans or that accept only certain values)20options.valid?21=> true22

    23# To simply get the final url:24client.generate_take_url(options)25=> "https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com..."26

    27# To actually get the image (the response body of a request to the previous url)28client.take(options)29=> "\xFF\xD8\xFF\xE0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xFF\..."

    1// Add the library via nuget using the package manager console: PM> Install-Package ScreenshotOne.dotnetsdk2// Or from the .NET CLI as: dotnet add package ScreenshotOne.dotnetsdk3

    4// And generate a screenshot URL without executing request:5var client = new Client("<access key>", "<secret key>");6var options = TakeOptions.Url("https://www.amazon.com")7  .FullPage(true)8  .Format(Format.PNG)9  .BlockCookieBanners(true);10

    11var url = client.GenerateTakeUrl(options);12// url = https://api.screenshotone.com/take?url=https%3A%2F%2Fwww.amazon.com&full_page=true&format=png&block_cookie_banners=true&access_key=_OzqMIjpCw-ARQ&signature=8a08e62d13a5c3490fda0734b6707791d3decc9ab9ba41e8cc045288a39db50213

    14// Or take a screenshot and save the image in the file:15var client = new Client("<access key>", "<secret key>");16var options = TakeOptions.Url("https://www.google.com")17  .FullPage(true)18  .Format(Format.PNG)19  .BlockCookieBanners(true);20

    21var bytes = await client.Take(options);22

    23File.WriteAllBytes(@"c:\temp\example.png", bytes);

Mike Roberts

Founder, [SpyFu](https://www.spyfu.com/)

> ScreenshotOne is the best product on the market - and that's before you take into account how responsive and easy Dmytro is to work with.

> 

> Any time we've found a rare edge case, it's been resolved in hours.

> 

> Great company, great founder - can't say enough!

Without writing a line of code

No-code PDF generation

----------------------

Quickly render PDF documents with Zapier, Airtable, Make and other popular no-code platforms of your choice.

[](/integrations/zapier/)[](/integrations/airtable/)[](/integrations/make/)[](/integrations/bubble/)[](/integrations/n8n/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/how-website-report-uses-screenshotone
----

How GetWebsite.Report uses ScreenshotOne for screenshot automation tasks

========================================================================

If you are interested in diving deeper into the GetWebsite.Report use case and discover if ScreenshotOne might be useful for you, too, keep reading.

[Customer story](/blog/tags/customer-stories/) 2 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jun 4, 2024

I saw a testimonial from a paying customer of ScreenshotOne on Twitter and reached out to them to get more information about their product, how they use the ScreenshotOne API, and if they are satisfied or not.

[](https://x.com/trippy_hustler/status/1788192233776439743)

What does GetWebsite.Report do?

-------------------------------

[GetWebsite.Report](https://www.getwebsite.report/) generates a comprehensive webpage audit that’s packed with tailored insights and proven tactics instantly using AI and ScreenshotOne:

[](https://www.getwebsite.report/)

GetWebsite.Report and ScreenshotOne

-----------------------------------

### How did you discover ScreenshotOne?

> Oh well, honestly, we were browsing through some unrelated products and found that they were displaying website image screenshots after entering the URL. I went through the network logs and found ScreenshotOne.

### Did you check any alternatives?

> We did explore [URLBox](https://urlbox.com/) and a few others mentioned in their footer. We found URLBox to be a decent product. However, we went ahead with ScreenshotOne because it was pretty easy to get started with, and easy to configure, and also felt the pricing was quite affordable compared to the former.

### In what application do you use it?

> At [GetWebsite.Report](https://getwebsite.report), we built a website auditing tool for design, UX, and conversion. We use the website images on desktop and mobile from ScreenshotOne and apply certain business logic to create audit reports for a site.

### How does it help you in your business?

> Well, without ScreenshotOne, we would have needed to build a website scraper using Puppeteer or something similar. This is extremely time-consuming and inefficient.

> 

> With ScreenshotOne, all of this is solved. We would probably never even achieve 30% of what [ScreenshotOne](https://screenshotone.com/) does if we tried to build this in-house. We now process over 2000 screenshots every month, and we couldn’t have achieved this without ScreenshotOne.

### Anything you would like to add?

> Kudos to the team for building it. It’s been more than 4 months now, and there’s hardly been an outage/downtime.

> 

> ScreenshotOne handled even the rarest of edge cases where websites were loading slowly, which I found other products in the market failed to do.

> 

> Lastly, the support has been extremely top-notch, which is like a cherry on top.

More Examples and Use Cases

---------------------------

You might be also interested in how [SpyFu uses ScreenshotOne for RivalFlowAI for competitive content analysis with AI](/blog/rivalflowai-by-spyfu/).

ScreenshotOne supports a huge variety of uses including but not only:

*   [Automating Open Graph image generation](/use-cases/open-graph-images/).

*   [Generating personalized videos](/use-cases/automate-personalized-videos/).

*   [Rendering site thumbnails for search previews](/use-cases/preview-search-results/)

And [many more](/use-cases/).

Read more customer stories

--------------------------

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

[View all posts](/blog/tags/customer-stories/)

#### [ScreenshotOne took away one major complexity off the Supawrite plate](/blog/supawrite/)

A short story about how ScreenshotOne helps a content marketing platform automate their screenshot workflow.

Read more

#### [How RivalFlowAI uses ScreenshotOne to help its customers improve existing content](/blog/rivalflowai-by-spyfu/)

RivalFlowAI is a new product by SpyFu, launched in 2023. The product helps to improve existing content with AI by finding the missing pieces your page needs to rank.

Read more

#### [SEOBot uses ScreenshotOne API to generate screenshots for articles](/blog/seobot-automates-screenshot-generation-for-articles/)

Customers can your product in unpredictable and surprising ways. SEOBot now uses ScreenshotOne API to enhance its articles with screenshots, making content more engaging and visually appealing.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/integrations/ravenala
----

Integrations

1 min read

Ravenala

========

Use ScreenshotOne with Ravenala.

No-Code AI

Resources

---------

*   [ScreenshotOne on Ravenala](https://www.ravenala.ai/apps/screenshotone)

Capturing screenshots sounds easy until you try to do it yourself and run into N number of cases.

Dmytro has done a wonderful job in all 3 aspects: The product, The documentation, The wonderful human behind this!

Nabil Kazi

Co-Founder, [BugSmash](https://screenshotone.com/blog/bugsmash-story/)

Check more Integrations

-----------------------

No-code tools, AI, code libraries, and more.

[Check more Integrations](/integrations/)

No-Code Automation

### Clay

Generate website screenshots inside Clay to qualify leads, assess content, and enrich rows with visual context automatically.

[Read more →](/integrations/clay/)

No-Code Automation

### Zapier

Automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos in Zapier.

[Read more →](/integrations/zapier/)

No-Code Automation

### n8n

Use ScreenshotOne in n8n workflows to render website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

[Read more →](/integrations/n8n/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/playwright
----

What is Playwright

==================

What is Playwright and what you can use it for.

[Blog post](/blog/) 2 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

May 6, 2024

#### Tags

[Playwright guides](/blog/tags/playwright-guides/)

[Playwright](https://playwright.dev/) is an open-source framework for cross-browser automation and end-to-end web application testing. It was developed by Microsoft to provide a fast, reliable, and robust test automation solution.

[](https://playwright.dev/)

Playwright has a lot of use cases.

Use cases

---------

### End-to-End (E2E) Testing

Playwright allows you to write reliable end-to-end tests for modern web applications. It can automate interactions with web pages, including clicking, typing, navigating, and asserting on page content.

### Cross-Browser Testing

Playwright supports all major rendering engines, including Chromium, WebKit (Safari), and Firefox. This allows you to test your web application’s compatibility across different browsers and platforms.

### Web Scraping

Playwright can be used to automate web scraping tasks, allowing you to extract data from websites programmatically.

### Mobile Web Testing

Playwright provides native mobile emulation for Google Chrome on Android and Mobile Safari, enabling you to test your web application’s mobile experience.

### Parallel Testing

Playwright supports running tests in parallel across multiple browser contexts, improving test execution speed. \[2\]\[3\]

### Debugging and Tracing

Playwright offers built-in debugging tools, such as the Playwright Inspector and Trace Viewer, to help you investigate and troubleshoot test failures.

Code examples

-------------

The following is an example of using the Playwright Library directly to launch Chromium, go to a page, and check its title:

    1import { chromium, devices } from "playwright";2import assert from "node:assert";3

    4(async () => {5    // Setup6    const browser = await chromium.launch();7    const context = await browser.newContext(devices["iPhone 11"]);8    const page = await context.newPage();9

    10    // The actual interesting bit11    await context.route("**.jpg", (route) => route.abort());12    await page.goto("https://example.com/");13

    14    assert((await page.title()) === "Example Domain"); // 👎 not a Web First assertion15

    16    // Teardown17    await context.close();18    await browser.close();19})();

You can also use Playwright in Python:

1.  [Use Playwright in Python to take website screenshots](/blog/playwright-python-screenshots/).

2.  [Use Playwright in Python to take full page website screenshots](/blog/playwright-python-full-page-website-screenshots/).

Playwright alternatives

-----------------------

[Puppeteer](/blog/puppeteer/) can be considered an alternative to Playwright for browser automation and web scraping tasks. While they have some differences, both Puppeteer and Playwright are powerful Node.js libraries that enable developers to automate interactions with web pages.

But the main difference is the purpose of libraries. Puppeteer is more of an abstraction of a browser, while Playwright is a testing framework and [most of their differences](/blog/puppeteer-versus-playwright/) arise from there.

Summary

-------

Playwright is a powerful and versatile framework that enables developers to write reliable, cross-browser, and end-to-end tests for their modern web applications. It is designed to be fast, resilient, and easy to use, making it a popular choice for web automation and testing.

Read more Playwright guides

---------------------------

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

[View all posts](/blog/tags/playwright-guides/)

#### [How to Take Full Page Screenshots with Playwright in Python](/blog/playwright-python-full-page-website-screenshots/)

Learn how to capture full page screenshots with Playwright in Python. Master the full\_page parameter, handle infinite scroll pages, lazy-loaded images, and maximum size limits.

Read more

#### [How to Take Bulk Screenshots with Playwright in Python](/blog/bulk-screenshots-playwright-python/)

Learn how to automate bulk website screenshots with Playwright in Python. Master async batch processing, concurrent screenshots, rate limiting, and error handling for large-scale screenshot automation.

Read more

#### [How to Take Website Screenshots with Playwright in Python](/blog/playwright-python-screenshots/)

A complete guide to taking website screenshots with Playwright in Python. Learn page.screenshot() parameters, async patterns, element screenshots, dark mode, and device emulation.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/generate-advertising-content
----

Automate Website Screenshots

1 min read

Advertising Material Creation and Management

============================================

Facilitate the creation and storage of advertising content in various sizes.

Producing advertising content for networks in precise dimensions is key for impactful digital advertising. ScreenshotOne API aids in generating and maintaining these materials in assorted sizes.

Role of ScreenshotOne API

-------------------------

The website screenshot API empowers marketers to automatically produce advertising images in specified dimensions, ensuring uniformity and high quality across different media. This is particularly beneficial for conducting A/B tests and enhancing ad efficiency.

Benefits and Time Optimization

------------------------------

Adopting ScreenshotOne for the generation of advertising materials circumvents the need for manual adjustment and refinement, drastically lowering production time and effort. It provides a scalable approach to crafting high-quality advertising content, augmenting campaign productivity and impact.

ScreenshotOne is a really helpful service provider. All that I need for my work is combined here.

Service is comfortable, fast, and consistent. It has a nice support service that always stays active to problems of users and has an immediate response time.

I really appreciate and recommend ScreenshotOne to everyone.

Alexandr Bezhan

Chief Product Officer, [AMS Pilot](https://www.amspilot.com/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/guides/how-to-use-proxies
----

[Skip to content](#_top)

How to use proxies

==================

Copy page

ScreenshotOne doesn’t include rotating residential proxies as part of the product, but you can plug in easily any external proxy provider you like, in three simple steps.

Did you know?

If you need to use proxies to bypass CAPTCHAs, [check out our guide on how to bypass CAPTCHAs](/docs/guides/how-to-bypass-captchas).

1\. Sign up to a proxy provider

-------------------------------

There are plenty of them, like [Decodo](https://decodo.com/https://smartproxy.com/), [Bright Data](https://brightdata.com/), or [Geonode](https://geonode.com/).

You can find the Internet proxy providers that you prefer by price and quality. Choose and sign up for the proxy provider.

Not because it is the best one or the cheapest one, but in this guide, I will use [Decodo](https://decodo.com/) as an example.

2\. Get the proxy URL

---------------------

Tip

In this guide, we use residential proxies as an example, but **we highly recommend using data center proxies first, as their cost is much lower than that of residential proxies**. If that doesn’t work for you, only then should you switch to residential or even mobile proxies.

Choose pay-as-you-go residential proxies in Decodo or any other proxy provider you picked in the previous step.

And your goal is to copy the HTTP URL of the proxy with the desired configuration.

In the case of Decodo, it would look like:

.

3\. Use the proxy with the ScreenshotOne API

--------------------------------------------

Once you have the HTTP proxy URL, not HTTPS, nor SOCKS5. You can specify it when sending an API request with the [proxy](/docs/options/#proxy) parameter, just like this:

    1https://api.screenshotone.com/take?proxy=<your proxy url>&access_key=<your API key>&url=<the site you want to screenshot>

Where `<your proxy url>` is your proxy URL, or in the case of our example is `http://user12345:somepass@us.smartproxy.com:10000`.

Recommendations

---------------

A few tips to improve your success rate when using proxies:

1.  **Consider using data center proxies first**, as the cost is much lower than residential proxies. If they don’t work for you, only then switch to residential or even mobile proxies.

2.  **Don’t use random location proxies.** Use proxies located in the United States or your specific location, rather than random locations. For most proxy providers, stability is unlikely when using random locations.

3.  **Don’t send many requests through the same proxy.** If you plan to send many requests in parallel through the same proxy, consider using different ports if available or even different proxies. Using a single channel is highly likely to slow down your API requests, cause timeouts, and result in more errors.

4.  If you encounter network issues, check the balance and reach out the proxy provider support, but we also noticed that for some providers, you sometimes need to recreate your proxy user/account to make it work again.

Reach out if anything

---------------------

You see, it was that easy. In case if you have any questions or encounter any problems, please, don’t hesitate to reach out at `support@screenshotone.com`.

----
url: https://screenshotone.com/docs/guides/how-to-translate-and-render-a-website-as-a-screenshot
----

[Skip to content](#_top)

How to translate and render a website as a screenshot

=====================================================

Copy page

It is possible to translate and take a screenshot of the translated website with ScreenshotOne because the API supports scripts via the `scripts` option.

You can use any translation API of your choice. But as an example, in this guide, I will go with Google Translate API.

Get your Google Translate API key

---------------------------------

To get your Google API key:

1.  Go to [the API credentials page in Google Cloud Platform](https://console.cloud.google.com/apis/credentials).

2.  Generate your API key and make sure you restrict it to using only for Google Translate.

3.  Make sure you set budgets, and notifications, and follow other [best practices](https://cloud.google.com/blog/products/ai-machine-learning/four-best-practices-for-translating-your-website) for Google Translate.

Write a script to translate your websites

-----------------------------------------

You need to write a script that efficiently will check all text nodes on the website, batch them, and send requests efficiently to save your costs.

Danger

Please, make sure to optimize the script for your use case and that it doesn’t overuse your quota. It is an example script and ScreenshotOne is not responsible for you using it and causing any damage to your business by the script. Use it at your own risk.

Here is an example script you can try and use as a basis, but I highly recommend writing yours for production and making sure it has retries and other necessary logic:

    1const translateTextAsync = async (texts, targetLang, apiKey) => {2    const url = `https://translation.googleapis.com/language/translate/v2?key=${apiKey}`;3    const data = {4        q: texts,5        target: targetLang,6    };7

    8    const response = await fetch(url, {9        method: "POST",10        headers: { "Content-Type": "application/json" },11        body: JSON.stringify(data),12    });13

    14    if (!response.ok) throw new Error("Network response was not ok.");15

    16    const json = await response.json();17    return json.data.translations.map((t) => t.translatedText);18};19

    20const isVisible = (element) => {21    return element.offsetWidth > 0 && element.offsetHeight > 0;22};23

    24const shouldTranslate = (node) => {25    return (26        node.nodeType === Node.TEXT_NODE &&27        node.nodeValue.trim() &&28        isVisible(node.parentElement) &&29        !isDescendantOf(node, ["script", "code"])30    );31};32

    33const isDescendantOf = (node, tagNames) => {34    let parent = node.parentElement;35    while (parent && parent !== document.body) {36        if (tagNames.includes(parent.tagName.toLowerCase())) {37            return true;38        }39        parent = parent.parentElement;40    }41    return false;42};43

    44const batchTranslate = async (nodes, targetLang, apiKey) => {45    let batch = [];46    let totalLength = 0;47    const results = [];48

    49    for (const node of nodes) {50        const text = node.nodeValue.trim();51        if (text.length + totalLength > 5000 || batch.length >= 128) {52            // Translate current batch53            const translations = await translateTextAsync(54                batch,55                targetLang,56                apiKey57            );58            translations.forEach((translatedText, index) => {59                results.push({ node: nodes[index], translatedText });60            });61

    62            // Reset for next batch63            batch = [text];64            totalLength = text.length;65        } else {66            batch.push(text);67            totalLength += text.length;68        }69    }70

    71    // Translate remaining batch72    if (batch.length > 0) {73        const translations = await translateTextAsync(74            batch,75            targetLang,76            apiKey77        );78        translations.forEach((translatedText, index) => {79            results.push({80                node: nodes[nodes.length - batch.length + index],81                translatedText,82            });83        });84    }85

    86    return results;87};88

    89const translatePageContent = async (element, targetLang, apiKey) => {90    const textNodes = [];91    const walker = document.createTreeWalker(92        element,93        NodeFilter.SHOW_TEXT,94        {95            acceptNode: (node) => {96                return shouldTranslate(node)97                    ? NodeFilter.FILTER_ACCEPT98                    : NodeFilter.FILTER_REJECT;99            },100        },101        false102    );103

    104    let node;105    while ((node = walker.nextNode())) {106        textNodes.push(node);107    }108

    109    const translations = await batchTranslate(textNodes, targetLang, apiKey);110    translations.forEach(({ node, translatedText }) => {111        node.nodeValue = translatedText;112    });113};114

    115// Replace with your actual API key116const apiKey = "<your API key>";117// Target language code (e.g., 'es' for Spanish)118const targetLang = "es";119

    120translatePageContent(document.body, targetLang, apiKey)121    .then(() => console.log("Translation completed"))122    .catch((error) => console.error("Translation error:", error));

Rendered translated websites

----------------------------

Once you have a working script, make sure you URL-encode it and then send it to ScreenshotOne when rendering a screenshot. You can use either POST or GET requests.

But in this example, I will share with you a GET request example:

    1https://api.screenshotone.com/take?access_key=<your API key>&url=https://example.com&scripts=<URL-encoded script>&delay=10

You can see the example.com website rendered in the Spanish language:

I hope the guide helps you translate and render any HTML or website content, and have a nice day!

----
url: https://screenshotone.com/blog/open-graph-images
----

Open Graph images

=================

You can control the preview image rendered when your site is shared on social media, messengers, or apps that support the Open Graph protocol.

[Blog post](/blog/) 12 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Jan 21, 2026

Also known as social cards or link previews, these images make a difference between the click and the visit to your site or ignoring it. Boost your brand awareness by generating Open Graph images.

In this article, I share with you a few quick ways how you can easily add support the Open Graph images to your site.

If you already have an image

----------------------------

If you already have an image for social media, upload it to your server or any other file hosting and add the following tags to your HTML head section:

    1<!-- Open Graph / Meta (Facebook) -->2<meta property="og:type" content="website" />3<meta property="og:url" content="https://example.com/" />4<meta property="og:title" content="Your title" />5<meta property="og:description" content="Your description" />6<meta property="og:image" content="https://example.com/ogimage.png" />7

    8<!-- Twitter -->9<meta property="twitter:card" content="summary_large_image" />10<meta property="twitter:url" content="https://example.com" />11<meta property="twitter:title" content="Your title" />12<meta property="twitter:description" content="Your description" />13<meta property="twitter:image" content="https://example.com/ogimage.png" />

There are [a few requirements and recommendations](#open-graph-image-requirements) to avoid common pitfalls:

1.  Don’t use a relative URL. Always use an absolute URL of the images in tags. Not every social network or app knows how to resolve it.

2.  The recommended image size is 1200x630px for most social networks, and the file size must not exceed a few hundred kilobytes.

And there are a few downsides to using static OG images:

1.  They are not updated dynamically to reflect the updates on a page.

2.  You need manually set up OG images for different pages.

3.  You need to spend time and periodically update them.

These downsides can be solved by generating images dynamically.

Generate open graph images dynamically

--------------------------------------

There are two ways to generate Open Graph images dynamically: building a custom solution with a rendering engine like Puppeteer or using a well-established API or product that solves that problem.

What to choose depends on your preferences and resource limitations. If you like building and writing code, go with a custom solution. If you are short on time, go with a proven solution.

### Generate Open Graph images with a custom solution

You can draw pictures using low-level libraries or render HTML with browsers and take screenshots. There are so many ways to generate images dynamically.

I will show quickly you four options on how to easily render HTML as an image for open graph images:

1.  Using [Puppeteer](https://github.com/puppeteer/puppeteer);

2.  Using [satori by Vercel](https://github.com/vercel/satori);

3.  Using [ScreenshotOne](https://screenshotone.com);

4.  Or go with [ogimage.org](https://ogimage.org).

Why HTML as images? Because it is a declarative language that is easy to read and edit. In addition to that, you can use modern CSS frameworks to style your OG image quickly. And you can easily scale elements to larger or lesser image sizes if needed.

### Using Puppeteer to generate OG images

I have written [a complete guide on how to render URLs or HTML as images (screenshots) with Puppeteer](https://screenshotone.com/blog/how-to-take-a-screenshot-with-puppeteer/).

Before rendering an HTML, let’s create a simple example of a dynamic HTML template for our OG image:

    1<!DOCTYPE html>2<html>3    <head>4        <meta charset="UTF-8" />5        <meta name="viewport" content="width=device-width, initial-scale=1.0" />6        <script src="https://cdn.tailwindcss.com"></script>7    </head>8    <body class="bg-violet-700 h-screen flex">9        <div class="m-auto">10            <h1 class="text-white text-7xl font-serif">11                <span class="underline decoration-sky-500">Open Graph</span>12                images13            </h1>14            <h2 class="text-white text-3xl mt-5 font-light">15                Are easy and powerful way to increase your brand awarness16            </h2>17        </div>18    </body>19</html>

And now let’s render it with `Puppeteer`:

    1"use strict";2

    3// npm i puppeteer4import puppeteer from "puppeteer";5

    6(async () => {7    const content = `<!doctype html>8    <html>9    <head>10      <meta charset="UTF-8">11      <meta name="viewport" content="width=device-width, initial-scale=1.0">12      <script src="https://cdn.tailwindcss.com"></script>13    </head>14     <body class="bg-violet-700 h-screen flex">15        <div class="m-auto">16         <h1 class="text-white text-7xl font-serif"><span class="underline decoration-sky-500">Open Graph</span> images</h1>17         <h2 class="text-white text-3xl mt-5 font-light">Are easy and powerful way to increase your brand awareness</h2>18       </div>19    </body>20    </html>`;21

    22    const browser = await puppeteer.launch();23    try {24        const page = await browser.newPage();25        await page.setViewport({26            width: 1200,27            height: 630,28            deviceScaleFactor: 1,29        });30        await page.setContent(content);31        await page.screenshot({ path: "screenshot.png" });32    } catch (e) {33        console.log(e);34    } finally {35        await browser.close();36    }37})();

And the result is:

Let’s create a simple API around it:

    1"use strict";2

    3// npm i puppeteer4import puppeteer from "puppeteer";5// npm i express6import express from "express";7

    8const template = (prefix, title, subtitle) => `<!doctype html>9<html>10<head>11  <meta charset="UTF-8">12  <meta name="viewport" content="width=device-width, initial-scale=1.0">13  <script src="https://cdn.tailwindcss.com"></script>14</head>15 <body class="bg-violet-700 h-screen flex">16    <div class="m-auto">17     <h1 class="text-white text-7xl font-serif"><span class="underline decoration-sky-500">${prefix}</span>${title}</h1>18     <h2 class="text-white text-3xl mt-5 font-light">${subtitle}</h2>19   </div>20</body>21</html>`;22

    23const app = express();24

    25app.get("/ogi", async function (req, res) {26    const content = template(27        req.query.prefix,28        req.query.title,29        req.query.subtitle30    );31

    32    const browser = await puppeteer.launch();33    try {34        const page = await browser.newPage();35        await page.setViewport({36            width: 1200,37            height: 630,38            deviceScaleFactor: 1,39        });40        await page.setContent(content);41        const image = await page.screenshot({42            type: "png",43            encoding: "binary",44        });45

    46        res.set("Content-Type", "image/png");47        res.send(image);48    } catch (e) {49        console.error(e);50        res.status(500).send(51            "Failed to render the Open Graph image, see error logs"52        );53    } finally {54        await browser.close();55    }56});57

    58app.listen(3000);

I start and close a browser on every request because these requests from social networks might be rare if the number of pages you have is minimal.

But running a browser in the background might cause many issues—it is a complex case to handle.

Let’s test it:

    1http://localhost:3000/ogi?prefix=Open Graph&title= images&subtitle=are easy and powerful way to increase your awareness

And the result is:

Once it works, specify URLs in your HTML meta tags:

    1<!-- Open Graph / Meta (Facebook) -->2<meta property="og:type" content="website" />3<meta property="og:url" content="https://example.com/" />4<meta property="og:title" content="Your title" />5<meta property="og:description" content="Your description" />6<meta7    property="og:image"8    content="https://example.com/ogi?prefix=Open%20Graph&title=%20images&subtitle=are%20easy%20and%20powerful%20way%20to%20increase%20your%20awareness"9/>10

    11<!-- Twitter -->12<meta property="twitter:card" content="summary_large_image" />13<meta property="twitter:url" content="https://example.com" />14<meta property="twitter:title" content="Your title" />15<meta property="twitter:description" content="Your description" />16<meta17    property="twitter:image"18    content="https://example.com/ogi?prefix=Open%20Graph&title=%20images&subtitle=are%20easy%20and%20powerful%20way%20to%20increase%20your%20awareness"19/>

Use your domain where you deployed the API instead of `example.com`.

And the last is you need to deploy an API or integrate it as part of your app. But be careful because deploying Puppeteer manually to a server has a few pitfalls that you should be aware of:

1.  It might have memory leaks.

2.  It consumes a lot of CPU and memory.

3.  It might periodically crash.

There is a new and lightweight alternative tailored for rendering OG images—satori by Vercel. Or, if you don’t want to deal with infrastructure and code, feel free to jump to the section about [how to use API to render HTML](#using-simple-and-tailored-solution-for-open-graph-images).

### Using satori by Vercel to generate OG images

[satori](https://github.com/vercel/satori) is an engine made by Vercel to generate SVG images from simple HTML code that can be used in many use cases. And Vercel provides native support for satori to render Open Graph images.

If you need to generate OG images for your [Next.js](https://nextjs.org/) app, consider hosting your app on Vercel and using their OG image solution.

Install `satori` and friends:

    1npm i satori satori-html @resvg/resvg-js

Let’s render a simple HTML:

    1"use strict";2

    3import satori from "satori";4import { Resvg } from "@resvg/resvg-js";5import { html as toReactElement } from "satori-html";6// npm i express7import express from "express";8import fsPromises from "fs/promises";9

    10const template = (11    prefix,12    title,13    subtitle14) => `<div style="background-color: rgb(109 40 217); color: white; height: 100vh; width: 100%; display: flex; align-items: center; justify-content: center; flex-direction: column">15    <h1 style="font-size: 40px">${prefix}${title}</h1>16    <h2 style="font-size: 20px">${subtitle}</h2>17</div>`;18

    19const app = express();20

    21// at least one font file is required22const fontFile = await fsPromises.readFile("inter-latin-ext-700-normal.woff");23const font = fontFile;24

    25app.get("/ogi", async function (req, res) {26    const content = template(27        req.query.prefix,28        req.query.title,29        req.query.subtitle30    );31

    32    try {33        const width = 1200;34

    35        const svg = await satori(toReactElement(content), {36            width,37            height: 630,38            fonts: [39                {40                    name: "Inter Latin",41                    data: font,42                    style: "normal",43                },44            ],45        });46

    47        const resvg = new Resvg(svg, {48            fitTo: {49                mode: "width",50                value: width,51            },52        });53

    54        const image = resvg.render();55

    56        res.set("Content-Type", "image/png");57        res.send(image.asPng());58    } catch (e) {59        console.error(e);60        res.status(500).send(61            "Failed to render the Open Graph image, see error logs"62        );63    }64});65

    66app.listen(3000);

To properly render the example, download [the font](inter-latin-ext-700-normal.woff) and place it in the same directory as the script.

And for a request:

    1http://localhost:3000/ogi?prefix=Open%20Graph&title=%20images&subtitle=are%20easy%20and%20powerful%20way%20to%20increase%20your%20awareness

The result is:

And updating the HTML meta tags:

    1<!-- Open Graph / Meta (Facebook) -->2<meta property="og:type" content="website" />3<meta property="og:url" content="https://example.com/" />4<meta property="og:title" content="Your title" />5<meta property="og:description" content="Your description" />6<meta7    property="og:image"8    content="https://example.com/ogi?prefix=Open%20Graph&title=%20images&subtitle=are%20easy%20and%20powerful%20way%20to%20increase%20your%20awareness"9/>10

    11<!-- Twitter -->12<meta property="twitter:card" content="summary_large_image" />13<meta property="twitter:url" content="https://example.com" />14<meta property="twitter:title" content="Your title" />15<meta property="twitter:description" content="Your description" />16<meta17    property="twitter:image"18    content="https://example.com/ogi?prefix=Open%20Graph&title=%20images&subtitle=are%20easy%20and%20powerful%20way%20to%20increase%20your%20awareness"19/>

Use your domain where you deployed the API instead of `example.com`.

The beauty of using `satori` instead of Puppeteer is that it works faster, consumes less memory, and can be embedded into your main app.

But the downside is that satori is a comparatively new library, so it might have a lot of rendering issues, and it doesn’t fully support all the latest HTML and CSS properties. If your rendering capabilities for you are enough to use satori, I would advise going with it. But if you want to make sure that everything works like a charm and supports the latest HTML features, I would advice using an established API to render images.

### Using simple and tailored solution for Open Graph images

In case you want to save time and money and don’t want to deal with HTML rendering engines and headless browsers. You can use a well-established screenshot API to generate OG images—[ScreenshotOne](https://screenshotone.com/).

Let’s examine how easier it is use an API rather Puppeteer or rendering engine like satori.

First, sign up at [ScreenshotOne](https://screenshotone.com/) to get an API key. Then install [an official SDK for JavaScript](https://screenshotone.com/docs/code-examples/#javascript-and-typescript-nodejs), but it is [available for many languages](https://screenshotone.com/docs/code-examples/):

    1npm i screenshotone-api-sdk

Let’s render an image:

    1import * as screenshotone from "screenshotone-api-sdk";2

    3// create API client4const client = new screenshotone.Client("M73PaLOC8lchKQ", "VjuscNqAfGCC4A");5

    6const template = (prefix, title, subtitle) => `<!doctype html>7<html>8<head>9  <meta charset="UTF-8">10  <meta name="viewport" content="width=device-width, initial-scale=1.0">11  <script src="https://cdn.tailwindcss.com"></script>12</head>13 <body class="bg-violet-700 h-screen flex">14    <div class="m-auto">15     <h1 class="text-white text-7xl font-serif"><span class="underline decoration-sky-500">${prefix}</span>${title}</h1>16     <h2 class="text-white text-3xl mt-5 font-light">${subtitle}</h2>17   </div>18</body>19</html>`;20

    21const generateOGImageURL = (prefix, title, subtitle) =>22    client.generateTakeURL(23        screenshotone.TakeOptions.html(template(prefix, title, subtitle))24    );25

    26const url = generateOGImageURL(27    "Open Graph",28    " images",29    "Are easy and powerful way to increase your brand awareness"30);31console.log(url);32// expected output: https://api.screenshotone.com/take?html=%3C%21doctype+html%3E%0...

The result is:

I hide the chat widgets to make a clean screenshot. If needed, you can also [block ads](https://screenshotone.com/docs/options/#block_ads) and [block cookie banners](https://screenshotone.com/docs/options/#block_cookie_banners).

Let’s update the meta tags:

    1<!-- Open Graph / Meta (Facebook) -->2<!-- ... other Open Graph tags -->3<!-- Use your template engine to render the URL. You don't need API routes, browsers, engines, or additional libraries. -->4<meta5    property="og:image"6    content="{{ generateOGImageURL('Open Graph', ' images', 'Are easy and powerful way to increase your brand awareness')  }}"7/>8

    9<!-- Twitter -->10<!-- ... other Twitter Graph tags -->11<!-- Use your template engine to render the URL. You don't need API routes, browsers, engines, or additional libraries. -->12<meta13    property="twitter:image"14    content="{{ generateOGImageURL('Open Graph', ' images', 'Are easy and powerful way to increase your brand awareness') }}"15/>

You don’t need hosting, API routes, handling memory issues, and care about bugs. Most of the problems are already covered.

You can also dynamically generate an OG image based on the site’s screenshot or selector. You can block cookie banners, ads, and chats to make the screenshot look clean. .

It is a headache-less API. [Sign up](https://screenshotone.com/). It is free to start.

### Using an OG image generator like ogimage.org

Another alternative is to use fully-fledged solution like [ogimage.org](https://ogimage.org) that allows you to outsource all the headaches related to generating OG images.

They have a library of [OG image templates](https://ogimage.org/templates) and can even set up everything for you. It is an option worth checking out.

Test Open Graph images

----------------------

Once you finish your solution, test it, and it works fine. Test and validate your open graph images with official debuggers:

1.  Use a [debugger from Meta (Facebook)](https://developers.facebook.com/tools/debug/).

2.  Try a [social card validator from Twitter](https://opengraphdebug.com/posts/x-twitter-og-debugger).

3.  Test with a [LinkedIn Post Inspector](https://www.linkedin.com/post-inspector/).

4.  Use a [Pinterest URL debugger](https://developers.pinterest.com/tools/url-debugger/).

5.  For Telegram, WhatsApp or iMessage, send the link to your friend.

Or use [one of the best Open Graph Debuggers](https://opengraphdebug.com/) that supports all of the above and more.

Known issues

------------

I encountered many issues while rendering and working with OG images. And I want to share them with you.

### Open Graph image requirements

The recommended image size is 1200x630px for most social networks, and the file size must not exceed a few hundred kilobytes.

Check out [the Open Graph image requirements guide by OpenGraphDebug.com](https://opengraphdebug.com/posts/og-image-requirements) for more details.

### Refresh cache for OG image in Telegram

In order to refresh the cache if the image has been changed, go to [@webpagebot](https://telegram.me/webpagebot) and send the URL (10 is maximum) you want to clear the cache for.

Telegram servers automatically will scan your site and generate a new Open Graph image preview, site name, and description.

Remember to have the OG prefix in your `HTML` tag as: `<html prefix="og: http://ogp.me/ns#">` or the Telegram bot will not update the graph cache.

### Always use an absolute URL

It might be a simple task for you, but many apps don’t crawl an OG image path right if it is specified as relative.

Always specify an absolute URL, including the host and protocol, to the image:

    1<!-- Not this: -->2<meta property="og:image" content="/image.png" />3<meta property="twitter:image" content="/image.png" />4

    5<!-- But this: -->6<meta property="og:image" content="https://example.com/image.png" />7<meta property="twitter:image" content="https://example.com/image.png" />

A few tips on the social card design

------------------------------------

I prepared a few tips that you might find helpful to increase the click rate for the link to your site on social media networks. They are not proven to be always working, it is not a science, and you need to test it.

### Place a button on the image

Many reported that placing a button on the OG image increased click through rate.

Nothing is guaranteed. You may want to test it.

### Increase the font size

Unless it is an intention or design effect to attract attention, don’t use small fonts, and make the font size as large as possible. Test if you can read the text on the resulting image.

### Brand colors and fonts

Obvious, but many forget to reuse their brand colors and fonts. Social cards aim to increase your brand awareness and, if possible, to invite users for a click.

### Adapt to social networks if possible

Always test how it looks in social networks, white and back styles.

And you might try to adapt to Twitter because twitter has a special meta tag. You can try to play with Twitter colors and button styles to make it feels native.

### Get inspiration from others

Check out [Open Graph Examples](https://opengraphexamples.com/) for advice, helpful content, and tools to make your Open Graph social cards stand out.

A closing thought

-----------------

In case you like building, I advise you to use Puppeteer or satori from Vercel (especially if you use Next.js). But if you want a quick and hassle-free solution, feel free to use [ScreenshotOne API](https://screenshotone.com/), which is ready to render any kind of HTML for your needs. I hope you enjoyed our journey to link previews and how to generate them.

Have a nice day!

Read more posts

---------------

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

[View all posts](/blog/)

#### [OpenClaw with Playwright or Puppeteer: how to install browser support](/blog/openclaw-playwright-puppeteer/)

A practical guide to OpenClaw browser automation, why Playwright is the documented path, where Puppeteer fits, how to make screenshots, and when ScreenshotOne is the better choice for screenshot-only flows.

Read more

#### [ScreenshotOne reached $200K ARR with 400+ paying customers](/blog/200000-arr-and-400-paying-customers/)

It is a good milestone to make a compact snapshot of the insights that (maybe?) led to it.

Read more

#### [NemoClaw an enterprise alternative to OpenClaw by NVIDIA](/blog/openclaw-alternative-by-nvidia/)

A practical look at what NemoClaw appears to be, what OpenClaw already is, and the main differences between them as of March 11, 2026.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/open-graph-images
----

Automate Website Screenshots

1 min read

Automate Open Graph image generation

====================================

You can use our screenshot API to effortlessly generate images when sharing links on social media or messengers.

Producing open graph visuals is crucial for increasing engagement with links on social media channels. ScreenshotOne facilitates this by allowing you to generate open graph images for links to your website with one simple API call. Don’t lose on potential for increasing your link clicks.

How our screenshot API can help

-------------------------------

Employing the website screenshot API, developers can straightforwardly produce visuals ideal for open graph tags, ensuring shared links on social networks are paired with attractive previews.

You can do that in 3 simple steps:

1.  [Sign up to ScreenshotOne](https://dash.screenshotone.com/sign-up) and get your API key.

2.  Prepare the HTML template you want to use as an Open Graph image for your website pages.

3.  Generate the image with ScreenshotOne and use it in meta tags.

How ScreenshotOne already helps

-------------------------------

There are a lot of examples of how our customers use ScreenshotOne for automating screenshots. But let us share a pair of examples related to Open Graph image generation:

1.  [Stagetimer uses ScreenshotOne for Open Graph image generation.](/blog/how-stagetimer-automates-og-image-generation/)

2.  [How ogimage.org adopted ScreenshotOne.](/blog/how-ilias-ism-a-founder-of-the-magicspace-seo-agency-uses-screenshotone-daily/)

And there are many more to come.

Alternatives

------------

With our API we get you covered and you get full control over your image generation without developing your own solution or using complex libraries.

But! we have [a complete guide](/blog/open-graph-images/) on how you can generate open graph images yourself.

ScreenshotOne helps us easily make instant OG images for all our clients at our [SEO agency](http://magicspace.agency), it's the easiest way to make quick screenshots fast and they look amazing.

Ilias Ism

Founder, [ogimage.org](https://ogimage.org/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/font-trends
----

Automate Website Screenshots

1 min read

Font Trends Analysis

====================

Use our font detection API to provide insights into typography trends of top-ranking websites across various industries.

Use [ScreenshotOne font detection API](/font-detection-api/) to provide insights into the typography trends of top-ranking websites in various industries.

Typography Trend Analysis

-------------------------

Understanding what design choices successful websites make can provide valuable competitive intelligence. ScreenshotOne’s font detection API enables SEO tools to analyze the typography patterns of top-ranking websites, revealing trends that may contribute to their success.

Competitive Typography Intelligence

-----------------------------------

SEO and marketing professionals can use font detection data to understand how competitors present their content and whether certain typography choices correlate with better search rankings or user engagement. This information helps inform design decisions for optimization.

Check out [our guide on how to detect website fonts](/docs/guides/how-to-detect-website-fonts/) for more details.

Data-Driven Design Decisions

----------------------------

By integrating ScreenshotOne API, SEO tools can automatically analyze typography across large sets of websites, identifying patterns and trends without manual inspection. This saves countless hours of research and provides actionable insights that would be impractical to gather manually.

I found ScreenshotOne very easy to get started with. The intuitive playground feature allowed me to seamlessly integrate and test our campaigns.

I love the playground, and it just works.

Stefan Wirth

Maker, [Bridesmaid For Hire](https://bridesmaidforhire.com/ai-wedding-speech-and-vow-generators)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

### Personalized Onboarding

Personalize onboarding by analyzing a customer's website visually and using screenshots throughout the setup flow.

[Read more →](/use-cases/personalized-onboarding/)

### Automated Web Audits with Font Analysis

With our font detection API generate comprehensive typography reports to optimize websites for aesthetics and performance.

[Read more →](/use-cases/automated-web-audits-fonts/)

### Design Tools Font Detection

Use our font detection API to help designers identify and analyze typography on any website.

[Read more →](/use-cases/design-apps-font-detection/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/8
----

Changes and updates

-------------------

Stay updated with the latest information about new features, bug fixes, and optimizations at ScreenshotOne

### Product updates in the last 12 months

Dec 13, 2024

#### [Improved blocking of banners and popups](/changelog/improved-blocking-of-banners-and-popups/)

Improved generic algorithm to bypass blockers and better banner exclusion heuristics.

Read more →

1 min read

Dec 3, 2024

#### [Improved full-page scrolling for lazy-loaded content](/changelog/improved-full-page-scrolling-for-lazy-loaded-content/)

Better scrolling routine to load content reliably on long pages.

Read more →

1 min read

Nov 27, 2024

#### [Get favicon used by a website with ScreenshotOne API](/changelog/metadata-icon/)

Now you can get favicon used by a website with ScreenshotOne API in just one simple API call.

Read more →

1 min read

Nov 19, 2024

#### [Documentation for LLMs](/changelog/docs-for-llms/)

ScreenshotOne now supports documentation format specifically targeted for LLMs—llms.txt and llms-full.txt.

Read more →

1 min read

Nov 13, 2024

#### [Fail if there is nothing to click on](/changelog/error-on-click-selector-not-found/)

A new option has been added to fail or not to fail the screenshot rendering if there is nothing to click on.

Read more →

1 min read

Nov 12, 2024

#### [Update your company information in the dashboard](/changelog/company-information-management/)

Starting today, you can update your company information in the dashboard. It includes updating the address, tax number, company number, and company name.

Read more →

1 min read

Nov 7, 2024

#### [ScreenshotOne Playground has been improved](/changelog/improved-playground-synchronized-all-options/)

A few important updates in ScreenshotOne Playground.

Read more →

1 min read

Oct 29, 2024

#### [Choose the full page screenshot algorithm](/changelog/full-page-algorithm/)

Now, you can choose the full page screenshot algorithm.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/integrations/bubble
----

Integrations

1 min read

Bubble

======

Add website screenshots to your Bubble content with a plugin.

No-Code Automation CMS

Resources

---------

*   [Documentation](https://screenshotone.com/docs/no-code/bubble/)

“It is super simple, works very well and fast.

Klaas Foppen

Founder, [Promptwatch](https://screenshotone.com/blog/promptwatch/)

Check more Integrations

-----------------------

No-code tools, AI, code libraries, and more.

[Check more Integrations](/integrations/)

No-Code Automation

### Make

Use ScreenshotOne with Make to automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

[Read more →](/integrations/make/)

No-Code Automation

### Clay

Generate website screenshots inside Clay to qualify leads, assess content, and enrich rows with visual context automatically.

[Read more →](/integrations/clay/)

No-Code Automation

### Zapier

Automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos in Zapier.

[Read more →](/integrations/zapier/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/customer-support-enhancement
----

Automate Website Screenshots

1 min read

Customer Support Enhancement

============================

Use screenshots to quickly resolve customer queries about website navigation or features.

Small companies can elevate their customer support experience by integrating ScreenshotOne API to capture and share real-time screenshots of their website or application. This method is particularly effective for visualizing solutions to customer queries regarding website navigation or feature utilization.

Enhancing Support with Real-Time Visuals

----------------------------------------

With the ScreenshotOne API, support teams can generate screenshots on-demand, providing visual guidance to customers. This not only clarifies instructions but also reduces the back-and-forth often required when resolving support tickets, leading to a more efficient and satisfactory customer experience.

Cost-Effective Support Solution

-------------------------------

Implementing a screenshot API is a cost-effective alternative to more labor-intensive support solutions. It minimizes the need for lengthy textual explanations and reduces the potential for miscommunication, saving time for both the support team and the customer.

["ScreenshotOne](/) is our screenshot solution that has powerful and flexible tools. This tool suits ourbusiness, as they are developing what you need precisely and helping integrate it into our business.

The best is we can reach support in minutes!

[ScreenshotOne](/) saves us money & time, and best of all, it brings reliability to our business. We just set up & forgot.It works smoothly.

Luvian Cotak

Founder, [PDFflyers.com](https://pdfflyers.com/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/how-to-take-website-screenshots-with-go
----

How to take website screenshots with Go

=======================================

The article examines how you can take screenshots of any URL with Go (a.k.a. Golang) by using Selenium, Puppeteer alternatives, Playwright, or screenshot API as a service.

[Blog post](/blog/) 4 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Jun 10, 2022

#### Tags

[Screenshot rendering](/blog/tags/screenshot-rendering/)

Let’s check out:

1.  [Selenium WebDriver client for Go](#selenium-webdriver-client-for-go).

2.  You can use [the Go analog of Puppeteer](#go-analog-of-puppeteer).

3.  [Playwright library](#playwright).

4.  Or [Screenshot API as a service](#screenshot-api-as-a-service).

They might overlap, but there is no best solution. Each depends on your use case and requirements.

Selenium WebDriver client for Go

--------------------------------

Selenium is a well-known kid in the QA automation area, so it is easy to start taking screenshots if you plan to write automation tests or already do it.

Install [Selenium WebDriver client for Go](https://github.com/tebeka/selenium) into your project:

Terminal window

    1go get github.com/tebeka/selenium

Download the latest version [ChromeDriver](https://sites.google.com/chromium.org/driver/) and the latest [remote Selenium WebDriver standalone server](https://selenium-release.storage.googleapis.com/index.html), place them in the same source directory, and you are ready to Go:

    1package main2

    3import (4  "fmt"5  "os"6

    7  "github.com/tebeka/selenium"8)9

    10func main() {11  const (12    seleniumPath     = "./selenium-server-standalone-3.5.3.jar"13    chromeDriverPath = "./chromedriver"14    port             = 808015  )16  opts := []selenium.ServiceOption{17    selenium.ChromeDriver(chromeDriverPath),18    selenium.Output(os.Stderr),19  }20  selenium.SetDebug(true)21  service, err := selenium.NewSeleniumService(seleniumPath, port, opts...)22  if err != nil {23    panic(err) // panic is used only as an example and is not otherwise recommended24  }25  defer service.Stop()26

    27  // connect to the WebDriver instance running locally28  caps := selenium.Capabilities{"browserName": "chrome"}29  wd, err := selenium.NewRemote(caps, fmt.Sprintf("http://localhost:%d/wd/hub", port))30  if err != nil {31    panic(err)32  }33  defer wd.Quit()34

    35  if err := wd.Get("https://scalabledeveloper.com"); err != nil {36    panic(err)37  }38

    39  screenshot, err := wd.Screenshot()40  if err != nil {41    panic(err)42  }43

    44  out, err := os.Create("scalabledeveloper.jpg")45  if err != nil {46    panic(err)47  }48  defer out.Close()49

    50  _, err = out.Write(screenshot)51  if err != nil {52    panic(err)53  }54}

If you just want to take one or two screenshots locally, the Selenium WebDriver client is not the best fit. As I wrote earlier, it better serves you already write automation tests with Selenium or plan to write them.

Go analog of Puppeteer

----------------------

[chromedp](https://github.com/chromedp/chromedp) is the closest analog to [Node.js Puppeteer](https://screenshotone.com/blog/how-to-take-a-screenshot-with-puppeteer/) in Go, a faster, more straightforward way to drive browsers supporting the [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/) in Go without external dependencies.

While you can also use `chromedp` for automation testing, it is much light weighter and simpler than Selenium and allows any automation over the browser. Everything you can do manually with a browser, you can also do with `chromedp`.

And it is super easy to use:

Terminal window

    1go get github.com/chromedp/chromedp

And then just:

    1func main() {2  ctx, cancel := chromedp.NewContext(context.Background())3  defer cancel()4

    5  var buf []byte6  if err := chromedp.Run(ctx,7    chromedp.Navigate(`https://example.com`),8    chromedp.FullScreenshot(&buf, 95),9  ); err != nil {10    log.Fatal(err)11  }12

    13  if err := ioutil.WriteFile("example.jpg", buf, 0644); err != nil {14    log.Fatal(err)15  }16}

It is very lightweight compared to Selenium and allows a broad spectrum for automation of the browser. You can use it for crawling, scrapping, taking screenshots, etc.

If you need the simplest way to take screenshots, you do not expect to take millions of them, and I would go with `chromedp`. But if you want to take screenshots from different browsers or think about managing instances of browsers, there is a more straightforward way to go.

Playwright

----------

[Playwright](https://github.com/playwright-community/playwright-go) is the best Go library to automate [Chromium](https://www.chromium.org/Home), [Firefox](https://www.mozilla.org/en-US/firefox/new/), and [WebKit](https://webkit.org/) with a unified API. It is built to enable cross-browser web automation.

If you want to take screenshots in different browsers, Playwright is the best choice.

Install the library with `go get`:

Terminal window

    1go get github.com/playwright-community/playwright-go

Do not forget to install browser and OS dependencies:

Terminal window

    1go run github.com/playwright-community/playwright-go/cmd/playwright install --with-deps

And then take a screenshot:

    1package main2

    3import (4  "log"5

    6  "github.com/playwright-community/playwright-go"7)8

    9func main() {10  pw, err := playwright.Run()11  if err != nil {12    log.Fatalf("could not launch playwright: %v", err)13  }14  browser, err := pw.Chromium.Launch()15  if err != nil {16    log.Fatalf("could not launch Chromium: %v", err)17  }18  page, err := browser.NewPage()19  if err != nil {20    log.Fatalf("could not create page: %v", err)21  }22  if _, err = page.Goto("https://example.com/", playwright.PageGotoOptions{23    WaitUntil: playwright.WaitUntilStateNetworkidle,24  }); err != nil {25    log.Fatalf("could not goto: %v", err)26  }27  if _, err = page.Screenshot(playwright.PageScreenshotOptions{28    Path: playwright.String("example.png"),29  }); err != nil {30    log.Fatalf("could not create screenshot: %v", err)31  }32  if err = browser.Close(); err != nil {33    log.Fatalf("could not close browser: %v", err)34  }35  if err = pw.Stop(); err != nil {36    log.Fatalf("could not stop Playwright: %v", err)37  }38}

`Playwright` is the best choice. It is as powerful as `chromedp` but allows you to run different browser instances if needed.

If you plan to take millions of screenshots and manage browser instances, you can do it yourself, but it is better to outsource to well-established services.

Screenshot API as a service

---------------------------

We specialize in taking screenshots and managing browser instances at scale. We provide [a high-quality Go client to take screenshots](https://github.com/screenshotone/gosdk) and cover a variety of use cases.

Easy to install:

Terminal window

    1go get github.com/screenshotone/gosdk

And easy to use:

    1client, err := screenshots.NewClient("IVmt2ghj9TG_jQ", "Sxt94yAj9aQSgg")2if err != nil {3    // ...4}5

    6options := screenshots.NewTakeOptions("https://example.com").7    Format("png").8    FullPage(true).9    DeviceScaleFactor(2).10    BlockAds(true).11    BlockTrackers(true)12

    13image, _, err := client.Take(context.TODO(), options)14if err != nil {15    // ...16}17

    18out, err := os.Create("example.png")19if err != nil {20    // ...21}22defer out.Close()23

    24_, err = out.Write(out, image)25if err != nil {26    // ...27}

If you feel that it is the best fit for you, feel free [to sign up for our screenshot API](https://screenshotone.com/) and get the access key.

Summary

-------

Pick the solution which suits your needs best. If you decide to go with our API, please ask any questions and mail us at [support@screenshotone.com](mailto:support@screenshotone.com). And have a nice day 👋

By the way, you might also find interesting how to:

*   [take web screenshots with Java](/blog/how-to-take-website-screenshots-with-java/)

*   [take web screenshots with JavaScript or TypeScript (Node.js)](/blog/how-to-take-website-screenshots-with-javascript-and-typescript-nodejs)

*   [take web screenshots with PHP](/blog/how-to-take-website-screenshots-with-php/)

Read more Screenshot rendering

------------------------------

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

[View all posts](/blog/tags/screenshot-rendering/)

#### [How to Take Bulk Screenshots with Playwright in Python](/blog/bulk-screenshots-playwright-python/)

Learn how to automate bulk website screenshots with Playwright in Python. Master async batch processing, concurrent screenshots, rate limiting, and error handling for large-scale screenshot automation.

Read more

#### [What is a screenshot or HTML rendering API?](/blog/what-is-a-screenshot-or-html-rendering-api/)

A screenshot API or a screenshot as a service is usually a cloud or a remote server service that provides the ability to render any website, HTML, Markdown, or even PDF by making a request to the service, be it over HTTP, TCP, or any other protocol.

Read more

#### [How to Take Screenshots with pyppeteer in Python](/blog/pyppeteer-python-screenshots/)

Guide to taking screenshots with pyppeteer in Python. Learn the basics, full page captures, and why you should migrate to Playwright.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/tags/screenshot-rendering/4
----

Screenshot Rendering

--------------------

Best practices for rendering reliable website screenshots.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to add custom scripts to a page in Puppeteer](/blog/how-to-add-custom-scripts-to-a-page-in-puppeteer/)

How to add custom scripts to a page in Puppeteer. Let's discover how it works quickly."

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jun 24, 2022

•

2 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to add custom styles to a page in Puppeteer](/blog/how-to-add-custom-styles-to-a-page-in-puppeteer/)

To add custom styles to any page use Puppeteer's page method \`page.addStyleTag(options)\`. Let's discover how it works quickly.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jun 24, 2022

•

2 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots with PHP](/blog/how-to-take-website-screenshots-with-php/)

The article examines how you can take screenshots of any URL with PHP by using Selenium, Puppeteer alternatives, or screenshot API as a service.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jun 14, 2022

•

3 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots with JavaScript or TypeScript (Node.js)](/blog/how-to-take-website-screenshots-with-javascript-or-typescript-nodejs/)

The article examines how you can take screenshots of any URL with Javascript and TypeScript (Node.js) by using Selenium, Puppeteer alternatives, Playwright, or screenshot API as a service.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jun 14, 2022

•

4 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots with Java](/blog/how-to-take-website-screenshots-with-java/)

The article examines how you can take screenshots of any URL with Java by using Selenium, Puppeteer alternatives, Playwright, or screenshot API as a service.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jun 10, 2022

•

3 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots with Go](/blog/how-to-take-website-screenshots-with-go/)

The article examines how you can take screenshots of any URL with Go (a.k.a. Golang) by using Selenium, Puppeteer alternatives, Playwright, or screenshot API as a service.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jun 10, 2022

•

4 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take screenshots with Puppeteer](/blog/how-to-take-a-screenshot-with-puppeteer/)

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

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Apr 29, 2025

•

11 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/6
----

Changes and updates

-------------------

Stay updated with the latest information about new features, bug fixes, and optimizations at ScreenshotOne

### Product updates in the last 12 months

Apr 19, 2025

#### [Better numbers formatting in the dashboard](/changelog/better-numbers-formatting-in-the-dashboard/)

We improve UI/UX of rendering numbers in the dashboard for better readability.

Read more →

1 min read

Apr 17, 2025

#### [More algorithms for screenshots by selectors](/changelog/selector-algorithm/)

We added more algorithms for screenshots by selectors.

Read more →

1 min read

Apr 9, 2025

#### [Better code examples in the playground](/changelog/improved-code-examples-in-playground/)

Improved code examples in the playground and added all official supported ScreenshotOne SDKs.

Read more →

1 min read

Apr 8, 2025

#### [Improved design of the authentication pages](/changelog/updated-design-of-authentication-pages/)

We updated the design of the authentication pages to make them more user-friendly and consistent.

Read more →

1 min read

Mar 17, 2025

#### [Fail ScreenshotOne API requests on purpose](/changelog/fail-if-request-failed/)

Use a new option to fail ScreenshotOne API requests on purpose.

Read more →

1 min read

Mar 17, 2025

#### [Convert any website to Markdown format with ScreenshotOne API](/changelog/website-to-markdown-format/)

Now you can convert any website to Markdown format with ScreenshotOne API in just one simple API call.

Read more →

1 min read

Mar 16, 2025

#### [Trigger screenshot download](/changelog/attachment-name/)

Now you can set attachment filename to trigger screenshot download in the browser.

Read more →

1 min read

Mar 7, 2025

#### [Remove organization members](/changelog/remove-organization-member/)

Improvements to the organization management.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/contributors/daniel-kempe
----

Daniel Kempe

------------

View all Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [ScreenshotOne took away one major complexity off the Supawrite plate](/blog/supawrite/)

A short story about how ScreenshotOne helps a content marketing platform automate their screenshot workflow.

Written by

[Daniel Kempe](/contributors/daniel-kempe/)

Published on

Dec 2, 2025

•

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/monitoring-website-changes
----

Monitoring website changes

==========================

I tried many ways to monitor and detect website changes. But I was always disappointed by the results. I want to share a few tips that might help you to get better results, if you plan to do the same.

[Blog post](/blog/) 4 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Apr 27, 2025

Why monitor websites and detect changes

---------------------------------------

There is a lot of use cases on why and when to monitor websites and detect changes. Most of them are related to competitor monitoring.

### Competitor monitoring

#### Pricing “wars”

Knowing the moment a rival drops (or hikes) a price lets you react before customers notice. It keeps your own prices nimble and protects margin.

You do not need to react to every single price change of your competitors. But overall monitoring your niche and what happens, can help you to stay ahead or at least to keep up with the market.

#### Product strategy

While the feedback from your customers is the most important source of product strategy, tracking changes when your competitors rename a plan, add a “free trial” banner, or quietly remove a feature can give you a hint what is working (or failing) for them.

#### Marketing moves

New hero images, headline tests, or fresh testimonials show which story they are betting recently.

#### SEO signals

Monitoring title tags, meta descriptions, and schema helps you catch sudden plays to change ranking and adapt accordingly.

### Compliance and legal

If one of your suppliers changes their terms of service, privacy pages, or disclaimer edits, you need to know about it.

It can expose you to new risks or new requirements.

### Stock, inventory, and availability

If you rely on suppliers to provide you with stock status, you need to know when it changes.

If a product page flips from “out of stock” to “ships today,” that is actionable information in retail and e-commerce.

How to monitor website changes

------------------------------

For this example, let’s say we want to monitor your competitor’s website for changes.

### Start simple, prototype

1.  **Pick the pages to monitor.** Start lean: 10-20 URLs that actually drive revenue or traffic for the competitor. Expand only when alerts stay useful.

2.  **Fetch the page.**

    *   _Static sites:_ a simple GET request plus an HTML diff is often enough.

    *   _Dynamic or single-page apps:_ load with Playwright or Puppeteer so the JavaScript runs and the price actually appears.

3.  **Normalize the noise.** Strip timestamps, CSRF tokens, rotating IDs, and ad placeholders before you diff. A regex pass or DOM select-and-delete keeps false positives low.

4.  **Choose your diff.**

    *   **DOM diff** for structural changes (price node moved).

    *   **Text diff** for wording tweaks (plan names).

    *   **Screenshot diff** for pixel-level shifts (banner swapped, button color). A headless browser + ScreenshotOne or similar gives you a freeze-frame you can compare later.

5.  **Store snapshots.** Dump raw HTML and/or PNGs to any S3-compatible or your database with a timestamp. Space is cheap; history is priceless.

6.  **Run on a schedule.** A cron every 15 minutes to 24 hours covers most needs. Burstier pages (flash sales) may need tighter loops with exponential back-off.

7.  **Hide your footsteps.** Rotate user-agents, keep cookies minimal, and go through residential or datacenter proxies when geo or rate limits block you.

8.  **Alert wisely.** Webhook to Slack, e-mail, or even a small dashboard. Bundle related changes so you don’t spam yourself. Silence is as valuable as noise.

Automate and scale once the basic algorithm works.

Nuances and pitfalls of website change monitoring

-------------------------------------------------

It would take a book to cover all nuances and pitfalls of website change monitoring. But I want to share a few of them that I encountered.

### CAPTCHA and bot protections

Many websites have CAPTCHA and bot protections. It might break your monitoring process. How to solve? You need to use stealth

1.  Use stealth browsers.

2.  Use residential or datacenter proxies.

3.  Use a warm human cookie jar, user-agent, and other browser fingerprints.

4.  Use web scraping services that have built-in protections against CAPTCHA and bot protections.

But always consider working within the legal boundaries. Respect the terms of service of the website you are monitoring.

### Login walls

Some important information only appears after sign-in. Use a dedicated account, store its cookies, and refresh the session with realistic pauses.

Notice that many services prohibit automation of user interactions after the user has signed in.

### Content based on location

A US sale might not show up from an EU IP—use region-matched proxies.

### Changing markup

Their front-end teams refactor classes, IDs, and other markup. Your CSS selectors break. Prefer stable attributes (data-id) or use fuzzy CSS selectors. Or check out if you can use AI for selectors.

### Dynamic widgets

Currency converters, chat bubbles, or randomized testimonials change every load and pollute diffs. Remove them in a preprocessing step.

### A/B tests

It is one of the toughest challenges.

Competitors can run multivariate tests, so two pulls five minutes apart may disagree.

If possible try to keep your browser session. Or render a few pages and and only detect changes in the majority of similar pages.

### Rate limits

Too many rapid requests flag you as a bot. Space calls and randomize timing. But always consider the rate limits of the website you are monitoring and respect their terms of service.

### Localize the change

Small annoyances add up. Most “false alarms” come from markup churn or random tokens—spend an hour cleaning those early and you save days later.

Try to localize the area you want to monitor. E.g. if it is only a pricing block or headline.

Conclusion

----------

The high-level approach is simple:

1.  Decide what matters.

2.  Capture snapshots with the least friction and try to localize the changes.

3.  Diff, filter, and alert only on the signals you care about.

But as I mentioned website change monitoring is not easy.

Playwright, Puppeteer, a few proxies, and disciplined diffing cover 90% of use cases. Start simple, tune thresholds, and let the data tell the story.

Read more posts

---------------

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

[View all posts](/blog/)

#### [How to take a screenshot of a webpage in Haskell](/blog/how-to-take-a-screenshot-of-a-webpage-in-haskell/)

It's very a common need to take a screenshot of a live website. On a project I worked on recently, we had a legal requirement to take screenshots of forms which our users filled, as at the time they filled the forms, for consent documentation purposes.

Read more

#### [ScreenshotOne is featured in the Cloudflare "Built With" series](/blog/screenshotone-and-cloudflare/)

The Cloudflare platform is at the core of ScreenshotOne—it is used for caching, API gateway, storage for screenshots, and many other functions. It was an opportunity to learn about the company from a closer distance.

Read more

#### [OpenAI 4o image generation and marketing opportunities](/blog/openai-4o-marketing-opportunities/)

OpenAI 4o image generation is a really good model that can change the way you automate marketing

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/improved-blocking-of-banners-and-popups
----

Improved blocking of banners and popups

=======================================

Improved generic algorithm to bypass blockers and better banner exclusion heuristics.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Dec 13, 2024

ScreenshotOne now does a better job at keeping screenshots clean from cookie banners and popups:

*   Improved make the algorithm more generic to bypass common website blockers before rendering.

*   Improved banner exclusion heuristics to reduce false positives and avoid accidental navigations.

These updates decrease the chance of obstructive elements leaking into screenshots, especially on websites that deploy aggressive overlays or consent widgets.

If you notice a page where banners still slip through, please send an example to `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Fixed a validation issue in the playground](/changelog/fixed-a-playground-issue/)

We fixed a validation issue in the ScreenshotOne playground caused by selector scroll into view.

Read more →

1 min read

#### [Better numbers formatting in the dashboard](/changelog/better-numbers-formatting-in-the-dashboard/)

We improve UI/UX of rendering numbers in the dashboard for better readability.

Read more →

1 min read

#### [Support for multiple API keys](/changelog/multiple-api-keys/)

You can now use multiple API keys to the access ScreenshotOne API.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/tags/customer-stories
----

Customer Stories

----------------

Customer stories and case studies from teams using ScreenshotOne.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [How AdKit automated onboarding](/blog/adkit/)

A short story by the founder of AdKit about how they use ScreenshotOne for onboarding automation.

Written by

[Nicolas Jeannen](/contributors/nicolas-jeannen/)

Published on

Mar 12, 2026

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Why FrameKit chose ScreenshotOne for their business](/blog/framekit/)

A short story about how and why FrameKit chose ScreenshotOne for their use case.

Written by

[Anatoly Pashias](/contributors/anatoly-pashias/)

Published on

Mar 2, 2026

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Why Promptwatch wins in the AI search space](/blog/promptwatch/)

About how Promptwatch uses ScreenshotOne to automate website screenshots and why that matters.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Klaas Foppen](/contributors/klaas-foppen/)

Updated on

Feb 11, 2026

•

3 min read

[Customer stories](/blog/tags/customer-stories/)

#### [ScreenshotOne took away one major complexity off the Supawrite plate](/blog/supawrite/)

A short story about how ScreenshotOne helps a content marketing platform automate their screenshot workflow.

Written by

[Daniel Kempe](/contributors/daniel-kempe/)

Published on

Dec 2, 2025

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Landing Gallery uses ScreenshotOne to automate screenshot generation](/blog/landing-gallery/)

How and why "Landing Gallery" uses ScreenshotOne to automate screenshot generation for their landing page inspiration platform.

Written by

[Chris Jayden](/contributors/chris-jayden/)

Published on

Nov 30, 2025

•

3 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How RankPill uses ScreenshotOne](/blog/rankpill/)

Sharing how RankPill uses ScreenshotOne to automate website screenshot generation for SEO and GEO automation.

Written by

[Modest Mitkus](/contributors/modest-mitkus/), [Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Nov 6, 2025

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How and why Saaspo uses ScreenshotOne to automate screenshot generation](/blog/saaspo/)

Saaspo chose ScreenshotOne to automate tedious and boring work to generate pixel-perfect screenshots for their platform. Why?

Written by

[Andy Hooke](/contributors/andy-hooke/), [Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Nov 4, 2025

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Outrank enriches content generation with ScreenshotOne](/blog/outrank/)

A short story about how and why Outrank uses ScreenshotOne for screenshot generation to enrich SEO content.

Written by

[Eugene Zolotarenko](/contributors/eugene-zolotarenko/), [Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jun 29, 2025

•

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/contributors/dmytro-krasun/4
----

Dmytro Krasun

-------------

With more than a decade of experience in software engineering, I share the best practices and solutions you can apply to your problems in the space of headless browsers. You can also find me on [Twitter](https://twitter.com/DmytroKrasun) and [LinkedIn](https://www.linkedin.com/in/dmytrokrasun)

View all Changelog

#### [OpenAI 4o image generation and marketing opportunities](/blog/openai-4o-marketing-opportunities/)

OpenAI 4o image generation is a really good model that can change the way you automate marketing

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 30, 2025

•

2 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Magic Pages: Showcasing Product Adoption with Screenshots](/blog/magic-pages/)

How and why "Magic Pages" used ScreenshotOne to showcase how their customers use their product.

Written by

[Jannis Fedoruk-Betschki](/contributors/jannis-fedorukbetschki/), [Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 28, 2025

•

1 min read

#### [Monitoring website changes](/blog/monitoring-website-changes/)

I tried many ways to monitor and detect website changes. But I was always disappointed by the results. I want to share a few tips that might help you to get better results, if you plan to do the same.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Apr 27, 2025

•

4 min read

#### [A Chrome Extension by ScreenshotOne for rendering full-page screenshots](/blog/full-page-chrome-extension/)

We just launched a new full-page screenshot Chrome extension that allows you to take full page screenshots of any websites and annotate them in a few clicks.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Dec 28, 2024

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Integrating ScreenshotOne into the directory management platform](/blog/makeadir-feedback/)

How and why "Make a Directory" used ScreenshotOne to automate screenshots for directory websites.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Bohdan Shulha](/contributors/bohdan-shulha/)

Published on

Dec 23, 2024

•

3 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Automating screenshots for directory websites with ScreenshotOne](/blog/directify-feedback/)

How and why "Directify" used ScreenshotOne to automate screenshots for directory websites.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Sergey Karakhanyan](/contributors/sergey-karakhanyan/)

Published on

Dec 15, 2024

•

2 min read

#### [Blast Banners with ScreenshotOne](/blog/blast-banners/)

A funny game built on top of ScreenshotOne API.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Oct 29, 2024

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Branding 5 uses ScreenshotOne for competitor analysis](/blog/how-branding5-uses-screenshotone/)

If you are interested in diving deeper into the Branding 5 use case and discover if ScreenshotOne might be useful for you, too, keep reading.

Written by

[Matthias Neumayer](/contributors/matthias-neumayer/), [Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Oct 4, 2024

•

2 min read

[Engineering](/blog/tags/engineering/)

#### [Cloudflare Workers as an API gateway](/blog/cloudflare-workers/)

Check out how ScreenshotOne relies on Cloudflare Workers as an API gateway to enhance performance, reliability, and cost-efficiency.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Aug 3, 2024

•

7 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Spectate uses ScreenshotOne to improve incident observability](/blog/how-spectate-uses-screenshotone/)

If you are interested in diving deeper into the Spectate use case and discover if ScreenshotOne might be useful for you, too, keep reading.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Bjarn Bronsveld](/contributors/bjarn-bronsveld/)

Published on

Jul 21, 2024

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How GetWebsite.Report uses ScreenshotOne for screenshot automation tasks](/blog/how-website-report-uses-screenshotone/)

If you are interested in diving deeper into the GetWebsite.Report use case and discover if ScreenshotOne might be useful for you, too, keep reading.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jun 4, 2024

•

2 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How FounderPal uses ScreenshotOne for landing page analysis](/blog/how-founderpal-uses-screenshotone/)

If you are interested in diving deeper into the FounderPal use case and discover if ScreenshotOne might be useful for you, too, keep reading.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jun 2, 2024

•

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/debugging-and-fixing-a-tricky-issue
----

A four day hiking trip into ScreenshotOne infrastructure to solve an issue

==========================================================================

A short story about how I debugged and fixed an uptime issue.

[Blog post](/blog/) 3 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jul 21, 2025

#### Tags

[Engineering](/blog/tags/engineering/)

For three days, I have been hunting an issue that caused one of my uptime monitors to go wild. I could barely sleep.

I fixed it. **No customers were impacted at all.**

But before you laugh and judge me, please read.

One of the monitors started to alert

------------------------------------

On July 17, one of my monitors that checks real rendering with browsers started to alert me about timeouts.

I immediately checked other critical monitors, especially the main API gateway, and everything was working without any issues.

I started debugging…

Everything was working fine

---------------------------

I checked if the API receives a ton of new requests and is overloaded, but the cluster just can’t keep up with autoscaling.

But not, everything was as usual.

Let’s then check if there is increased load on the cluster. Maybe a new API usage pattern that causes degraded performance?

No, the usage pattern was like it was any other day.

I decided to check our changelog. Maybe I deployed something that causes timeouts but doesn’t impact the load.

But most commits were related to improving rendering and blocking banners and ads. I reverted them anyway, but it didn’t help. I was still receiving alerts.

Of course, I asked ChatGPT, and other LLMs, describing all the inputs I had and sharing all the screenshots.

Damn, of course, I should have checked networking.

I wrote a tool to diagnose DNS resolution performance and networking connections, deployed it to the cluster, and… no issues! The networking was stable.

Damn! It was day two. The world was falling apart. I started to traverse code…

Turns out this monitor check was bypassing browser locks and interfering with actual rendering. I created a real account and started to use it for monitoring. And…

It didn’t help:

Rendering worked perfectly for my customers, though. Their success rates are within the norm for their use cases.

I started to question my sanity. The site I was screenshotting was literally example.com. It just works.

Getting closer to the issue

---------------------------

I started to render the ScreenshotOne.com landing page, and it worked perfectly.

Which made me think…

Wait, wait, wait… but what if example.com is not that stable?

And I checked. And indeed, turns out it might be blocking automated requests and is often inaccessible 😂 They probably improved protection or something.

But what if I only checked their documentation?

A few thoughts on AI

--------------------

From one side, I wanted my monitor to be as close as possible to production checks.

But on the other side, it is based on something I don’t have control over at all.

One note about AI: no matter how I prompted it, it never suggested that it might be the issue.

But once I knew the issue, I saw how I could improve my prompting to get to the solution faster.

But how to do that with unknowns? It is still an open question for me.

Lessons learned

---------------

### 1\. Trusted targets might fail, too

I didn’t expect example.com to fail. But it did. It is better to have my own controllable environment to test against. But make it as close as possible to the production environment.

### 2\. The more monitors, the better

I have more than one monitor and it allowed me to still have some mental space because I knew that the customers were not impacted and the API kept working.

### 3\. AI is not a silver bullet

It might help if you only know the solution. But what if you don’t? How to prompt it effectively is still a huge and open question for me.

### 4\. Diagnostics tools are super important

If I had networking diagnostics tools, I would exclude these issues faster.

### 5\. Failure is an opportunity to learn

First of all, I improved a lot of processes and tools on the way. But secondly, I still marketed my product a bit.

Last words

----------

I hope you enjoyed the reading and learned something from my mistakes.

If you have any questions or are interested in website rendering, feel free to email at `support@screenshotone.com`.

Read more Engineering

---------------------

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

[View all posts](/blog/tags/engineering/)

#### [Cloudflare Workers as an API gateway](/blog/cloudflare-workers/)

Check out how ScreenshotOne relies on Cloudflare Workers as an API gateway to enhance performance, reliability, and cost-efficiency.

Read more

#### [Let's build a screenshot API](/blog/building-screenshot-api/)

Two years have passed since the launch of ScreenshotOne, and I want to do a fun coding exercise and build a tiny subset of what the API is today, but from scratch.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/how-to-take-a-screenshot-of-a-webpage-in-haskell
----

How to take a screenshot of a webpage in Haskell

================================================

It's very a common need to take a screenshot of a live website. On a project I worked on recently, we had a legal requirement to take screenshots of forms which our users filled, as at the time they filled the forms, for consent documentation purposes.

[Blog post](/blog/) 3 min read

#### Written by

[Anthony Alaribe](/contributors/anthony-alaribe/)

#### Updated on

Oct 23, 2022

There are many ways to do this manually. A straightforward way is to open the form and use the shortcuts `Command-Shift-3` on macOS. But this is not good enough when you need to take these screenshots automatically, based on user actions, or even just as part of batch processes. I won’t want to take 1000 screenshots manually, but I would happily write a script to automate taking those screenshots.

Let’s explore some approaches to taking a screenshot of a webpage in Haskell. We will take screenshots of the [APItoolkit.io](https://apitoolkit.io) which uses AI to help you manage, monitor, and document your APIs, so you always know what’s going on in your backends and can debug issues that come up immediately.

Side note: All the code examples are standalone Haskell shell scripts. Copy them into a file on a Unix environment and execute them like any other executable shell script.

This is possible due to the line ”#!/usr/bin/env stack” at the top of the file. Note, Haskell stack is required on your local machine and can be installed via [GHCup](%22https://www.haskell.org/ghcup/%22).

Using Haskell Selenium WebDriver

--------------------------------

Selenium is a well-known player in the QA and Web testing space. And with the web driver specification, we can control any browser. We will use the `webdriver-w3c` dependency for this test from `hackage`. Feel free to install that. Since we’re using a Haskell shell script, we only need to include the dependencies on the second line with the stack resolver:

    1#!/usr/bin/env stack2-- stack --resolver nightly-2022-10-18 script --package "bytestring webdriver-w3c"3

    4{-# LANGUAGE OverloadedStrings #-}5

    6import Control.Monad.IO.Class (liftIO)7import qualified Data.ByteString as B8import Web.Api.WebDriver9

    10main :: IO ()11main = do12  execWebDriverT13    defaultWebDriverConfig14    (runIsolated_ defaultChromeCapabilities takePageScreenshot)15  return ()16

    17takePageScreenshot :: WebDriverT IO ()18takePageScreenshot = do19  fullscreenWindow20  navigateTo "https://apitoolkit.io"21  img <- takeScreenshot22  liftIO $ B.writeFile "screenshot.png" img23  return ()

That’s pretty much all the code we need. But if we run this code, we will get an error that looks like this:

Terminal window

    1./Webdriver.hs2

    32022-10-21 00:04:53 DEBUG  Request Request POST http://localhost:4444/session4{5    "capabilities": {6        "alwaysMatch": {7            "browserName": "chrome"8        }9    },10    "desiredCapabilities": {11        "browserName": "chrome"12    }13}142022-10-21 00:04:53 ERROR  Error Unable to connect to WebDriver server152022-10-21 00:04:53 ERROR  Error No session in progress

This error is because we need to run a server process which our script can interact with. This process differs for different browsers. There is `geckodriver`, `firefoxdriver`, `chromedriver`, etc.

First, download the `chromedriver` from [https://chromedriver.chromium.org/](https://chromedriver.chromium.org/), and then we can start it in a separate process with the following command:

Terminal window

    1chromedriver --port=4444

Port 4444 is the default port for the `WebDriverConfig` we used in our Haskell program. Next, we restart our Haskell shell program. It would spit out some logs, then spin up a chrome window, open the API toolkit on the window, take a screenshot and save it to screenshot.png.

Using the ScreenshotOne API

---------------------------

[ScreenshotOne is a screenshot as a service API](https://screenshotone.com) that lets us take screenshots using just their API and is also a viable option, especially when we don’t want to deal with the hassle of managing a chrome or other browser instance.

The code is quite straightforward, as we simply need to make a GET request to an endpoint. Let’s do this with the `wreq` Haskell library.

    1#!/usr/bin/env stack2-- stack --resolver nightly-2022-10-18 script --package "bytestring wreq lens"3

    4{-# LANGUAGE OverloadedStrings #-}5

    6import Control.Lens7import qualified Data.ByteString as B8import Data.Maybe (fromMaybe)9import Network.Wreq (get, responseBody)10

    11main :: IO ()12main = do13  let accessKey = "<your access key>"14  let url = "https://apitoolkit.io"15  r <- get $ "https://api.screenshotone.com/take?access_key=" <> accessKey <> "&url=" <> url <> "&device_scale_factor=1&format=jpg&cache=false"16  B.writeFile "screenshot-api.png" (B.toStrict $ fromMaybe "" $ r ^? responseBody)

An API versus Selenium WebDriver and alternatives

-------------------------------------------------

I would advise trying Selenium WebDriver for quick prototyping, and if the volumes of screenshots are small, I mean counted by tens.

In addition, API usually has many other problems, like blocking pop-ups, banners, and ads and fixing full-page artifacts.

But if you expect to take screenshots constantly, it is better to examine using existing screenshot API. There is a vast choice nowadays of what to choose. Look at the list of [the best screenshot APIs](https://screenshotone.com/the-best-screenshot-api/).

Summary

-------

Pick the solution that fits your needs. But it’s helpful to know we have options, especially while building Haskell applications.

Read more posts

---------------

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

[View all posts](/blog/)

#### [How to set a time zone in Puppeteer for page](/blog/how-to-set-a-time-zone-in-puppeteer-for-page/)

Puppeteer allows changing the time zone on a per-page basis. In automation testing, you can use it to test how the website behaves for different time zones. Or you can use it for scrapping to imitate the user from the expected time zone by the site.

Read more

#### [ScreenshotOne November 2025 updates](/blog/screenshotone-november-2025-updates/)

Error metrics in the dashboard, Postman Public API Network, and Landing Gallery customer story.

Read more

#### [Monitoring website changes](/blog/monitoring-website-changes/)

I tried many ways to monitor and detect website changes. But I was always disappointed by the results. I want to share a few tips that might help you to get better results, if you plan to do the same.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/integrations/make
----

Integrations

1 min read

Make

====

Use ScreenshotOne with Make to automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

No-Code Automation

Resources

---------

*   [Documentation](https://screenshotone.com/docs/no-code/make/)

When OpenAI launched GPT-4 Vision I immediately thought that this would be great to give instant feedback to founders on their landing pages.

I wanted to launch an MVP in just a day or two to try it out and immediately ran into the problem of getting great screenshots of landing pages from a URL. It turned out that cookie banners, animations, and more often got in the way.

Then I found ScreenshotOne which had a fantastic integration with Zapier. It just immediately worked out of the box. Four weeks later, and hundreds of founders have had thousands of tests run on their landing pages. I couldn't be a happier user of ScreenshotOne!

Elias Stråvik

Founder, [Roast as a Service](https://www.roastasaservice.com/)

Check more Integrations

-----------------------

No-code tools, AI, code libraries, and more.

[Check more Integrations](/integrations/)

Code API

### SDK and Code Examples

Use the SDKs and code examples to take screenshots in your own code.

[Read more →](/integrations/code/)

No-Code Automation

### n8n

Use ScreenshotOne in n8n workflows to render website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

[Read more →](/integrations/n8n/)

No-Code Automation

### Zapier

Automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos in Zapier.

[Read more →](/integrations/zapier/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/how-to-take-website-screenshots-with-java
----

How to take website screenshots with Java

=========================================

The article examines how you can take screenshots of any URL with Java by using Selenium, Puppeteer alternatives, Playwright, or screenshot API as a service.

[Blog post](/blog/) 3 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Jun 10, 2022

#### Tags

[Screenshot rendering](/blog/tags/screenshot-rendering/)

Today, there are many options to make screenshots of any URL with Java:

1.  [Selenium](#selenium).

2.  [Playwright library](#playwright).

3.  Or [Screenshot API as a service](#screenshot-api-as-a-service).

They might overlap, but there is no best solution. Each depends on your use case and requirements.

Selenium

--------

Selenium is a well-known kid in the QA automation area, so it is easy to start taking screenshots if you plan to write automation tests or already do it.

For Maven, add the _selenium-java_ dependency in your project `pom.xml` file:

    1<dependency>2    <groupId>org.seleniumhq.selenium</groupId>3    <artifactId>selenium-java</artifactId>4    <version>4.0.0</version>5</dependency>

For Gradle, add the _selenium-java_ dependency in your project `build.gradle` file:

    1dependencies {2    compile group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '4.0.0'3}

And then:

    1import org.apache.commons.io.FileUtils;2import org.openqa.selenium.chrome.ChromeDriver;3import org.openqa.selenium.*;4

    5import java.io.File;6

    7public class App {8    public static void main(String[] args) throws Exception {9        WebDriver driver = new ChromeDriver();10

    11        driver.get("http://www.example.com");12

    13        File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);14        FileUtils.copyFile(scrFile, new File("./example.png"));15

    16        driver.quit();17    }18}

If you just want to take one or two screenshots locally, the Selenium WebDriver client is not the best fit. As I wrote earlier, it better serves you already write automation tests with Selenium or plan to write them.

Playwright

----------

[Playwright](https://playwright.dev/java/docs/intro) is the best Java library to automate [Chromium](https://www.chromium.org/Home), [Firefox](https://www.mozilla.org/en-US/firefox/new/), and [WebKit](https://webkit.org/) with a unified API. It is built to enable cross-browser web automation.

If you want to take screenshots in different browsers, Playwright is the best choice.

Install the library:

    1<dependencies>2    <dependency>3        <groupId>com.microsoft.playwright</groupId>4        <artifactId>playwright</artifactId>5        <version>1.17.1</version>6    </dependency>7</dependencies>

And then take a screenshot:

    1import com.microsoft.playwright.*;2

    3import java.nio.file.Paths;4

    5public class App {6    public static void main(String[] args) throws Exception {7        try (Playwright playwright = Playwright.create()) {8            Browser browser = playwright.webkit().launch();9            Page page = browser.newPage();10            page.navigate("https://example.com/");11            page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("example.png")));12        }13    }14}

`Playwright` is the best choice. It is as powerful and allows you to run different browser instances if needed.

If you plan to take millions of screenshots and manage browser instances, you can do it yourself, but it is better to outsource to well-established services.

Screenshot API as a service

---------------------------

We specialize in taking screenshots and managing browser instances at scale. We provide [a high-quality Java client to take screenshots](https://github.com/screenshotone/jsdk) and cover a variety of use cases.

Easy to install:

    1<dependencies>2    <dependency>3        <groupId>com.screenshotone.jsdk</groupId>4        <artifactId>screenshotone-api-jsdk</artifactId>5        <version>[1.0.0,2.0.0)</version>6    </dependency>7</dependencies>

And easy to use:

    1import com.screenshotone.jsdk.Client;2import com.screenshotone.jsdk.TakeOptions;3

    4import java.io.File;5import java.nio.file.Files;6

    7public class App {8    public static void main(String[] args) throws Exception {9        final Client client = Client.withKeys("IVmt2ghj9TG_jQ", "Sxt94yAj9aQSgg");10        TakeOptions takeOptions = TakeOptions.url("https://scalabledeveloper.com")11                .fullPage(true)12                .deviceScaleFactor(1)13                .viewportHeight(1200)14                .viewportWidth(1200)15                .format("png")16                .omitBackground(true);17        final byte[] image = client.take(takeOptions);18

    19        Files.write(new File("./example.png").toPath(), image);20    }21}

Or if you need to place just an URL inside the image tag, you can generate only the URL of the screenshot:

    1import com.screenshotone.jsdk.Client;2import com.screenshotone.jsdk.TakeOptions;3

    4public class App {5    public static void main(String[] args) throws Exception {6        final Client client = Client.withKeys("IVmt2ghj9TG_jQ", "Sxt94yAj9aQSgg");7        TakeOptions takeOptions = TakeOptions.url("https://scalabledeveloper.com")8                .fullPage(true)9                .deviceScaleFactor(1)10                .viewportHeight(1200)11                .viewportWidth(1200)12                .format("png")13                .omitBackground(true);14        final String url = client.generateTakeUrl(takeOptions);15

    16        System.out.println(url);17        // Output: https://api.screenshotone.com/take?url=...18    }19}

If you feel that it is the best fit for you, feel free [to sign up for our screenshot API](https://screenshotone.com/) and get the access key.

Summary

-------

Pick the solution which suits your needs best. If you decide to go with our API, please ask any questions and mail us at [support@screenshotone.com](mailto:support@screenshotone.com). And have a nice day 👋

By the way, you might also find interesting how to:

*   [take web screenshots in Go](/blog/how-to-take-website-screenshots-with-go/)

*   [take web screenshots with JavaScript or TypeScript (Node.js)](/blog/how-to-take-website-screenshots-with-javascript-and-typescript-nodejs)

*   [take web screenshots with PHP](/blog/how-to-take-website-screenshots-with-php/)

Read more Screenshot rendering

------------------------------

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

[View all posts](/blog/tags/screenshot-rendering/)

#### [How to render screenshots with Playwright](/blog/how-to-render-screenshots-with-playwright/)

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

Read more

#### [How to Take Screenshots with pyppeteer in Python](/blog/pyppeteer-python-screenshots/)

Guide to taking screenshots with pyppeteer in Python. Learn the basics, full page captures, and why you should migrate to Playwright.

Read more

#### [How to take website screenshots with PHP](/blog/how-to-take-website-screenshots-with-php/)

The article examines how you can take screenshots of any URL with PHP by using Selenium, Puppeteer alternatives, or screenshot API as a service.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/heart-touching-feedback-from-gregory
----

Heart-touching feedback from Gregory

====================================

Daily and nightly, I work on improving the quality and performance of ScreenshotOne (your friendly screenshot API) and ensuring I help customers solve their problems and prosper.

[Customer story](/blog/tags/customer-stories/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Nov 20, 2022

And receiving great feedback from paying customers is what makes me move further and pushes my motivation to the sky.

Recently, I received heart-touching feedback from [Gregory Borelli](https://www.linkedin.com/in/gregoryborelli/), creator of [layouts.divifree.com](https://layouts.divifree.com/) that I want to share with you today:

> ScreenshotOne is the best screenshot tool with amazing support. For my project I had short-term needs for several thousand screenshots. I selected and tested 10 tools, all without exception had several blocking bugs for my project.

> 

> I wrote to several companies and only ScreenshotOne took my requests into account and was able to solve 100% of my problems, most of them in a standard way and for the most complex with custom code.

> 

> I have never seen such efficient and responsive support. It is undoubtedly the best solution for all your screenshot needs today.

> 

> I have more than 10,000 captures to my credit and the result is incredible, as proof of the creation of a catalog of WordPress / Divi layouts made entirely with [layouts.divifree.com](https://layouts.divifree.com/). This is just the start of using ScreenshotOne.

> 

> With a subscription of 10,000 screenshots per month, and all the features, I can leverage this tool to automate and create value in many of my projects. Amazing tool, thanks to Dmytro Krasum all ScreenshotOne team.

I am very happy to have Gregory as a customer and to serve the needs of his venture. I wish to prosper him, all my potential and current customers.

Read more customer stories

--------------------------

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

[View all posts](/blog/tags/customer-stories/)

#### [ScreenshotOne took away one major complexity off the Supawrite plate](/blog/supawrite/)

A short story about how ScreenshotOne helps a content marketing platform automate their screenshot workflow.

Read more

#### [Integrating ScreenshotOne into the directory management platform](/blog/makeadir-feedback/)

How and why "Make a Directory" used ScreenshotOne to automate screenshots for directory websites.

Read more

#### [How Ilias Ism, a founder of the MagicSpace SEO agency, uses ScreenshotOne daily](/blog/how-ilias-ism-a-founder-of-the-magicspace-seo-agency-uses-screenshotone-daily/)

We would love to share a quick review of ScreenshotOne by Ilias Ism, a founder of MagicSpace SEO agency and OG Image Generator on how he uses the API daily to generate screenshots and automate regular tasks associated with screenshots.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/async-webhooks-and-extra-limits
----

Async, Webhooks, and Extra Limits

=================================

May was a great month and full of new and exciting updates. Let's check them out quickly.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

May 25, 2023

Charging Extra

--------------

One of the most requested features for ScreenshotOne was a pay-as-you-go option. And I am happy to share that now it is publicly available.

From how you can specify an extra hard limit for your plan and never worry about hitting the limit again. You can read in detail [about how charging extra works in the ScreenshotOne docs](/docs/charging-extra/).

Asynchronous screenshot rendering and webhooks

----------------------------------------------

Today, [asynchronous screenshot rendering and webhooks](/docs/async-and-webhooks/) are publicly available for everybody. Now, you don’t need to wait until your [screenshot is uploaded to S3](/docs/upload-to-s3/). You can execute rendering and upload asynchronously and get the results delivered by webhook.

Feedback is much appreciated

----------------------------

Any feedback is much appreciated. Feel free to share if you plan to use new features or want to suggest new ones at ScreenshotOne support chat or send an email to `hey@screenshotone.com`

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [ScreenshotOne is now integrated into Summit](/changelog/summit-integration/)

The ScreenshotOne screenshot API is now natively integrated into Summit and you can perform anything on top of the powerful screenshot automation and Summit models—only the sky is the limit.

Read more →

1 min read

#### [Better error coverage and documentation](/changelog/all-errors-are-covered/)

Since a few months ago, it has been possible to check errors in the dashboard request log and get explanations and more details in the documentation. But!

Read more →

1 min read

#### [Improved error handling when networking fails](/changelog/improved-error-handling-when-networking-fails/)

We have improved error handling for network failures. Now, we ensure screenshot rendering fails instead of returning an error image.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/contributors/modest-mitkus
----

Modest Mitkus

-------------

View all Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [How RankPill uses ScreenshotOne](/blog/rankpill/)

Sharing how RankPill uses ScreenshotOne to automate website screenshot generation for SEO and GEO automation.

Written by

[Modest Mitkus](/contributors/modest-mitkus/), [Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Nov 6, 2025

•

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/integrations/cli
----

Integrations

1 min read

CLI

===

Use command line interface to automate screenshots in your workflows with ScreenshotOne.

Code API AI

Resources

---------

*   [ScreenshotOne CLI on GitHub](https://github.com/screenshotone/cli)

*   [ScreenshotOne CLI on Docker Hub](https://hub.docker.com/r/screenshotone/cli)

The best thing about [ScreenshotOne](/) is it just works!

With all the useful documentation in place and library support,it's very easy to setup ScreenshotOne.

On top of that, Dmytro's commitment towards improving the appmakes it an easy choice.

Rishi Mohan

Maker, [Pika.style](https://pika.style/)

Check more Integrations

-----------------------

No-code tools, AI, code libraries, and more.

[Check more Integrations](/integrations/)

No-Code Automation

### Zapier

Automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos in Zapier.

[Read more →](/integrations/zapier/)

No-Code Automation

### n8n

Use ScreenshotOne in n8n workflows to render website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

[Read more →](/integrations/n8n/)

No-Code Automation

### Clay

Generate website screenshots inside Clay to qualify leads, assess content, and enrich rows with visual context automatically.

[Read more →](/integrations/clay/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/support-of-the-openai-gpt-vision-api-in-screenshotone
----

Support of the OpenAI GPT Vision API in ScreenshotOne

=====================================================

From today, you can use our screenshot API together with the OpenAI Vision API. It allows you to send screenshots directly to the Vision API without building all the infrastructure yourself.

[Changelog](/changelog/) 2 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Nov 25, 2023

Yes, it is as simple as that.

Use cases

---------

Basically, anywhere you used ChatGPT vision for analyzing website screenshots, but now you can automate it with one simple API call.

But let’s consider a few ideas:

1.  You can use it for landing page design and copywriting feedback.

2.  You can use the screenshot API with the GPT vision to convert the website design into HTML and CSS code.

3.  You can use it in complex parsing cases, e.g. to extract emails.

And many more.

Bring your own API key

----------------------

The Vision API has very strict rate limits and allows only a handful amount of requests. Hence, it was decided to allow customers to bring their own API keys.

Your OpenAI API key is not stored in the permanent history of screenshots and is exempted from logs. But still, make sure to set strict hard limits.

Stability

---------

Currently, the API requests using the Vision API are as stable as the Vision API itself.

We often observe errors and slow performance. In that case, you will still get the screenshot, but not the prompt result.

Known Issues and Limitations

----------------------------

There are a few issues you might encounter:

1.  In case, if screenshot rendering fails, but prompt generation is succeeded. You will be charged by OpenAI, but you are not charged for any failed screenshots by ScreenshotOne.

2.  Use only JPG (JPEG) file formats for performance. They have smaller file sizes and the quality of the Vision API responses looks pretty much the same.

3.  Timeouts are a huge problem. Since the ScreenshotOne API limits the execution time to one minute. It is often hard to generate a screenshot and analyze it with the GPT vision API.

Pricing

-------

Currently, it is available for free and for all plans and all customers. But it might change in the future depending on the usage of the feature.

Alternative

-----------

If you don’t see it makes sense for you to use the native screenshot API integration with the GPT vision API, e.g. if you want to make sure your OpenAI key is not shared anywhere, you can still use ScreenshotOne but will need to perform an additional step.

1.  Render a screenshot and get a cache URL to it or upload it to any compatible S3 storage.

2.  Once uploaded, pass the link to the Vision API.

Or alternatively:

1.  You can get the binary response encoded with base64 encoding.

2.  And then send the encoded image to the OpenAI directly.

Choose whatever approach suits you better. Using direct/native integration is just a nice option you might use. You decide eventually.

Summary

-------

If you have built something interesting using ScreenshotOne, please, share. Send an email to [support@screenshotone.com](mailto:support@screenshotone.com).

We will consider featuring your product on our site and social media accounts.

In case you have any problems or questions related to the API reach out through the same email—[support@screenshotone.com](mailto:support@screenshotone.com).

And we will get back to you as soon as possible.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Playground Presets](/changelog/playground-presets/)

You can now create and save presets in the ScreenshotOne Playground!

Read more →

1 min read

#### [Fail rendering if the content contains a string](/changelog/fail-if-content-contains/)

There is a set of use cases when you want to fail screenshot rendering and retry it if the content of the page contains a string.

Read more →

1 min read

#### [Improved blocking of banners and popups](/changelog/improved-blocking-of-banners-and-popups/)

Improved generic algorithm to bypass blockers and better banner exclusion heuristics.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/taking-screenshots-with-puppeteer-in-gif-jp2-tiff-avif-heif-or-svg-format
----

Taking screenshots with Puppeteer in GIF, JP2, TIFF, AVIF, HEIF, or SVG format

==============================================================================

Puppeteer, by default, supports only four formats for taking screenshots or rendering HTML: PNG, JPEG, WebP, and PDF. But what if you want it to take it in a different format like GIF, JP2, TIFF, AVIF, HEIF, or SVG?

[Blog post](/blog/) 6 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jul 17, 2022

#### Tags

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

Why use other formats?

----------------------

PNG, JPEG, WebP, and PNG are the most popular formats on the Internet. You will never have any problem rendering them in browsers, besides a small minority of outdated browsers that do not support these formats.

But as an example, TIFF is a popular file format among production designers for high-quality graphic prints and photos.

Or in terms of image quality, JPEG 2000 (JP2) offers a better output than JPEG. It has higher compression ratios, which means it can handle and compress an image up to 200% more than a JPEG.

Or a developer might use a proprietary library for vectorizing images, and it might accept only specific formats, not PNG, JPEG, WebP, and PNG.

As you see, we can continue counting use cases further, but the idea is that there is a demand to render URLs or HTML in different formats.

Using image conversion library

------------------------------

### Using sharp library

The [sharp](https://sharp.pixelplumbing.com/) library (in Node.js) is a high-performance library for image processing — it allows converting, resing, and other image manipulations. Let’s install it:

Terminal window

    1npm install sharp

It is important to take screenshots or render them in PNG format since it is lossless (means doesn’t lose quality) and transform `PNG` to any desired format.

As an example, let’s transform `PNG` to `JPEG 2000 (JP2)`:

    1const puppeteer = require('puppeteer');2const sharp = require('sharp');3

    4(async () => {5    const browser = await puppeteer.launch({ headless: true });6    try {7        const page = await browser.newPage();8

    9        await page.goto('https://screenshotone.com/');10

    11        const binaryScreenshot = await page.screenshot({12            encoding: 'binary',13            type: 'png',14        });15

    16        await sharp(binaryScreenshot)17            .toFormat('jp2', { quality: 100 })18            .toFile('screenshotone.com.jp2')19

    20    } catch (e) {21        console.log(e)22    } finally {23        await browser.close();24    }25})();

As you see, toFormat() accepts arguments: format and format options. Feel free to specify: GIF, JP2, TIFF, AVIF, HEIF as a format. And it is important to specify quality property if it matters to you.

To enable the support of OpenJPEG (JPEG 2000 or JP2), you need to [install a custom version of libvips](https://sharp.pixelplumbing.com/install#custom-libvips). Otherwise, you will get an error like: “JP2 output requires libvips with support for OpenJPEG”.

### PNG with lower quality

By default, Puppeteer does not support exporting lower-quality PNG, but there is a trick. You can use `sharp` to do it for you. Let’s test it:

    1const puppeteer = require('puppeteer');2const sharp = require('sharp');3

    4(async () => {5    const browser = await puppeteer.launch({ headless: true });6    try {7        const page = await browser.newPage();8

    9        await page.goto('https://screenshotone.com/');10        await page.setViewport({width: 1280, height: 1024});11

    12        const binaryScreenshot = await page.screenshot({13            encoding: 'binary',14            type: 'png',15        });16

    17        await sharp(binaryScreenshot)18            .png({quality: 10})19            .toFile('low_quality_screenshotone.com.png')20

    21    } catch (e) {22        console.log(e)23    } finally {24        await browser.close();25    }26})();

The file size is different after applying the low quality, but do you see any difference in the pictures?

The original screenshot:

The result with low quality:

Base64

------

`Puppeteer` supports exporting rendered images in Base64 format, but only for PNG, JPEG, WebP, and PDF.

### Render PNG, JPEG, WebP, GIF, JP2, TIFF, AVIF, HEIF as Base64

Rendering PNG, JPEG, and WebP in Base64 encoding with Puppeetter is easy:

    1const puppeteer = require('puppeteer');2

    3(async () => {4    const browser = await puppeteer.launch({ headless: true });5    try {6        const page = await browser.newPage();7

    8        await page.goto('https://screenshotone.com/');9        await page.setViewport({width: 1280, height: 1024});10

    11        const base64Screenshot = await page.screenshot({12            encoding: 'base64',13            type: 'png',14        });15

    16        console.log(base64Screenshot)17        // iVBORw0KGg...18    } catch (e) {19        console.log(e)20    } finally {21        await browser.close();22    }23})();

But if you need to render OpenJPEG (JPEG 2000 or JP2) in Base64, you can use sharp to convert to JP2 and then format the buffer in Base64 encoding:

    1const puppeteer = require('puppeteer');2const sharp = require('sharp');3

    4(async () => {5    const browser = await puppeteer.launch({ headless: true });6    try {7        const page = await browser.newPage();8

    9        await page.goto('https://screenshotone.com/');10        await page.setViewport({ width: 1280, height: 1024 });11

    12        const binaryScreenshot = await page.screenshot({13            encoding: 'binary',14            type: 'png',15        });16

    17        const screenshotBuf = await sharp(binaryScreenshot).18            toFormat('jp2', { quality: 100 }).19            toBuffer();20

    21        console.log(screenshotBuf.toString('base64'));22        // /0//UQAyAA...23

    24    } catch (e) {25        console.log(e)26    } finally {27        await browser.close();28    }29})();

### Render URL or HTML to PDF as Base64

`Puppeteer` by default supports rendering URL or HTML to PDF, and encoding it to Base64 is fairly easy:

    1const puppeteer = require('puppeteer');2

    3(async () => {4    const browser = await puppeteer.launch({ headless: true });5    try {6        const page = await browser.newPage();7

    8        await page.goto('https://screenshotone.com/');9        await page.setViewport({ width: 1280, height: 1024 });10

    11        const binaryScreenshot = await await page.pdf({});12

    13        console.log(binaryScreenshot.toString('base64'));14        // JVBERi0xLj...15

    16    } catch (e) {17        console.log(e)18    } finally {19        await browser.close();20    }21})();

A “little nuance” with SVG

--------------------------

SVG represents vector graphics, a hugely different world from scalar graphics.

The idea of SVG is that you can scale an image to any size and won’t lose its quality. It is impossible to do the same with scalar-represented images, like PNG or JPEG.

Why is it so hard to create SVG? Because of the nature of this format. It is based on figures like squares, circles, Bézier, and other elliptical curves. These figures can be scaled without losing quality, but you need to find a way to convert scalar graphics into this representation of squares, curves, etc. And it is a complex task in itself.

But there is a trick: you can do it if you don’t care about scaling SVG for some reason, but you need this format. You can generate a PNG image in base64 form and paste it inside the SVG tag. It does not offer accurate vector graphics but will give an SVG format if needed.

So, let’s do it:

    1const puppeteer = require('puppeteer');2const fs = require('fs');3

    4(async () => {5    const browser = await puppeteer.launch({ headless: true });6    try {7        const page = await browser.newPage();8

    9        await page.goto('https://screenshotone.com/');10

    11        const screenshot = await page.screenshot({12            encoding: 'base64',13            type: 'png',14        });15

    16        const { width, height } = await page.viewport();17        const svg = `<svg  xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">18            <image href="data:image/png;charset=utf-8;base64,${screenshot}"19                width="${width}" height="${height}" />20        </svg>`;21

    22        fs.writeFileSync("screenshotone.com.svg", svg);23

    24    } catch (e) {25        console.log(e)26    } finally {27        await browser.close();28    }29})();

It works like a charm. Look at [the resulting SVG file](screenshotone.com.svg).

Cloudflare Image Resizing

-------------------------

Another beautiful way to generate screenshots or render HTML in a different format is to use Cloudflare as a proxy that converts images on the go and can transform and resize them.

[Cloudflare Image Resizing](https://developers.cloudflare.com/images/) allows using Cloudflare’s edge platform to convert images to WebP or AVIF format on the fly, independently of where they are stored.

In the post about [how to create a site thumbnail with Puppeteer](/blog/how-create-a-site-thumbnail-with-puppeteer/), I describe how to resize the website screenshot.

Ready API as a service

----------------------

Suppose you don’t want to ding with Puppeteer, write code, test it and make sure it is scalable. In that case, you can use a well-established solution — [ScreenshotOne.com API](/) that already supports different formats, resizing, and many more — [get started for free](https://dash.screenshotone.com/sign-up).

To render screenshots of URL or HTML in a specific format. You will only need to specify two options URL or HTML and desired [rendering format](/docs/options/#format). Can it be more straightforward than:

    1https://api.screenshotone.com/take?format=webp&url=https://apple.com&access_key=<your access key>

Summary

-------

If you have time and have already installed Puppeteer, you can easily use the sharp library for image conversion. But if you don’t want to deal with Puppeteer, you can use [ScreenshotOne.com API](/) to save time.

Have a nice day 👋 and you also might find helpful:

*   [the complete guide on how to take a screenshot with Puppeteer](/blog/how-take-a-screenshot-with-puppeteer)

Read more Puppeteer guides

--------------------------

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

[View all posts](/blog/tags/puppeteer-guides/)

#### [How to Take Screenshots with pyppeteer in Python](/blog/pyppeteer-python-screenshots/)

Guide to taking screenshots with pyppeteer in Python. Learn the basics, full page captures, and why you should migrate to Playwright.

Read more

#### [Puppeteer Performance Monitoring with Inspector](/blog/puppeteer-performance-monitoring-with-inspector/)

In this article I'll show you how to monitor performance and errors of a browser automation script written with Puppeteer.

Read more

#### [Capture beyond viewport in Puppeteer and Chrome DevTools Protocol](/blog/capture-beyond-viewport-in-puppeteer-and-chrome-devtools-protocol/)

Let's talk about the captureBeyondViewport parameter introduced in Chrome DevTools Protocol which will soon be supported by Puppeteer or even supported now at the time when you are reading the post.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/multiple-api-keys
----

Support for multiple API keys

=============================

You can now use multiple API keys to the access ScreenshotOne API.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jun 10, 2025

Many ScreenshotOne customers asked to support more than one API key to access the API. Some need that for local development, some for testing or to separate different environments, and some for security reasons.

It took us some time to implement this feature and test everything, but now it is available.

Since today you can create and use multiple API keys to access the ScreenshotOne API. Check out [the access page in the dashboard](https://dash.screenshotone.com/access):

[](https://dash.screenshotone.com/access)

A few notes:

1.  Concurrency limit is shared between all API keys.

2.  Quota is shared between all API keys.

3.  You can regenerate or delete any API key. But cached screenshots might be still available.

4.  At least one API key is required to exist. You can’t delete all of them.

If you have any questions or need any assistance, please, reach out at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Navigate Pages when recording Scrolling Screenshots](/changelog/scrolling-screenshots-navigation/)

You can record a page navigation when recording scrolling screenshot video. It allows render less boring and more engaging videos.

Read more →

1 min read

#### [Add ScreenshotOne to Clay](/changelog/clay-integration/)

Generate website screenshots inside Clay to qualify leads, assess content, and enrich rows with visual context automatically.

Read more →

1 min read

#### [Improved the behavior and stability of the "scroll\_into\_view" option](/changelog/improved-scroll-into-view/)

Before the change, there was a subset of cases when the rendering requests were failing when using the scroll\_into\_view option. Now, it is improved and will make rendering more stable.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/tags/crawling-and-scraping
----

Crawling and Scraping

---------------------

Guides for crawling, scraping, and processing website data.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

[Crawling and scraping](/blog/tags/crawling-and-scraping/)

#### [3 best scraping APIs in 2026](/blog/best-scraping-apis/)

ScreenshotOne is not a scraping API, but what if you could achieve your goals with it and get perfect screenshots as an additional benefit?

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jan 6, 2026

•

2 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/ai-agents
----

Automate Website Screenshots

1 min read

AI Agents With Browser Observation

==================================

Give AI agents reliable screenshots of web pages so they can inspect, compare, and act with visual context.

AI agents often need to understand what happened in a browser, not just what the DOM or extracted text says. ScreenshotOne gives those agents a dependable way to capture a page visually and use that image for review, analysis, or downstream decisions.

If you want the short landing-page version first, see [The screenshot API for AI agents](/agents/).

Why screenshots matter for agents

---------------------------------

An AI agent can use screenshots to verify page state, inspect layouts, compare before-and-after changes, and attach visual evidence to a task result. This is especially useful in workflows like competitor tracking, landing page analysis, publishing checks, and automated QA.

More reliable than rolling your own browser stack

-------------------------------------------------

Teams regularly underestimate how much work is involved in taking stable screenshots across real-world websites. Anti-bot measures, rendering quirks, timing issues, and scaling challenges make in-house solutions expensive to maintain. ScreenshotOne removes that operational burden and gives agent workflows a simple API for production use.

A practical building block for agentic products

-----------------------------------------------

If you are building AI agents that browse, audit, monitor, or report on websites, screenshots become part of the agent’s memory and evidence trail. ScreenshotOne helps turn those workflows into something dependable enough to ship.

We thought making a screenshot tool for our AI agents would be simple. But we faced countless unexpected problems.

So, we ditched the idea and chose ScreenshotOne API instead. It saved us lots of time and it just works!

John Rush

Founder, [Unicorn Platform](https://unicornplatform.com)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

### Screenshots for OpenClaw Workflows

Use ScreenshotOne to automate website screenshots inside OpenClaw workflows for visual checks, proactive monitoring, and image-based reporting.

[Read more →](/use-cases/openclaw-workflows/)

### AI Vision For Analyzing Web Pages

Use AI to extract insights from web page visuals for enhanced content strategy and market analysis.

[Read more →](/use-cases/ai-vision-web-page-analysis/)

### Landing Page Evaluation with AI

Automate landing page roasting for your customers or yourself with modern technologies like OpenAI Vision.

[Read more →](/use-cases/ai-landing-page-roasting/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/change-ownership-for-subscribed
----

Change organization owner for already subscribed customers

==========================================================

Starting today, you can change organization owner for already subscribed customers.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Aug 16, 2025

Until today if you already were a paying customer, you couldn’t change the organization owner. It was related to our architecture and historical approach on how we handle billing.

We refactored the billing system to be more robust and more flexible to handle different scenarios.

And starting today, you can change organization owner for already subscribed customers:

If you have any questions or suggestions, feel free to contact us at [support@screenshotone.com](mailto:support@screenshotone.com).

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Get favicon used by a website with ScreenshotOne API](/changelog/metadata-icon/)

Now you can get favicon used by a website with ScreenshotOne API in just one simple API call.

Read more →

1 min read

#### [Detect any website fonts with a ScreenshotOne API](/changelog/detect-any-website-fonts-with-a-screenshotone-api/)

Now you can detect fonts used by any website with ScreenshotOne API in just one simple API call.

Read more →

1 min read

#### [Error metrics in the dashboard](/changelog/error-metrics/)

You can now see error metrics in the dashboard to quickly understand what errors are happening and how often.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/http-response-metadata
----

Get the HTTP response status code and headers with screenshots

==============================================================

On rare occasions, you might need to get the HTTP status code and headers of the target host. It is pretty easy to do now.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Aug 2, 2024

We deployed a new version of the API that returns the HTTP response status code and headers when possible.

To get the status code or the headers, just set one of the needed parameters to true: `metadata_http_response_headers=true` or `metadata_http_response_status_code=true`. And you will get all the data when available:

In the example, above it is rendered as JSON, because response\_type is set to `json` and `cache` to `true`. But if you render a binary screenshot, not JSON, you can get that data from the API response headers as `X-ScreenshotOne-HTTP-Response-Status-Code` and `ScreenshotOne-HTTP-Response-Status-Headers`.

Headers and status codes might not be available when the target host DNS name is not resolved, there is a network error, or even just timeout error and the host doesn’t respond.

Hope you find it helpful, enjoy and have a nice day!

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Better Markdown output](/changelog/better-markdown-output/)

Markdown output is now cleaner by removing non-content HTML blocks during conversion.

Read more →

1 min read

#### [ScreenshotOne integration with Dirstarter](/changelog/dirstarter-integration/)

Build a directory with Dirstarter and add website screenshots automatically with ScreenshotOne.

Read more →

1 min read

#### [Better numbers formatting in the dashboard](/changelog/better-numbers-formatting-in-the-dashboard/)

We improve UI/UX of rendering numbers in the dashboard for better readability.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/include-shadow-dom
----

Include shadow DOM when requesting the page content

===================================================

A new version of the ScreenshotOne API has been just deployed. It allows you to include the shadow DOM contents when requesting the page content.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Feb 7, 2025

In order to include the shadow DOM contents when requesting the page content, you only need to specify the `include_shadow_dom` option in the request as `true`, like this:

    1https://api.screenshotone.com/take?include_shadow_dom=true&url...&access_key=...

The API will try to include all open and closed shadow DOM roots in the content. By default, they are not included.

In case you encounter any issues, or have any questions, please feel free to reach out to us at [support@screenshotone.com](mailto:support@screenshotone.com).

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Fail rendering if the content contains a string](/changelog/fail-if-content-contains/)

There is a set of use cases when you want to fail screenshot rendering and retry it if the content of the page contains a string.

Read more →

1 min read

#### [Available in Context7](/changelog/available-in-context7/)

ScreenshotOne documentation is now available in Context7.

Read more →

1 min read

#### [Rendering errors in webhooks](/changelog/screenshotone-webhook-errors/)

Check out how to get notified about rendering errors when using webhooks.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/building-screenshot-api
----

Let's build a screenshot API

============================

Two years have passed since the launch of ScreenshotOne, and I want to do a fun coding exercise and build a tiny subset of what the API is today, but from scratch.

[Blog post](/blog/) 16 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

May 26, 2024

#### Tags

[Engineering](/blog/tags/engineering/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

_In case you don’t want to read the tutorial, feel free to check out the complete result [a screenshot API on GitHub](https://github.com/screenshotone/learnshot)._

A few reasons behind the exercise:

1.  Because I want to assess the modern landscape of technologies that enable screenshot rendering. And I want to rethink some architectural choices I made for [ScreenshotOne](https://screenshotone.com/) back at times.

2.  Also, I want to have a simple guide to share for those who seek an alternative for screenshot APIs or want to build a competitor solution to ScreenshotOne. Yes, the more [APIs](https://screenshotone.com/blog/best-screenshot-apis-2024/) the better for the screenshot automation market.

3.  And the last but not the least, I want to share with you how much more complex screenshot API turns out to be than it seems. But yet you will have a good option to go without relying on the third-party APIs.

It fascinates me that I still have fun building a screenshot API, especially, the second time.

Features

--------

To shorten this tutorial from the book to a short blog post, I selected a few simple features to implement:

1.  Full page screenshots with triggering lazy loading of images.

2.  Blocking cookie banners.

3.  Changing viewport parameters like dimensions and device scale factor.

4.  Upload screenshots to any S3-compatible storage.

Of course, there are [a hundred more features](https://screenshotone.com/docs/options/) that screenshot APIs have, but these few will be enough for demonstration purposes.

API comes first

---------------

It should be customer needs and documentation first, but for simplicity, I will take a small subset of features of ScreenshotOne and just reimplement them right away by writing code.

### Technologies

I decided to go with:

1.  [Hono](https://hono.dev/)—a simple and fast framework for processing HTTP requests.

2.  OpenAPI specification—for documentation, SDK generation, validation ([Hono has a decent middleware for that](https://hono.dev/snippets/zod-openapi)), and interoperability with modern AI and other systems.

3.  TypeScript—I am lazy and static typing saves me from overthinking.

4.  Node.js—it is bullet-proof, battle-tested, and will be with us for years to come. Also, most of the best libraries like Puppeteer and Playwright for working headless browsers are written for Nodejs. Playwright however supports many other languages and is worth considering, too.

5.  [LocalStack](https://github.com/localstack/localstack) for running AWS S3 storage locally for playing and testing purposes.

I also have a decent experience with these technologies and that matters a lot. If you are good with Python, consider going with it, [Python also can render website screenshots](https://screenshotone.com/blog/how-to-take-website-screenshots-in-python/).

### API for rendering screenshots

Starting with Hono is as simple as:

Terminal window

    1npm create hono@latest

I chose the Node.js runtime.

Hono combined with Zod is a turbo rocket. Let’s define the request and response schemes in `src/schema.ts`:

    1import { z } from "@hono/zod-openapi";2

    3export const ScreenshotOptionsSchema = z.object({4    url: z.string().url().openapi({5        description: "A website URL.",6        example: "https://example.com",7    }),8    block_cookie_banners: z.boolean().default(true).openapi({9        description: "Render clean screenshots.",10        example: false,11    }),12    viewport_width: z.coerce.number().int().min(1).default(1920).openapi({13        description: "Change the viewport width.",14        example: 1920,15    }),16    viewport_height: z.coerce.number().int().min(1).default(1080).openapi({17        description: "Change the viewport height.",18        example: 600,19    }),20    device_scale_factor: z.coerce.number().int().min(1).default(1).openapi({21        description: "Change the device scale factor.",22        example: 2,23    }),24    full_page: z.boolean().default(false).openapi({25        description: "Render the full page screenshot.",26        example: false,27    }),28});29

    30export const ScreenshotResultSchema = z31    .object({32        screenshot_url: z.string().url(),33    })34    .openapi("Screenshot");

As you see, I added all the options that reflect features we are going to build: changing viewport parameters, full page screenshots, blocking cookie banners, and the URL of the rendered screenshots as a result.

Now, see how easy it is to define a route and handle typed requests and return typed responses—everything is really typesafe:

    1import { OpenAPIHono } from "@hono/zod-openapi";2import { createRoute } from "@hono/zod-openapi";3

    4import { ScreenshotOptionsSchema, ScreenshotResultSchema } from "./schema";5

    6const app = new OpenAPIHono();7

    8app.openapi(9    createRoute({10        method: "get",11        path: "/screenshot",12        request: {13            query: ScreenshotOptionsSchema,14        },15        responses: {16            200: {17                content: {18                    "application/json": {19                        schema: ScreenshotResultSchema,20                    },21                },22                description: "Rendered screenshot.",23            },24        },25    }),26    (c) => {27        const screenshotOptions = c.req.valid("query");28        console.log(screenshotOptions);29        // Output:30        // {31        //     "block_cookie_banners": true,32        //     "viewport_width": 1920,33        //     "viewport_height": 1080,34        //     "device_scale_factor": 1,35        //     "full_page": false36        // }37

    38        const screenshotUrl = "https://example.com";39

    40        return c.json({ screenshot_url: screenshotUrl });41

    42        // For http://localhost:3000/screenshot, it returns:43        // {"screenshot_url":"https://example.com"}44    }45);46

    47app.doc("/openapi.json", {48    openapi: "3.0.0",49    info: {50        version: "1.0.0",51        title: "The Screenshot API",52    },53});54

    55export default app;

Then I just update the `src/index.ts` file:

    1import { serve } from "@hono/node-server";2import app from "./app";3

    4const port = 3000;5console.log(`Server is running on port ${port}`);6

    7serve({8    fetch: app.fetch,9    port,10});

And that’s it. The API is ready to handle screenshot rendering requests.

As a bonus, we get the OpenAPI specification automatically at the `/openapi.json` route:

    1{2    "openapi": "3.0.0",3    "info": {4        "version": "1.0.0",5        "title": "The Screenshot API"6    },7    "components": {8        "schemas": {9            "Screenshot": {10                "type": "object",11                "properties": {12                    "screenshot_url": {13                        "type": "string",14                        "format": "uri"15                    }16                },17                "required": ["screenshot_url"]18            }19        },20        "parameters": {}21    },22    "paths": {23        "/screenshot": {24            "get": {25                "parameters": [26                    {27                        "schema": {28                            "type": "string",29                            "format": "uri",30                            "description": "A website URL.",31                            "example": "https://example.com"32                        },33                        "required": true,34                        "name": "url",35                        "in": "query"36                    },37                    {38                        "schema": {39                            "type": "boolean",40                            "default": true,41                            "description": "Render clean screenshots.",42                            "example": false43                        },44                        "required": true,45                        "name": "block_cookie_banners",46                        "in": "query"47                    },48                    {49                        "schema": {50                            "type": "integer",51                            "minimum": 1,52                            "default": 1920,53                            "description": "Change the viewport width.",54                            "example": 192055                        },56                        "required": true,57                        "name": "viewport_width",58                        "in": "query"59                    },60                    {61                        "schema": {62                            "type": "integer",63                            "minimum": 1,64                            "default": 1080,65                            "description": "Change the viewport height.",66                            "example": 60067                        },68                        "required": true,69                        "name": "viewport_height",70                        "in": "query"71                    },72                    {73                        "schema": {74                            "type": "integer",75                            "minimum": 1,76                            "default": 1,77                            "description": "Change the device scale factor.",78                            "example": 279                        },80                        "required": true,81                        "name": "device_scale_factor",82                        "in": "query"83                    },84                    {85                        "schema": {86                            "type": "boolean",87                            "default": false,88                            "description": "Render the full page screenshot.",89                            "example": false90                        },91                        "required": true,92                        "name": "full_page",93                        "in": "query"94                    }95                ],96                "responses": {97                    "200": {98                        "description": "Render a Screenshot",99                        "content": {100                            "application/json": {101                                "schema": {102                                    "$ref": "#/components/schemas/Screenshot"103                                }104                            }105                        }106                    }107                }108            }109        }110    }111}

### Asynchronous versus synchronous API

It is a simple synchronous API method for rendering screenshots, but if I were to start today again I would consider building an asynchronous-first API from scratch.

Because it is much easier to scale and manage resources. But it requires a lot of work upfront, like queues, and database, and also complicates the integration for customers.

For users, it might be much easier to start with synchronous API. But there is a way to encourage them to use asynchronous if it matters, for example, to allow cheaper prices or charge fewer credits per asynchronous requests.

Unfortunately, building the asynchronous API is out of the scope of this tutorial.

Now, let’s proceed to the most fun part (at least for me)—rendering screenshots.

Rendering screenshots

---------------------

### One simple function to render screenshots

To make sure we are now focused on building only the core features, let’s introduce a simple function in `src/screenshots.ts`:

    1import { ScreenshotOptions } from "./schema";2

    3export async function render(options: ScreenshotOptions): Promise<{ url: string }> {4    // return the URL of the screenshot5

    6    return { url: "https://example.com" };7}

It requires new type introduced as in `src/schema.ts`:

    1export const ScreenshotOptionsSchema = z.object({2    url: z.string().url().openapi({3        description: "A website URL.",4        example: "https://example.com",5    }),6    // ...7});8

    9export type ScreenshotOptions = z.infer<typeof ScreenshotOptionsSchema>;

And let’s use it in the route handler (`src/app.ts`):

    1// ...2import { render } from "./screenshots";3

    4app.openapi(5    createRoute({6        // ...7    }),8    async (c) => {9        const screenshotOptions = c.req.valid("query");10

    11        const result = await render(screenshotOptions);12

    13        return c.json({ screenshot_url: result.url });14    }15);

Now, we can fully focus on implementing rendering.

### Preferring Puppeteer to Playwright

[Playwright](https://playwright.dev/) seems to be a superior library for working with headless browsers than [Puppeteer](https://pptr.dev/), but I will go with Puppeteer.

Playwright is focused more on automation testing, while Puppeteer is about browser automation. Puppeteer is still actively developed and has a much better ecosystem in terms of plugs you can use for screenshotting, like blocking ads, cookie banners, and much much more.

Long story short, These are libraries designed with different goals and they suit different needs. If you are interested read more about [the differences and similarities between Puppeteer and Playwright](/blog/puppeteer-versus-playwright/).

And, frankly, I have plenty of experience with Puppeteer—it is a decent library that just does the job.

If you are curious, you can read more about [how to take screenshots with Puppeteer](https://screenshotone.com/blog/how-to-take-a-screenshot-with-puppeteer/).

Now, let’s install Puppeteer:

Terminal window

    1npm i puppeteer

And try to render our first screenshot.

### The first screenshot

In the first simple implementation, we omit blocking banners and scrolling before rendering the full page and uploading it to any S3-compatible storage. But everything else is fairly easy to implement:

    1import { ScreenshotOptions } from "./schema";2

    3import puppeteer from "puppeteer";4

    5export async function render(options: ScreenshotOptions): Promise<{ url: string }> {6    const browser = await puppeteer.launch();7

    8    const page = await browser.newPage();9    await page.setViewport({10        width: options.viewport_width,11        height: options.viewport_height,12        deviceScaleFactor: options.device_scale_factor,13    });14

    15    await page.goto(options.url);16

    17    const encodedScreenshot = await page.screenshot({18        type: "jpeg",19        encoding: "base64",20        fullPage: options.full_page,21    });22

    23    await browser.close();24

    25    return { url: `data:image/jpeg;base64,${encodedScreenshot}` };26}

I went with the JPEG format, since it is more performant and returned the image in the Base64 encoding for simplicity but in the [data URL format](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs).

If you request to render the example.com website as:

Terminal window

    1curl "http://localhost:3000/screenshot?url=https://example.com"

You will get a response as:

    1{ "screenshot_url": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ..." }

You can copy and paste the URL into the browser and you will see the screenshot:

### Block cookie banners

We won’t implement [the complete solution to block cookies with Puppeteer](https://screenshotone.com/blog/how-to-hide-cookie-banners-when-taking-a-screenshot-with-puppeteer/), but we will one simple solution to demonstrate how it can be done—by using a plugin to block banners.

Let’s install and use the plugin first:

Terminal window

    1npm install @cliqz/adblocker-puppeteer cross-fetch

Integrating the plugin takes only a few lines of code:

    1import { ScreenshotOptions } from "./schema";2

    3import puppeteer, { Page } from "puppeteer";4import { PuppeteerBlocker } from "@cliqz/adblocker-puppeteer";5import fetch from "cross-fetch";6

    7let blocker: PuppeteerBlocker | null = null;8async function blockCookieBanners(page: Page) {9    if (!blocker) {10        blocker = await PuppeteerBlocker.fromLists(fetch, [11            // the list of the cookie banners to block from the https://easylist.to/ website12            "https://secure.fanboy.co.nz/fanboy-cookiemonster.txt",13        ]);14    }15

    16    await blocker.enableBlockingInPage(page);17}18

    19export async function render(options: ScreenshotOptions): Promise<{ url: string }> {20    const browser = await puppeteer.launch();21

    22    const page = await browser.newPage();23    if (options.block_cookie_banners) {24        await blockCookieBanners(page);25    }26

    27    await page.setViewport({28        width: options.viewport_width,29        height: options.viewport_height,30        deviceScaleFactor: options.device_scale_factor,31    });32

    33    await page.goto(options.url);34

    35    const encodedScreenshot = await page.screenshot({36        type: "jpeg",37        encoding: "base64",38        fullPage: options.full_page,39    });40

    41    await browser.close();42

    43    return { url: `data:image/jpeg;base64,${encodedScreenshot}` };44}

Now, let’s try and check if it blocks the cookie banners for StackOverflow. First without banners:

    1curl http://localhost:3000/screenshot?url=https://stackoverflow.com/&block_cookie_banners=false

And the result is:

And now, without:

    1curl http://localhost:3000/screenshot?url=https://stackoverflow.com/&block_cookie_banners=true

And:

But there are many corner cases where cookie banner blocking won’t work. In this case, you will need to block them by selectors and develop many other heuristics that search for “accept cookie” in buttons and similar.

It took me years to developer a sophisticated and yet working algorithm to block most cookie banners in [ScreenshotOne](https://screenshotone.com/).

### Trigger lazy loading for full-page screenshots

Most of the websites don’t render the images below the fold and use lazy loading techniques for that to speed up performance of loading the website.

It causes problems when taking full-page screenshots. The fastest wait to fix that is just to scroll the page till the bottom before taking the full page screenshot.

For example, look at this Apple full page screenshot without scrolling:

And then we add scrolling:

    1// ...2

    3async function scroll(page: Page) {4    return await page.evaluate(async () => {5        return await new Promise((resolve, reject) => {6            var i = setInterval(() => {7                window.scrollBy(0, window.innerHeight);8                if (9                    document.scrollingElement &&10                    document.scrollingElement.scrollTop + window.innerHeight >=11                        document.scrollingElement.scrollHeight12                ) {13                    window.scrollTo(0, 0);14                    clearInterval(i);15                    resolve(null);16                }17            }, 100);18        });19    });20}21

    22//...23

    24export async function render(options: ScreenshotOptions): Promise<{ url: string }> {25    // ...26    await page.goto(options.url);27

    28    if (options.full_page) {29        await scroll(page);30    }31

    32    const encodedScreenshot = await page.screenshot({33        type: "jpeg",34        encoding: "base64",35        fullPage: options.full_page,36    });37

    38    // ...39}40

    41//...

Now, look at the result:

All images are loaded and the full-page screenshot is rendered properly.

If you are curious, read more about [how to take full page screenshots with Puppeteer](https://screenshotone.com/blog/a-complete-guide-on-how-to-take-full-page-screenshots-with-puppeteer-playwright-or-selenium/#wait-for-lazy-load-images).

### Uploading to S3 storage

Later you can use any S3 compatible storage because the code I write will still work, but for testing purposes on my local machine, I will use [LocalStack](https://github.com/localstack/localstack):

Terminal window

    1python3 -m pip install localstack

And start it:

    1localstack start -d

Configure your AWS CLI (set access/secret keys to “test”):

Terminal window

    1aws configure --profile localstack

Create your bucket:

Terminal window

    1aws s3 mb s3://screenshots --endpoint-url http://localhost:4566 --profile localstack

Install the AWS SDK for JavaScript:

    1npm install @aws-sdk/client-s3 @aws-sdk/lib-storage

Now, let’s try to upload screenshots to the bucket:

    1import { CompleteMultipartUploadCommandOutput, S3Client, S3ClientConfig } from "@aws-sdk/client-s3";2import { Upload } from "@aws-sdk/lib-storage";3

    4// ...5

    6const cfg: S3ClientConfig = {7    region: process.env.S3_REGION ?? "us-west-2",8    maxAttempts: 5,9    retryMode: "standard",10    credentials: {11        accessKeyId: process.env.ACCESS_KEY_ID ?? "test",12        secretAccessKey: process.env.SECRET_ACCESS_KEY ?? "test",13    },14    endpoint: process.env.S3_ENDPOINT ?? "http://localhost:4566",15    forcePathStyle: true,16};17

    18const client = new S3Client(cfg);19

    20export async function uploadToS3Storage(screenshot: Buffer, key: string, contentType: string) {21    const bucket = "screenshots";22

    23    const upload = new Upload({24        client: client,25        params: {26            Bucket: bucket,27            Key: key,28            Body: screenshot,29            ContentType: contentType,30            StorageClass: "STANDARD",31        },32        queueSize: 4,33        partSize: 1024 * 1024 * 5,34        leavePartsOnError: false,35    });36

    37    const result: CompleteMultipartUploadCommandOutput = await upload.done();38    if (!result.Location) {39        throw new Error("Failed to upload");40    }41

    42    return result.Location;43}44

    45export async function render(options: ScreenshotOptions): Promise<{ url: string }> {46    // ...47

    48    const location = await uploadToS3Storage(screenshot, "example.jpeg", "image/jpeg");49

    50    return { url: location };51}

The result URL will be just `http://localhost/screenshots/example.jpeg` which is not correct, since it doesn’t contain the port.

As an exercise, you can fix that and also add a parameter to specify the resulting filename or compute it automatically from the website URL.

Containerize

------------

Since we went with Puppeteer, it already provides instructions on how to build a Docker and run a headless browser with Node.js:

    1FROM node:20@sha256:cb7cd40ba6483f37f791e1aace576df449fc5f75332c19ff59e2c6064797160e2

    3# Install latest chrome dev package and fonts4# to support major charsets (Chinese, Japanese, Arabic, Hebrew, Thai and a few others)5# Note: this installs the necessary libs to make the bundled version of Chrome that Puppeteer6# installs, work.7RUN apt-get update \8    && apt-get install -y wget gnupg \9    && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | gpg --dearmor -o /usr/share/keyrings/googlechrome-linux-keyring.gpg \10    && sh -c 'echo "deb [arch=amd64 signed-by=/usr/share/keyrings/googlechrome-linux-keyring.gpg] https://dl-ssl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \11    && apt-get update \12    && apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-khmeros fonts-kacst fonts-freefont-ttf libxss1 dbus dbus-x11 \13    --no-install-recommends \14    && service dbus start \15    && rm -rf /var/lib/apt/lists/* \16    && groupadd -r apiuser && useradd -rm -g apiuser -G audio,video apiuser17

    18USER apiuser19

    20WORKDIR /home/apiuser/app21

    22COPY --chown=apiuser:apiuser package*json tsconfig.json  ./23COPY --chown=apiuser:apiuser src ./src24

    25RUN npm ci && \26    npm run build && \27    npm prune --production28

    29CMD ["node", "/home/apiuser/app/build/index.js"]

I also changed the TypeScript configuration (`tsconfig.json`):

    1{2    "compilerOptions": {3        "target": "ESNext",4        "strict": true,5        "module": "commonjs",6        "esModuleInterop": true,7        "types": ["node"],8        "outDir": "./build"9    },10    "exclude": ["node_modules"],11    "include": ["**/*.ts"]12}

Then I installed the TypeScript compiler:

Terminal window

    1npm i typescript --save-dev

I updated the `scripts` section in `package.json`:

    1{2    // ...3    "scripts": {4        "dev": "tsx watch src/index.ts",5        "build": "tsc"6    }7    // ...8}

And tuned a bit the configuration of the browser when launching:

    1const browser = await puppeteer.launch({2    args: [3        "--disable-setuid-sandbox",4        "--disable-dev-shm-usage",5        "--disable-accelerated-2d-canvas",6        "--no-first-run",7        "--single-process",8        "--disable-gpu",9    ],10    headless: true,11});

Now, let’s check that it works:

Terminal window

    1docker build -t learnshot .

And:

Terminal window

    1docker run -p 3000:3000 learnshot -e S3_ENDPOINT=... -e ACCESS_KEY_ID=... # and other S3-related environment variables

_Pay attention that using the local version of S3, won’t work with Docker out-of-the-box. You can either use the real S3 bucket or to find the way to make sure that the localhost is available to the internal Docker network._

It should work and respond as before.

Containerizing the application will allow us to host the API anywhere from serverless to VPS.

Deploy

------

For ScreenshotOne, I use a combination of bare metal servers with GPU, managed Kubernetes, and Google Cloud Run.

But there are one thousand more ways to deploy the screenshot API we have just built.

### Kubernetes

It has a lot of upsides and I enjoy using it. Some of them are:

1.  **Scalability:** It can automatically adjust resources based on demand.

2.  **Flexibility:** It supports a wide range of environments, including on-premises, cloud, and hybrid clouds.

3.  **Rich and strong ecosystem:** Offers a rich set of features and integrations thanks to its widespread adoption and active community.

But it also has two serious downsides:

1.  **Complexity**: Setting up and managing a Kubernetes cluster can be complex, requiring significant expertise. Start with the managed option first. Even that will be complex most of the time.

2.  **Cost:** While Kubernetes itself is open-source and free, running it, especially in cloud environments, can incur substantial costs based on the resources utilized. But I consider it much cheaper option compared to Google Cloud Run and AWS Fargate as an alternative.

I wouldn’t start with Kubernetes today for most of the cases, but at later stages of the project, it can be irreplaceable and super valuable.

### AWS Fargate, Google Cloud Run, or Azure Container

I use Google Cloud Run and I still believe it is still the easiest and the fastest option to start with. Typical upsides of such platforms are:

1.  **Arguable, but serverless approach:** these environments remove the need to manage servers or clusters, simplifying deployment and management.

2.  **Scalability:** Automatically scales computing capacity in response to application demands.

3.  **Integration:** Seamlessly integrates with other Google Cloud Platform, AWS, or Azure services, offering a comprehensive ecosystem for deployment, monitoring, and security.

The main downside for me is cost, it is expensive for long-running and resource-intensive applications (like headless browsers!) due to its pricing model.

### VPS

Virtual Private Servers (VPS) provide another viable option for deploying our screenshot API. And that’s how I actually started, but it quickly gets out of control, once you have a considerable load, you need to always adjust and check the capacity of your servers.

The main upside is cost-effectiveness, but managing VPS is still painful which can be solved with PaaS like [Heroku](https://www.heroku.com/), [Render](https://render.com/), or similar.

Or you can use \[[https://kamal-deploy.org/](https://kamal-deploy.org/)\] and GitHub actions for automating at least deploys, but there are still will be issues that you will need to solve.

### PaaS

Heroku and similar providers can simplify the server management issues, but you can use something much better that can combine both cost efficiency and ease of deployment—[Coolify](https://coolify.io/):

[](https://coolify.io/)

It can automate your CI/CD process, generate SSL certificates, provision servers, and has powerful server automation and monitoring.

If I were starting today again, I would seriously consider using Coolify and provisioning and managing my own servers with it.

What is next?

-------------

You might want to continue further development, but there is so much more about screenshot APIs. Let’s grasp quickly what could be done next.

### Caching

Except for specific categories of sites like news, most sites don’t change frequently and you can enable caching for rendered screenshots.

For example, [ScreenshotOne](https://screenshotone.com) does that by utilizing Cloudflare Workers, Cache, and R2 storage. It is also provided as a free option for all ScreenshotOne customers since it almost costs nothing.

### Proxies and retries

Requests to websites often fail, networking fails, and everything fails. Sometimes your screenshot is blocked.

Combine using proxies and retry requests if the site does not respond.

### Advanced image processing

You can add a feature to specify the image size, and format and convert it on the fly.

It is not requested frequently but is used by some of my customers to store already processed images and serve them from the cache.

There are a lot more features to build but I listed the most frequently asked features.

### Improve error handling

Make sure to handle all the possible errors from Puppeteer and when uploading screenshots to the S3 storage.

Also, for every function you can call, always set timeouts and make sure to handle them properly if the function call exceeds the configured timeout.

### Automate testing

Screenshotting websites have so many pitfalls that I would recommend to write automation tests if it is possible.

You often fix one thing, and two others is now broken. Writing automated tests can help to prevent that. And make sure you deliver the stable quality of your services.

The end

-------

I know that screenshot APIs are boring, that’s what most developers tell me. But I hope I shared a little bit of my passion for this domain with you and you learned a thing or two.

Thanks for reading!

Read more Engineering

---------------------

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

[View all posts](/blog/tags/engineering/)

#### [How to take website screenshots with JavaScript or TypeScript (Node.js)](/blog/how-to-take-website-screenshots-with-javascript-or-typescript-nodejs/)

The article examines how you can take screenshots of any URL with Javascript and TypeScript (Node.js) by using Selenium, Puppeteer alternatives, Playwright, or screenshot API as a service.

Read more

#### [How to Take Full Page Screenshots with Playwright in Python](/blog/playwright-python-full-page-website-screenshots/)

Learn how to capture full page screenshots with Playwright in Python. Master the full\_page parameter, handle infinite scroll pages, lazy-loaded images, and maximum size limits.

Read more

#### [Uploading website screenshots to any S3-compatible storage](/blog/uploading-website-screenshots-to-any-s3-compatible-storage/)

In this note, I share how I take website screenshots or render HTML and upload the resulted images or PDF to any S3-compatible storage like Amazon S3, Cloudflare R2, or Backblaze B2.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/website-archivation
----

Automate Website Screenshots

1 min read

Website Archivation for Historical Reference

============================================

Automate the archival of website versions for historical reference and data retrieval.

Website archivation is an essential task for businesses aiming to maintain a historical record of their online presence. By using the ScreenshotOne API, companies can automate the process of capturing and saving snapshots of their websites at regular intervals. This ensures a comprehensive archive for future reference, compliance needs, or data retrieval purposes.

Why ScreenshotOne API?

----------------------

The ScreenshotOne API offers a straightforward and efficient solution for website archivation. It can capture full-page screenshots of websites, preserving the visual and textual content as it appeared at a specific point in time. This is particularly useful for tracking changes in web design, content updates, and more. Compared to manual archiving methods, the API saves time and ensures accuracy and consistency in the archival process.

Value Proposition

-----------------

Utilizing a website screenshot API for archivation offers several benefits over traditional methods. It significantly reduces the manpower and time required to archive web pages manually. Additionally, it provides an accurate historical record of a website’s evolution, which can be invaluable for legal reasons, compliance verification, or analyzing the progression of online marketing strategies. The ScreenshotOne API simplifies website archivation, making it an indispensable tool for businesses focused on maintaining a detailed and accessible online history.

We thought making a screenshot tool for our AI agents would be simple. But we faced countless unexpected problems.

So, we ditched the idea and chose ScreenshotOne API instead. It saved us lots of time and it just works!

John Rush

Founder, [Unicorn Platform](https://unicornplatform.com)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/code-examples/go
----

[Skip to content](#_top)

Go SDK and Code Examples

========================

Copy page

If you have any questions, please, reach out at `support@screenshotone.com`.

It takes minutes to start taking screenshots in Go. Just [sign up](https://dash.screenshotone.com/sign-up) to get access and secret keys, import the client, and you are ready to go.

### Installation

Terminal window

    1go get github.com/screenshotone/gosdk

### Usage

Import the library:

    1import screenshots "github.com/screenshotone/gosdk"

Generate a screenshot URL without executing request:

    1client, err := screenshots.NewClient("IVmt2ghj9TG_jQ", "Sxt94yAj9aQSgg")2if err != nil {3    // ...4}5

    6options := screenshots.NewTakeOptions("https://scalabledeveloper.com").7    Format("png").8    FullPage(true).9    DeviceScaleFactor(2).10    BlockAds(true).11    BlockTrackers(true)12

    13u, err := client.GenerateTakeURL(options)14if err != nil {15    // ...16}17

    18fmt.Println(u.String())19// Output: https://api.screenshotone.com/take?access_key=IVmt2ghj9TG_jQ&block_ads=true&block_trackers=true&device_scale_factor=2&format=png&full_page=true&url=https%3A%2F%2Fscalabledeveloper.com&signature=85aabf7ac251563ec6158ef6839dd019bb79ce222cc85288a2e8cea0291a824e

Take a screenshot and save the image in the file:

    1client, err := screenshots.NewClient("IVmt2ghj9TG_jQ", "Sxt94yAj9aQSgg")2if err != nil {3    // ...4}5

    6options := screenshots.NewTakeOptions("https://example.com").7    Format("png").8    FullPage(true).9    DeviceScaleFactor(2).10    BlockAds(true).11    BlockTrackers(true)12

    13image, err := client.Take(context.TODO(), options)14if err != nil {15    // ...16}17

    18defer image.Close()19out, err := os.Create("example.png")20if err != nil {21    // ...22}23

    24defer out.Close()25io.Copy(out, image)

Check out [other SDKs and code examples](/docs/code-examples/).

----
url: https://screenshotone.com/changelog/selector-scroll-into-view-option
----

Control scrolling into view when taking screenshots by selector

===============================================================

You can now control scrolling into view when taking screenshots by selector. It allows render more accurate screenshots.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jan 12, 2025

Before this update, when you took a screenshot of an element by [selector](#selector), the page was scrolled into view and it caused some issues, e.g. sticky elements were overlapping the target element on the screenshot.

Now, you can control if you want to scroll the page into view or not with the [selector\_scroll\_into\_view](#selector_scroll_into_view) option.

The option is set to `true` by default. But now you can set it to `false` to avoid scrolling the page into view.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Choose the format of the page content returned by the ScreenshotOne API](/changelog/metadata-content-format/)

Now you can choose the format of the page content returned by ScreenshotOne API with the metadata\_content\_format option.

Read more →

1 min read

#### [Added a "copy page" button in documentation](/changelog/copy-page-button-in-docs/)

You can now copy the page content as Markdown for LLMs and more.

Read more →

1 min read

#### [Improved uploading and error handling to S3-compatible storage](/changelog/improved-storage-upload/)

Today, the new version of ScreenshotOne API was deployed to production that enables a retries mechanism when uploading to an S3 storage and more granular error handling.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/how-to-take-website-screenshots-in-python
----

How to take website screenshots in Python

=========================================

With Python, you can take website screenshots in multiple ways. But the best way to do it depends solely on your needs and your use case. Let's quickly examine all the options.

[Blog post](/blog/) 8 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Mar 18, 2024

#### Tags

[Screenshot rendering](/blog/tags/screenshot-rendering/)

Quick Overview

--------------

[Playwright](#playwright-in-python) is the best library to automate website screenshots in Python today—no doubts. It is easy to install and use.

But if you have a few minutes and want to examine all the options to take screenshots of web pages in Python, you can use the following:

1.  An old but battle-tested automation testing framework like [Selenium](#selenium-in-python) with a web driver of choice.

2.  [pyppeteer](#pyppeteer), **although not maintained and outdated**, is still a usable Python port of the JavaScript (headless) Chrome/Chromium browser automation library. It is also one of the ways to screenshot a webpage without Selenium.

3.  [Playwright](#playwright-in-python), a modern successor to both Selenium and pyppeteer, allows for browser automation and automated testing.

4.  You can use [any URL to screenshot API](#url-to-screenshot-api) to quickly start without managing browsers and access a variety of useful automation features out-of-the-box.

Let’s quickly give an example for each option and assess which one is better to use and when.

Selenium in Python

------------------

**A quick tip:** Use Selenium for rendering screenshots in Python if you already have that library in your stack. Otherwise, if the goal is to render to screenshots only, go with [Playwright](#playwright-in-python). Prefer Playwright to Selenium for testing also, since the former is actively developed and supports assertions and almost all modern browsers.

Selenium is a library for automating web browsers. It allows you to control a web browser, such as Google Chrome, Firefox, or Safari, from Python.

Selenium provides a way to write scripts in Python that can interact with web pages in a way that simulates a user interacting with the web page through a web browser. It is useful for a variety of tasks, such as testing web applications, automating boring and repetitive tasks, taking screenshots and web scraping.

Selenium requires a web driver to control a web browser through Python. Some popular web drivers include `chromedriver` for Google Chrome, `geckodriver` for Mozilla Firefox, and `safaridriver` for Safari.

Install Selenium and your driver of choice using `pip`:

Terminal window

    1pip install selenium2pip install chromedriver # or geckodriver, or safaridriver

And now let’s write a simple script to take a screenshot in Python:

    1from selenium import webdriver2

    3# 1. create a web driver instance4driver = webdriver.Chrome()5

    6# 2. navigate to the website7driver.get("https://magician.design/")8

    9# 3. save a screenshot of the current page10driver.save_screenshot("magician.design.png")11

    12# 4. close the web driver13driver.quit()

The result is:

Use Selenium if you want to take screenshots from a different browser, but keep in mind that its screenshot capabilities are minimal. If you are OK with using Chrome or Chromium and don’t care about other browsers but need a powerful library to take screenshots, check out [pyppeteer](#pyppeteer).

pyppeteer

---------

**A quick tip:** The pyppeteer library is outdated and not maintained anymore. For simple use cases you might still use it, but consider using [Playwright](#playwright-in-python) instead.

[pyppeteer](https://pypi.org/project/pyppeteer/) is a Python port of the JavaScript (headless) Chrome/Chromium browser automation library called Puppeteer.

Install with `pip` from PyPI (`pyppeteer` requires Python >= 3.6):

    1pip install pyppeteer

Let’s open a webpsite and take a screenshot of it:

    1import asyncio2from pyppeteer import launch3

    4async def main():5    browser = await launch()6    page = await browser.newPage()7    await page.goto('https://softstart.app/')8    await page.screenshot({'path': 'softstart.png'})9    await browser.close()10

    11asyncio.get_event_loop().run_until_complete(main())

The screenshot is stored at `softstart.png`. That’s it and that’s how simple it is:

Playwright in Python

--------------------

**A quick tip**

[Playwright](https://playwright.dev/python/docs/intro) is specifically designed to meet the requirements of end-to-end testing.

Playwright offers support for all contemporary rendering engines, such as Chromium, WebKit, and Firefox.And it allows testing across various operating systems including Windows, Linux, and macOS, whether locally or on continuous integration (CI) systems, and supports both headless and headed modes with native mobile emulation.

It is a very powerful library and it can do mostly everything that a browser can do:

*   To crawl a single-page application or generate server-side rendered content.

*   To take screenshots and create PDF documents of web pages.

*   To automate tasks such as form submission, user interface testing, and keyboard input.

*   To set up an automated testing environment using current JavaScript and browser capabilities.

*   To record a timeline trace of your website to troubleshoot performance issues.

*   To automate testing of Chrome extensions.

But’s get back to the screenshots and check how easy it is to do it with Playwright.

First, install it:

Terminal window

    1pip install playwright2playwright install

Then let’s take a screenshot:

    1from playwright.sync_api import sync_playwright2

    3def run(playwright):4    # launch the browser5    browser = playwright.chromium.launch()6    # opens a new browser page7    page = browser.new_page()8    # navigate to the website9    page.goto('https://example.com')10    # take a full-page screenshot11    page.screenshot(path='example.png', full_page=True)12    # always close the browser13    browser.close()14

    15with sync_playwright() as playwright:16    run(playwright)

That’s how simple it is:

If you want to screenshot webpages without Selenium, Playwright is your best choice.

You might encounter a few issues while using Playwright, let’s quickly consider how to solve them if you get to them.

URL to Screenshot API

---------------------

One of the most significant downsides of taking screenshots with `Selenium`, `pyppeteer` or even `Playwright` is handling infrastructure and taking care of browsers. They are resource intensive. You might encounter crashes, memory leaks, and high levels of CPU consumption.

So, if you need to take 5-10 screenshots and not that often, I would go with `Selenium`, `pyppeteer` or `Playwright`. But if you need a scale or don’t want to deal with infrastructure issues, I would use a third-party API, like [ScreenshotOne—an URL to screenshot API](https://screenshotone.com/).

> I am a founder of ScreenshotOne, and of course, I would love to everybody be my customers. But that’s not the goal. The goal is to serve the customers who can extract the maximum value from my product.

> 

> If you do have time to deal with screenshot issues and corner cases, I would recommend choosing Playwright and going with it. But if you want to offload that work to somebody else and focus on your core business priorities, I am happy to help.

It is free to get started and supports various options—like removing chat widgets, blocking cookie banners, rendering in dark mode, and even animations.

Sign up to get your API access and secret key, and let’s try [ScreenshotOne’s official SDK for Python](https://pypi.org/project/screenshotone/):

Terminal window

    1pip install screenshotone

And:

    1import shutil2from screenshotone import Client, TakeOptions3

    4# create API client5client = Client('<your access key>', '<your secret key>')6

    7# set up options8options = (TakeOptions.url('https://screenshotone.com')9    .format("png")10    .viewport_width(1024)11    .viewport_height(768)12    .block_cookie_banners(True)13    .block_chats(True))14

    15# or render a screenshot and download the image as stream16image = client.take(options)17

    18# store the screenshot the example.png file19with open('screenshotone.png', 'wb') as result_file:20    shutil.copyfileobj(image, result_file)

That’s it. The result is:

That’s how simple it was!

If you have any questions, please, reach out to `support@screenshotone.com` and I would love help. I am so passionate about my niche that I will help you with screenshot automation even if you are not my customer and don’t plan to be.

Summary

-------

I would recommend using Selenium only if you are already using it. But if you need screenshots using Python, the best options are to use Playwright or to use a screenshot API.

Every time, I would choose Playwright and prefer it to anything, except if you know that you need to take screenshots at scale and don’t want to deal with the corner cases. Then I would give a try to [URL to screenshot API like ScreenshotOne](https://screenshotone.com/)

I hope I helped you a little bit to choose the best Python library to take screenshots and have a nice day!

Frequently Asked Questions

--------------------------

As a bonus material, I am gathering all the questions users often ask related to Python screenshotting. If you have any, also, please send me at `support@screenshotone.com`.

**1\. What are the main differences between Selenium, pyppeteer, and Playwright?**

1.  **Selenium** is a robust library for browser automation that supports multiple browsers and is great for web scraping, testing, and automation tasks. It requires a separate driver for each browser.

2.  **pyppeteer** is a Python port of Puppeteer (a headless Chrome/Chromium browser automation library), but it’s outdated and not maintained. It’s simpler for Chrome/Chromium-specific tasks but less versatile compared to Selenium and Playwright.

3.  **Playwright** is a modern tool that supports all modern web browsers, including Chrome, Firefox, and Safari. It’s designed for automated testing, browser automation, and is capable of taking screenshots, generating PDFs, and more. It’s the most recommended tool for new projects due to its extensive features and active development.

**2\. Can I use these tools for automating tasks other than taking screenshots?**

Yes, all three tools—Selenium, pyppeteer, and Playwright—are capable of automating a wide range of browser tasks beyond taking screenshots, such as web scraping, automated testing, and simulating user interactions with web pages.

**3\. Are there any cost implications for using Playwright or Selenium compared to using a URL to Screenshot API like ScreenshotOne?**

Using Playwright or Selenium primarily incurs no direct costs as they are open-source tools; however, infrastructure and maintenance costs may apply, especially as you scale. In contrast, a URL to Screenshot API like ScreenshotOne might have a free tier, but will typically have costs associated with higher usage tiers, offering the benefit of managed infrastructure.

**4\. How do I handle dynamic content or login-required pages when taking screenshots?**

For dynamic content, using Playwright or Selenium allows for executing JavaScript or waiting for elements to load before taking screenshots. For login-required pages, scripts can be written to automate the login process before taking a screenshot. Care should be taken to manage credentials securely.

**5\. What should I do if I encounter a specific error or issue while using one of these tools?**

For detailed technical issues not covered in the post, it’s best to consult the official documentation or communities for each tool (e.g., GitHub issues, Stack Overflow). For Playwright and Selenium, they have active communities where users can ask for help.

For issues related to ScreenshotOne, reaching out to our support as mentioned in the post would be the recommended course of action.

Read more Screenshot rendering

------------------------------

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

[View all posts](/blog/tags/screenshot-rendering/)

#### [Puppeteer waitUntil: how to wait for page load](/blog/puppeteer-wait-until-the-page-is-ready/)

Join me in exploring how to find the ideal wait time or event of when to take the page screenshot with Puppeteer.

Read more

#### [How to take website screenshots with PHP](/blog/how-to-take-website-screenshots-with-php/)

The article examines how you can take screenshots of any URL with PHP by using Selenium, Puppeteer alternatives, or screenshot API as a service.

Read more

#### [Rendering screenshots of social media pages](/blog/how-to-take-screenshots-of-social-media-pages/)

Social media platforms often restrict automation, but with the right tools and care for compliance, capturing screenshots is possible.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/screenshot-api/nodejs
----

[What's new API error insights API error insights in the dashboard](/changelog/error-metrics/)

Node.js Screenshot API

======================

Capture pixel-perfect website screenshots in Node.js with a simple API call. No Puppeteer setup, no browser management—just clean, reliable screenshots.

----------------------

----------------------------

------------------------------------

Take screenshots with Node.js

-----------------------------

Use our official Node.js SDK or send simple HTTP requests to capture screenshots.

    1// $ npm install screenshotone-api-sdk --save2

    3import * as fs from 'fs';4import * as screenshotone from 'screenshotone-api-sdk';5

    6// create API client7const client = new screenshotone.Client("<access key>", "<secret key>");8

    9// set up options10const options = screenshotone.TakeOptions11    .url("https://example.com")12    .delay(3)13    .blockAds(true);14

    15// generate URL16const url = client.generateTakeURL(options);17console.log(url);18// expected output: https://api.screenshotone.com/take?url=...19

    20// or download the screenshot21const imageBlob = await client.take(options);22const buffer = Buffer.from(await imageBlob.arrayBuffer());23fs.writeFileSync("example.png", buffer)24// the screenshot is stored in the example.png file

Mike Roberts

Founder, [SpyFu](https://www.spyfu.com/)

> ScreenshotOne is the best product on the market - and that's before you take into account how responsive and easy Dmytro is to work with.

> 

> Any time we've found a rare edge case, it's been resolved in hours.

> 

> Great company, great founder - can't say enough!

Without writing a line of code

No-code integrations

--------------------

Quickly render website screenshots with Zapier, Airtable, Make and other popular no-code platforms of your choice.

[](/integrations/zapier/)[](/integrations/airtable/)[](/integrations/make/)[](/integrations/bubble/)[](/integrations/n8n/)

Read

Lessons from running screenshot rendering infrastructure

--------------------------------------------------------

Practical guides and real updates based on our experience operating rendering infrastructure at production scale.

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots with JavaScript or TypeScript (Node.js)](/blog/how-to-take-website-screenshots-with-javascript-or-typescript-nodejs/)

The article examines how you can take screenshots of any URL with Javascript and TypeScript (Node.js) by using Selenium, Puppeteer alternatives, Playwright, or screenshot API as a service.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jun 14, 2022

•

4 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Taking care of WordPress Sites with ScreenshotOne](/blog/kinsta/)

How Kinsta uses ScreenshotOne to deliver reliable automatic updates.

Written by

[Roger Williams](/contributors/roger-williams/), [Barnabás Ürmössy](/contributors/barnabs-rmssy/)

Published on

Apr 29, 2025

•

2 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Typeshare uses ScreenshotOne for image generation](/blog/how-typeshare-uses-screenshotone/)

Typeshare is a digital writing platform designed to enhance the writing experience by offering a suite of tools aimed at reducing common barriers writers face.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Apr 14, 2024

•

2 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/no-code/n8n
----

[Skip to content](#_top)

How to automate website screenshots with n8n

============================================

Copy page

[n8n](https://n8n.io/) is a free and open-source workflow platform.

It allows create workflows using a lot of different integrations with simple and intuitive drag-and-drop interface:

[](https://n8n.io/)

Community nodes

---------------

There is an official [ScreenshotOne node](https://www.npmjs.com/package/n8n-nodes-screenshotone) available for n8n.

[](https://www.npmjs.com/package/n8n-nodes-screenshotone)

You can also find it in the [n8n community nodes](https://docs.n8n.io/integrations/community-nodes/) section.

Guides

------

Guides on how to automate website screenshots with n8n:

1.  [Capture URL Screenshots Automatically from Google Sheets & Drive with ScreenshotOne & Gmail Alerts](https://n8n.io/workflows/3321-capture-url-screenshots-from-google-sheets-with-screenshotone-and-save-to-drive-with-gmail-alerts/).

[](https://n8n.io/workflows/3321-capture-url-screenshots-from-google-sheets-with-screenshotone-and-save-to-drive-with-gmail-alerts/)

----
url: https://screenshotone.com/docs/errors/internal-application-error
----

[Skip to content](#_top)

Internal Application Error

==========================

Copy page

It is an API error returned when the API fails to serve the request due to internal reasons:

    1{2    "is_successful": false,3    "error_message": "The API failed to serve your request. You can try replay the request. If the error is repeated after a few retries, please, reach out at `support@screenshotone.com.`",4    "error_code": "internal_application_error",5    "documentation_url": "https://screenshotone.com/docs/errors/internal-application-error/"6}

Retry

-----

On rare occasions it can be caused by the website you try to screenshot. So, you can retry the request. It is free, ScreenshotOne doesn’t charge you for retries and cached requests.

Reach out to support

--------------------

Most of the time, the error is triggered because of some issues in the API or even because of some bugs.

If nothing helps you, please, reach out to `support@screenshotone.com` and we will try to help you as fast as possible.

----
url: https://screenshotone.com/contributors/dmytro-krasun/2
----

Dmytro Krasun

-------------

With more than a decade of experience in software engineering, I share the best practices and solutions you can apply to your problems in the space of headless browsers. You can also find me on [Twitter](https://twitter.com/DmytroKrasun) and [LinkedIn](https://www.linkedin.com/in/dmytrokrasun)

View all Changelog

[Screenshot rendering](/blog/tags/screenshot-rendering/) [Playwright guides](/blog/tags/playwright-guides/)

#### [How to Take Bulk Screenshots with Playwright in Python](/blog/bulk-screenshots-playwright-python/)

Learn how to automate bulk website screenshots with Playwright in Python. Master async batch processing, concurrent screenshots, rate limiting, and error handling for large-scale screenshot automation.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 14, 2026

•

7 min read

[Desktop screen capture](/blog/tags/desktop-screen-capture/)

#### [How to Capture Desktop Screen with DXcam in Python](/blog/dxcam-python-screenshots/)

Complete guide to DXcam, the fastest Python screen capture library. Learn high-FPS capture, video mode, region capture, and DXcam vs Python MSS performance comparison.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 14, 2026

•

4 min read

[Desktop screen capture](/blog/tags/desktop-screen-capture/)

#### [How to Take Screenshots with PyAutoGUI in Python](/blog/pyautogui-python-screenshots/)

Complete guide to taking screenshots with PyAutoGUI in Python. Learn screenshot(), region parameters, locateOnScreen(), and common errors with ImageNotFoundException.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 13, 2026

•

3 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to Take Screenshots with pyppeteer in Python](/blog/pyppeteer-python-screenshots/)

Guide to taking screenshots with pyppeteer in Python. Learn the basics, full page captures, and why you should migrate to Playwright.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jan 19, 2026

•

2 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Website Screenshots with Selenium in Python](/blog/selenium-python-screenshots/)

Complete guide to taking screenshots with Selenium in Python. Learn save\_screenshot(), element screenshots, full page workarounds, and headless mode setup.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 11, 2026

•

5 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take bulk screenshots with Puppeteer](/blog/bulk-screenshots-with-puppeteer/)

Learn how to take screenshots of multiple URLs with Puppeteer, including concurrency management, error handling, retries, and proxy support.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Dec 16, 2025

•

8 min read

#### [ScreenshotOne November 2025 updates](/blog/screenshotone-november-2025-updates/)

Error metrics in the dashboard, Postman Public API Network, and Landing Gallery customer story.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Dec 2, 2025

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How RankPill uses ScreenshotOne](/blog/rankpill/)

Sharing how RankPill uses ScreenshotOne to automate website screenshot generation for SEO and GEO automation.

Written by

[Modest Mitkus](/contributors/modest-mitkus/), [Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Nov 6, 2025

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How and why Saaspo uses ScreenshotOne to automate screenshot generation](/blog/saaspo/)

Saaspo chose ScreenshotOne to automate tedious and boring work to generate pixel-perfect screenshots for their platform. Why?

Written by

[Andy Hooke](/contributors/andy-hooke/), [Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Nov 4, 2025

•

1 min read

#### [ScreenshotOne October 2025 updates](/blog/screenshotone-october-2025-updates/)

Metadata content format, upgraded dashboard, improved webhooks, updated Go SDK, Make conference, and AWS disruption lessons.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Nov 1, 2025

•

1 min read

#### [Lessons learned from the AWS disruption](/blog/lessons-from-the-aws-us-east-1-disruption/)

Sharing thoughts and lessons learned from the AWS (us-east-1) disruption, including impact on ScreenshotOne.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Oct 30, 2025

•

3 min read

#### [ScreenshotOne made it to the official Make conference](/blog/make-conference/)

One of our friends noticed ScreenshotOne at the official Make conference

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Oct 16, 2025

•

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/tools/above-the-fold
----

Check what renders above the fold

---------------------------------

Capture the visible viewport of any website and compare the first screen on desktop and mobile.

[Tools](/tools/) Free Above the Fold Checker

Your website URL

Capture only the visible viewport before the first scroll.

Device

Block banners and ads

Hide cookie banners, popups, and ads for a cleaner above-the-fold screenshot.

Render

Screenshot Preview

If you need to automate website screenshot rendering or integrate screenshotting into your application or SaaS, please, check out [the best screenshot API—ScreenshotOne](/).  

Check out more [screenshot tools](/tools/).

Frequently Asked Questions

--------------------------

Discover quick and comprehensive answers to common questions about our platform, services, and features.

What does the above-the-fold checker do?

It captures the visible part of a webpage before any scrolling happens, so you can review what users actually see first on desktop or mobile.

Why should I check above the fold?

It is the first impression of the page. Checking it helps you catch weak messaging, hidden calls to action, intrusive banners, layout breakage, and mobile rendering issues before they affect conversions.

Why is the above-the-fold area important?

That area often determines whether visitors keep reading, click a button, or leave. Clear copy, visible CTAs, and a stable layout above the fold usually have the biggest impact on engagement.

Can I check mobile above-the-fold layouts too?

Yes. The tool includes desktop and mobile presets, so you can quickly compare what loads first on a larger screen and on a phone-sized viewport.

Why is ScreenshotOne offering this for free?

The tool demonstrates how ScreenshotOne can automate viewport screenshots and rendering workflows. It is a practical example of the screenshot API in action.

What should I look for in an above-the-fold check?

Look for visible navigation, a readable headline, a clear primary action, fast-loading media, and any overlapping elements such as sticky bars, chat widgets, or cookie banners.

Integrate today

Automate screenshot rendering with the language you love

--------------------------------------------------------

Send simple HTTP requests or use native libraries for your language of choice.

Java Go Node.js PHP Python Ruby C# (.NET)

    1// add com.screenshotone.jsdk:screenshotone-api-jsdk:[1.0.0,2.0.0)2// to your `pom.xml` or `build.gradle`3

    4import com.screenshotone.jsdk.Client;5import com.screenshotone.jsdk.TakeOptions;6

    7import java.io.File;8import java.nio.file.Files;9

    10public class App {11    public static void main(String[] args) throws Exception {12        final Client client = Client.withKeys("<access key>", "<secret key>");13        TakeOptions takeOptions = TakeOptions.url("https://example.com")14                .fullPage(true)15                .deviceScaleFactor(1)16                .viewportHeight(1200)17                .viewportWidth(1200)18                .format("png")19                .omitBackground(true);20        final String url = client.generateTakeUrl(takeOptions);21

    22        System.out.println(url);23        // Output: https://api.screenshotone.com/take?url=...24

    25        // or download the screenshot26        final byte[] image = client.take(takeOptions);27

    28        Files.write(new File("./example.png").toPath(), image);29        // the screenshot is stored in the example.png file30    }31}

    1// go get github.com/screenshotone/gosdk2

    3import screenshots "github.com/screenshotone/gosdk"4

    5client, err := screenshots.NewClient("<access key>", "<secret key>")6// check err7

    8options := screenshots.NewTakeOptions("https://example.com").9    Format("png").10    FullPage(true).11    DeviceScaleFactor(2).12    BlockAds(true).13    BlockTrackers(true)14

    15u, err := client.GenerateTakeURL(options)16// check err17

    18fmt.Println(u.String())19// Output: https://api.screenshotone.com/take?url=...20

    21// or download the screenshot22image, err := client.Take(context.TODO(), options)23// check err24

    25defer image.Close()26out, err := os.Create("example.png")27// check err28

    29defer out.Close()30io.Copy(out, image)31// the screenshot is stored in the example.png file

    1// $ npm install screenshotone-api-sdk --save2

    3import * as fs from 'fs';4import * as screenshotone from 'screenshotone-api-sdk';5

    6// create API client7const client = new screenshotone.Client("<access key>", "<secret key>");8

    9// set up options10const options = screenshotone.TakeOptions11    .url("https://example.com")12    .delay(3)13    .blockAds(true);14

    15// generate URL16const url = client.generateTakeURL(options);17console.log(url);18// expected output: https://api.screenshotone.com/take?url=...19

    20// or download the screenshot21const imageBlob = await client.take(options);22const buffer = Buffer.from(await imageBlob.arrayBuffer());23fs.writeFileSync("example.png", buffer)24// the screenshot is stored in the example.png file

    1<?php2

    3// composer require screenshotone/sdk:^1.04

    5use ScreenshotOneSdkClient;6use ScreenshotOneSdkTakeOptions;7

    8$client = new Client("<access key>", "<secret key>");9

    10$options = TakeOptions::url("https://example.com")11    ->fullPage(true)12    ->delay(2)13    ->geolocationLatitude(48.857648)14    ->geolocationLongitude(2.294677)15    ->geolocationAccuracy(50);16

    17$url = $client->generateTakeUrl($options);18echo $url.PHP_EOL;19// expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com...20

    21$image = $client->take($options);22file_put_contents('example.png', $image);23// the screenshot is stored in the example.png file

    1# pip install screenshotone2

    3import shutil4from screenshotone import Client, TakeOptions5

    6# create API client7client = Client('<access key>', '<secret key>')8

    9# set up options10options = (TakeOptions.url('https://screenshotone.com')11    .format("png")12    .viewport_width(1024)13    .viewport_height(768)14    .block_cookie_banners(True)15    .block_chats(True))16

    17# generate the screenshot URL and share it with a user18url = client.generate_take_url(options)19# expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fscreenshotone.com&viewport_width=1024&viewport_height=768&block_cookie_banners=True&block_chats=True&access_key=&signature=6afc9417a523788580fa01a9f668ea82c78a9d2b41441d2a696010bf2743170f20

    21# or render a screenshot and download the image as stream22image = client.take(options)23

    24# store the screenshot the example.png file25with open('example.png', 'wb') as result_file:26    shutil.copyfileobj(image, result_file)

    1# Add this gem to your Gemfile:2# gem 'screenshotone'3

    4# If you don't need to add a signature5client = ScreenshotOne::Client.new('<access key>')6

    7# Or ff you do need to add a signature8client = ScreenshotOne::Client.new('<access key>', '<secret key>')9

    10# You can set any available option, in a camel_case format, for example:11options = ScreenshotOne::TakeOptions.new(url: 'https://example.com').12            full_page(true).13            delay(2).14            geolocation_latitude(48.857648).15            geolocation_longitude(2.294677).16            geolocation_accuracy(50)17

    18# Verify all the parameters are valid (we will validate the parameters that should be19# numeric, booleans or that accept only certain values)20options.valid?21=> true22

    23# To simply get the final url:24client.generate_take_url(options)25=> "https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com..."26

    27# To actually get the image (the response body of a request to the previous url)28client.take(options)29=> "\xFF\xD8\xFF\xE0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xFF\..."

    1// Add the library via nuget using the package manager console: PM> Install-Package ScreenshotOne.dotnetsdk2// Or from the .NET CLI as: dotnet add package ScreenshotOne.dotnetsdk3

    4// And generate a screenshot URL without executing request:5var client = new Client("<access key>", "<secret key>");6var options = TakeOptions.Url("https://www.amazon.com")7  .FullPage(true)8  .Format(Format.PNG)9  .BlockCookieBanners(true);10

    11var url = client.GenerateTakeUrl(options);12// url = https://api.screenshotone.com/take?url=https%3A%2F%2Fwww.amazon.com&full_page=true&format=png&block_cookie_banners=true&access_key=_OzqMIjpCw-ARQ&signature=8a08e62d13a5c3490fda0734b6707791d3decc9ab9ba41e8cc045288a39db50213

    14// Or take a screenshot and save the image in the file:15var client = new Client("<access key>", "<secret key>");16var options = TakeOptions.Url("https://www.google.com")17  .FullPage(true)18  .Format(Format.PNG)19  .BlockCookieBanners(true);20

    21var bytes = await client.Take(options);22

    23File.WriteAllBytes(@"c:\temp\example.png", bytes);

Mike Roberts

Founder, [SpyFu](https://www.spyfu.com/)

> ScreenshotOne is the best product on the market - and that's before you take into account how responsive and easy Dmytro is to work with.

> 

> Any time we've found a rare edge case, it's been resolved in hours.

> 

> Great company, great founder - can't say enough!

Without writing a line of code

No-code integrations

--------------------

Quickly render website screenshots with Zapier, Airtable, Make and other popular no-code platforms of your choice.

[](/integrations/zapier/)[](/integrations/airtable/)[](/integrations/make/)[](/integrations/bubble/)[](/integrations/n8n/)

Read

Lessons from running screenshot rendering infrastructure

--------------------------------------------------------

Practical guides and real updates based on our experience operating rendering infrastructure at production scale.

[Playwright guides](/blog/tags/playwright-guides/)

#### [Playwright "Execution context was destroyed": how to fix navigation and page.evaluate errors](/blog/playwright-execution-context-was-destroyed-most-likely-because-of-a-navigation/)

Fix the Playwright "Execution context was destroyed, most likely because of a navigation" error after click, form submit, redirect, reload, or page.evaluate.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 13, 2026

•

4 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [page.waitForTimeout is not a function in Puppeteer](/blog/page-waitfortimeout-is-not-a-function-in-puppeteer/)

Puppeteer removed page.waitForTimeout(). Learn why the error happens and which modern alternatives to use instead.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 13, 2026

•

2 min read

#### [OpenClaw with Playwright or Puppeteer: how to install browser support](/blog/openclaw-playwright-puppeteer/)

A practical guide to OpenClaw browser automation, why Playwright is the documented path, where Puppeteer fits, how to make screenshots, and when ScreenshotOne is the better choice for screenshot-only flows.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 12, 2026

•

6 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/errors/resulting-image-too-large
----

[Skip to content](#_top)

Resulting Image Too Large

=========================

Copy page

It is an API error returned when the resulting image is too large for the specified format.

    1{2    "is_successful": false,3    "error_message": "The resulting image is too large for the specified format.",4    "error_code": "resulting_image_too_large",5    "documentation_url": "https://screenshotone.com/docs/errors/resulting-image-too-large/"6}

Reasons and how to fix

----------------------

### Using image formats with size limits for full-page screenshots

The JPEG format has a height limit of 65,535 pixels, WebP format has a height limit of 16,383 pixels.

Full-page screenshots that don’t fit the size limits will trigger the error `resulting_image_too_large`.

A solution would be is to choose the format that fits your use case better. E.g. if you use WebP, try to use JPEG. Or maybe try PNG.

### Limiting the height of the full-page screenshot

If it happens for full-page screenshots, you can set the `full_page_max_height` option to make sure the height of the resulting image always fits the specified format, e.g. set it to 16000 for WebP format or 60000 for JPEG format.

### Reducing the device scale factor

If the issue is with the size of the page, you can try to reduce the device scale factor by setting the `device_scale_factor` option to a lower value, e.g. `1` instead of `2`.

Combining the options

---------------------

You can try to combine all the options above to find the best solution for your use case.

Or you can even send API requests as-is, but when you encounter the error, just perform a retry with the limited full page height or lower device scale factor, or even a different format.

Reach out to support

--------------------

If you continue to face issues, please reach out to `support@screenshotone.com`, and we will assist you as soon as possible.

----
url: https://screenshotone.com/blog/bugsmash-story
----

How BugSmash automates website screenshot rendering

===================================================

How and why BugSmash uses ScreenshotOne for critical screenshot rendering tasks.

[Customer story](/blog/tags/customer-stories/) 2 min read

#### Written by

[Nabil Kazi](/contributors/nabil-kazi/), [Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Apr 27, 2025

I (Dmytro, the founder of ScreenshotOne) asked Nabil Kazi, a co-founder of [BugSmash](https://bugsmash.io) about how they use ScreenshotOne for their screenshot automation tasks. And today I want to share their story with you.

BugSmash

--------

[BugSmash](https://bugsmash.io) is a collaborative feedback and annotation tool designed for agencies, product & marketing teams to streamline the process of reviewing and sharing feedback on digital assets.

It allows users to upload, annotate & comment directly on live websites, videos, PDFs, images, audios, and mobile apps.

All feedback, progress, and resolutions in one place—no more messy feedback loops, screenshots or scattered communication.

How did they discover ScreenshotOne?

------------------------------------

From social media.

I have been a long-time follower of the ScreenshotOne founder, Dmytro on [X](http://x.com/DmytroKrasun/).

> “Capturing screenshots sounds easy until you try to do it yourself and run into N number of cases. Dmytro has done a wonderful job in all 3 aspects - The product, The documentation, The wonderful human behind this!”

Why and when choose ScreenshotOne over Puppeteer?

-------------------------------------------------

BugSmash has 4 different scenarios where we take screenshots:

### 1\. Project Thumbnails

When users enter the website URL to start reviewing a website and adding comments/feedback on it, we need to generate the website thumbnail behind the scenes for it to be visible on the dashboard and also to be used in the Share URL as the meta image.

Since these screenshots are the ones visible on the main dashboard, we cannot risk running into issues like unclear screenshots due to popups, slow loading, etc.

### 2\. Website AI Roast

Capturing entire page screenshots when the user submits their website for a free AI roast. We use Puppeteer over here. It is a good open-source solution but it brings all the headache of managing the server and parallel processing of multiple screenshots on our head.

We launched this feature using Puppeteer, but are planning to migrate this to ScreenshotOne in the coming week.

### 3\. Feedback on the website

Taking screenshot on the frontend via a DOM parsing library. We cannot use server-side processing here since the screenshot has to be exact what the user is seeing right now when they click to add feedback. The position of moving elements, the opened popup and so on.

### 4\. Browser Extension

Taking a screenshot via the BugSmash browser extension. This is more accurate than the DOM parsing and is used when the user has a browser extension installed.

### Conclusion

BugSmash experience with screenshot automation suggests that doing everything yourself is not always the best idea, especially for screenshots.

By using ScreenshotOne for the important rendering parts for thumbnails and full-page screenshots, their team can focus on features users notice instead of fixing corner cases and other rendering-related issues.

Read more customer stories

--------------------------

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

[View all posts](/blog/tags/customer-stories/)

#### [How and why Saaspo uses ScreenshotOne to automate screenshot generation](/blog/saaspo/)

Saaspo chose ScreenshotOne to automate tedious and boring work to generate pixel-perfect screenshots for their platform. Why?

Read more

#### [Taking care of WordPress Sites with ScreenshotOne](/blog/kinsta/)

How Kinsta uses ScreenshotOne to deliver reliable automatic updates.

Read more

#### [How Elias Stråvik uses GPT-4 Vision and Zapier for landing page feedback automation](/blog/generating-landing-page-feedback-with-vision/)

A quick review of ScreenshotOne by Elias Stråvik, a founder of Roast as A Service on how he uses the ScreenshotOne daily to automate regular tasks associated with screenshots.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/screenshotone-august-2025-updates
----

ScreenshotOne August 2025 updates

=================================

Playground presets, screenshot URL in webhooks, improved full‑page rendering, and ownership change for subscribed orgs.

[Blog post](/blog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Sep 1, 2025

A short summary of the four major product updates we shipped in August 2025:

**1/4:** [Playground Presets](/changelog/playground-presets/): Create and save reusable presets in Playground for faster, consistent workflows across your team.

[](/changelog/playground-presets/)

**2/4:** [Screenshot URL in webhooks](/changelogs/screenshot-url-in-webhooks/): Webhook responses can now include a temporary screenshot URL when not stored in S3.

[](/changelog/screenshot-url-in-webhooks/)

**3/4:** [Improved full-page screenshot rendering](/changelog/improved-full-page-rendering/): Better handling of wrapped content containers and improved content visibility in tricky cases.

**4/4:** [Change organization owner for already subscribed customers](/changelog/change-ownership-for-subscribed/): You can now transfer organization ownership even if the org is already subscribed.

[](/changelog/change-ownership-for-subscribed/)

Questions or feedback? Reach out at `support@screenshotone.com`.

Read more posts

---------------

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

[View all posts](/blog/)

#### [ScreenshotOne made it to the official Make conference](/blog/make-conference/)

One of our friends noticed ScreenshotOne at the official Make conference

Read more

#### [How to take a screenshot of a webpage in Haskell](/blog/how-to-take-a-screenshot-of-a-webpage-in-haskell/)

It's very a common need to take a screenshot of a live website. On a project I worked on recently, we had a legal requirement to take screenshots of forms which our users filled, as at the time they filled the forms, for consent documentation purposes.

Read more

#### [NemoClaw an enterprise alternative to OpenClaw by NVIDIA](/blog/openclaw-alternative-by-nvidia/)

A practical look at what NemoClaw appears to be, what OpenClaw already is, and the main differences between them as of March 11, 2026.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/browserless
----

Rendering screenshot with Browserless

=====================================

A few words about what is Browserless, when to use it, and if it is suitable for screenshots or not.

[Blog post](/blog/) 4 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

May 6, 2024

Browserless

-----------

[](https://browserless.io/)

[Browserless](https://browserless.io/) is a headless Chrome/Chromium browser-as-a-service that allows you to automate web-based tasks like data collection, PDF generation, and QA testing. It provides an API and a dashboard to manage your browser sessions and monitor usage.

Some key features of Browserless include:

*   Handling the setup and maintenance of a Chrome/Chromium browser environment, which can be challenging to do on your own servers.

*   Providing options to wait for specific events, selectors, or timeouts before taking a screenshot or PDF.

*   Allowing you to inject custom scripts and styles into the page being rendered.

*   Offering dedicated plans for predictable high-volume usage, as well as usage-based plans for more sporadic needs.

*   Providing remote debugging capabilities through its WebSocket connection.

### Motivations

A few words about why Browserless was created by its authors:

> Running Chrome on lambda or on your own is a fantastic idea but in practice is quite challenging in production. You’re met with pretty tough cloud limits, possibly building Chrome yourself, and then dealing with odd invocation issues should everything else go ok. A lot of issues in various repositories are due to just challenges of getting Chrome running smoothly in AWS. You can see for yourself by going to nearly any library and sorting issues by most commented.

> 

> Getting Chrome running well in docker is also a challenge as there’s quiet a few packages you need in order to get Chrome running. Once that’s done then there’s still missing fonts, getting libraries to work with it, and having limitations on service reliability. This is also ignoring CVEs, access-controls, and scaling strategies.

> 

> All of these issues prompted us to build a first-class image and workflow for interacting with Chrome in a more streamlined way. With Browserless you never have to worry about fonts, extra packages, library support, security, or anything else. It just works reliably like any other modern web service. On top of that it comes with a prescribed approach on how you interact with Chrome, which is through socket connections (similar to a database or any other external appliance). What this means is that you get the ability to drive Chrome remotely without having to do updates/releases to the thing that runs Chrome since it’s divorced from your application.

### Open Source

Browserless is almost fully [an open-source project](https://github.com/browserless/browserless) and community loves it.

While it is free for for non-commercial uses, you need to get a license of subscribe to the service to use it for your commercial projects.

### Pricing

Browserless is not cheap. The cheapest plan starts at $200 per month. Yes, the pricing is predictable, but complicated if you need to render only screenshots, for example.

[](https://browserless.io/pricing/)

### Rendering screenshots with Browserless

Browserless has [a simple API to render screenshots](https://docs.browserless.io/HTTP-APIs/screenshot):

Terminal window

    1curl -X POST \2  https://production-sfo.browserless.io/screenshot?token=MY_API_TOKEN \3  -H 'Cache-Control: no-cache' \4  -H 'Content-Type: application/json' \5  -d '{6  "url": "https://example.com/",7  "options": {8    "fullPage": true,9    "type": "png"10  }11}'

But if you need more capabilities, highly likely you will need to implement them yourself or upgrade to their enterprise plan.

An alternative to Browserless for rendering screenshots

-------------------------------------------------------

[](https://screenshotone.com/)

In comparison, [ScreenshotOne](https://screenshotone.com/) is a screenshot-as-a-service API that aims to simplify the process of taking website screenshots. Some key differences are:

*   ScreenshotOne is focused solely on taking screenshots, while Browserless offers a broader set of automation capabilities.

*   ScreenshotOne handles complex cases like removing cookie consent banners, while Browserless provides more customization options.

*   ScreenshotOne provides no-code integrations with tools like Zapier, while Browserless requires more technical integration through its APIs.

It is really hard to compare them, since Scree

### Pricing

ScreenshotOne pricing is simple. You just pay for screenshots you need, any extra and the cheapest plan starts at $17.

[](https://screenshotone.com/pricing/)

### Rendering screenshots with ScreenshotOne

What can be easier than that?

    1// $ npm install screenshotone-api-sdk --save2

    3import * as fs from "fs";4import * as screenshotone from "screenshotone-api-sdk";5

    6// create API client7const client = new screenshotone.Client("<access key>", "<secret key>");8

    9// set up options10const options = screenshotone.TakeOptions.url("https://example.com")11    .delay(3)12    .blockAds(true);13

    14// generate URL15const url = client.generateTakeURL(options);16console.log(url);17// expected output: https://api.screenshotone.com/take?url=...18

    19// or download the screenshot20const imageBlob = await client.take(options);21const buffer = Buffer.from(await imageBlob.arrayBuffer());22fs.writeFileSync("example.png", buffer);23// the screenshot is stored in the example.png file

You can also block banners, chats, pop-ups, render videos, request dark mode, or whatever you need to get the most crisp screenshots.

Summary

-------

[Browserless](https://browserless.io/) is a comprehensive browser automation service, while [ScreenshotOne](https://screenshotone.com/) is a specialized screenshot API. Browserless may be better suited for complex web automation tasks, while [ScreenshotOne](https://screenshotone.com/) could be a simpler option for your most advanced screenshot needs.

Read more posts

---------------

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

[View all posts](/blog/)

#### [ScreenshotOne August 2025 updates](/blog/screenshotone-august-2025-updates/)

Playground presets, screenshot URL in webhooks, improved full‑page rendering, and ownership change for subscribed orgs.

Read more

#### [What is OpenClaw and how can it help?](/blog/openclaw/)

A short practical introduction to OpenClaw, what it is good at, and why it is useful if you want a proactive AI assistant that lives in your chat apps.

Read more

#### [Is it legal to screenshot websites?](/blog/screenshots-and-law/)

A few thoughts on the topic of screenshots and law.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/adkit
----

How AdKit automated onboarding

==============================

A short story by the founder of AdKit about how they use ScreenshotOne for onboarding automation.

[Customer story](/blog/tags/customer-stories/) 1 min read

#### Written by

[Nicolas Jeannen](/contributors/nicolas-jeannen/)

#### Published on

Mar 12, 2026

I’m building [AdKit](https://adkit.so), an ad library for SaaS and mobile apps.

One of the problems I wanted to solve is **removing friction for users**. When someone adds a company or a website, I don’t want them to manually fill in forms about the brand, industry, colors, logo, or description. Nobody likes doing that.

So instead, I automate everything.

When a user submits a website, I call **ScreenshotOne** to capture a screenshot of the page. But I don’t only use the image — I also request **metadata and parts of the HTML** from the page.

From there:

*   I extract **CSS variables and styles** to get accurate **brand colors**.

*   I pull the **favicon and assets** to identify the **logo**.

*   I pass the screenshot to **AI** so it can understand the **company, industry, and general context of the page**.

The combination works really well.

AI is great at understanding **what the website is about**, but it’s not always precise when it comes to **exact design details** like brand colors or logos. That’s where the metadata and HTML help — they give structured signals the AI can’t reliably infer on its own.

With all that data combined, I can **automatically fill the brand profile** for the user.

> “I have my own infrastructure, so I could do it myself, but I need the screenshot at a critical time. ScreenshotOne never failed me once! And it's also much faster than my own system.”

So instead of asking them to fill a long form, the product already knows:

*   what the company does;

*   what industry it belongs to;

*   its colors;

*   its logo;

*   and other branding information.

That makes the [onboarding experience](/use-cases/personalized-onboarding/) **much faster and smoother**, which makes the product feel nicer and easier to use.

Read more customer stories

--------------------------

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

[View all posts](/blog/tags/customer-stories/)

#### [ScreenshotOne took away one major complexity off the Supawrite plate](/blog/supawrite/)

A short story about how ScreenshotOne helps a content marketing platform automate their screenshot workflow.

Read more

#### [Automating screenshots for directory websites with ScreenshotOne](/blog/directify-feedback/)

How and why "Directify" used ScreenshotOne to automate screenshots for directory websites.

Read more

#### [How Branding 5 uses ScreenshotOne for competitor analysis](/blog/how-branding5-uses-screenshotone/)

If you are interested in diving deeper into the Branding 5 use case and discover if ScreenshotOne might be useful for you, too, keep reading.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/landing-gallery
----

How Landing Gallery uses ScreenshotOne to automate screenshot generation

========================================================================

How and why "Landing Gallery" uses ScreenshotOne to automate screenshot generation for their landing page inspiration platform.

[Customer story](/blog/tags/customer-stories/) 3 min read

#### Written by

[Chris Jayden](/contributors/chris-jayden/)

#### Published on

Nov 30, 2025

The post is written by Chris Jayden (and published as-is), the maker of [Landing Gallery](https://landing.gallery/) and shares how he uses ScreenshotOne to automate screenshot workflow for his design-inspiration platform.

Landing Gallery

---------------

[Landing Gallery](https://landing.gallery/) is a landing page inspiration site that helps you find the best landing pages for your new venture.

[](https://landing.gallery/)

My application started as a landing page inspiration site. I was following the work of [Danny Postma](https://www.dannypostma.com/), the creator of [HeadshotPro](https://headshotpro.com/) and [Landingfolio](https://landingfolio.com/). Landingfolio is a simple landing page inspiration site, but I noticed it wasn’t getting many updates. I thought: maybe I should just build my own.

I knew ranking was difficult, so I was looking for a niche. I initially focused on no-code tools like Framer, Webflow, and similar platforms. But that market proved challenging; it’s hard to find sites consistently, and you have to manually verify everything.

Eventually, I converted it from No Code Gallery to Landing Gallery. The domain was surprisingly still available and today, the site attracts **around 5,000 visitors monthly**.

Discovering ScreenshotOne on social media

-----------------------------------------

I discovered ScreenshotOne about three to four years ago while building what was then called NoCodeGallery. I was searching for a screenshot API to replace the older one I’d been using—it was kind of working, but I wanted something newer, faster, and with features like webhook delivery that my existing solution lacked.

I stumbled upon ScreenshotOne on Twitter, and it immediately caught my attention.

[](https://x.com/DmytroKrasun/status/1994390298819248609)

Not only was it incredibly affordable, but the founder, Dmytro, was really active on the platform and responded to all my inquiries. Whether through Twitter or the chat support via Crisp, he just responds to everything. That level of accessibility and engagement made a real difference.

ScreenshotOne Alternatives

--------------------------

I did check alternatives in the market, of course. But there was something about ScreenshotOne that made me believe in the founder. I’d rather stick with someone I can connect with and trust than use an API where I have no idea who’s behind it. That personal connection and transparency set ScreenshotOne apart from the competition.

> The combination of a fast, reliable API, transparent pricing, and a founder who genuinely engages with his users makes it an easy choice.

Integrating ScreenshotOne was easy

----------------------------------

Integrating ScreenshotOne was really easy. At first, I did a normal integration using regular JavaScript, and then when Dmytro [released the SDK](https://screenshotone.com/integrations/code/), I switched to that.

I still have another project that uses the plain JavaScript API, and even then, it’s super easy to integrate. One thing I’ll mention: the API is powerful and comes with a lot of options, which can feel overwhelming at first.

I integrated this back before AI assistance was as good as it is today, so navigating all those options took some exploration. But the flexibility is ultimately a strength once you get familiar with it.

How ScreenshotOne Powers My Workflow

------------------------------------

My daily workflow involves adding two to three new sites to the gallery. I’ve built an admin interface where I input URLs, and from there, the system automatically scrapes metadata like website names and Open Graph images, we actually have [a dedicated OG image inspiration section too](https://www.landing.gallery/og-image-examples).

[](https://www.landing.gallery/og-image-examples)

It also runs technology detection through [StackSee, a technology identifier API I built](https://stacksee.com), which identifies whether a site was made with Framer, Webflow, or other tools. This data feeds directly into my programmatic SEO pages.

ScreenshotOne helps me do almost nothing when it comes to taking screenshots—and I mean that in the best way possible. Before, I used a Chrome extension to capture full-page screenshots manually. **Now, I just use ScreenshotOne to take around 10 screenshots from one website at a time, and it finishes within 2 to 3 minutes. That’s a massive time saver.**

Feedback

--------

I’m a huge fan of ScreenshotOne and everything Dmytro is doing. The combination of a fast, reliable API, transparent pricing, and a founder who genuinely engages with his users makes it an easy choice. If you’re building anything that requires automated screenshots, I’d highly recommend giving it a try.

Read more customer stories

--------------------------

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

[View all posts](/blog/tags/customer-stories/)

#### [Magic Pages: Showcasing Product Adoption with Screenshots](/blog/magic-pages/)

How and why "Magic Pages" used ScreenshotOne to showcase how their customers use their product.

Read more

#### [Taking care of WordPress Sites with ScreenshotOne](/blog/kinsta/)

How Kinsta uses ScreenshotOne to deliver reliable automatic updates.

Read more

#### [Boosting email CTR for "Bridesmaid For Hire" with ScreenshotOne](/blog/braidsmade-for-hire-case-study/)

How and why "Bridesmaid for Hire" used ScreenshotOne to boost their email campaign CTR.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/saaspo
----

How and why Saaspo uses ScreenshotOne to automate screenshot generation

=======================================================================

Saaspo chose ScreenshotOne to automate tedious and boring work to generate pixel-perfect screenshots for their platform. Why?

[Customer story](/blog/tags/customer-stories/) 1 min read

#### Written by

[Andy Hooke](/contributors/andy-hooke/), [Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Nov 4, 2025

Saaspo

------

[Saaspo](https://saaspo.com/) is a design resource for SaaS websites. You can find inspiration and examples of:

*   [landing pages by industry, style or stack](https://saaspo.com/);

*   [sections of the pages](https://saaspo.com/sections);

*   [open graph image examples](https://saaspo.com/templates);

*   and [even templates for your SaaS or agency](https://saaspo.com/templates).

 Sorry, your browser doesn't support embedded videos.

You can [submit your own landing page](https://saaspo.com/submit) and if you are lucky and have a good design you might be featured on the site.

> “I’ve been using ScreenshotOne for 3 years and couldn’t run Saaspo without it. You can tell Dmytro really cares about the product as it keeps getting better.“

On the easiness of integrating ScreenshotOne

--------------------------------------------

Andy discovered ScreenshotOne about 3 years ago (probably on [Indie Hackers](https://www.indiehackers.com/product/screenshotone-the-best-screenshot-api)).

He shares that at the time, he hadn’t used API’s much so was unsure if he’d be able to do it. But he found [a tutorial showing how to connect to Airtable via scripts](https://screenshotone.com/blog/how-to-build-a-programmatic-seo-site-with-automated-website-screenshots-using-screenshotone-airtable-and-launchman/) and was actually very easy.

> “Highly recommend to anyone looking for a screenshot tool!“

How ScreenshotOne helps Saaspo

------------------------------

Andy shares:

> I started out using a few different Chrome extensions and manually taking every screenshot, but this was a frustrating process when adding at scale. They also struggled when pages had lots of motion, and I found myself having to stitch them together in Figma, which took ages! So was very relieved when I automated this process with ScreenshotOne.

> 

> It’s made adding new sites significantly easier, so the library is growing at a much faster rate. It’s also allowed me to add screenshots of different sizes, so the library included mobile views now as well.

Summary

-------

Andy chose ScreenshotOne for [Saaspo](https://saaspo.com/) to automate screenshot generation instead of manually capturing images using Chrome extensions. And the automation eliminated the frustrating manual process of taking screenshots at scale.

By the way, if you have any questions about how ScreenshotOne can help automate screenshot generation for your project, feel free to reach out to our support team at `support@screenshotone.com`. We are always happy to help you find the best solution for your needs.

Read more customer stories

--------------------------

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

[View all posts](/blog/tags/customer-stories/)

#### [Boosting email CTR for "Bridesmaid For Hire" with ScreenshotOne](/blog/braidsmade-for-hire-case-study/)

How and why "Bridesmaid for Hire" used ScreenshotOne to boost their email campaign CTR.

Read more

#### [How Stagetimer automates Open Graph image generation](/blog/how-stagetimer-automates-og-image-generation/)

We would love to share a quick review of ScreenshotOne by Lukas Hermann, a co-founder of Stagetimer on how he uses the API daily to generate screenshots and automate regular tasks associated with screenshots.

Read more

#### [How RivalFlowAI uses ScreenshotOne to help its customers improve existing content](/blog/rivalflowai-by-spyfu/)

RivalFlowAI is a new product by SpyFu, launched in 2023. The product helps to improve existing content with AI by finding the missing pieces your page needs to rank.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/code-examples/ruby
----

[Skip to content](#_top)

Ruby SDK and Code Examples

==========================

Copy page

If you have any questions, please, reach out at `support@screenshotone.com`.

Massive thanks and rays of goodness to [Gustavo Garcia](https://twitter.com/theluctus) from [Dailytics](https://dailytics.com/) for providing the fully-featured high-quality Ruby SDK.

### Installation

Update your Gemfile:

    1gem 'screenshotone'

Then execute:

Terminal window

    1bundle install

### Usage

Don’t forget to [sign up](https://dash.screenshotone.com/sign-up) to get access and secret keys.

Generate a screenshot URL without executing the request. Or download the screenshot. It is up to you:

    1# If you don't need to add a signature2client = ScreenshotOne::Client.new('my_access_key')3

    4# If you do need to add a signature5client = ScreenshotOne::Client.new('my_access_key', 'my_secret_key')6

    7# You can set any available option, in a camel_case format, for example:8options = ScreenshotOne::TakeOptions.new(url: 'https://example.com').9            full_page(true).10            delay(2).11            geolocation_latitude(48.857648).12            geolocation_longitude(2.294677).13            geolocation_accuracy(50)14

    15# Verify all the parameters are valid (we will validate the parameters that should be16# numeric, booleans or that accept only certain values)17options.valid?18=> true19

    20# To simply get the final url:21client.generate_take_url(options)22=> "https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com..."23

    24# To actually get the image (the response body of a request to the previous url)25client.take(options)26=> "\xFF\xD8\xFF\xE0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xFF\..."

Check out [other SDKs and code examples](/docs/code-examples/).

----
url: https://screenshotone.com/docs/guides/screenshot-google-docs
----

[Skip to content](#_top)

How to render Google Documents as JPEG, PNG or WebP screenshots

===============================================================

Copy page

By default, you can not render Google Docs as screenshots with the ScreenshotOne API. But if you managed to export it as HTML, you can make it work.

Make Google Documents available as HTML

---------------------------------------

To make Google Documents available as HTML, you need to export it as HTML from the Google Docs editor.

I created [a simple Google Documents example](https://docs.google.com/document/d/1cY0QhA2GGCdhsoFCJYBCeCproSMzWwvUqkbnylwUGog/edit?usp=sharing) to demonstrate how to do that.

(1) For document, go to share settings:

(2) Change the settings to make the document public and shareable:

After that you can use either Google Docs API or make the link shareable and public to everyone and then modify it to the link like: `https://docs.google.com/document/d/<document id>/export/html`.

Render Google Documents as screenshots

--------------------------------------

Get your ScreenshotOne API key at the [ScreenshotOne dashboard](https://dashboard.screenshotone.com/).

And then implement the following example in TypeScript or any other language you want:

    1// validate URL2const documentUrl = new URL(url);3if (!documentUrl.hostname.includes("docs.google.com")) {4    throw new Error("Invalid URL: Must be a Google Doc document URL");5}6

    7// Extract document ID from the Google Doc URL8const match = documentUrl.pathname.match(/document\/d\/([\w-]+)/);9if (!match) {10    throw new Error("Invalid Google Docs URL format");11}12

    13const documentId = match[1];14// for documents, change to "document"15const exportUrl = `https://docs.google.com/document/d/${documentId}/export/html`;16url = exportUrl;17

    18// Prepare ScreenshotOne API parameters19const params: Record<string, string> = {20    url: url,21    access_key: SCREENSHOTONE_ACCESS_KEY as string,22};23

    24const apiUrl = `https://api.screenshotone.com/take`;25console.log("Making request to ScreenshotOne API...");26

    27// Make request to ScreenshotOne API28const screenshotResponse = await axios({29    method: "post",30    url: apiUrl,31    data: params,32    headers: {33        "Content-Type": "application/json",34    },35    responseType: "stream",36    maxContentLength: Infinity,37    maxBodyLength: Infinity,38    timeout: 60000, // increase timeout to 60 seconds39});40

    41// Process the image

Notice that we use a POST HTTP request to the `https://api.screenshotone.com/take` endpoint. It is good if you want to send HTML yourself, but also works with URLs. Also, you can just send a regular GET request.

The resulting video will be something like:

Set custom styles

-----------------

In case, you do not like how Google Slides or Documents look like by default, you can set custom styles via the `style` option:

    1style=<your CSS styles>

Adding such a style option to Google Documents, will make look them differently.

A working example

-----------------

You can find a fully working example (written in Node.js/TypeScript) in the [ScreenshoOne integration examples directory](https://github.com/screenshotone/examples/tree/main/nodejs/google-slides-scrolling-screenshots). However, it is for Google Slides and downloads HTML to render it with ScreenshotOne, but today you do not need that, you can render Google Documents and Slides directly with ScreenshotOne.

Suggestions

-----------

1.  If possible, use the official Google Docs API to get the HTML. It is more reliable and easier to use.

2.  If you build this solution for third-party use, consider if you can automate the processing of authentication with Google Docs and extract the HTML.

Google Slides

-------------

Check out [our guide on how to render Google Slides as scrolling screenshots](/docs/guides/google-slides-as-scrolling-screenshots/).

Support

-------

In case you have any questions or suggestions, feel free to reach out at `support@screenshotone.com`.

----
url: https://screenshotone.com/blog/how-spectate-uses-screenshotone
----

How Spectate uses ScreenshotOne to improve incident observability

=================================================================

If you are interested in diving deeper into the Spectate use case and discover if ScreenshotOne might be useful for you, too, keep reading.

[Customer story](/blog/tags/customer-stories/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Bjarn Bronsveld](/contributors/bjarn-bronsveld/)

#### Published on

Jul 21, 2024

[Spectate](https://spectate.net/) is a one-stop solution for observability to incident management. It is more than just a monitoring platform.

They use ScreenshotOne to render error pages and send them to their customers for troubleshooting.

Spectate and ScreenshotOne

--------------------------

Here is what Bjarn Bronsveld a founder shared with us about their integration with ScreenshotOne:

### How did you discover ScreenshotOne?

> I basically discovered ScreenshotOne on X. I don’t remember via who exactly, but I believe it might’ve been the For You algorithm showing all kinds of posts by fellow indie hackers.

### Did you check any alternatives?

> To be honest, not really. Just a quick Google Search and I was looking into building “screenshots” in-house. But that was a lot of work to get it work right (there’s a lot of edge cases in my case) and just opted for ScreenshotOne because of the pricing and great API.

### How does it help you in your business

> ScreenshotOne is used heavily by Spectate’s screenshot feature. When someone’s monitor is down, for example because of a 502 Bad Gateway, we make a screenshot so the user immediately can see what is going on. Maybe it’s the Cloudflare error page, maybe it’s their own. Now they know! This only works for these kind of errors. If someone’s monitor is down because of a time-out… then making a screenshot won’t work.

More Examples and Use Cases

---------------------------

You might be also interested in how [SpyFu uses ScreenshotOne for RivalFlowAI for competitive content analysis with AI](/blog/rivalflowai-by-spyfu/).

ScreenshotOne supports a huge variety of uses including but not only:

*   [Automating Open Graph image generation](/use-cases/open-graph-images/).

*   [Generating personalized videos](/use-cases/automate-personalized-videos/).

*   [Rendering site thumbnails for search previews](/use-cases/preview-search-results/)

And [many more](/use-cases/).

Read more customer stories

--------------------------

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

[View all posts](/blog/tags/customer-stories/)

#### [Integrating ScreenshotOne into the directory management platform](/blog/makeadir-feedback/)

How and why "Make a Directory" used ScreenshotOne to automate screenshots for directory websites.

Read more

#### [How Ilias Ism, a founder of the MagicSpace SEO agency, uses ScreenshotOne daily](/blog/how-ilias-ism-a-founder-of-the-magicspace-seo-agency-uses-screenshotone-daily/)

We would love to share a quick review of ScreenshotOne by Ilias Ism, a founder of MagicSpace SEO agency and OG Image Generator on how he uses the API daily to generate screenshots and automate regular tasks associated with screenshots.

Read more

#### [Heart-touching feedback from Gregory](/blog/heart-touching-feedback-from-gregory/)

Daily and nightly, I work on improving the quality and performance of ScreenshotOne (your friendly screenshot API) and ensuring I help customers solve their problems and prosper.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/better-supabase-storage-support
----

Improved Supabase Storage integration

=====================================

Improved Supabase storage integration.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Sep 23, 2025

When you upload screenshots to [Supabase Storage](https://supabase.com/docs/guides/storage), you specify your storage URL like this:

    1https://<your-project-id>.supabase.co/...

Now you can also specify your storage url like this:

    1https://<your-project-id>.storage.supabase.co/...

ScreenshotOne will now automatically detect the storage URL and apply the appropriate configuration

If you have any questions or suggestions, please let us know at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Stop scrolling screenshots when a given selector is visible](/changelog/animated-scrolling-till-selector/)

New options were added to the ScreenshotOne API to stop scrolling screenshots when a given selector is reached.

Read more →

1 min read

#### [Add ScreenshotOne to Clay](/changelog/clay-integration/)

Generate website screenshots inside Clay to qualify leads, assess content, and enrich rows with visual context automatically.

Read more →

1 min read

#### [Notifications when the usage reaches 50% of the limit](/changelog/half-quota-reached-notifications/)

You can now get notifications when the usage reaches 50% of the limit.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/guides/google-slides-as-scrolling-screenshots
----

[Skip to content](#_top)

How to render Google Slides as scrolling screenshots with ScreenshotOne

=======================================================================

Copy page

By default, you can not render Google Slides as scrolling screenshots with the ScreenshotOne API. But if you managed to export it as HTML, you can make it work.

Make Google Slides available as HTML

------------------------------------

To make Google Slides available as HTML, you need to export it as HTML from the Google Slides editor.

I created [a simple example Google Slides presentation](https://docs.google.com/presentation/d/1fsaM1LaLUEzNn9pTPRdY0XBz1WxaFcWBD2WY50SrqwY/edit?usp=sharing) to demonstrate how to do that.

(1) For you presentation, go to share settings:

(2) Change the settings to make the presentation public and shareable:

After that you can use either Google Slides API or make the link shareable and public to everyone and then modify it to the link like: `https://docs.google.com/presentation/d/<presentation id>/export/html`

Render Google Slides as scrolling screenshots

---------------------------------------------

Get your ScreenshotOne API key at the [ScreenshotOne dashboard](https://dashboard.screenshotone.com/).

And then implement the following example in TypeScript or any other language you want:

    1// validate URL2const presentationUrl = new URL(url);3if (!presentationUrl.hostname.includes("docs.google.com")) {4    throw new Error("Invalid URL: Must be a Google Slides presentation URL");5}6

    7// Extract presentation ID from the Google Slides URL8const match = presentationUrl.pathname.match(/presentation\/d\/([\w-]+)/);9if (!match) {10    throw new Error("Invalid Google Slides URL format");11}12

    13const presentationId = match[1];14const exportUrl = `https://docs.google.com/presentation/d/${presentationId}/export/html`;15url = exportUrl;16

    17// Prepare ScreenshotOne API parameters18const params: Record<string, string> = {19    url: url,20    access_key: SCREENSHOTONE_ACCESS_KEY as string,21    format: "mp4",22    scenario: "scroll",23    delay: "2", // wait for 2 seconds before starting to scroll24};25

    26const apiUrl = `https://api.screenshotone.com/animate`;27console.log("Making request to ScreenshotOne API...");28

    29// Make request to ScreenshotOne API30const screenshotResponse = await axios({31    method: "post",32    url: apiUrl,33    data: params,34    headers: {35        "Content-Type": "application/json",36    },37    responseType: "stream",38    maxContentLength: Infinity,39    maxBodyLength: Infinity,40    timeout: 60000, // increase timeout to 60 seconds41});42

    43// Process the video

Notice that we use a POST HTTP request to the `https://api.screenshotone.com/animate` endpoint. It is good if you want to send HTML yourself, but also works with URLs. Also, you can just send a regular GET request.

The resulting video will be something like:

 Sorry, your browser doesn't support embedded videos.

Custom styles

-------------

You can set custom styles via the `style` option:

    1style=<your CSS styles>

A working example

-----------------

You can find a fully working example (written in Node.js/TypeScript) in the [ScreenshoOne integration examples directory](https://github.com/screenshotone/examples/tree/main/nodejs/google-slides-scrolling-screenshots). However, it downloads HTML to render it with ScreenshotOne, but today you do not need that, you can render Google Documents and Slides directly with ScreenshotOne.

Suggestions

-----------

1.  If possible, use the official Google Slides API to get the HTML. It is more reliable and easier to use.

2.  If you build this solution for third-party use, consider if you can automate the processing of authentication with Google Slides and extract the HTML.

Google Documents

----------------

Check out [our guide on how to render Google Documents as screenshots](/docs/guides/screenshot-google-docs/).

Support

-------

In case you have any questions or suggestions, feel free to reach out at `support@screenshotone.com`.

----
url: https://screenshotone.com/changelog/improved-banner-blocking-for-specific-websites
----

Improved blocking of banners for specific websites

==================================================

We just released an updated version of our algorithm to block banners for specific websites by heuristics.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Sep 2, 2025

Blocking banners is a hard problem and partially why many companies prefer using our API to invent and build their internal solution.

There are many methods to block banners. One of them is to traverse all the buttons and elements on the website and try to click them if their text matches “Accept all cookies” or something similar.

We use such an approach with a combination of other methods. But it gave false positives by sometimes opening a and navigating to a new webpage on the website.

Today, we added a few checks and improved the algorithm to reduce false positives and yet make sure that the banners are still blocked and you can render clear screenshots. We did it only for a specific list of popular websites.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Better numbers formatting in the dashboard](/changelog/better-numbers-formatting-in-the-dashboard/)

We improve UI/UX of rendering numbers in the dashboard for better readability.

Read more →

1 min read

#### [Improved full page screenshot algorithm](/changelog/fixed-a-corner-case-for-full-page-screenshots/)

We fixed issues with full page screenshots when the viewport was overridden together with the device option.

Read more →

1 min read

#### [Improved proxy validation](/changelog/improved-proxy-validation/)

Stricter proxy option validation to prevent misconfiguration.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/how-to-add-custom-styles-to-a-page-in-puppeteer
----

How to add custom styles to a page in Puppeteer

===============================================

To add custom styles to any page use Puppeteer's page method \`page.addStyleTag(options)\`. Let's discover how it works quickly.

[Blog post](/blog/) 2 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Jun 24, 2022

#### Tags

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

To add custom styles to any page use Puppeteer’s page method `page.addStyleTag(options)`.

You can inject:

*   stylesheet by providing URL;

*   stylesheet from the machine where the Puppeteer instance is running;

*   raw content.

We are going to add a custom style to an [example](https://example.com) site:

We will style to with `h1 {color: red;}`:

Let’s go!

Adding custom stylesheet by URL

-------------------------------

To add custom stylesheet in Puppeteer by URL, use `page.addStyleTag({url: 'https://example.com/custom.css'})`:

As an example:

    1const puppeteer = require('puppeteer');2

    3(async () => {4    const browser = await puppeteer.launch({});5    try {6        const page = await browser.newPage();7

    8        await page.goto('https://example.com/');9

    10        await page.addStyleTag({ url: 'https://example.com/custom.css' });11

    12        await page.screenshot({ path: 'example.com.png' });13    } catch (e) {14        console.log(e)15    } finally {16        await browser.close();17    }18})();19```

No need to worry and wait until the CSS file is included, because the promise for `page.addStyleTag` will resolve only when the added tag when the stylesheet’s `onload` event is fired.

Adding custom stylesheet by path

--------------------------------

You also can add a custom stylesheet by specifying the path, use `page.addStyleTag({path: 'custom.css'})`. If the path is relative, it is relative to the working directory.

As an example, I created `custom.css`:

    1h1 {2    color: red;3}

And then:

    1const puppeteer = require('puppeteer');2

    3(async () => {4    const browser = await puppeteer.launch({});5    try {6        const page = await browser.newPage();7

    8        await page.goto('https://example.com/');9

    10        await page.addStyleTag({ path: 'custom.css' });11

    12        await page.screenshot({ path: 'example.com.png' });13    } catch (e) {14        console.log(e)15    } finally {16        await browser.close();17    }18})();

Adding raw CSS content

----------------------

In our [screenshot API](/), you can easily add custom styles by specifying [the styles parameter](/docs/options/#styles).

And the simplest way to add CSS custom style is just add raw CSS content by using `page.addStyleTag({content: '<selector> { <property>: <value>; }'})`:

    1const puppeteer = require('puppeteer');2

    3(async () => {4    const browser = await puppeteer.launch({});5    try {6        const page = await browser.newPage();7

    8        await page.goto('https://example.com/');9

    10        await page.addStyleTag({ content: 'h1 {color: red;}' })11

    12        await page.screenshot({ path: 'example.com.png' });13    } catch (e) {14        console.log(e)15    } finally {16        await browser.close();17    }18})();

I hope I helped you today to solve your problem and have a nice day 👋

You might also find helpful:

*   [how to add custom scripts to a page in Puppeteer](/blog/how-to-add-custom-scripts-to-a-page-in-puppeteer)

*   [the complete guide on how to take a screenshot with Puppeteer](/blog/how-take-a-screenshot-with-puppeteer)

*   [how to render HTML with Puppeteer](/blog/how-to-render-html-with-puppeteer)

Read more Puppeteer guides

--------------------------

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

[View all posts](/blog/tags/puppeteer-guides/)

#### [How to add custom scripts to a page in Puppeteer](/blog/how-to-add-custom-scripts-to-a-page-in-puppeteer/)

How to add custom scripts to a page in Puppeteer. Let's discover how it works quickly."

Read more

#### [What is Puppeteer](/blog/puppeteer/)

What is Puppeteer and what you can use it for.

Read more

#### [How to Take Bulk Screenshots in Python with a Screenshot API](/blog/bulk-screenshots-python/)

Learn how to automate bulk website screenshots in Python using ScreenshotOne API. Process thousands of URLs efficiently with async requests, rate limiting, and error handling.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/tags/customer-stories/3
----

Customer Stories

----------------

Customer stories and case studies from teams using ScreenshotOne.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [How Spectate uses ScreenshotOne to improve incident observability](/blog/how-spectate-uses-screenshotone/)

If you are interested in diving deeper into the Spectate use case and discover if ScreenshotOne might be useful for you, too, keep reading.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Bjarn Bronsveld](/contributors/bjarn-bronsveld/)

Published on

Jul 21, 2024

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How GetWebsite.Report uses ScreenshotOne for screenshot automation tasks](/blog/how-website-report-uses-screenshotone/)

If you are interested in diving deeper into the GetWebsite.Report use case and discover if ScreenshotOne might be useful for you, too, keep reading.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jun 4, 2024

•

2 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How FounderPal uses ScreenshotOne for landing page analysis](/blog/how-founderpal-uses-screenshotone/)

If you are interested in diving deeper into the FounderPal use case and discover if ScreenshotOne might be useful for you, too, keep reading.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jun 2, 2024

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Boosting email CTR for "Bridesmaid For Hire" with ScreenshotOne](/blog/braidsmade-for-hire-case-study/)

How and why "Bridesmaid for Hire" used ScreenshotOne to boost their email campaign CTR.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

May 21, 2024

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Typeshare uses ScreenshotOne for image generation](/blog/how-typeshare-uses-screenshotone/)

Typeshare is a digital writing platform designed to enhance the writing experience by offering a suite of tools aimed at reducing common barriers writers face.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Apr 14, 2024

•

2 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How RivalFlowAI uses ScreenshotOne to help its customers improve existing content](/blog/rivalflowai-by-spyfu/)

RivalFlowAI is a new product by SpyFu, launched in 2023. The product helps to improve existing content with AI by finding the missing pieces your page needs to rank.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Apr 9, 2024

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Stagetimer automates Open Graph image generation](/blog/how-stagetimer-automates-og-image-generation/)

We would love to share a quick review of ScreenshotOne by Lukas Hermann, a co-founder of Stagetimer on how he uses the API daily to generate screenshots and automate regular tasks associated with screenshots.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Lukas Hermann](/contributors/lukas-hermann/)

Published on

Mar 5, 2024

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Elias Stråvik uses GPT-4 Vision and Zapier for landing page feedback automation](/blog/generating-landing-page-feedback-with-vision/)

A quick review of ScreenshotOne by Elias Stråvik, a founder of Roast as A Service on how he uses the ScreenshotOne daily to automate regular tasks associated with screenshots.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Elias Stravik](/contributors/elias-stravik/)

Updated on

Mar 4, 2024

•

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/font-accessibility-checks
----

Automate Website Screenshots

1 min read

Font Accessibility Checks

=========================

Use our font detection API to check fonts and and research whether websites use readable fonts for people with visual impairments or reading disabilities.

Use [ScreenshotOne font detection API](/font-detection-api/) to analyze whether websites are using fonts that are readable for people with visual impairments or reading disabilities, aiding in the creation of more inclusive web content.

Inclusive Web Design

--------------------

Accessibility is a critical aspect of modern web design, and typography plays a crucial role in ensuring content is readable for all users. ScreenshotOne’s font detection API enables accessibility tools to automatically evaluate font choices against accessibility best practices.

Automated Accessibility Audits

------------------------------

The API helps identify fonts. And then this information might be used to identify if these fonts may be difficult to read for users with dyslexia, low vision, or other reading challenges. Accessibility tools can use this information to provide recommendations for more inclusive typography choices, ensuring websites meet WCAG guidelines.

Check out [our guide on how to detect website fonts](/docs/guides/how-to-detect-website-fonts/) for more details.

Compliance and Accessibility

----------------------------

By integrating ScreenshotOne’s font detection capabilities, accessibility audit tools can provide comprehensive reports on typography accessibility without requiring manual font inspection. This helps organizations create more inclusive web experiences while ensuring compliance with accessibility standards and regulations.

Compared to the tool I used before ScreenshotOne's image generation is very quick. Even the full-page screenshot only takes a couple of seconds.

I love the URL signing feature! It allows me to use a serverless stack without exposing the API key.

If you need a screenshot API, ScreenshotOne is the way to go!

Lukas Hermann

Co-Founder, [stagetimer.io](https://stagetimer.io/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

### Brand Consistency Font Checks

Use ScreenshotOne font detection API to automatically verify font consistency across web pages to maintain brand integrity.

[Read more →](/use-cases/brand-consistency-font-checks/)

### Font Legal Compliance Check

Ensure fonts used on websites are legally compliant to avoid copyright issues.

[Read more →](/use-cases/font-legal-compliance/)

### UX Font Analysis

Examine the impact of different fonts on user engagement and website usability.

[Read more →](/use-cases/ux-font-analysis/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/improved-playground-synchronized-all-options
----

ScreenshotOne Playground has been improved

==========================================

A few important updates in ScreenshotOne Playground.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Nov 7, 2024

ScreenshotOne Playground is a main entry point that allows you to test and preview our screenshot API options before you start using it in your projects.

Today, it is finally has been synchronized with all available screenshot options.

In addition to that a lot of minor improvements have been made:

1.  Reordering options and option groups, and adding “HTML”, “Markdown” or “URL” source selector.

2.  Improved validation for some options.

3.  Improved design and responsiveness.

It is only beginning and there will be a lot of changes.

If you have any suggestions or ideas, please let us know at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Choose the full page screenshot algorithm](/changelog/full-page-algorithm/)

Now, you can choose the full page screenshot algorithm.

Read more →

1 min read

#### [Improved uploading and error handling to S3-compatible storage](/changelog/improved-storage-upload/)

Today, the new version of ScreenshotOne API was deployed to production that enables a retries mechanism when uploading to an S3 storage and more granular error handling.

Read more →

1 min read

#### [Improved webhooks documentation and playground](/changelog/improved-webhooks-documentation-and-playground/)

We improved the webhooks documentation and playground.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/code-examples/java
----

[Skip to content](#_top)

Java SDK and Code Examples

==========================

Copy page

If you have any questions, please, reach out at `support@screenshotone.com`.

It takes minutes to start taking screenshots in Java. Just [sign up](https://dash.screenshotone.com/sign-up) to get access and secret keys, import the client, and you are ready to go.

### Installation

Add dependency to your `pom.xml`:

    1<dependencies>2    <dependency>3        <groupId>com.screenshotone.jsdk</groupId>4        <artifactId>screenshotone-api-jsdk</artifactId>5        <version>[1.0.0,2.0.0)</version>6    </dependency>7</dependencies>

### Usage

Generate a screenshot URL without executing request:

    1import com.screenshotone.jsdk.Client;2import com.screenshotone.jsdk.TakeOptions;3

    4public class App {5    public static void main(String[] args) throws Exception {6        final Client client = Client.withKeys("IVmt2ghj9TG_jQ", "Sxt94yAj9aQSgg");7        TakeOptions takeOptions = TakeOptions.url("https://scalabledeveloper.com")8                .fullPage(true)9                .deviceScaleFactor(1)10                .viewportHeight(1200)11                .viewportWidth(1200)12                .format("png")13                .omitBackground(true);14        final String url = client.generateTakeUrl(takeOptions);15

    16        System.out.println(url);17        // Output: https://api.screenshotone.com/take?access_key=IVmt2ghj9TG_jQ&device_scale_factor=1&format=png&full_page=true&omit_background=true&url=https%3A%2F%2Fscalabledeveloper.com&viewport_height=1200&viewport_width=1200&signature=3c0c5543599067322e8c84470702330e3687c6a08eef6b7311b71c32d04e1bd518    }19}

Usually you generate URL to place it inside the image tag () or to share it.

Take a screenshot and save the image in the file:

    1import com.screenshotone.jsdk.Client;2import com.screenshotone.jsdk.TakeOptions;3

    4import java.io.File;5import java.nio.file.Files;6

    7public class App {8    public static void main(String[] args) throws Exception {9        final Client client = Client.withKeys("IVmt2ghj9TG_jQ", "Sxt94yAj9aQSgg");10        TakeOptions takeOptions = TakeOptions.url("https://scalabledeveloper.com")11                .fullPage(true)12                .deviceScaleFactor(1)13                .viewportHeight(1200)14                .viewportWidth(1200)15                .format("png")16                .omitBackground(true);17        final byte[] image = client.take(takeOptions);18

    19        Files.write(new File("./example.png").toPath(), image);20    }21}

Check out [other SDKs and code examples](/docs/code-examples/).

----
url: https://screenshotone.com/docs/guides/how-to-screenshot-an-area-of-a-site
----

[Skip to content](#_top)

How to screenshot an area of a site

===================================

Copy page

When rendering website screenshots with the ScreenshotOne Screenshot API, you can specify [clip options](https://screenshotone.com/docs/options/#clip) to render only a specific area of the website.

You must specify all clip options, otherwise, it won’t work.

For example, let’s clip a square of the ScreenshotOne landing page:

    1https://api.screenshotone.com/take?access_key=<your api key>&url=https://screenshotone.com&clip_x=100&clip_y=100&clip_width=500&clip_height=500

The resulting image will be:

In case you can rely on a selector, it is better to use [the selector option](https://screenshotone.com/docs/options/#selector) than precise coordinates. It will allow you to produce more stable results. But in case you know what you do and prefer to rely on specific coordinates, it is OK to use clip options.

A few typical uses of the feature:

1.  **Content Monitoring**. Businesses can use this feature to monitor their website’s content regularly, ensuring that updates are correctly deployed and that there are no visual anomalies or layout issues.

2.  **Competitor Analysis**. Companies can clip and analyze key sections of competitors’ websites, such as product pages or promotional banners, to stay informed about market trends and competitor strategies.

3.  **QA Testing**. Web developers and QA teams can automate the process of taking screenshots of different sections of a webpage across various devices and browsers for testing purposes, ensuring consistency and identifying layout issues.

Enjoy it. If you have any questions, please, feel free to send an email to `support.screenshotone.com`.

----
url: https://screenshotone.com/docs/errors/matched-failed-request
----

[Skip to content](#_top)

Matched Failed Request

======================

Copy page

This API error is returned when a request matched by the specified pattern in the `fail_if_request_failed` option has been failed:

    1{2    "is_successful": false,3    "error_code": "matched_failed_request",4    "error_message": "A request matched by the specified pattern by the `fail_if_request_failed` option has been failed. If it seems to be a mistake or not what you expected, please, reach out to `support@screenshotone.com` as quickly as possible, and we will assist and try to resolve your problem.",5    "documentation_url": "https://screenshotone.com/docs/errors/matched-failed-request/"6}

Reasons and how to fix

----------------------

The reason you get this error message is because you specified the [fail\_if\_request\_failed](/docs/options/#fail_if_request_failed) option.

If you want to disable this behavior, you simply need to remove the parameter from your request. If you have a request like:

    1https://api.screenshotone.com/take?access_key=<your access key>&url=https://example.com&fail_if_request_failed=**example.com**

Make it like this:

    1https://api.screenshotone.com/take?access_key=<your access key>&url=https://example.com

In case, if the error persists, please immediately reach out to `support@screenshotone.com`, and we will try to fix that as soon as possible.

Reach out to support

--------------------

Also, if you encounter any issues or bugs, please reach out to `support@screenshotone.com`, and we will assist you as soon as possible.

----
url: https://screenshotone.com/changelog/improved-error-handling-when-networking-fails
----

Improved error handling when networking fails

=============================================

We have improved error handling for network failures. Now, we ensure screenshot rendering fails instead of returning an error image.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Feb 16, 2025

For a short period of time, there was a temporary and sporadic issue with the screenshot rendering. It was reported by many customers, but it was hard to reproduce and fix.

The issue was that the screenshot rendering was failing because of a networking issue, but screenshots were still returned and returned an error image like:

It was a temporary and occasional issue, but it was super annoying for many customers.

After a thorough investigation, applying [the best practices on navigation error handling with Puppeteer](https://puppeteer.guide/posts/handling-navigation-errors/), and a few more improvements, I found the root cause, managed to reproduce it and fixed it.

Now, the screenshot rendering will fail instead of returning an error image. And you can safely retry such requests. Also, we will be notified now, cause the uptime monitor will fail too.

Super sorry for the inconvenience! But hopes it won’t be repeated again.

If you encounter any other issues, please, reach out at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Remove organization members](/changelog/remove-organization-member/)

Improvements to the organization management.

Read more →

1 min read

#### [Set PDF margins](/changelog/pdf-margin/)

Now you can set PDF margins for the resulting PDF file.

Read more →

1 min read

#### [Updated the official Go SDK](/changelog/updated-gosdk/)

We updated the Go SDK to support the latest API features.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/selector-algorithm
----

More algorithms for screenshots by selectors

============================================

We added more algorithms for screenshots by selectors.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Apr 17, 2025

Now you can specify the algorithm to use for screenshots by selectors, e.g. `selector_algorithm=clip`.

The default algorithm is `default` which means to use the browser tools to screenshot the element by selector. But the new algorithm `clip` allows more flexibility and better results for some cases.

E.g. if you need to screenshot the element by selector and the element is not fully visible, or it requires scrolling to screenshot the element, the `clip` algorithm will be more suitable.

If you have more questions or feedback, please, reach out to us at [support@screenshotone.com](mailto:support@screenshotone.com).

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Stop scrolling screenshots when a given selector is visible](/changelog/animated-scrolling-till-selector/)

New options were added to the ScreenshotOne API to stop scrolling screenshots when a given selector is reached.

Read more →

1 min read

#### [Better numbers formatting in the dashboard](/changelog/better-numbers-formatting-in-the-dashboard/)

We improve UI/UX of rendering numbers in the dashboard for better readability.

Read more →

1 min read

#### [Improved API request log](/changelog/introducing-request-log/)

A new and improved request log has been deployed. That is a good beginning of the week! Check out why.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/kinsta
----

Taking care of WordPress Sites with ScreenshotOne

=================================================

How Kinsta uses ScreenshotOne to deliver reliable automatic updates.

[Customer story](/blog/tags/customer-stories/) 2 min read

#### Written by

[Roger Williams](/contributors/roger-williams/), [Barnabás Ürmössy](/contributors/barnabs-rmssy/)

#### Published on

Apr 29, 2025

Kinsta, a leading [managed WordPress hosting provider](https://kinsta.com), uses ScreenshotOne as a key part of its visual regression testing for automatic plugin and theme updates.

By capturing and comparing website screenshots before and after updates, Kinsta ensures that customer websites stay visually intact—giving site owners the confidence that their business operations will not be disrupted by unexpected changes.

Through this integration, Kinsta automates the update process, improves reliability at scale, and delivers a higher standard of care to its customers.

About Kinsta

------------

Founded in 2013, Kinsta is a premium hosting platform specializing in managed WordPress solutions, serving businesses, agencies, and enterprise organizations globally.

[](https://kinsta.com/clients/hall/)

Known for its high-performance infrastructure, proactive security practices, and expert support, [Kinsta consistently innovates to provide its customers with reliable, seamless website operations](https://kinsta.com/clients/hall/).

The problem: Ensuring Smooth Updates Without Visual Breakages

-------------------------------------------------------------

Automatic plugin and theme updates are essential for WordPress site security, performance, and long-term viability. However, even small changes can unintentionally affect the appearance or functionality of a live website.

For Kinsta, the challenge was clear: **How can we offer automatic updates that strengthen security while ensuring that customer websites continue to look and function exactly as intended?**

Visual regressions—even subtle ones—could harm the user experience and customer trust. Detecting these issues early, before an update goes live, was crucial.

The solution: Integrating ScreenshotOne for Visual Regression Testing

---------------------------------------------------------------------

Kinsta integrated ScreenshotOne into its automatic update workflow to add a visual safety net. Before making WordPress Plugin and Theme updates, Kinsta captures a “before” screenshot of the site. After the update is applied, a second “after” screenshot is taken. The two images are then compared to detect any unexpected changes.

> “We use ScreenshotOne as part of a visual regression test we run before certain updates. Their service allows us to capture screenshots of our sites before and after changes, helping us easily compare the differences and determine whether a rollback is needed.”

By automating this process with ScreenshotOne’s reliable API and clean SDKs, Kinsta added an extra layer of protection without slowing down the update process.

The result: faster, safer updates — and the peace of mind that website owners rightfully expect from a premium hosting provider.

Results and Impact

------------------

Since adopting ScreenshotOne, Kinsta has been able to:

1.  Confidently roll out automatic plugin and theme updates at scale.

2.  Detect and address visual regressions before they affect live users.

3.  Provide customers with additional assurance that their websites will continue to function and appear as expected.

Ultimately, the integration supports Kinsta’s commitment to operational excellence and strengthens trust with its global customer base.

ScreenshotOne: A Trusted and Responsive Partner

-----------------------------------------------

Beyond the technical advantages, Kinsta found the partnership with ScreenshotOne to be exceptional.

> “Working with Dmytro from ScreenshotOne has been an overwhelmingly positive and refreshing experience. He’s incredibly responsive, quick to act, and genuinely committed to making his service work for our needs.”

When Kinsta’s engineers needed adjustments to request rate limits or SDK improvements, ScreenshotOne delivered—often within minutes.

> “Dmytro also offered suggestions on how we could optimise our API usage, and when we noticed a method missing from the Node SDK (one already available in the API and critical for us), he had it fixed and released within minutes.”

The ease of integration, high-quality documentation, and proactive support have made ScreenshotOne a true partner rather than just another vendor.

Lessons Learned

---------------

For product teams managing critical site infrastructure, reliable partners are super important.

Kinsta’s experience highlights key takeaways:

*   Building everything in-house can slow down innovation. But carefully chosen partners accelerate it.

*   Visual regression testing is no longer a luxury, it is a necessity for delivering trustworthy automatic updates.

*   Responsive, proactive service from partners like ScreenshotOne creates compounding value over time, far beyond the original integration.

By investing in smart tools and strong partnerships, Kinsta continues to protect customer experiences and raise the standard for WordPress hosting worldwide.

Read more customer stories

--------------------------

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

[View all posts](/blog/tags/customer-stories/)

#### [How GetWebsite.Report uses ScreenshotOne for screenshot automation tasks](/blog/how-website-report-uses-screenshotone/)

If you are interested in diving deeper into the GetWebsite.Report use case and discover if ScreenshotOne might be useful for you, too, keep reading.

Read more

#### [How Branding 5 uses ScreenshotOne for competitor analysis](/blog/how-branding5-uses-screenshotone/)

If you are interested in diving deeper into the Branding 5 use case and discover if ScreenshotOne might be useful for you, too, keep reading.

Read more

#### [How Spectate uses ScreenshotOne to improve incident observability](/blog/how-spectate-uses-screenshotone/)

If you are interested in diving deeper into the Spectate use case and discover if ScreenshotOne might be useful for you, too, keep reading.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/tools/full-page-screenshot-chrome-extension
----

Render and annotate full-page screenshots in a few clicks

---------------------------------------------------------

Render and annotate full-page screenshots of any website as a single image—click and download. No API key or subscription required and privacy-friendly.

[Tools](/tools/) Full-page Screenshot Chrome Extension

[Add to Chrome for free](/full-page-screenshot-chrome-extension/)

 Sorry, your browser doesn't support embedded videos.

If you need to automate website screenshot rendering or integrate screenshotting into your application or SaaS, please, check out [the best screenshot API—ScreenshotOne](/).  

Check out more [screenshot tools](/tools/).

Frequently Asked Questions

--------------------------

Discover quick and comprehensive answers to common questions about our platform, services, and features.

What is the ScreenshotOne full-page screenshot Chrome extension?

The ScreenshotOne full-page screenshot Chrome extension is a free tool that allows you to take full-page screenshots of any website and annotate them in just a few clicks. It doesn't require an API key or subscription to use.

What about privacy?

Yes, the extension doesn't send any data anywhere and doesn't store anything. It works directly in Chrome without any API calls to any third-party services.

When should I use the ScreenshotOne API instead?

You should use the ScreenshotOne API if you need to automate screenshot capture at scale or integrate screenshot functionality into your own application or SaaS product. The extension is better suited for individual users taking occasional screenshots.

Integrate today

Automate screenshot rendering with the language you love

--------------------------------------------------------

Send simple HTTP requests or use native libraries for your language of choice.

Java Go Node.js PHP Python Ruby C# (.NET)

    1// add com.screenshotone.jsdk:screenshotone-api-jsdk:[1.0.0,2.0.0)2// to your `pom.xml` or `build.gradle`3

    4import com.screenshotone.jsdk.Client;5import com.screenshotone.jsdk.TakeOptions;6

    7import java.io.File;8import java.nio.file.Files;9

    10public class App {11    public static void main(String[] args) throws Exception {12        final Client client = Client.withKeys("<access key>", "<secret key>");13        TakeOptions takeOptions = TakeOptions.url("https://example.com")14                .fullPage(true)15                .deviceScaleFactor(1)16                .viewportHeight(1200)17                .viewportWidth(1200)18                .format("png")19                .omitBackground(true);20        final String url = client.generateTakeUrl(takeOptions);21

    22        System.out.println(url);23        // Output: https://api.screenshotone.com/take?url=...24

    25        // or download the screenshot26        final byte[] image = client.take(takeOptions);27

    28        Files.write(new File("./example.png").toPath(), image);29        // the screenshot is stored in the example.png file30    }31}

    1// go get github.com/screenshotone/gosdk2

    3import screenshots "github.com/screenshotone/gosdk"4

    5client, err := screenshots.NewClient("<access key>", "<secret key>")6// check err7

    8options := screenshots.NewTakeOptions("https://example.com").9    Format("png").10    FullPage(true).11    DeviceScaleFactor(2).12    BlockAds(true).13    BlockTrackers(true)14

    15u, err := client.GenerateTakeURL(options)16// check err17

    18fmt.Println(u.String())19// Output: https://api.screenshotone.com/take?url=...20

    21// or download the screenshot22image, err := client.Take(context.TODO(), options)23// check err24

    25defer image.Close()26out, err := os.Create("example.png")27// check err28

    29defer out.Close()30io.Copy(out, image)31// the screenshot is stored in the example.png file

    1// $ npm install screenshotone-api-sdk --save2

    3import * as fs from 'fs';4import * as screenshotone from 'screenshotone-api-sdk';5

    6// create API client7const client = new screenshotone.Client("<access key>", "<secret key>");8

    9// set up options10const options = screenshotone.TakeOptions11    .url("https://example.com")12    .delay(3)13    .blockAds(true);14

    15// generate URL16const url = client.generateTakeURL(options);17console.log(url);18// expected output: https://api.screenshotone.com/take?url=...19

    20// or download the screenshot21const imageBlob = await client.take(options);22const buffer = Buffer.from(await imageBlob.arrayBuffer());23fs.writeFileSync("example.png", buffer)24// the screenshot is stored in the example.png file

    1<?php2

    3// composer require screenshotone/sdk:^1.04

    5use ScreenshotOneSdkClient;6use ScreenshotOneSdkTakeOptions;7

    8$client = new Client("<access key>", "<secret key>");9

    10$options = TakeOptions::url("https://example.com")11    ->fullPage(true)12    ->delay(2)13    ->geolocationLatitude(48.857648)14    ->geolocationLongitude(2.294677)15    ->geolocationAccuracy(50);16

    17$url = $client->generateTakeUrl($options);18echo $url.PHP_EOL;19// expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com...20

    21$image = $client->take($options);22file_put_contents('example.png', $image);23// the screenshot is stored in the example.png file

    1# pip install screenshotone2

    3import shutil4from screenshotone import Client, TakeOptions5

    6# create API client7client = Client('<access key>', '<secret key>')8

    9# set up options10options = (TakeOptions.url('https://screenshotone.com')11    .format("png")12    .viewport_width(1024)13    .viewport_height(768)14    .block_cookie_banners(True)15    .block_chats(True))16

    17# generate the screenshot URL and share it with a user18url = client.generate_take_url(options)19# expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fscreenshotone.com&viewport_width=1024&viewport_height=768&block_cookie_banners=True&block_chats=True&access_key=&signature=6afc9417a523788580fa01a9f668ea82c78a9d2b41441d2a696010bf2743170f20

    21# or render a screenshot and download the image as stream22image = client.take(options)23

    24# store the screenshot the example.png file25with open('example.png', 'wb') as result_file:26    shutil.copyfileobj(image, result_file)

    1# Add this gem to your Gemfile:2# gem 'screenshotone'3

    4# If you don't need to add a signature5client = ScreenshotOne::Client.new('<access key>')6

    7# Or ff you do need to add a signature8client = ScreenshotOne::Client.new('<access key>', '<secret key>')9

    10# You can set any available option, in a camel_case format, for example:11options = ScreenshotOne::TakeOptions.new(url: 'https://example.com').12            full_page(true).13            delay(2).14            geolocation_latitude(48.857648).15            geolocation_longitude(2.294677).16            geolocation_accuracy(50)17

    18# Verify all the parameters are valid (we will validate the parameters that should be19# numeric, booleans or that accept only certain values)20options.valid?21=> true22

    23# To simply get the final url:24client.generate_take_url(options)25=> "https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com..."26

    27# To actually get the image (the response body of a request to the previous url)28client.take(options)29=> "\xFF\xD8\xFF\xE0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xFF\..."

    1// Add the library via nuget using the package manager console: PM> Install-Package ScreenshotOne.dotnetsdk2// Or from the .NET CLI as: dotnet add package ScreenshotOne.dotnetsdk3

    4// And generate a screenshot URL without executing request:5var client = new Client("<access key>", "<secret key>");6var options = TakeOptions.Url("https://www.amazon.com")7  .FullPage(true)8  .Format(Format.PNG)9  .BlockCookieBanners(true);10

    11var url = client.GenerateTakeUrl(options);12// url = https://api.screenshotone.com/take?url=https%3A%2F%2Fwww.amazon.com&full_page=true&format=png&block_cookie_banners=true&access_key=_OzqMIjpCw-ARQ&signature=8a08e62d13a5c3490fda0734b6707791d3decc9ab9ba41e8cc045288a39db50213

    14// Or take a screenshot and save the image in the file:15var client = new Client("<access key>", "<secret key>");16var options = TakeOptions.Url("https://www.google.com")17  .FullPage(true)18  .Format(Format.PNG)19  .BlockCookieBanners(true);20

    21var bytes = await client.Take(options);22

    23File.WriteAllBytes(@"c:\temp\example.png", bytes);

Mike Roberts

Founder, [SpyFu](https://www.spyfu.com/)

> ScreenshotOne is the best product on the market - and that's before you take into account how responsive and easy Dmytro is to work with.

> 

> Any time we've found a rare edge case, it's been resolved in hours.

> 

> Great company, great founder - can't say enough!

Without writing a line of code

No-code integrations

--------------------

Quickly render website screenshots with Zapier, Airtable, Make and other popular no-code platforms of your choice.

[](/integrations/zapier/)[](/integrations/airtable/)[](/integrations/make/)[](/integrations/bubble/)[](/integrations/n8n/)

Read

Lessons from running screenshot rendering infrastructure

--------------------------------------------------------

Practical guides and real updates based on our experience operating rendering infrastructure at production scale.

[Playwright guides](/blog/tags/playwright-guides/)

#### [Playwright "Execution context was destroyed": how to fix navigation and page.evaluate errors](/blog/playwright-execution-context-was-destroyed-most-likely-because-of-a-navigation/)

Fix the Playwright "Execution context was destroyed, most likely because of a navigation" error after click, form submit, redirect, reload, or page.evaluate.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 13, 2026

•

4 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [page.waitForTimeout is not a function in Puppeteer](/blog/page-waitfortimeout-is-not-a-function-in-puppeteer/)

Puppeteer removed page.waitForTimeout(). Learn why the error happens and which modern alternatives to use instead.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 13, 2026

•

2 min read

#### [OpenClaw with Playwright or Puppeteer: how to install browser support](/blog/openclaw-playwright-puppeteer/)

A practical guide to OpenClaw browser automation, why Playwright is the documented path, where Puppeteer fits, how to make screenshots, and when ScreenshotOne is the better choice for screenshot-only flows.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 12, 2026

•

6 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/the-best-screenshot-api
----

Updated on Apr 30, 2025

What is the best screenshot API?

================================

[There is a better guide on how to choose a screenshot API and what is the best screenshot API available](/blog/best-screenshot-apis/).

This guide is outdated and not updated anymore. We realized that sharing many options creates a lot of noise and leads to analysis paralysis, so check out [our updated guide on the best screenshot APIs](/blog/best-screenshot-apis/).

I want to make [ScreenshotOne the best screenshot API possible](/) in the market that will allow you to render HTML or URL into the image or PDF easily and cheaply.

If you are one of the competitors mentioned in the comparison and you see a typo, or I described your API wrong, please, [contact me as soon as possible](mailto:hey@screenshotone.com). I want to provide the most objective comparison to choose the best screenshot API.

While writing this screenshot comparison, I was curious if my product — [ScreenshotOne screenshot API](/), is the best screenshot API and, if not, what is the best product in the market, and how I can beat it.

But how can I do it without comparing it to alternatives and checking that it is the best?

It is hard to find the proper comparison angle. Some products might lack features but have excellent product support, or I found products with pricing models that are not comparable.

I went with the straightforward approach. I analyzed all the features provided by the APIs and their pricing models. The best screenshot API is simply the one with the most features, and the average screenshot price is the cheapest.

I searched for “screenshot API”. And each API I found, I will review and compare each API thoroughly to determine the best one.

These are the best site screenshot APIs:

*   **[ScreenshotOne](#screenshotone)**

*   [Urlbox.io](#urlboxio)

*   [thum.io](#thumio)

*   [ProxyCrawl](#proxycrawl)

*   [Add Screenshots](#add-screenshots)

*   [WhoisXMLAPI](#whoisxmlapi)

*   [Pikwy](#pikwy)

*   [purplescreenshots.com](#purplescreenshotscom)

*   [Bannerbear](#bannerbear)

*   [screendot](#screendot)

*   [GeoScreenshot](#geoscreenshot)

*   [ScrapingBee](#scrapingbee)

*   [URL2PNG](#url2png)

*   [GetScreenshot](#getscreenshot)

*   [Restpack](#restpack)

*   [Geekflare](#geekflare)

*   [NoCodeAPI](#nocodeapi)

*   [ApiFlash](#apiflash)

*   [URL To Screenshot](#url-to-screenshot)

*   [Abstract](#abstract)

*   [screenshotlayer API](#screenshotlayer-api)

*   [Screenshot Machine](#screenshot-machine)

*   [ScreenshotAPI](#screenshotapi)

The best screenshot API

-----------------------

The best API is [thum.io](#thumio) because it has the most features and the cheapest pricing in terms of average price per 1000 screenshots — **$5.33**.

I try to make the comparison objectively, and the best one might or not be my product. But if you see any feature lacking in my API, feel free to [send a feature request](mailto:hey@screenshotone.com).

The best API and how it is compared by basic features to the **ScreenshotOne** API:

Feature / API

[ScreenshotOne](#screenshotone)

[thum.io](#thumio)

URL

HTML

Selector

Viewport size

Device scale factor

Full page

Lazy load

Cache

Cache ttl

Cache ignore

Wait for event

User agent

Authentication

Accept languages

Custom cookies

Custom headers

Custom css

Custom js

The best API and how it is compared by advanced features to the **ScreenshotOne** API:

Feature / API

[ScreenshotOne](#screenshotone)

[thum.io](#thumio)

Omit background

Fail on status

Geolocation

Custom proxy

Block cookie banners

Block ads

Scroll to element

Custom html

Custom css url

Delay

Thumbnail width

Thumbnail height

Markdown

Signed links

Click by selector

Hide by selector

Clip

Custom renders on errors

Uptime sla

Custom js url

Grayscale

Extract html

Extract text

Dark mode

Block tracking

Placeholder

Export to ftp

Export to s3

Image quality

Block chats

Dedicated workers

Highlight

Wait for selector

Block requests

Ip location

Email

Webhook

No js

Timeout

Zapier

Sdk

Schedule

Metadata

Custom domain

Timezone

Stealth mode

Gpu rendering

Export to azure

Bplogin

Fail on redirect

Emulate touch screen

Emulate mobile

Emulate landscape

Download

Hover

Brightness

Blur

Contrast

Emulate media

File name

Track changes

Reduced motion

Viewport device

Rotate flip

Pdf landscape

Pdf print background

Pdf to image

Pdf format

Pdf media

Element overlap

The best API and how it is compared by supported formats to the **ScreenshotOne** API:

Feature / API

[ScreenshotOne](#screenshotone)

[thum.io](#thumio)

JPG (JPEG)

PNG

WebP

PDF

GIF

JSON

Base64

SVG

AVIF

HEIF

TIFF

JP2 (JPEG 2000)

HTML

And comparison by pricing:

API

Average price per 1000 screenshots

The cheapest paid monthly plan per # of screenshots

Free option

Free screenshots

**[ScreenshotOne](#screenshotone)**

**$2.85**

**$14 per 1500**

**100**

[thum.io](#thumio)

$5.33

$1 per 1000

Comparison by basic features

----------------------------

I gathered all the basic required features from most screenshot API users and sorted all APIs by core feature support. I decided not to render all APIs since it barely makes sense. And as a result, you can see **the top 5 screenshot APIs** by core features support:

Feature / API

[Urlbox.io](#urlboxio)

[ScreenshotOne](#screenshotone)

[ApiFlash](#apiflash)

[ScreenshotAPI](#screenshotapi)

[Add Screenshots](#add-screenshots)

URL

HTML

Selector

Viewport size

Device scale factor

Full page

Lazy load

Cache

Cache ttl

Cache ignore

Wait for event

User agent

Authentication

Accept languages

Custom cookies

Custom headers

Custom css

Custom js

A short explanation of each core feature:

*   **URL**: Specify the URL of the site. Some APIs also allow rendering of HTML, not only URL.

*   **HTML**: Specify HTML to render as an image.

*   **Selector**: Specify the target element for the screenshot based on an element with a matching CSS selector. If the element is not found, some APIs can return an error, some can produce a full page screenshot, and some can allow you to configure the behavior.

*   **Viewport size**: Change the browser window size.

*   **Device scale factor**: Render screenshot with higher pixel density. It is suitable when screenshots might be displayed on Apple Retina displays or other high-definition equivalents.

*   **Full page**: Take the full page screenshot of a website versus the area visible in the viewport upon rendering. Usually, this feature is accompanied by scrolling to the bottom and back to trigger a load of lazy loading elements like images.

*   **Lazy load**: To lazy load images and other elements hidden from the viewport, a screenshot API will usually scroll down the entire page and scroll up.

*   **Cache**: Cache screenshot rendering. It allows rendering the same URL or HTML faster. It is usually implemented by using CDN and is usually not billed. But should be checked on a per API basis.

*   **Cache ttl**: Specify the time of how long the cached screenshot can be stored in the cache.

*   **Cache ignore**: Ignore caching and force taking a fresh screenshot.

*   **Wait for event**: Wait for page events like “idle network” or “DOM content loaded” before taking a screenshot.

*   **User agent**: Set custom `User-Agent` header. It is not always supported by screenshot APIs as a separated feature and usually can be emulated with custom headers.

*   **Authentication**: Set `Authorization` header, which allows bypassing basic authentication or authentication by tokens.

*   **Accept languages**: Set the `Accept-Language` header before taking a screenshot. It is suitable for multilingual sites to force them to render in the requested language.

*   **Custom cookies**: Set custom cookies for the request to a specified URL. You might want to specify credentials to bypass the login page.

*   **Custom headers**: Set custom headers for the request to the specified URL. You might want to specify credentials if required by the site or headers like `Accept-Language` if screenshot API does not support setting this header separately.

*   **Custom css**: Inject custom CSS code to change visuals before taking a screenshot.

*   **Custom js**: Inject custom JavaScript code to inject behavior before taking a screenshot.

Comparison by advanced features

-------------------------------

Most of the APIs have basic core features, but each API might provide a set of different, sometimes unique features. **The top 5 screenshot APIs** by advanced features support:

Feature / API

[Add Screenshots](#add-screenshots)

[ScreenshotAPI](#screenshotapi)

[Urlbox.io](#urlboxio)

[ScreenshotOne](#screenshotone)

[ApiFlash](#apiflash)

Omit background

Fail on status

Geolocation

Custom proxy

Block cookie banners

Block ads

Scroll to element

Custom html

Custom css url

Delay

Thumbnail width

Thumbnail height

Markdown

Signed links

Click by selector

Hide by selector

Clip

Custom renders on errors

Uptime sla

Custom js url

Grayscale

Extract html

Extract text

Dark mode

Block tracking

Placeholder

Export to ftp

Export to s3

Image quality

Block chats

Dedicated workers

Highlight

Wait for selector

Block requests

Ip location

Email

Webhook

No js

Timeout

Zapier

Sdk

Schedule

Metadata

Custom domain

Timezone

Stealth mode

Gpu rendering

Export to azure

Bplogin

Fail on redirect

Emulate touch screen

Emulate mobile

Emulate landscape

Download

Hover

Brightness

Blur

Contrast

Emulate media

File name

Track changes

Reduced motion

Viewport device

Rotate flip

Pdf landscape

Pdf print background

Pdf to image

Pdf format

Pdf media

Element overlap

A short explanation of each advanced feature:

*   **Omit background**: Omit background feature removes the background from websites with a basic white background and makes it transparent. It is applicable only for formats that support transparency, like PNG.

*   **Fail on status**: If the target site responds with HTTP status code 400-599 inclusively, you can take screenshot of the sites’s error page or return an error from the screenshot API.

*   **Geolocation**: The feature emulates accuracy and coordinates (longitude and latitude) for the browser’s Geolocation API.

*   **Custom proxy**: Using proxy for proxing all requests to the target website. You should provide proxy address and credentials. It is not provided by the screenshot API for free.

*   **Block cookie banners**: Block or hide cookie banners on websites before taking a screenshot. It makes a screenshot looks cleaner.

*   **Block ads**: Block and hide ads from common and popular ad networks to make screenshots cleaner, and if it is applicable, don’t spend advertiser budgets.

*   **Scroll to element**: Target a specific element for the browser to scroll to before taking a screenshot. It might be useful if a given element is lazy loaded but fully loaded in the viewport.

*   **Custom html**: Instead of providing an URL of a site, you can render any HTML.

*   **Custom css url**: Inject the custom CSS code URL to change visuals before taking a screenshot.

*   **Delay**: The time delay before taking a screenshot. It is helpful when the screenshot you took is half-rendered and you want to wait until it is fully loaded.

*   **Thumbnail width**: Generate a thumbnail of the screenshot — a miniature of the full-size screenshot. The height of the screenshot thumbnail is usually computed automatically.

*   **Thumbnail height**: The height of the screenshot thumbnail.

*   **Markdown**: Specify Markdown to render as an HTML text or an image.

*   **Signed links**: If you share links to screenshots in public with your API keys, you can sign them to ensure that nobody else can use your API key without (usually) knowing the secret key.

*   **Click by selector**: Click on the element by described CSS selector. It might help close annoying banners and popups.

*   **Hide by selector**: Hide or remove elements by a selector. It is usable to hide annoying details and make screenshots look cleaner.

*   **Clip**: Take a screenshot of the area, usually by specifying coordinates of the “screenshotting” rectangle.

*   **Custom renders on errors**: Instead of returning an error, an API can produce an image placeholder if it has failed to take a screenshot.

*   **Uptime sla**: Some APIs could guarantee SLA and compensation if they failed to deliver the guaranteed SLA.

*   **Custom js url**: Inject the custom JavaScript code URL to inject behavior before taking a screenshot.

*   **Grayscale**: Apply grayscale filter to the screenshot.

*   **Extract html**: In addition to the screenshot, extract and attach the HTML of the page. Usually, it is served as a JSON response.

*   **Extract text**: In addition to the screenshot, extract and attach the text of the page. Usually, it is served as a JSON response.

*   **Dark mode**: Hint the browser to render the page in the dark mode.

*   **Block tracking**: Block trackers to speed up the page load and take screenshots faster.

*   **Placeholder**: While a screenshot is being taken, you can ask an API to return a placeholder.

*   **Export to ftp**: Export a screenshot to FTP.

*   **Export to s3**: Export a screenshot to Amazon S3 or S3-compatible storage.

*   **Image quality**: Specify the image quality. Usually, the lower the image quality, the faster screenshot is rendered.

*   **Block chats**: Hide or remove chat widgets to make screenshots look cleaner.

*   **Dedicated workers**: Some APIs can provide dedicated workers to take screenhots. But usually, it is too ambiguous to understand what that means.

*   **Highlight**: You can highlight a custom word or phrase. Some APIs also allow customizing the text and background colors of the highlight.

*   **Wait for selector**: Wait until the provided CSS selector matches an element present on the page before taking a screenshot.

*   **Block requests**: Block requests triggered by the site. Usually, it helps to block ad providers or to speed up taking screenshots.

*   **Ip location**: Take screenshots from a specified location, usually done through proxies provided by an API. And it might allow bypassing bot blockers.

*   **Email**: Send a screenshot to email.

*   **Webhook**: Send a screenshot to an HTTP endpoint.

*   **No js**: Do not execute JavaScript.

*   **Timeout**: The request must fail if a screenshot is not taken in the specified timeout time.

*   **Zapier**: Integration with Zapier — a rich automation platform that allows combining APIs, tools, and mostly everything.

*   **Sdk**: API might support native SDKs for programming languages.

*   **Schedule**: Scheduling taking screenshots.

*   **Metadata**: Store any metadata associated with a screenshot.

*   **Custom domain**: Serve screenshots from the custom domain.

*   **Timezone**: Emulate time zone for browser.

*   **Stealth mode**: Steal tries to hide the fact the request is sent under an automated browser. But usually without any guarantee from the API side.

*   **Gpu rendering**: Use GPU for rendering screenshots.

*   **Export to azure**: Export screenshot to Microsoft Azure Cloud.

*   **Bplogin**: Execute a request to sign in to a site before taking a screenshot.

*   **Fail on redirect**: You can force API to return an error if the target URL triggers a redirect.

*   **Emulate touch screen**: Emulate the device with a touch screen.

*   **Emulate mobile**: Emulate a mobile device.

*   **Emulate landscape**: Renders page in landscape mode, usually valid for mobile emulation.

*   **Download**: Request triggering a download of the screenshot or PDF in the browser instead of rendering.

*   **Hover**: Hover an element by CSS selector.

*   **Brightness**: Change the brightness of the screenshot.

*   **Blur**: Make the screenshot blurred.

*   **Contrast**: Change the contrast of the screenshot.

*   **Emulate media**: Emulate CSS media for print or screen.

*   **File name**: Specify the filename of the screenshot. Sometimes, it is limited to generating a filename from the URL.

*   **Track changes**: Track and notify about screenshot changes.

*   **Reduced motion**: Request emulation of reduced motion.

*   **Viewport device**: A fixed list of devices to use for viewport settings.

*   **Rotate flip**: Rotate or flip the resulted screenshot.

*   **Pdf landscape**: Render PDF in the landscape format.

*   **Pdf print background**: Print the background of the site in PDF.

*   **Pdf to image**: Render PDF as a set of images.

*   **Pdf format**: Page format like A0-A6 and so on.

*   **Pdf media**: Optimize a PDF for printing or render it exactly as the HTML or website is rendered.

*   **Element overlap**: When taking a screenshot of the element by CSS selector, take the screenshot of the elements that overlap the element.

Comparison by supported formats

-------------------------------

You might find helpful the short guide on how you can [take screenshots with Puppeteer in GIF, JP2, TIFF, AVIF, HEIF, or SVG format](/blog/taking-screenshots-with-puppeteer-in-gif-jp2-tiff-avif-heif-or-svg-format/).

A comparison table for **the top 5 screenshot APIs** by output formats that API supports:

Feature / API

[ScreenshotOne](#screenshotone)

[Urlbox.io](#urlboxio)

[screendot](#screendot)

[Restpack](#restpack)

[ScreenshotAPI](#screenshotapi)

JPG (JPEG)

PNG

WebP

PDF

GIF

JSON

Base64

SVG

AVIF

HEIF

TIFF

JP2 (JPEG 2000)

HTML

A short description of the formats:

*   **JPG (JPEG)**: A most common format which contains compressed image data

*   **PNG**: A format which supports lossless data compression

*   **WebP**: An image format that provides superior lossless and lossy compression primarily for images on the web

*   **PDF**: A file format developed to present documents, including text formatting and images, in a manner independent of application software, hardware, and operating systems

*   **GIF**: A bitmap image format that supports animations

*   **JSON**: JSON containing Base64-encoded data or URL of the rendered image

*   **Base64**: A Base64-encoded image

*   **SVG**: A web-friendly vector file format

*   **AVIF**: An open-sourced and royalty free optimised image format which supports any image codec

*   **HEIF**: A container format for storing individual digital images and image sequences

*   **TIFF**: An image file format for storing raster graphics images, popular among graphic artists, the publishing industry, and photographers

*   **JP2 (JPEG 2000)**: An image compression standard and coding system. It was developed with the intention of superseding the original JPEG standard.

*   **HTML**: A markup text that can be rendered by APIs from URL.

Comparison by pricing

---------------------

The APIs are sorted from cheapest to the most expensive by normalized average price per 1000 screenshots:

API

Average price per 1000 screenshots

The cheapest paid monthly plan per # of screenshots

Free option

Free screenshots

[Geekflare](#geekflare)

$0.37

$10 per 10000

500

[NoCodeAPI](#nocodeapi)

$0.46

$12 per 10000

60

[ScrapingBee](#scrapingbee)

$0.48

$49 per 20000

[screendot](#screendot)

$0.57

$20 per 10000

1000

[GetScreenshot](#getscreenshot)

$1.03

$7.99 per 2500

[screenshotlayer API](#screenshotlayer-api)

$1.17

$19.99 per 10000

100

[ProxyCrawl](#proxycrawl)

$1.2

$39 per 10000

[Abstract](#abstract)

$1.22

$9 per 3000

100

[Pikwy](#pikwy)

$1.89

$3 per 1000

[ApiFlash](#apiflash)

$2.05

$7 per 1000

100

[URL To Screenshot](#url-to-screenshot)

$2.08

$9.99 per 5000

1000

**[ScreenshotOne](#screenshotone)**

**$2.85**

**$14 per 1500**

**100**

[Screenshot Machine](#screenshot-machine)

$2.92

$9 per 2500

100

[purplescreenshots.com](#purplescreenshotscom)

$3.45

$29 per 5000

[Add Screenshots](#add-screenshots)

$3.88

$9 per 2500

100

[Restpack](#restpack)

$4.54

$9.95 per 1000

[URL2PNG](#url2png)

$4.96

$29 per 5000

[thum.io](#thumio)

$5.33

$1 per 1000

[Bannerbear](#bannerbear)

$5.67

$49 per 1000

[Urlbox.io](#urlboxio)

$5.68

$10 per 1000

[ScreenshotAPI](#screenshotapi)

$6.11

$9 per 1000

100

[WhoisXMLAPI](#whoisxmlapi)

$6.87

$19 per 1000

500

[GeoScreenshot](#geoscreenshot)

$36.85

$49 per 2500

The average price is a normalized average place per screenshot for each plan.

For example, consider an API with two plans: plan A with 1000 screenshots for $10 and plan B with 2000 screenshots for $50.

Plan A’s average price per screenshot is `$10/1000 = $0.01`. And the average per screenshot for plan B is `$50/2000 = $0.025`.

The average of the average is `($0.01 + $0.025) / 2 = $0.0175`. But to simplify the number reading, I multiply it by 1000 to represent the average price for 1000 screenshots `$0.0175 * 1000 = $17.5`.

Complete review of best screenshot APIs

---------------------------------------

In case you are interested, one by one, I review each screenshot API and compare its features and pricing to ScreenshotOne API.

### ScreenshotOne

URL: [https://screenshotone.com/](https://screenshotone.com/)

ScreenshotOne is one of the best screenshot APIs on the market, made by [Dmytro Krasun](/contributors/dmytro-krasun/) (it is me 😉), perfected to near excellence, and because of optimized operating costs, provides one of the most affordable pricing structures on the market.

Basic features:

Feature / API

[ScreenshotOne](#screenshotone)

URL

HTML

Selector

Viewport size

Device scale factor

Full page

Lazy load

Cache

Cache ttl

Cache ignore

Wait for event

User agent

Authentication

Accept languages

Custom cookies

Custom headers

Custom css

Custom js

Advanced features:

Feature / API

[ScreenshotOne](#screenshotone)

Omit background

Fail on status

Geolocation

Custom proxy

Block cookie banners

Block ads

Scroll to element

Custom html

Custom css url

Delay

Thumbnail width

Thumbnail height

Markdown

Signed links

Click by selector

Hide by selector

Clip

Custom renders on errors

Uptime sla

Custom js url

Grayscale

Extract html

Extract text

Dark mode

Block tracking

Placeholder

Export to ftp

Export to s3

Image quality

Block chats

Dedicated workers

Highlight

Wait for selector

Block requests

Ip location

Email

Webhook

No js

Timeout

Zapier

Sdk

Schedule

Metadata

Custom domain

Timezone

Stealth mode

Gpu rendering

Export to azure

Bplogin

Fail on redirect

Emulate touch screen

Emulate mobile

Emulate landscape

Download

Hover

Brightness

Blur

Contrast

Emulate media

File name

Track changes

Reduced motion

Viewport device

Rotate flip

Pdf landscape

Pdf print background

Pdf to image

Pdf format

Pdf media

Element overlap

Supported formats:

Feature / API

[ScreenshotOne](#screenshotone)

JPG (JPEG)

PNG

WebP

PDF

GIF

JSON

Base64

SVG

AVIF

HEIF

TIFF

JP2 (JPEG 2000)

HTML

Pricing:

API

Average price per 1000 screenshots

The cheapest paid monthly plan per # of screenshots

Free option

Free screenshots

[ScreenshotOne](#screenshotone)

$2.85

$14 per 1500

100

### Urlbox.io

URL: [https://www.urlbox.io/](https://www.urlbox.io/)

Urlbox was founded in 2012 to turn HTML into images and URLs into screenshots. It is a solid company that fixed the most complicated issues on taking screenshots and has a good trek record of customers — one of the best in the screenshot API niches.

Comparison by basic features:

Feature / API

[Urlbox.io](#urlboxio)

[ScreenshotOne](#screenshotone)

URL

HTML

Selector

Viewport size

Device scale factor

Full page

Lazy load

Cache

Cache ttl

Cache ignore

Wait for event

User agent

Authentication

Accept languages

Custom cookies

Custom headers

Custom css

Custom js

Comparison by advanced features:

Feature / API

[Urlbox.io](#urlboxio)

[ScreenshotOne](#screenshotone)

Omit background

Fail on status

Geolocation

Custom proxy

Block cookie banners

Block ads

Scroll to element

Custom html

Custom css url

Delay

Thumbnail width

Thumbnail height

Markdown

Signed links

Click by selector

Hide by selector

Clip

Custom renders on errors

Uptime sla

Custom js url

Grayscale

Extract html

Extract text

Dark mode

Block tracking

Placeholder

Export to ftp

Export to s3

Image quality

Block chats

Dedicated workers

Highlight

Wait for selector

Block requests

Ip location

Email

Webhook

No js

Timeout

Zapier

Sdk

Schedule

Metadata

Custom domain

Timezone

Stealth mode

Gpu rendering

Export to azure

Bplogin

Fail on redirect

Emulate touch screen

Emulate mobile

Emulate landscape

Download

Hover

Brightness

Blur

Contrast

Emulate media

File name

Track changes

Reduced motion

Viewport device

Rotate flip

Pdf landscape

Pdf print background

Pdf to image

Pdf format

Pdf media

Element overlap

Comparison by supported formats:

Feature / API

[ScreenshotOne](#screenshotone)

[Urlbox.io](#urlboxio)

JPG (JPEG)

PNG

WebP

PDF

GIF

JSON

Base64

SVG

AVIF

HEIF

TIFF

JP2 (JPEG 2000)

HTML

Comparison by pricing:

API

Average price per 1000 screenshots

The cheapest paid monthly plan per # of screenshots

Free option

Free screenshots

**[ScreenshotOne](#screenshotone)**

**$2.85**

**$14 per 1500**

**100**

[Urlbox.io](#urlboxio)

$5.68

$10 per 1000

### thum.io

URL: [https://www.thum.io/](https://www.thum.io/)

thum.io is focused on screenshot API, and they have an exciting feature — rendering PDF as images. But the solution is built on PhantomJS, a discontinued headless browser for automating web page interaction.

Comparison by basic features:

Feature / API

[ScreenshotOne](#screenshotone)

[thum.io](#thumio)

URL

HTML

Selector

Viewport size

Device scale factor

Full page

Lazy load

Cache

Cache ttl

Cache ignore

Wait for event

User agent

Authentication

Accept languages

Custom cookies

Custom headers

Custom css

Custom js

Comparison by advanced features:

Feature / API

[ScreenshotOne](#screenshotone)

[thum.io](#thumio)

Omit background

Fail on status

Geolocation

Custom proxy

Block cookie banners

Block ads

Scroll to element

Custom html

Custom css url

Delay

Thumbnail width

Thumbnail height

Markdown

Signed links

Click by selector

Hide by selector

Clip

Custom renders on errors

Uptime sla

Custom js url

Grayscale

Extract html

Extract text

Dark mode

Block tracking

Placeholder

Export to ftp

Export to s3

Image quality

Block chats

Dedicated workers

Highlight

Wait for selector

Block requests

Ip location

Email

Webhook

No js

Timeout

Zapier

Sdk

Schedule

Metadata

Custom domain

Timezone

Stealth mode

Gpu rendering

Export to azure

Bplogin

Fail on redirect

Emulate touch screen

Emulate mobile

Emulate landscape

Download

Hover

Brightness

Blur

Contrast

Emulate media

File name

Track changes

Reduced motion

Viewport device

Rotate flip

Pdf landscape

Pdf print background

Pdf to image

Pdf format

Pdf media

Element overlap

Comparison by supported formats:

Feature / API

[ScreenshotOne](#screenshotone)

[thum.io](#thumio)

JPG (JPEG)

PNG

WebP

PDF

GIF

JSON

Base64

SVG

AVIF

HEIF

TIFF

JP2 (JPEG 2000)

HTML

Comparison by pricing:

API

Average price per 1000 screenshots

The cheapest paid monthly plan per # of screenshots

Free option

Free screenshots

**[ScreenshotOne](#screenshotone)**

**$2.85**

**$14 per 1500**

**100**

[thum.io](#thumio)

$5.33

$1 per 1000

### ProxyCrawl

URL: [https://proxycrawl.com/screenshots-api](https://proxycrawl.com/screenshots-api)

ProxyCrawl is a company developed around crawling and scrapping, but they also support taking screenshots. They provide native SDKs and have good experience working with headless browsers, but screenshot API capabilities are a bit limited.

Comparison by basic features:

Feature / API

[ScreenshotOne](#screenshotone)

[ProxyCrawl](#proxycrawl)

URL

HTML

Selector

Viewport size

Device scale factor

Full page

Lazy load

Cache

Cache ttl

Cache ignore

Wait for event

User agent

Authentication

Accept languages

Custom cookies

Custom headers

Custom css

Custom js

Comparison by advanced features:

Feature / API

[ScreenshotOne](#screenshotone)

[ProxyCrawl](#proxycrawl)

Omit background

Fail on status

Geolocation

Custom proxy

Block cookie banners

Block ads

Scroll to element

Custom html

Custom css url

Delay

Thumbnail width

Thumbnail height

Markdown

Signed links

Click by selector

Hide by selector

Clip

Custom renders on errors

Uptime sla

Custom js url

Grayscale

Extract html

Extract text

Dark mode

Block tracking

Placeholder

Export to ftp

Export to s3

Image quality

Block chats

Dedicated workers

Highlight

Wait for selector

Block requests

Ip location

Email

Webhook

No js

Timeout

Zapier

Sdk

Schedule

Metadata

Custom domain

Timezone

Stealth mode

Gpu rendering

Export to azure

Bplogin

Fail on redirect

Emulate touch screen

Emulate mobile

Emulate landscape

Download

Hover

Brightness

Blur

Contrast

Emulate media

File name

Track changes

Reduced motion

Viewport device

Rotate flip

Pdf landscape

Pdf print background

Pdf to image

Pdf format

Pdf media

Element overlap

Comparison by supported formats:

Feature / API

[ScreenshotOne](#screenshotone)

[ProxyCrawl](#proxycrawl)

JPG (JPEG)

PNG

WebP

PDF

GIF

JSON

Base64

SVG

AVIF

HEIF

TIFF

JP2 (JPEG 2000)

HTML

Comparison by pricing:

API

Average price per 1000 screenshots

The cheapest paid monthly plan per # of screenshots

Free option

Free screenshots

[ProxyCrawl](#proxycrawl)

$1.2

$39 per 10000

**[ScreenshotOne](#screenshotone)**

**$2.85**

**$14 per 1500**

**100**

### Add Screenshots

URL: [https://www.addscreenshots.com/](https://www.addscreenshots.com/)

Add Screenshots is a mature API that can be used as a product without an API. It allows export to a variety of file storage, scheduling, and screenshot comparisons.

Comparison by basic features:

Feature / API

[ScreenshotOne](#screenshotone)

[Add Screenshots](#add-screenshots)

URL

HTML

Selector

Viewport size

Device scale factor

Full page

Lazy load

Cache

Cache ttl

Cache ignore

Wait for event

User agent

Authentication

Accept languages

Custom cookies

Custom headers

Custom css

Custom js

Comparison by advanced features:

Feature / API

[Add Screenshots](#add-screenshots)

[ScreenshotOne](#screenshotone)

Omit background

Fail on status

Geolocation

Custom proxy

Block cookie banners

Block ads

Scroll to element

Custom html

Custom css url

Delay

Thumbnail width

Thumbnail height

Markdown

Signed links

Click by selector

Hide by selector

Clip

Custom renders on errors

Uptime sla

Custom js url

Grayscale

Extract html

Extract text

Dark mode

Block tracking

Placeholder

Export to ftp

Export to s3

Image quality

Block chats

Dedicated workers

Highlight

Wait for selector

Block requests

Ip location

Email

Webhook

No js

Timeout

Zapier

Sdk

Schedule

Metadata

Custom domain

Timezone

Stealth mode

Gpu rendering

Export to azure

Bplogin

Fail on redirect

Emulate touch screen

Emulate mobile

Emulate landscape

Download

Hover

Brightness

Blur

Contrast

Emulate media

File name

Track changes

Reduced motion

Viewport device

Rotate flip

Pdf landscape

Pdf print background

Pdf to image

Pdf format

Pdf media

Element overlap

Comparison by supported formats:

Feature / API

[ScreenshotOne](#screenshotone)

[Add Screenshots](#add-screenshots)

JPG (JPEG)

PNG

WebP

PDF

GIF

JSON

Base64

SVG

AVIF

HEIF

TIFF

JP2 (JPEG 2000)

HTML

Comparison by pricing:

API

Average price per 1000 screenshots

The cheapest paid monthly plan per # of screenshots

Free option

Free screenshots

**[ScreenshotOne](#screenshotone)**

**$2.85**

**$14 per 1500**

**100**

[Add Screenshots](#add-screenshots)

$3.88

$9 per 2500

100

### WhoisXMLAPI

URL: [https://website-screenshot.whoisxmlapi.com/api](https://website-screenshot.whoisxmlapi.com/api)

WhoisXMLApi is mostly centered around domain & IP data intelligence, but as a bonus, they provide a screenshot API. It is not their primary focus.

Comparison by basic features:

Feature / API

[ScreenshotOne](#screenshotone)

[WhoisXMLAPI](#whoisxmlapi)

URL

HTML

Selector

Viewport size

Device scale factor

Full page

Lazy load

Cache

Cache ttl

Cache ignore

Wait for event

User agent

Authentication

Accept languages

Custom cookies

Custom headers

Custom css

Custom js

Comparison by advanced features:

Feature / API

[ScreenshotOne](#screenshotone)

[WhoisXMLAPI](#whoisxmlapi)

Omit background

Fail on status

Geolocation

Custom proxy

Block cookie banners

Block ads

Scroll to element

Custom html

Custom css url

Delay

Thumbnail width

Thumbnail height

Markdown

Signed links

Click by selector

Hide by selector

Clip

Custom renders on errors

Uptime sla

Custom js url

Grayscale

Extract html

Extract text

Dark mode

Block tracking

Placeholder

Export to ftp

Export to s3

Image quality

Block chats

Dedicated workers

Highlight

Wait for selector

Block requests

Ip location

Email

Webhook

No js

Timeout

Zapier

Sdk

Schedule

Metadata

Custom domain

Timezone

Stealth mode

Gpu rendering

Export to azure

Bplogin

Fail on redirect

Emulate touch screen

Emulate mobile

Emulate landscape

Download

Hover

Brightness

Blur

Contrast

Emulate media

File name

Track changes

Reduced motion

Viewport device

Rotate flip

Pdf landscape

Pdf print background

Pdf to image

Pdf format

Pdf media

Element overlap

Comparison by supported formats:

Feature / API

[ScreenshotOne](#screenshotone)

[WhoisXMLAPI](#whoisxmlapi)

JPG (JPEG)

PNG

WebP

PDF

GIF

JSON

Base64

SVG

AVIF

HEIF

TIFF

JP2 (JPEG 2000)

HTML

Comparison by pricing:

API

Average price per 1000 screenshots

The cheapest paid monthly plan per # of screenshots

Free option

Free screenshots

**[ScreenshotOne](#screenshotone)**

**$2.85**

**$14 per 1500**

**100**

[WhoisXMLAPI](#whoisxmlapi)

$6.87

$19 per 1000

500

### Pikwy

URL: [https://pikwy.com/](https://pikwy.com/)

Pikwy has reasonable pricing, and it is not expensive. But they don’t support blocking ads and cookie banners, which might be an essential feature for many customers.

Comparison by basic features:

Feature / API

[ScreenshotOne](#screenshotone)

[Pikwy](#pikwy)

URL

HTML

Selector

Viewport size

Device scale factor

Full page

Lazy load

Cache

Cache ttl

Cache ignore

Wait for event

User agent

Authentication

Accept languages

Custom cookies

Custom headers

Custom css

Custom js

Comparison by advanced features:

Feature / API

[ScreenshotOne](#screenshotone)

[Pikwy](#pikwy)

Omit background

Fail on status

Geolocation

Custom proxy

Block cookie banners

Block ads

Scroll to element

Custom html

Custom css url

Delay

Thumbnail width

Thumbnail height

Markdown

Signed links

Click by selector

Hide by selector

Clip

Custom renders on errors

Uptime sla

Custom js url

Grayscale

Extract html

Extract text

Dark mode

Block tracking

Placeholder

Export to ftp

Export to s3

Image quality

Block chats

Dedicated workers

Highlight

Wait for selector

Block requests

Ip location

Email

Webhook

No js

Timeout

Zapier

Sdk

Schedule

Metadata

Custom domain

Timezone

Stealth mode

Gpu rendering

Export to azure

Bplogin

Fail on redirect

Emulate touch screen

Emulate mobile

Emulate landscape

Download

Hover

Brightness

Blur

Contrast

Emulate media

File name

Track changes

Reduced motion

Viewport device

Rotate flip

Pdf landscape

Pdf print background

Pdf to image

Pdf format

Pdf media

Element overlap

Comparison by supported formats:

Feature / API

[ScreenshotOne](#screenshotone)

[Pikwy](#pikwy)

JPG (JPEG)

PNG

WebP

PDF

GIF

JSON

Base64

SVG

AVIF

HEIF

TIFF

JP2 (JPEG 2000)

HTML

Comparison by pricing:

API

Average price per 1000 screenshots

The cheapest paid monthly plan per # of screenshots

Free option

Free screenshots

[Pikwy](#pikwy)

$1.89

$3 per 1000

**[ScreenshotOne](#screenshotone)**

**$2.85**

**$14 per 1500**

**100**

### purplescreenshots.com

URL: [https://purplescreenshots.com/](https://purplescreenshots.com/)

purplescreenshots is a new kid in the town but currently has a limited set of features — only basic ones.

Comparison by basic features:

Feature / API

[ScreenshotOne](#screenshotone)

[purplescreenshots.com](#purplescreenshotscom)

URL

HTML

Selector

Viewport size

Device scale factor

Full page

Lazy load

Cache

Cache ttl

Cache ignore

Wait for event

User agent

Authentication

Accept languages

Custom cookies

Custom headers

Custom css

Custom js

Comparison by advanced features:

Feature / API

[ScreenshotOne](#screenshotone)

[purplescreenshots.com](#purplescreenshotscom)

Omit background

Fail on status

Geolocation

Custom proxy

Block cookie banners

Block ads

Scroll to element

Custom html

Custom css url

Delay

Thumbnail width

Thumbnail height

Markdown

Signed links

Click by selector

Hide by selector

Clip

Custom renders on errors

Uptime sla

Custom js url

Grayscale

Extract html

Extract text

Dark mode

Block tracking

Placeholder

Export to ftp

Export to s3

Image quality

Block chats

Dedicated workers

Highlight

Wait for selector

Block requests

Ip location

Email

Webhook

No js

Timeout

Zapier

Sdk

Schedule

Metadata

Custom domain

Timezone

Stealth mode

Gpu rendering

Export to azure

Bplogin

Fail on redirect

Emulate touch screen

Emulate mobile

Emulate landscape

Download

Hover

Brightness

Blur

Contrast

Emulate media

File name

Track changes

Reduced motion

Viewport device

Rotate flip

Pdf landscape

Pdf print background

Pdf to image

Pdf format

Pdf media

Element overlap

Comparison by supported formats:

Feature / API

[ScreenshotOne](#screenshotone)

[purplescreenshots.com](#purplescreenshotscom)

JPG (JPEG)

PNG

WebP

PDF

GIF

JSON

Base64

SVG

AVIF

HEIF

TIFF

JP2 (JPEG 2000)

HTML

Comparison by pricing:

API

Average price per 1000 screenshots

The cheapest paid monthly plan per # of screenshots

Free option

Free screenshots

**[ScreenshotOne](#screenshotone)**

**$2.85**

**$14 per 1500**

**100**

[purplescreenshots.com](#purplescreenshotscom)

$3.45

$29 per 5000

### Bannerbear

URL: [https://www.bannerbear.com/use-cases/scenarios/auto-generate-screenshots-via-api/](https://www.bannerbear.com/use-cases/scenarios/auto-generate-screenshots-via-api/)

Bannerbear is a marketing automation API that allows creating templates and generating images from them. Screenshot API is not the central area of focus, but it has a limited set of features.

Comparison by basic features:

Feature / API

[ScreenshotOne](#screenshotone)

[Bannerbear](#bannerbear)

URL

HTML

Selector

Viewport size

Device scale factor

Full page

Lazy load

Cache

Cache ttl

Cache ignore

Wait for event

User agent

Authentication

Accept languages

Custom cookies

Custom headers

Custom css

Custom js

Comparison by advanced features:

Feature / API

[ScreenshotOne](#screenshotone)

[Bannerbear](#bannerbear)

Omit background

Fail on status

Geolocation

Custom proxy

Block cookie banners

Block ads

Scroll to element

Custom html

Custom css url

Delay

Thumbnail width

Thumbnail height

Markdown

Signed links

Click by selector

Hide by selector

Clip

Custom renders on errors

Uptime sla

Custom js url

Grayscale

Extract html

Extract text

Dark mode

Block tracking

Placeholder

Export to ftp

Export to s3

Image quality

Block chats

Dedicated workers

Highlight

Wait for selector

Block requests

Ip location

Email

Webhook

No js

Timeout

Zapier

Sdk

Schedule

Metadata

Custom domain

Timezone

Stealth mode

Gpu rendering

Export to azure

Bplogin

Fail on redirect

Emulate touch screen

Emulate mobile

Emulate landscape

Download

Hover

Brightness

Blur

Contrast

Emulate media

File name

Track changes

Reduced motion

Viewport device

Rotate flip

Pdf landscape

Pdf print background

Pdf to image

Pdf format

Pdf media

Element overlap

Comparison by supported formats:

Feature / API

[ScreenshotOne](#screenshotone)

[Bannerbear](#bannerbear)

JPG (JPEG)

PNG

WebP

PDF

GIF

JSON

Base64

SVG

AVIF

HEIF

TIFF

JP2 (JPEG 2000)

HTML

Comparison by pricing:

API

Average price per 1000 screenshots

The cheapest paid monthly plan per # of screenshots

Free option

Free screenshots

**[ScreenshotOne](#screenshotone)**

**$2.85**

**$14 per 1500**

**100**

[Bannerbear](#bannerbear)

$5.67

$49 per 1000

### screendot

URL: [https://screendot.io/](https://screendot.io/)

screendot is a new kid in the town with moderate pricing (not expensive) and supports essential features to take screenshots.

Comparison by basic features:

Feature / API

[ScreenshotOne](#screenshotone)

[screendot](#screendot)

URL

HTML

Selector

Viewport size

Device scale factor

Full page

Lazy load

Cache

Cache ttl

Cache ignore

Wait for event

User agent

Authentication

Accept languages

Custom cookies

Custom headers

Custom css

Custom js

Comparison by advanced features:

Feature / API

[ScreenshotOne](#screenshotone)

[screendot](#screendot)

Omit background

Fail on status

Geolocation

Custom proxy

Block cookie banners

Block ads

Scroll to element

Custom html

Custom css url

Delay

Thumbnail width

Thumbnail height

Markdown

Signed links

Click by selector

Hide by selector

Clip

Custom renders on errors

Uptime sla

Custom js url

Grayscale

Extract html

Extract text

Dark mode

Block tracking

Placeholder

Export to ftp

Export to s3

Image quality

Block chats

Dedicated workers

Highlight

Wait for selector

Block requests

Ip location

Email

Webhook

No js

Timeout

Zapier

Sdk

Schedule

Metadata

Custom domain

Timezone

Stealth mode

Gpu rendering

Export to azure

Bplogin

Fail on redirect

Emulate touch screen

Emulate mobile

Emulate landscape

Download

Hover

Brightness

Blur

Contrast

Emulate media

File name

Track changes

Reduced motion

Viewport device

Rotate flip

Pdf landscape

Pdf print background

Pdf to image

Pdf format

Pdf media

Element overlap

Comparison by supported formats:

Feature / API

[ScreenshotOne](#screenshotone)

[screendot](#screendot)

JPG (JPEG)

PNG

WebP

PDF

GIF

JSON

Base64

SVG

AVIF

HEIF

TIFF

JP2 (JPEG 2000)

HTML

Comparison by pricing:

API

Average price per 1000 screenshots

The cheapest paid monthly plan per # of screenshots

Free option

Free screenshots

[screendot](#screendot)

$0.57

$20 per 10000

1000

**[ScreenshotOne](#screenshotone)**

**$2.85**

**$14 per 1500**

**100**

### GeoScreenshot

URL: [https://www.geoscreenshot.com/](https://www.geoscreenshot.com/)

GeoScreenshot is a product that emphasizes UI testing from different geo locations, but as a bonus, they have a screenshot API.

Comparison by basic features:

Feature / API

[ScreenshotOne](#screenshotone)

[GeoScreenshot](#geoscreenshot)

URL

HTML

Selector

Viewport size

Device scale factor

Full page

Lazy load

Cache

Cache ttl

Cache ignore

Wait for event

User agent

Authentication

Accept languages

Custom cookies

Custom headers

Custom css

Custom js

Comparison by advanced features:

Feature / API

[ScreenshotOne](#screenshotone)

[GeoScreenshot](#geoscreenshot)

Omit background

Fail on status

Geolocation

Custom proxy

Block cookie banners

Block ads

Scroll to element

Custom html

Custom css url

Delay

Thumbnail width

Thumbnail height

Markdown

Signed links

Click by selector

Hide by selector

Clip

Custom renders on errors

Uptime sla

Custom js url

Grayscale

Extract html

Extract text

Dark mode

Block tracking

Placeholder

Export to ftp

Export to s3

Image quality

Block chats

Dedicated workers

Highlight

Wait for selector

Block requests

Ip location

Email

Webhook

No js

Timeout

Zapier

Sdk

Schedule

Metadata

Custom domain

Timezone

Stealth mode

Gpu rendering

Export to azure

Bplogin

Fail on redirect

Emulate touch screen

Emulate mobile

Emulate landscape

Download

Hover

Brightness

Blur

Contrast

Emulate media

File name

Track changes

Reduced motion

Viewport device

Rotate flip

Pdf landscape

Pdf print background

Pdf to image

Pdf format

Pdf media

Element overlap

Comparison by supported formats:

Feature / API

[ScreenshotOne](#screenshotone)

[GeoScreenshot](#geoscreenshot)

JPG (JPEG)

PNG

WebP

PDF

GIF

JSON

Base64

SVG

AVIF

HEIF

TIFF

JP2 (JPEG 2000)

HTML

Comparison by pricing:

API

Average price per 1000 screenshots

The cheapest paid monthly plan per # of screenshots

Free option

Free screenshots

**[ScreenshotOne](#screenshotone)**

**$2.85**

**$14 per 1500**

**100**

[GeoScreenshot](#geoscreenshot)

$36.85

$49 per 2500

### ScrapingBee

URL: [https://www.scrapingbee.com/features/screenshot/](https://www.scrapingbee.com/features/screenshot/)

ScrappingBee is a company developed around crawling and scrapping, but they also support taking screenshots. They have good experience working with headless browsers, but screenshot API capabilities are limited since this is not their primary area of focus.

Comparison by basic features:

Feature / API

[ScreenshotOne](#screenshotone)

[ScrapingBee](#scrapingbee)

URL

HTML

Selector

Viewport size

Device scale factor

Full page

Lazy load

Cache

Cache ttl

Cache ignore

Wait for event

User agent

Authentication

Accept languages

Custom cookies

Custom headers

Custom css

Custom js

Comparison by advanced features:

Feature / API

[ScreenshotOne](#screenshotone)

[ScrapingBee](#scrapingbee)

Omit background

Fail on status

Geolocation

Custom proxy

Block cookie banners

Block ads

Scroll to element

Custom html

Custom css url

Delay

Thumbnail width

Thumbnail height

Markdown

Signed links

Click by selector

Hide by selector

Clip

Custom renders on errors

Uptime sla

Custom js url

Grayscale

Extract html

Extract text

Dark mode

Block tracking

Placeholder

Export to ftp

Export to s3

Image quality

Block chats

Dedicated workers

Highlight

Wait for selector

Block requests

Ip location

Email

Webhook

No js

Timeout

Zapier

Sdk

Schedule

Metadata

Custom domain

Timezone

Stealth mode

Gpu rendering

Export to azure

Bplogin

Fail on redirect

Emulate touch screen

Emulate mobile

Emulate landscape

Download

Hover

Brightness

Blur

Contrast

Emulate media

File name

Track changes

Reduced motion

Viewport device

Rotate flip

Pdf landscape

Pdf print background

Pdf to image

Pdf format

Pdf media

Element overlap

Comparison by supported formats:

Feature / API

[ScreenshotOne](#screenshotone)

[ScrapingBee](#scrapingbee)

JPG (JPEG)

PNG

WebP

PDF

GIF

JSON

Base64

SVG

AVIF

HEIF

TIFF

JP2 (JPEG 2000)

HTML

Comparison by pricing:

API

Average price per 1000 screenshots

The cheapest paid monthly plan per # of screenshots

Free option

Free screenshots

[ScrapingBee](#scrapingbee)

$0.48

$49 per 20000

**[ScreenshotOne](#screenshotone)**

**$2.85**

**$14 per 1500**

**100**

### URL2PNG

URL: [https://www.url2png.com/](https://www.url2png.com/)

URL2PNG is one of the oldest screenshot APIs without a free plan but with a limited set of features.

Comparison by basic features:

Feature / API

[ScreenshotOne](#screenshotone)

[URL2PNG](#url2png)

URL

HTML

Selector

Viewport size

Device scale factor

Full page

Lazy load

Cache

Cache ttl

Cache ignore

Wait for event

User agent

Authentication

Accept languages

Custom cookies

Custom headers

Custom css

Custom js

Comparison by advanced features:

Feature / API

[ScreenshotOne](#screenshotone)

[URL2PNG](#url2png)

Omit background

Fail on status

Geolocation

Custom proxy

Block cookie banners

Block ads

Scroll to element

Custom html

Custom css url

Delay

Thumbnail width

Thumbnail height

Markdown

Signed links

Click by selector

Hide by selector

Clip

Custom renders on errors

Uptime sla

Custom js url

Grayscale

Extract html

Extract text

Dark mode

Block tracking

Placeholder

Export to ftp

Export to s3

Image quality

Block chats

Dedicated workers

Highlight

Wait for selector

Block requests

Ip location

Email

Webhook

No js

Timeout

Zapier

Sdk

Schedule

Metadata

Custom domain

Timezone

Stealth mode

Gpu rendering

Export to azure

Bplogin

Fail on redirect

Emulate touch screen

Emulate mobile

Emulate landscape

Download

Hover

Brightness

Blur

Contrast

Emulate media

File name

Track changes

Reduced motion

Viewport device

Rotate flip

Pdf landscape

Pdf print background

Pdf to image

Pdf format

Pdf media

Element overlap

Comparison by supported formats:

Feature / API

[ScreenshotOne](#screenshotone)

[URL2PNG](#url2png)

JPG (JPEG)

PNG

WebP

PDF

GIF

JSON

Base64

SVG

AVIF

HEIF

TIFF

JP2 (JPEG 2000)

HTML

Comparison by pricing:

API

Average price per 1000 screenshots

The cheapest paid monthly plan per # of screenshots

Free option

Free screenshots

**[ScreenshotOne](#screenshotone)**

**$2.85**

**$14 per 1500**

**100**

[URL2PNG](#url2png)

$4.96

$29 per 5000

### GetScreenshot

URL: [https://www.getscreenshotapi.com/](https://www.getscreenshotapi.com/)

GetScreenshot is a fresh API that supports blocking ads and cookie banners. The bonus of the API is that you can use the same API key for their scrapping project if needed.

Comparison by basic features:

Feature / API

[ScreenshotOne](#screenshotone)

[GetScreenshot](#getscreenshot)

URL

HTML

Selector

Viewport size

Device scale factor

Full page

Lazy load

Cache

Cache ttl

Cache ignore

Wait for event

User agent

Authentication

Accept languages

Custom cookies

Custom headers

Custom css

Custom js

Comparison by advanced features:

Feature / API

[ScreenshotOne](#screenshotone)

[GetScreenshot](#getscreenshot)

Omit background

Fail on status

Geolocation

Custom proxy

Block cookie banners

Block ads

Scroll to element

Custom html

Custom css url

Delay

Thumbnail width

Thumbnail height

Markdown

Signed links

Click by selector

Hide by selector

Clip

Custom renders on errors

Uptime sla

Custom js url

Grayscale

Extract html

Extract text

Dark mode

Block tracking

Placeholder

Export to ftp

Export to s3

Image quality

Block chats

Dedicated workers

Highlight

Wait for selector

Block requests

Ip location

Email

Webhook

No js

Timeout

Zapier

Sdk

Schedule

Metadata

Custom domain

Timezone

Stealth mode

Gpu rendering

Export to azure

Bplogin

Fail on redirect

Emulate touch screen

Emulate mobile

Emulate landscape

Download

Hover

Brightness

Blur

Contrast

Emulate media

File name

Track changes

Reduced motion

Viewport device

Rotate flip

Pdf landscape

Pdf print background

Pdf to image

Pdf format

Pdf media

Element overlap

Comparison by supported formats:

Feature / API

[ScreenshotOne](#screenshotone)

[GetScreenshot](#getscreenshot)

JPG (JPEG)

PNG

WebP

PDF

GIF

JSON

Base64

SVG

AVIF

HEIF

TIFF

JP2 (JPEG 2000)

HTML

Comparison by pricing:

API

Average price per 1000 screenshots

The cheapest paid monthly plan per # of screenshots

Free option

Free screenshots

[GetScreenshot](#getscreenshot)

$1.03

$7.99 per 2500

**[ScreenshotOne](#screenshotone)**

**$2.85**

**$14 per 1500**

**100**

### Restpack

URL: [https://restpack.io/screenshot](https://restpack.io/screenshot)

Restpack provides mature screenshot API with support of native SDKs. They support all necessary screenshot API features primarily.

Comparison by basic features:

Feature / API

[ScreenshotOne](#screenshotone)

[Restpack](#restpack)

URL

HTML

Selector

Viewport size

Device scale factor

Full page

Lazy load

Cache

Cache ttl

Cache ignore

Wait for event

User agent

Authentication

Accept languages

Custom cookies

Custom headers

Custom css

Custom js

Comparison by advanced features:

Feature / API

[ScreenshotOne](#screenshotone)

[Restpack](#restpack)

Omit background

Fail on status

Geolocation

Custom proxy

Block cookie banners

Block ads

Scroll to element

Custom html

Custom css url

Delay

Thumbnail width

Thumbnail height

Markdown

Signed links

Click by selector

Hide by selector

Clip

Custom renders on errors

Uptime sla

Custom js url

Grayscale

Extract html

Extract text

Dark mode

Block tracking

Placeholder

Export to ftp

Export to s3

Image quality

Block chats

Dedicated workers

Highlight

Wait for selector

Block requests

Ip location

Email

Webhook

No js

Timeout

Zapier

Sdk

Schedule

Metadata

Custom domain

Timezone

Stealth mode

Gpu rendering

Export to azure

Bplogin

Fail on redirect

Emulate touch screen

Emulate mobile

Emulate landscape

Download

Hover

Brightness

Blur

Contrast

Emulate media

File name

Track changes

Reduced motion

Viewport device

Rotate flip

Pdf landscape

Pdf print background

Pdf to image

Pdf format

Pdf media

Element overlap

Comparison by supported formats:

Feature / API

[ScreenshotOne](#screenshotone)

[Restpack](#restpack)

JPG (JPEG)

PNG

WebP

PDF

GIF

JSON

Base64

SVG

AVIF

HEIF

TIFF

JP2 (JPEG 2000)

HTML

Comparison by pricing:

API

Average price per 1000 screenshots

The cheapest paid monthly plan per # of screenshots

Free option

Free screenshots

**[ScreenshotOne](#screenshotone)**

**$2.85**

**$14 per 1500**

**100**

[Restpack](#restpack)

$4.54

$9.95 per 1000

### Geekflare

URL: [https://geekflare.com/api/screenshot](https://geekflare.com/api/screenshot)

Geekflare was launched in 2015 as a knowledge and idea base. But then API collection was added. And now it supports screenshot API. It does not support many features like other APIs.

Comparison by basic features:

Feature / API

[ScreenshotOne](#screenshotone)

[Geekflare](#geekflare)

URL

HTML

Selector

Viewport size

Device scale factor

Full page

Lazy load

Cache

Cache ttl

Cache ignore

Wait for event

User agent

Authentication

Accept languages

Custom cookies

Custom headers

Custom css

Custom js

Comparison by advanced features:

Feature / API

[ScreenshotOne](#screenshotone)

[Geekflare](#geekflare)

Omit background

Fail on status

Geolocation

Custom proxy

Block cookie banners

Block ads

Scroll to element

Custom html

Custom css url

Delay

Thumbnail width

Thumbnail height

Markdown

Signed links

Click by selector

Hide by selector

Clip

Custom renders on errors

Uptime sla

Custom js url

Grayscale

Extract html

Extract text

Dark mode

Block tracking

Placeholder

Export to ftp

Export to s3

Image quality

Block chats

Dedicated workers

Highlight

Wait for selector

Block requests

Ip location

Email

Webhook

No js

Timeout

Zapier

Sdk

Schedule

Metadata

Custom domain

Timezone

Stealth mode

Gpu rendering

Export to azure

Bplogin

Fail on redirect

Emulate touch screen

Emulate mobile

Emulate landscape

Download

Hover

Brightness

Blur

Contrast

Emulate media

File name

Track changes

Reduced motion

Viewport device

Rotate flip

Pdf landscape

Pdf print background

Pdf to image

Pdf format

Pdf media

Element overlap

Comparison by supported formats:

Feature / API

[ScreenshotOne](#screenshotone)

[Geekflare](#geekflare)

JPG (JPEG)

PNG

WebP

PDF

GIF

JSON

Base64

SVG

AVIF

HEIF

TIFF

JP2 (JPEG 2000)

HTML

Comparison by pricing:

API

Average price per 1000 screenshots

The cheapest paid monthly plan per # of screenshots

Free option

Free screenshots

[Geekflare](#geekflare)

$0.37

$10 per 10000

500

**[ScreenshotOne](#screenshotone)**

**$2.85**

**$14 per 1500**

**100**

### NoCodeAPI

URL: [https://nocodeapi.com/screenshot-api](https://nocodeapi.com/screenshot-api)

NoCodeAPI is a marketplace that provides simplified access to many APIs. In addition to that, they offer a simple screenshot API. The upside of using NoCodeAPI screenshot API is that you can also have access with the same key to their other products.

Comparison by basic features:

Feature / API

[ScreenshotOne](#screenshotone)

[NoCodeAPI](#nocodeapi)

URL

HTML

Selector

Viewport size

Device scale factor

Full page

Lazy load

Cache

Cache ttl

Cache ignore

Wait for event

User agent

Authentication

Accept languages

Custom cookies

Custom headers

Custom css

Custom js

Comparison by advanced features:

Feature / API

[ScreenshotOne](#screenshotone)

[NoCodeAPI](#nocodeapi)

Omit background

Fail on status

Geolocation

Custom proxy

Block cookie banners

Block ads

Scroll to element

Custom html

Custom css url

Delay

Thumbnail width

Thumbnail height

Markdown

Signed links

Click by selector

Hide by selector

Clip

Custom renders on errors

Uptime sla

Custom js url

Grayscale

Extract html

Extract text

Dark mode

Block tracking

Placeholder

Export to ftp

Export to s3

Image quality

Block chats

Dedicated workers

Highlight

Wait for selector

Block requests

Ip location

Email

Webhook

No js

Timeout

Zapier

Sdk

Schedule

Metadata

Custom domain

Timezone

Stealth mode

Gpu rendering

Export to azure

Bplogin

Fail on redirect

Emulate touch screen

Emulate mobile

Emulate landscape

Download

Hover

Brightness

Blur

Contrast

Emulate media

File name

Track changes

Reduced motion

Viewport device

Rotate flip

Pdf landscape

Pdf print background

Pdf to image

Pdf format

Pdf media

Element overlap

Comparison by supported formats:

Feature / API

[ScreenshotOne](#screenshotone)

[NoCodeAPI](#nocodeapi)

JPG (JPEG)

PNG

WebP

PDF

GIF

JSON

Base64

SVG

AVIF

HEIF

TIFF

JP2 (JPEG 2000)

HTML

Comparison by pricing:

API

Average price per 1000 screenshots

The cheapest paid monthly plan per # of screenshots

Free option

Free screenshots

[NoCodeAPI](#nocodeapi)

$0.46

$12 per 10000

60

**[ScreenshotOne](#screenshotone)**

**$2.85**

**$14 per 1500**

**100**

### ApiFlash

URL: [https://apiflash.com/](https://apiflash.com/)

ApiFlash has operated since 2017. It supports most of the required features by customers and runs on Google Chrome and AWS Lambda to ensure scalability.

Comparison by basic features:

Feature / API

[ScreenshotOne](#screenshotone)

[ApiFlash](#apiflash)

URL

HTML

Selector

Viewport size

Device scale factor

Full page

Lazy load

Cache

Cache ttl

Cache ignore

Wait for event

User agent

Authentication

Accept languages

Custom cookies

Custom headers

Custom css

Custom js

Comparison by advanced features:

Feature / API

[ScreenshotOne](#screenshotone)

[ApiFlash](#apiflash)

Omit background

Fail on status

Geolocation

Custom proxy

Block cookie banners

Block ads

Scroll to element

Custom html

Custom css url

Delay

Thumbnail width

Thumbnail height

Markdown

Signed links

Click by selector

Hide by selector

Clip

Custom renders on errors

Uptime sla

Custom js url

Grayscale

Extract html

Extract text

Dark mode

Block tracking

Placeholder

Export to ftp

Export to s3

Image quality

Block chats

Dedicated workers

Highlight

Wait for selector

Block requests

Ip location

Email

Webhook

No js

Timeout

Zapier

Sdk

Schedule

Metadata

Custom domain

Timezone

Stealth mode

Gpu rendering

Export to azure

Bplogin

Fail on redirect

Emulate touch screen

Emulate mobile

Emulate landscape

Download

Hover

Brightness

Blur

Contrast

Emulate media

File name

Track changes

Reduced motion

Viewport device

Rotate flip

Pdf landscape

Pdf print background

Pdf to image

Pdf format

Pdf media

Element overlap

Comparison by supported formats:

Feature / API

[ScreenshotOne](#screenshotone)

[ApiFlash](#apiflash)

JPG (JPEG)

PNG

WebP

PDF

GIF

JSON

Base64

SVG

AVIF

HEIF

TIFF

JP2 (JPEG 2000)

HTML

Comparison by pricing:

API

Average price per 1000 screenshots

The cheapest paid monthly plan per # of screenshots

Free option

Free screenshots

[ApiFlash](#apiflash)

$2.05

$7 per 1000

100

**[ScreenshotOne](#screenshotone)**

**$2.85**

**$14 per 1500**

**100**

### URL To Screenshot

URL: [https://urltoscreenshot.com/](https://urltoscreenshot.com/)

URL To Screenshot is an exemplary screenshot API with a minimal set of features that serves requests through the RapidAPI marketplace, which might be convenient for you if you already have access.

Comparison by basic features:

Feature / API

[ScreenshotOne](#screenshotone)

[URL To Screenshot](#url-to-screenshot)

URL

HTML

Selector

Viewport size

Device scale factor

Full page

Lazy load

Cache

Cache ttl

Cache ignore

Wait for event

User agent

Authentication

Accept languages

Custom cookies

Custom headers

Custom css

Custom js

Comparison by advanced features:

Feature / API

[ScreenshotOne](#screenshotone)

[URL To Screenshot](#url-to-screenshot)

Omit background

Fail on status

Geolocation

Custom proxy

Block cookie banners

Block ads

Scroll to element

Custom html

Custom css url

Delay

Thumbnail width

Thumbnail height

Markdown

Signed links

Click by selector

Hide by selector

Clip

Custom renders on errors

Uptime sla

Custom js url

Grayscale

Extract html

Extract text

Dark mode

Block tracking

Placeholder

Export to ftp

Export to s3

Image quality

Block chats

Dedicated workers

Highlight

Wait for selector

Block requests

Ip location

Email

Webhook

No js

Timeout

Zapier

Sdk

Schedule

Metadata

Custom domain

Timezone

Stealth mode

Gpu rendering

Export to azure

Bplogin

Fail on redirect

Emulate touch screen

Emulate mobile

Emulate landscape

Download

Hover

Brightness

Blur

Contrast

Emulate media

File name

Track changes

Reduced motion

Viewport device

Rotate flip

Pdf landscape

Pdf print background

Pdf to image

Pdf format

Pdf media

Element overlap

Comparison by supported formats:

Feature / API

[ScreenshotOne](#screenshotone)

[URL To Screenshot](#url-to-screenshot)

JPG (JPEG)

PNG

WebP

PDF

GIF

JSON

Base64

SVG

AVIF

HEIF

TIFF

JP2 (JPEG 2000)

HTML

Comparison by pricing:

API

Average price per 1000 screenshots

The cheapest paid monthly plan per # of screenshots

Free option

Free screenshots

[URL To Screenshot](#url-to-screenshot)

$2.08

$9.99 per 5000

1000

**[ScreenshotOne](#screenshotone)**

**$2.85**

**$14 per 1500**

**100**

### Abstract

URL: [https://www.abstractapi.com/api/website-screenshot-api](https://www.abstractapi.com/api/website-screenshot-api)

Abstract provides a set of APIs, and screenshot API is one of them. They probably offer a limited set of features because it is not their primary area of focus.

Comparison by basic features:

Feature / API

[ScreenshotOne](#screenshotone)

[Abstract](#abstract)

URL

HTML

Selector

Viewport size

Device scale factor

Full page

Lazy load

Cache

Cache ttl

Cache ignore

Wait for event

User agent

Authentication

Accept languages

Custom cookies

Custom headers

Custom css

Custom js

Comparison by advanced features:

Feature / API

[ScreenshotOne](#screenshotone)

[Abstract](#abstract)

Omit background

Fail on status

Geolocation

Custom proxy

Block cookie banners

Block ads

Scroll to element

Custom html

Custom css url

Delay

Thumbnail width

Thumbnail height

Markdown

Signed links

Click by selector

Hide by selector

Clip

Custom renders on errors

Uptime sla

Custom js url

Grayscale

Extract html

Extract text

Dark mode

Block tracking

Placeholder

Export to ftp

Export to s3

Image quality

Block chats

Dedicated workers

Highlight

Wait for selector

Block requests

Ip location

Email

Webhook

No js

Timeout

Zapier

Sdk

Schedule

Metadata

Custom domain

Timezone

Stealth mode

Gpu rendering

Export to azure

Bplogin

Fail on redirect

Emulate touch screen

Emulate mobile

Emulate landscape

Download

Hover

Brightness

Blur

Contrast

Emulate media

File name

Track changes

Reduced motion

Viewport device

Rotate flip

Pdf landscape

Pdf print background

Pdf to image

Pdf format

Pdf media

Element overlap

Comparison by supported formats:

Feature / API

[ScreenshotOne](#screenshotone)

[Abstract](#abstract)

JPG (JPEG)

PNG

WebP

PDF

GIF

JSON

Base64

SVG

AVIF

HEIF

TIFF

JP2 (JPEG 2000)

HTML

Comparison by pricing:

API

Average price per 1000 screenshots

The cheapest paid monthly plan per # of screenshots

Free option

Free screenshots

[Abstract](#abstract)

$1.22

$9 per 3000

100

**[ScreenshotOne](#screenshotone)**

**$2.85**

**$14 per 1500**

**100**

### screenshotlayer API

URL: [https://screenshotlayer.com/](https://screenshotlayer.com/)

screenshotlayer API is a product built and maintained by the apilayer company aiming to build a variety of reliable APIs. It supports basic screenshotting options but does not support blocking ads and cookie banners.

Comparison by basic features:

Feature / API

[ScreenshotOne](#screenshotone)

[screenshotlayer API](#screenshotlayer-api)

URL

HTML

Selector

Viewport size

Device scale factor

Full page

Lazy load

Cache

Cache ttl

Cache ignore

Wait for event

User agent

Authentication

Accept languages

Custom cookies

Custom headers

Custom css

Custom js

Comparison by advanced features:

Feature / API

[ScreenshotOne](#screenshotone)

[screenshotlayer API](#screenshotlayer-api)

Omit background

Fail on status

Geolocation

Custom proxy

Block cookie banners

Block ads

Scroll to element

Custom html

Custom css url

Delay

Thumbnail width

Thumbnail height

Markdown

Signed links

Click by selector

Hide by selector

Clip

Custom renders on errors

Uptime sla

Custom js url

Grayscale

Extract html

Extract text

Dark mode

Block tracking

Placeholder

Export to ftp

Export to s3

Image quality

Block chats

Dedicated workers

Highlight

Wait for selector

Block requests

Ip location

Email

Webhook

No js

Timeout

Zapier

Sdk

Schedule

Metadata

Custom domain

Timezone

Stealth mode

Gpu rendering

Export to azure

Bplogin

Fail on redirect

Emulate touch screen

Emulate mobile

Emulate landscape

Download

Hover

Brightness

Blur

Contrast

Emulate media

File name

Track changes

Reduced motion

Viewport device

Rotate flip

Pdf landscape

Pdf print background

Pdf to image

Pdf format

Pdf media

Element overlap

Comparison by supported formats:

Feature / API

[ScreenshotOne](#screenshotone)

[screenshotlayer API](#screenshotlayer-api)

JPG (JPEG)

PNG

WebP

PDF

GIF

JSON

Base64

SVG

AVIF

HEIF

TIFF

JP2 (JPEG 2000)

HTML

Comparison by pricing:

API

Average price per 1000 screenshots

The cheapest paid monthly plan per # of screenshots

Free option

Free screenshots

[screenshotlayer API](#screenshotlayer-api)

$1.17

$19.99 per 10000

100

**[ScreenshotOne](#screenshotone)**

**$2.85**

**$14 per 1500**

**100**

### Screenshot Machine

URL: [https://www.screenshotmachine.com/](https://www.screenshotmachine.com/)

Screenshot Machine is a mature screenshot API with a variety of options. They allow to set up image placeholders in case of screenshot rendering fails.

Comparison by basic features:

Feature / API

[ScreenshotOne](#screenshotone)

[Screenshot Machine](#screenshot-machine)

URL

HTML

Selector

Viewport size

Device scale factor

Full page

Lazy load

Cache

Cache ttl

Cache ignore

Wait for event

User agent

Authentication

Accept languages

Custom cookies

Custom headers

Custom css

Custom js

Comparison by advanced features:

Feature / API

[ScreenshotOne](#screenshotone)

[Screenshot Machine](#screenshot-machine)

Omit background

Fail on status

Geolocation

Custom proxy

Block cookie banners

Block ads

Scroll to element

Custom html

Custom css url

Delay

Thumbnail width

Thumbnail height

Markdown

Signed links

Click by selector

Hide by selector

Clip

Custom renders on errors

Uptime sla

Custom js url

Grayscale

Extract html

Extract text

Dark mode

Block tracking

Placeholder

Export to ftp

Export to s3

Image quality

Block chats

Dedicated workers

Highlight

Wait for selector

Block requests

Ip location

Email

Webhook

No js

Timeout

Zapier

Sdk

Schedule

Metadata

Custom domain

Timezone

Stealth mode

Gpu rendering

Export to azure

Bplogin

Fail on redirect

Emulate touch screen

Emulate mobile

Emulate landscape

Download

Hover

Brightness

Blur

Contrast

Emulate media

File name

Track changes

Reduced motion

Viewport device

Rotate flip

Pdf landscape

Pdf print background

Pdf to image

Pdf format

Pdf media

Element overlap

Comparison by supported formats:

Feature / API

[ScreenshotOne](#screenshotone)

[Screenshot Machine](#screenshot-machine)

JPG (JPEG)

PNG

WebP

PDF

GIF

JSON

Base64

SVG

AVIF

HEIF

TIFF

JP2 (JPEG 2000)

HTML

Comparison by pricing:

API

Average price per 1000 screenshots

The cheapest paid monthly plan per # of screenshots

Free option

Free screenshots

**[ScreenshotOne](#screenshotone)**

**$2.85**

**$14 per 1500**

**100**

[Screenshot Machine](#screenshot-machine)

$2.92

$9 per 2500

100

### ScreenshotAPI

URL: [https://www.screenshotapi.net/](https://www.screenshotapi.net/)

ScreenshotAPI is one of the most powerful APIs on the Internet. It is scalable, has various options, and has moderate pricing.

Comparison by basic features:

Feature / API

[ScreenshotOne](#screenshotone)

[ScreenshotAPI](#screenshotapi)

URL

HTML

Selector

Viewport size

Device scale factor

Full page

Lazy load

Cache

Cache ttl

Cache ignore

Wait for event

User agent

Authentication

Accept languages

Custom cookies

Custom headers

Custom css

Custom js

Comparison by advanced features:

Feature / API

[ScreenshotAPI](#screenshotapi)

[ScreenshotOne](#screenshotone)

Omit background

Fail on status

Geolocation

Custom proxy

Block cookie banners

Block ads

Scroll to element

Custom html

Custom css url

Delay

Thumbnail width

Thumbnail height

Markdown

Signed links

Click by selector

Hide by selector

Clip

Custom renders on errors

Uptime sla

Custom js url

Grayscale

Extract html

Extract text

Dark mode

Block tracking

Placeholder

Export to ftp

Export to s3

Image quality

Block chats

Dedicated workers

Highlight

Wait for selector

Block requests

Ip location

Email

Webhook

No js

Timeout

Zapier

Sdk

Schedule

Metadata

Custom domain

Timezone

Stealth mode

Gpu rendering

Export to azure

Bplogin

Fail on redirect

Emulate touch screen

Emulate mobile

Emulate landscape

Download

Hover

Brightness

Blur

Contrast

Emulate media

File name

Track changes

Reduced motion

Viewport device

Rotate flip

Pdf landscape

Pdf print background

Pdf to image

Pdf format

Pdf media

Element overlap

Comparison by supported formats:

Feature / API

[ScreenshotOne](#screenshotone)

[ScreenshotAPI](#screenshotapi)

JPG (JPEG)

PNG

WebP

PDF

GIF

JSON

Base64

SVG

AVIF

HEIF

TIFF

JP2 (JPEG 2000)

HTML

Comparison by pricing:

API

Average price per 1000 screenshots

The cheapest paid monthly plan per # of screenshots

Free option

Free screenshots

**[ScreenshotOne](#screenshotone)**

**$2.85**

**$14 per 1500**

**100**

[ScreenshotAPI](#screenshotapi)

$6.11

$9 per 1000

100

Summary

-------

I tried to make the comparison as objective as possible. Yes, it might be that my API is the best one, or it might not be. Nevertheless, I fully embrace it and am ready to improve. In the long term, I know it will be the best screenshot API anyway.

If you have any questions or want to suggest edits to the comparison, [feel free to contact me](mailto:hey@screenshotone.com).

I hope the post helped you to choose the best solution for your problem and have a nice day 👋

----
url: https://screenshotone.com/changelog/improved-webhooks-documentation-and-playground
----

Improved webhooks documentation and playground

==============================================

We improved the webhooks documentation and playground.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Oct 26, 2025

Ensured all webhooks options are available in the ScreenshotOne Playground and improved the documentation:

[Check out the full documentation on how to use webhooks with ScreenshotOne](/docs/async-and-webhooks/).

If you have any suggestions or ideas, please let us know at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Stop scrolling screenshots when a given selector is visible](/changelog/animated-scrolling-till-selector/)

New options were added to the ScreenshotOne API to stop scrolling screenshots when a given selector is reached.

Read more →

1 min read

#### [Documentation for LLMs](/changelog/docs-for-llms/)

ScreenshotOne now supports documentation format specifically targeted for LLMs—llms.txt and llms-full.txt.

Read more →

1 min read

#### [ScreenshotOne is available on Pipedream](/changelog/pipedream-integration/)

Automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos in Pipedream.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/code-examples/php
----

[Skip to content](#_top)

PHP SDK and Code Examples

=========================

Copy page

If you have any questions, please, reach out at `support@screenshotone.com`.

### Installation

Run the next command to install the PHP SDK to take screenshots:

Terminal window

    1composer require screenshotone/sdk:^1.0

### Usage

Don’t forget to [sign up](https://dash.screenshotone.com/sign-up) to get access and secret keys.

Generate a screenshot URL without executing the request. Or download the screenshot. It is up to you:

    1<?php2

    3use ScreenshotOne\Sdk\Client;4use ScreenshotOne\Sdk\TakeOptions;5

    6$client = new Client('<access key>', '<secret key>');7

    8$options = TakeOptions::url("https://example.com")9    ->fullPage(true)10    ->delay(2)11    ->geolocationLatitude(48.857648)12    ->geolocationLongitude(2.294677)13    ->geolocationAccuracy(50);14

    15$url = $client->generateTakeUrl($options);16echo $url.PHP_EOL;17// expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com...18

    19$image = $client->take($options);20file_put_contents('example.png', $image);21// the screenshot is stored in the example.png file

Check out [other SDKs and code examples](/docs/code-examples/).

----
url: https://screenshotone.com/docs/errors/content-contains-specified-string
----

[Skip to content](#_top)

Content Contains Specified String

=================================

Copy page

It is an API error returned when the page content contains a specified string that triggers a failure condition.

    1{2    "is_successful": false,3    "error_code": "content_contains_specified_string",4    "error_message": "The page content contains the specified string by the `fail_if_content_contains` option. If it seems to be a mistake or not what you expected, please, reach out to `support@screenshotone.com` as quickly as possible, and we will assist and try to resolve your problem.",5    "documentation_url": "https://screenshotone.com/docs/errors/content-contains-specified-string/"6}

The page content contains the specified string by the `fail_if_content_contains` option. If it seems to be a mistake or not what you expected, please, reach out to `support@screenshotone.com` as quickly as possible, and we will assist and try to resolve your problem.

----
url: https://screenshotone.com/changelog/7
----

Changes and updates

-------------------

Stay updated with the latest information about new features, bug fixes, and optimizations at ScreenshotOne

### Product updates in the last 12 months

Feb 24, 2025

#### [Transfer organization ownership](/changelog/organization-transfer-ownership/)

From today, you can transfer organization ownership to another user.

Read more →

1 min read

Feb 24, 2025

#### [Rendering website screenshots in LLMs](/changelog/mcp-server/)

Integrate ScreenshotOne to render website screenshots with any LLM that supports MCP.

Read more →

3 min read

Feb 16, 2025

#### [Improved error handling when networking fails](/changelog/improved-error-handling-when-networking-fails/)

We have improved error handling for network failures. Now, we ensure screenshot rendering fails instead of returning an error image.

Read more →

1 min read

Feb 7, 2025

#### [Include shadow DOM when requesting the page content](/changelog/include-shadow-dom/)

A new version of the ScreenshotOne API has been just deployed. It allows you to include the shadow DOM contents when requesting the page content.

Read more →

1 min read

Feb 2, 2025

#### [Fail rendering if the content is missing a string](/changelog/fail-if-content-missing/)

There is a set of use cases when you want to fail screenshot rendering and retry it if the content of the page is missing a string.

Read more →

1 min read

Jan 28, 2025

#### [Better authentication for ScreenshotOne dashboard](/changelog/improved-dashboard-authentication/)

Email and password authentication, email change flow, email verification, GitHub authentication, and improved UX/UI.

Read more →

6 min read

Jan 12, 2025

#### [Control scrolling into view when taking screenshots by selector](/changelog/selector-scroll-into-view-option/)

You can now control scrolling into view when taking screenshots by selector. It allows render more accurate screenshots.

Read more →

1 min read

Dec 17, 2024

#### [Improved proxy validation](/changelog/improved-proxy-validation/)

Stricter proxy option validation to prevent misconfiguration.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/tags/engineering
----

Engineering

-----------

Engineering notes, debugging stories, and product deep dives.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

[Engineering](/blog/tags/engineering/)

#### [A four day hiking trip into ScreenshotOne infrastructure to solve an issue](/blog/debugging-and-fixing-a-tricky-issue/)

A short story about how I debugged and fixed an uptime issue.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jul 21, 2025

•

3 min read

[Engineering](/blog/tags/engineering/)

#### [Cloudflare Workers as an API gateway](/blog/cloudflare-workers/)

Check out how ScreenshotOne relies on Cloudflare Workers as an API gateway to enhance performance, reliability, and cost-efficiency.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Aug 3, 2024

•

7 min read

[Engineering](/blog/tags/engineering/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Let's build a screenshot API](/blog/building-screenshot-api/)

Two years have passed since the launch of ScreenshotOne, and I want to do a fun coding exercise and build a tiny subset of what the API is today, but from scratch.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

May 26, 2024

•

16 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/integrations/dirstarter
----

Integrations

1 min read

Dirstarter

==========

Build a directory with Dirstarter and add website screenshots with ScreenshotOne.

Code CMS

[Dirstarter](https://dirstarter.com/) is a complete, customizable Next.js directory template with built-in payments, SEO, and AI content – pay once, launch unlimited directories.

[](https://dirstarter.com/)

You can build a directory with Dirstarter and add website screenshots with ScreenshotOne to it.

If you want a hosted directory solution and also with screenshots automation, check out [Directify with ScreenshotOne integration](/integrations/directify/) instead.

Resources

---------

*   [Documentation](https://dirstarter.com/docs/integrations/media)

“It is super simple, works very well and fast.

Klaas Foppen

Founder, [Promptwatch](https://screenshotone.com/blog/promptwatch/)

Check more Integrations

-----------------------

No-code tools, AI, code libraries, and more.

[Check more Integrations](/integrations/)

Code API

### SDK and Code Examples

Use the SDKs and code examples to take screenshots in your own code.

[Read more →](/integrations/code/)

No-Code Automation

### Make

Use ScreenshotOne with Make to automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

[Read more →](/integrations/make/)

No-Code Automation

### Clay

Generate website screenshots inside Clay to qualify leads, assess content, and enrich rows with visual context automatically.

[Read more →](/integrations/clay/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/rivalflowai-by-spyfu
----

How RivalFlowAI uses ScreenshotOne to help its customers improve existing content

=================================================================================

RivalFlowAI is a new product by SpyFu, launched in 2023. The product helps to improve existing content with AI by finding the missing pieces your page needs to rank.

[Customer story](/blog/tags/customer-stories/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Apr 9, 2024

How RivalFlowAI helps their customers

-------------------------------------

The idea is simple, you write and publish your content. And then [RivalFlowAI](https://www.rivalflow.com/):

1.  Looks at what your page ranks for.

2.  Identifies gaps between your page and pages that outrank it.

3.  Recommends improvements to fill the gaps.

Then you can update the content on your own or by using AI content generation and suggestions by RivalFlowAI.

Wait and you rank higher and get more traffic.

How RivalFlowAI uses ScreenshotOne

----------------------------------

RivalFlow needs to render a lot of screenshots to visualize the content and scrape the content to analyze the gaps.

[](https://www.rivalflow.com/)

ScreenshotOne processes a really high volume of screenshots with a high success rate. Taking all the boring and scaling work and allowing RivalFlowAI to focus on its core business.

Feedback by the RivalFlowAI founder

-----------------------------------

I asked Mike Roberts, a founder of [SpyFu](https://www.spyfu.com/), for a testimonial and that’s what [he replied](https://twitter.com/mrspy/status/1777742081508991425):

> ScreenshotOne is the best product on the market - and that’s before you take into account how responsive and easy Dmytro is to work with.

> 

> Any time we’ve found a rare edge case, it’s been resolved in hours.

> 

> Great company, great founder - can’t say enough!

More Examples and Use Cases

---------------------------

You might be also interested in how [Stagetimer automates Open Graph image generation](/blog/how-stagetimer-automates-og-image-generation/).

ScreenshotOne supports a huge variety of uses including but not only:

*   [Automating Open Graph image generation](/use-cases/open-graph-images/).

*   [Generating personalized videos](/use-cases/automate-personalized-videos/).

*   [Rendering site thumbnails for search previews](/use-cases/preview-search-results/)

And [many more](/use-cases/).

Read more customer stories

--------------------------

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

[View all posts](/blog/tags/customer-stories/)

#### [How Branding 5 uses ScreenshotOne for competitor analysis](/blog/how-branding5-uses-screenshotone/)

If you are interested in diving deeper into the Branding 5 use case and discover if ScreenshotOne might be useful for you, too, keep reading.

Read more

#### [Why Promptwatch wins in the AI search space](/blog/promptwatch/)

About how Promptwatch uses ScreenshotOne to automate website screenshots and why that matters.

Read more

#### [How Spectate uses ScreenshotOne to improve incident observability](/blog/how-spectate-uses-screenshotone/)

If you are interested in diving deeper into the Spectate use case and discover if ScreenshotOne might be useful for you, too, keep reading.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/tags/screenshot-rendering/2
----

Screenshot Rendering

--------------------

Best practices for rendering reliable website screenshots.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to screenshot websites in Next.js](/blog/nextjs-screenshots/)

There 3 simple ways to render website screenshots in Next.js—using Puppeteer, Cloudflare Browser Rendering, and a screenshot API like ScreenshotOne or similar.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

May 7, 2024

•

5 min read

[Engineering](/blog/tags/engineering/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Let's build a screenshot API](/blog/building-screenshot-api/)

Two years have passed since the launch of ScreenshotOne, and I want to do a fun coding exercise and build a tiny subset of what the API is today, but from scratch.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

May 26, 2024

•

16 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Why and how to choose a screenshot API](/blog/why-and-how-to-choose-a-screenshot-api/)

You don't need a screenshot API if it is a one-off task for you and you can use some library for screenshotting.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 20, 2024

•

6 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [3 best screenshot APIs in 2026](/blog/best-screenshot-apis/)

The truth is, that there is no single best screenshot API that fits everyone. But some APIs stand out and shine when compared to others. Also, it depends on your use case and needs which must be included in considering what API to use.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jan 6, 2026

•

7 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Rendering screenshots of social media pages](/blog/how-to-take-screenshots-of-social-media-pages/)

Social media platforms often restrict automation, but with the right tools and care for compliance, capturing screenshots is possible.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jul 4, 2025

•

2 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots with C# (.NET)](/blog/how-to-take-website-screenshots-with-csharp-dotnet/)

The article examines how you can take screenshots of any URL with C# (.NET) by using PuppeteerSharp, or screenshot API as a service.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 24, 2023

•

3 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Take a screenshot "from the surface" in Puppeteer and Chrome DevTools Protocol](/blog/take-a-screenshot-from-the-surface-in-puppeteer-and-chrome-devtools-protocol/)

Let's talk about the fromSurface parameter introduced in Chrome DevTools Protocol which will soon be supported by Puppeteer or even supported now at the time when you are reading the post.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 3, 2023

•

1 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots in Python](/blog/how-to-take-website-screenshots-in-python/)

With Python, you can take website screenshots in multiple ways. But the best way to do it depends solely on your needs and your use case. Let's quickly examine all the options.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Mar 18, 2024

•

8 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/errors/timeout
----

[Skip to content](#_top)

Timeout Error

=============

Copy page

It is an API error returned when the API can’t render screenshots or video within the specified timeout:

    1{2  "is_successful": false,3  "error_code": "timeout_error",4  "error_message": "The screenshot couldn't be taken within the specified timeout. Either the site doesn't respond quickly, or rendering takes longer than expected. Play with the `timeout` or the `navigation_timeout` options or reach the support for the investigation.",5  "documentation_url": "https://screenshotone.com/docs/errors/"6}

Reasons and how to fix

----------------------

Let’s quickly consider possible reasons and possible solutions.

### Timeout is too small

By default, the timeout is about 60 seconds. You must fit your rendering request within that timeout.

You can:

Either use asynchronous requests and webhooks to get the results. And set the timeout up to 300 seconds. Or you can try to increase the timeout up to 90 seconds.

### Delay is too big

Make sure that your delay is not too big, e.g. if you set it to 30 seconds, and it takes the website to load for 30 seconds, it is better to decrease the delay.

### A website is not loading properly

Some sites just take too much time to load or they don’t emit DOMContentLoaded events.

Try to play with different values of the wait\_until option and see if it helps.

### Long duration of the video

Often when you record a video of a long duration, the API must not respond in time. Since it takes to both record a video and stream it.

Try to decrease the video duration you are recording, it might help.

Reach out to support

--------------------

If nothing helps you, please, reach out to `support@screenshotone.com` and we will try to help you as fast as possible.

----
url: https://screenshotone.com/changelog/fixed-a-playground-issue
----

Fixed a validation issue in the playground

==========================================

We fixed a validation issue in the ScreenshotOne playground caused by selector scroll into view.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Oct 20, 2025

Enabling option to scroll the element into view in the playground was causing issues with form validations. Because, when it was disabled, it was still false, however in the API this option is not allowed to be sent in case if selector is not specified.

Now, the validation issue is fixed and the playground works as expected. The option is disabled by default when the selector is not specified.

If you have any feedback, please reach out to us at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [More algorithms for screenshots by selectors](/changelog/selector-algorithm/)

We added more algorithms for screenshots by selectors.

Read more →

1 min read

#### [Added a "copy page" button in documentation](/changelog/copy-page-button-in-docs/)

You can now copy the page content as Markdown for LLMs and more.

Read more →

1 min read

#### [Better and more extensible PDF rendering](/changelog/better-and-more-extensible-pdf-rendering/)

ScreenshotOne supports PDF rendering for a long time but it was used till recently by a small group of customers. Growing demand in PDF rendering required updating the API. And today, we introduce new options for PDF customization.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/how-to-build-a-programmatic-seo-site-with-automated-website-screenshots-using-screenshotone-airtable-and-launchman
----

How to build a Programmatic SEO site with automated website screenshots using ScreenshotOne, Airtable, and Launchman

====================================================================================================================

Programmatic SEO is a great growth hacking strategy where you create a large number of content pages that rank for long-tailed keywords on Google.

[Blog post](/blog/) 3 min read

#### Written by

[Sukh](/contributors/sukh/)

#### Published on

Jan 10, 2023

We will use [Launchman to create Programmatic SEO pages](https://launchman.com) from [Airtable](https://airtable.com) data and use [ScreenshotOne](https://screenshotone.com) to automate taking website screenshots, so we don’t have to do it manually one by one.

What we will build

------------------

For my Programmatic SEO site, we’ll be hand-picking the best “SaaS Landing pages” and creating pages out of them for designers/developers to get inspired by; very similar to [Landing Hunt (landing page examples)](https://landinghunt.com).

We will start by adding shopify.com and other known brands, for example.

 Sorry, your browser doesn't support embedded videos.

Step 1: Prepare your Airtable

-----------------------------

I prepared a simple Airtable that contains:

1.  Name - Name of the company.

2.  Description - What they do.

3.  Website - URL of the company.

You can duplicate my data by importing this CSV into Airtable.

Step 2: Set up ScreenshotOne

----------------------------

[ScreenshotOne](https://screenshotone.com) lets you take a screenshot by simply copy/pasting a URL into the browser. This is our secret sauce.

1.  Sign up for ScreenshotOne [here](https://dash.screenshotone.com/sign-in). The free plan lets you take 100 screenshots every month.

2.  From the Dashboard > Access, [Grab your Access key](https://dash.screenshotone.com/access).

3.  Test it out by taking a screenshot of the Google homepage. In your browser, type: `https://api.screenshotone.com/take?access_key={{YOUR ACCESS KEY}}&url=https://google.com&device_scale_factor=1&format=jpg&cache=false`. Be sure to replace the {{YOUR ACCESS KEY}} with your Access Key from the last step.

4.  If you see the Google screenshot as the response, you are good to go!

Step 3: Adding ScreenshotOne to Airtable

----------------------------------------

Airtable has an `Attachment` field that can hold images per row. We will automatically download the screenshot image we get from ScreenshotOne and save it in that column.

1.  Create a new column called “Image URL” that is of type “Formula”. The formula should be `CONCATENATE("https://api.screenshotone.com/take?access_key=&LCUB;&LCUB;ACCESS_KEY&RCUB;&RCUB;&url=", Website, "&device_scale_factor=1&format=jpg&cache=false")`. And click Create.

2.  Create another column called “Image” which is an “Attachment”. This is where we will store the downloaded image.

3.  On the top right, under **Extensions**, click “Add an extension”. Look for “Convert URLs to attachments” and click “Add script”.

3.  Open the script and add:

    *   Table as the current table

    *   URL field - Image URL

    *   Attachment field - Image

4.  Click Run. You can safely close the script and watch the images get populated in the “Image” column.

5.  If everything went correctly, you should see the Image column start to fill up with website screenshots for each row.

Step 4: Putting it all together in Launchman

--------------------------------------------

[Launchman](https://launchman.com) is a great no-code tool that helps you create Programmatic SEO pages quickly. You start by designing a page template and it takes care of applying Airtable data to it row by row and creating many pages from it.

1.  Sign up for an account [here](https://app.launchman.com).

2.  Create a new site and create a new collection called “Landing Pages”.

3.  Connect your Airtable’s URL and [API key](./https://airtable.com/account). This will automatically sync the data from Airtable to Launchman so we can start designing a page template.

4.  And the data is synced:

Step 5: Design a Page Template

------------------------------

1.  Click on “Page Designer”.

2.  Start by creating a title up top with a Text block that has the value:

        1# &LCUB;&LCUB;Name&RCUB;&RCUB; Landing Page

4.  We can now add the screenshot with the Image block:

        1&LCUB;&LCUB;Image_0&RCUB;&RCUB;

    This will bring in the website screenshots we took with ScreenshotOne.

5.  A small description of the website is a nice to have. Add the value:

        1&LCUB;&LCUB;Description&RCUB;&RCUB;2

        3[Visit URL ->](&LCUB;&LCUB;Website&RCUB;&RCUB;)

Great! We have a pretty good looking page now.

Step 6: Design the slugs

------------------------

Before we put the pages live, we should configure the slugs.

1.  Under the SEO settings, update the Slug to be “/&LCUB;&LCUB;Name&RCUB;&RCUB;“. This will make sure that the pages have appropriate names.

2.  Click “Save”.

3.  Your pages should now be published. Check them out by typing in your browser: `<sitename>.launchman.page/landing-page/shopify`

Summary

-------

Amazing! You just created a Programmatic SEO website using ScreenshotOne, Launchman, and Airtable!

Read more posts

---------------

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

[View all posts](/blog/)

#### [ScreenshotOne October 2025 updates](/blog/screenshotone-october-2025-updates/)

Metadata content format, upgraded dashboard, improved webhooks, updated Go SDK, Make conference, and AWS disruption lessons.

Read more

#### [ScreenshotOne made it to the official Make conference](/blog/make-conference/)

One of our friends noticed ScreenshotOne at the official Make conference

Read more

#### [Unveil the Power of Automation with ScreenshotOne and Zapier](/blog/unveil-the-power-of-automation-with-screenshotone-and-zapier/)

I am thrilled to announce an exciting update for the ScreenshotOne users – the much-anticipated integration of ScreenshotOne with Zapier. This powerful combination is here to enhance your automation journey and expand your workflow capabilities to new heights.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/dymaic-invoice-receipt-pdfs
----

Automate Website Screenshots

1 min read

Dynamic invoices and receipts

=============================

Generate pixel-perfect invoices and receipts from HTML templates.

SaaS apps, e‑commerce stores, and marketplaces all need to hand customers a clean, branded invoice every time money changes hands. Building that in‑house means running a full browser rendering stack, patching security updates, and fixing edge‑case CSS bugs—just to spit out a PDF.

[ScreenshotOne’s PDF Generation API](/pdf-generation-api/) removes all of that weight. Send the HTML template you already use for your on‑screen invoice (or its public URL) to the /take endpoint with format=pdf, and the API returns a pixel‑perfect PDF—fonts, images, and media queries included. You keep design control in your codebase; ScreenshotOne handles the heavy Chromium rendering, caching, and scaling.

The result is simple: less infrastructure, faster shipping, and invoices that always look right. No EC2 instances, no Puppeteer upkeep, and no late‑night “the PDF is blank” alerts. Drop the API call into your checkout flow and focus on building features your customers actually see.

ScreenshotOne is the best product on the market - and that's before you take into account how responsive and easy Dmytro is to work with.

Any time we've found a rare edge case, it's been resolved in hours.

Great company, great founder - can't say enough!

Mike Roberts

Founder, [SpyFu](https://www.spyfu.com/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/font-legal-compliance
----

Automate Website Screenshots

1 min read

Font Legal Compliance Check

===========================

Ensure fonts used on websites are legally compliant to avoid copyright issues.

Use [ScreenshotOne font detection API](/font-detection-api/) to ensure fonts used on websites are legally compliant to avoid copyright issues.

Preventing Font Licensing Issues

--------------------------------

Font licensing violations can result in significant legal and financial consequences. ScreenshotOne’s font detection API enables development and legal compliance tools to automatically identify all fonts used on a website and verify their licensing status.

Automated Compliance Audits

---------------------------

By integrating the API, companies can regularly audit their websites to ensure all fonts are properly licensed. This is especially important for organizations with multiple websites or large teams where manual font tracking becomes impractical.

Check out [our guide on how to detect website fonts](/docs/guides/how-to-detect-website-fonts/) for more details.

Risk Mitigation and Cost Savings

--------------------------------

Font licensing disputes can be expensive and damaging to a company’s reputation. By using ScreenshotOne API to automate font detection and compliance checking, organizations can proactively identify and resolve licensing issues before they become legal problems. This preventive approach saves significant costs compared to defending against copyright infringement claims.

Compared to the tool I used before ScreenshotOne's image generation is very quick. Even the full-page screenshot only takes a couple of seconds.

I love the URL signing feature! It allows me to use a serverless stack without exposing the API key.

If you need a screenshot API, ScreenshotOne is the way to go!

Lukas Hermann

Co-Founder, [stagetimer.io](https://stagetimer.io/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

### Font Accessibility Checks

Use our font detection API to check fonts and and research whether websites use readable fonts for people with visual impairments or reading disabilities.

[Read more →](/use-cases/font-accessibility-checks/)

### Automated Web Audits with Font Analysis

With our font detection API generate comprehensive typography reports to optimize websites for aesthetics and performance.

[Read more →](/use-cases/automated-web-audits-fonts/)

### Browser Extension Font Detection

Build browser extensions to allow users to identify and learn about fonts on any website with a single click.

[Read more →](/use-cases/browser-extension-font-detection/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/integrations/nemoclaw
----

Integrations

1 min read

NemoClaw

========

Use ScreenshotOne with NemoClaw to capture website screenshots for enterprise AI agents, browser verification, secure reporting, and visual audit trails.

AI Enterprise Automation

Resources

---------

*   [Screenshots for NemoClaw](https://screenshotone.com/nemoclaw/)

*   [More about the use case of website screenshots in NemoClaw](https://screenshotone.com/use-cases/nemoclaw-agents/)

I’ve been using ScreenshotOne for 3 years and couldn’t run Saaspo without it.

You can tell Dmytro really cares about the product as it keeps getting better.

Highly recommend to anyone looking for a screenshot tool!

Andy Hooke

Founder, [Saaspo](https://screenshotone.com/blog/saaspo/)

Check more Integrations

-----------------------

No-code tools, AI, code libraries, and more.

[Check more Integrations](/integrations/)

No-Code Automation

### Clay

Generate website screenshots inside Clay to qualify leads, assess content, and enrich rows with visual context automatically.

[Read more →](/integrations/clay/)

No-Code Automation

### Zapier

Automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos in Zapier.

[Read more →](/integrations/zapier/)

Code API

### SDK and Code Examples

Use the SDKs and code examples to take screenshots in your own code.

[Read more →](/integrations/code/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/openclaw-workflows
----

Automate Website Screenshots

3 min read

Screenshots for OpenClaw Workflows

==================================

Use ScreenshotOne to automate website screenshots inside OpenClaw workflows for visual checks, proactive monitoring, and image-based reporting.

OpenClaw is not just another chat interface. It is a personal AI assistant that lives in WhatsApp, Telegram, Discord, or other chat apps, runs proactively in the background, and can build its own skills when it needs a new capability.

That makes it a strong fit for web workflows: checking pages, reacting to events, preparing briefings, and following up automatically. But when a workflow touches the web, text alone is often not enough. You usually want to see what the page actually looked like.

If you are looking for a more enterprise-oriented setup, see [Screenshots for NemoClaw Agents](/use-cases/nemoclaw-agents/). NemoClaw is positioned more around controlled deployment, privacy, and internal review flows, while OpenClaw is a better fit when the workflow behaves more like a proactive assistant across chat surfaces.

[ScreenshotOne fits naturally here](/openclaw/). Let OpenClaw decide what to monitor, when to run, and who to notify. Let ScreenshotOne handle the hard part of rendering modern websites reliably and returning clean screenshots your Claw can send, store, or analyze.

Where ScreenshotOne fits in a Claw workflow

-------------------------------------------

OpenClaw is good at orchestration. It can watch inboxes, run on schedules, browse the web, and create new skills. ScreenshotOne is a good complement when the output of that work should include visual proof.

Instead of asking your Claw to maintain its own screenshot stack, you can have it call ScreenshotOne whenever it needs a stable image of a page. That keeps the workflow simple:

1.  OpenClaw notices something important.

2.  It sends the target URL to ScreenshotOne.

3.  It receives a screenshot back.

4.  It includes that image in a chat update, report, or downstream automation.

OpenClaw workflows that benefit from screenshots

------------------------------------------------

### Proactive website monitoring

OpenClaw’s heartbeat and scheduled tasks make it easy to watch landing pages, pricing pages, docs, status pages, or competitor websites. When something changes, ScreenshotOne can capture the exact state of the page so your Claw reports back with visual evidence instead of only a text summary.

This works well for:

*   tracking layout changes on your own site

*   catching broken pages after deploys

*   watching competitor launches or pricing updates

*   keeping a visual archive of important pages over time

### Daily and weekly briefings

Claw-style workflows often end in a briefing message: a morning update, a weekly report, or a summary sent to a team chat. Screenshots make those messages much more useful. Instead of saying “the homepage changed,” your Claw can attach what changed.

That is especially helpful for marketing, growth, SEO, and operations teams that review many pages quickly and need context without clicking through every link.

### Browser task verification

OpenClaw can browse the web, fill forms, and take action. After those actions, ScreenshotOne can capture the final page state for verification.

Examples:

*   confirm a listing or product page is live after publishing

*   save proof that a form submission reached the expected confirmation page

*   attach a screenshot when your Claw escalates a failed flow

*   keep a record of what an agent saw before making a decision

### Research and reporting workflows

Many OpenClaw users treat their Claw like a persistent collaborator that helps with recurring projects. If one of those projects involves websites, screenshots make the output easier to review and easier to trust.

Your Claw can gather links, extract structured data, and then use ScreenshotOne to add a visual layer for stakeholder updates, client deliverables, internal docs, or Notion reports.

Why use ScreenshotOne instead of building it inside the Claw?

-------------------------------------------------------------

OpenClaw can write its own skills, which is exactly why ScreenshotOne makes sense here. Your Claw does not need to become a screenshot infrastructure project.

Reliable website rendering has a lot of edge cases: timing, lazy-loaded content, modern frontends, anti-bot protections, and output consistency. ScreenshotOne gives OpenClaw a focused service for that part of the workflow, so the Claw can stay focused on planning, reacting, and communicating.

If you are building OpenClaw workflows that touch the web, ScreenshotOne is a simple tool to add whenever the result needs to be visual, shareable, and dependable.

That was a lot of work to get rendering screenshots work right (there's a lot of edge cases in my case) and I just opted for ScreenshotOne because of the pricing and great API.

Bjarn Bronsveld

Founder, [Spectate](https://spectate.net/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

### Screenshots for NemoClaw Agents

Use ScreenshotOne with NemoClaw to capture website screenshots for enterprise AI agents, browser verification, secure reporting, and visual audit trails.

[Read more →](/use-cases/nemoclaw-agents/)

### AI Vision For Analyzing Web Pages

Use AI to extract insights from web page visuals for enhanced content strategy and market analysis.

[Read more →](/use-cases/ai-vision-web-page-analysis/)

### Landing Page Evaluation with AI

Automate landing page roasting for your customers or yourself with modern technologies like OpenAI Vision.

[Read more →](/use-cases/ai-landing-page-roasting/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/guides/performance
----

[Skip to content](#_top)

Rendering performance

=====================

Copy page

> “You are never done working on performance.”

> 

> Guillermo Rauch

ScreenshotOne’s API is optimized for performance on permanent basis. However, due to a huge set of parameters that can be used to customize the rendering, there are some use cases where the default performance is not optimal.

The goal of this guide is to help you to tune the rendering parameters for your specific use case.

Of course, if you have any questions or need more help or assistance in performance tuning, please, reach out at `support@screenshotone.com`.

Disable blocking ads and banners

--------------------------------

Blocking ads, banners and other content seriously affects the performance of rendering since the API starts to listen for all the requests, waiting for elements to be shown, and many more tricks and heuristics are used to hide this type of content from the rendering.

In case if you render pages that do not contain any ads, banners or the pages belong to you and you can hide that content for the API, make sure to disable blocking ads, banners, and other content:

    1block_ads=false2block_cookie_banners=false3block_banners_by_heuristics=false4block_chats=false

Set these parameters explicitly to `false`, otherwise you rely on the default values that are not optimal for your use case and might be even changed in the future.

Disable or enable tracking scripts

----------------------------------

There is a lot of analytics and tracking scripts that might downgrade the performance of rendering. You can disable them by:

    1block_tracking=true

**However!** If you know that the websites you render doesn’t have tracking scripts, you can disable them by:

    1block_tracking=true

If you do not need them, disable blocking tracking scripts:

    1block_tracking=false

Because, to block tracking scripts, the API needs to sniff all the requests, analyze them and block.

This is a parameter that you need to play with for use case, and see what works the best.

Image format and quality

------------------------

Use either `JPEG` or `WebP` format for images:

    1format=jpeg or format=webp

It is faster to generate, the size is usually smaller than other formats, so it is also faster to transfer these.

The limitation of the `WebP` format is that you can’t use it for the huge full page screenshots. In general, it is not recommended to use it for the full page screenshots, or if you do you use it make sure to set `full_page_max_height` and check that the rendering is not broken for your use case.

In many cases, especially if you generate just tiny previews of the websites, you also don’t need high quality images. Try to set lower image quality for the images:

    1image_quality=80

And see if it satisfies your needs. However, for some formats reducing the quality might degrade performance. It is better to play with it.

Viewport size and device scale factor

-------------------------------------

For huge viewport size, screenshot rendering will take more time. But one of the critical parameters is the `device_scale_factor`.

When you set its value to more than `1`, you double the size of the screenshot. If you are screenshots are not planned to be used for the high DPI displays, you can set it to `1` to reduce the size of the screenshot and rendering time.

    1device_scale_factor=1

Make sure to check that the quality fits your needs.

It is also changed automatically to higher values if you use the `viewport_device` parameter with a device that automatically increases it:

    1viewport_device=iphone_16

`device_scale_factor` will be set to 3. Try to set it explicitly to `1` and see if it works for your use case:

    1viewport_device=iphone_162device_scale_factor=1

Wait options

------------

Try to play with the `wait_until` option. Start with `load` and see if it works for your case. Set it explicitly:

    1wait_until=load

If you anyway plan to render to full page screenshots and use scrolling, you don’t need to wait for everything to loaded since the page anyway will be scrolled to the bottom and likely this will cover and load all the content.

Full page screenshots

---------------------

### Try different algorithms

There are two algorithms for the full page screenshots: `by_sections` and `default`.

The default algorithm is the best one for the most of the cases. Try to use it first with disabled `full_page_scroll` and see if it works for your use case.

    1full_page_algorithm=default

However, if you need to try to use the `by_sections` algorithm:

    1full_page_algorithm=by_sections

It will render the page by sections, and will scroll anyway. It might be better algorithm if you need to trigger lazy loaded.

### Disable full page scrolling

If you do not need full page scrolling, disable it by:

    1full_page_scroll=false

It will dramatically reduce the rendering time. However, if your page contains lazy loaded content, it won’t be loaded.

### Tune full page scrolling

If you anyway need to scroll pages, try to play with the settings of the scrolling algorithm:

    1full_page_scroll_delay=100

If that still allows to render most of the images for your use case, go for it.

Summary

-------

It is hard to make the API product to satisfies all the use cases and still be performant. But with some tuning, it is achievable.

Please, feel free to reach out at `support@screenshotone.com` if you have any questions or need more help or assistance in performance tuning.

----
url: https://screenshotone.com/blog/uploading-website-screenshots-to-any-s3-compatible-storage
----

Uploading website screenshots to any S3-compatible storage

==========================================================

In this note, I share how I take website screenshots or render HTML and upload the resulted images or PDF to any S3-compatible storage like Amazon S3, Cloudflare R2, or Backblaze B2.

[Blog post](/blog/) 2 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jul 12, 2022

#### Tags

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

Using Puppeteer and AWS SDK

---------------------------

### Puppeteer

Puppeteer is a perfect library to automate your actions within the browser.

Let’s install it first:

    1npm i puppeteer

And then take a first screenshot:

    1const puppeteer = require('puppeteer');2

    3(async () => {4    const browser = await puppeteer.launch({});5    try {6        const page = await browser.newPage();7        await page.goto('https://example.com');8

    9        const blob = await page.screenshot({ encoding: 'binary' });10        // upload image blob to any S3-compatible storage11    } catch (e) {12        console.error(e);13    } finally {14        await browser.close();15    }16})();

In this example, we take a screenshot of the exemplary site and return the binary representation of the image. The last thing is to upload it to Amazon S3 or any S3-compatible storage.

### Upload to S3

With `aws-sdk`, it is fairly easy to do so. Let’s install it first:

    1npm install aws-sdk

And then we are ready to use it. Let’s for example, upload a screenshot to Cloudflare R2 instead of Amazon S3.

    1const puppeteer = require('puppeteer');2const S3 = require('aws-sdk/clients/s3');3

    4const accountId = '<account ID>';5const accessKeyId = '<access key ID>';6const accessKeySecret = '<access key secret>';7

    8(async () => {9    const s3 = new S3({10        endpoint: `https://${accountId}.r2.cloudflarestorage.com`,11        accessKeyId: `${accessKeyId}`,12        secretAccessKey: `${accessKeySecret}`,13        signatureVersion: 'v4',14    });15

    16    const browser = await puppeteer.launch({});17    try {18        const page = await browser.newPage();19        await page.goto('https://example.com');20

    21        const blob = await page.screenshot({ encoding: 'binary' });22

    23        const uploadedImage = await s3.upload({24            Bucket: "<bucket name>",25            Key: "example.png",26            Body: blob,27        }).promise();28

    29        const location = uploadedImage.Location;30        console.log(location);31    } catch (e) {32        console.error(e);33    } finally {34        await browser.close();35    }36})();

In this case, we used Cloudflare R2, but for Amazon S3, only the credentials and endpoint might be different. After you upload a screenshot, you receive its URL in the result’s `Location` attribute. You can return it in the response or do anything you need to do with it.

Using API

---------

One more approach to uploading website screenshots to S3 is to save time and use the ready screenshot API.

[ScreenshotOne API](/) already has built-in functionality to [upload screenshots to S3](/docs/options/#storing). It is scalable, reliable, fast, and uses CDN for storing screenshots.

You only need to configure your S3 access credentials in the dashboard and then specify a parameter in the request query.

[Get started for free](/).

Summary

-------

Decide on which approach suits you best. If you already have all infrastructure ready, have plenty of time, and can afford to build your solution, I would make it. Otherwise, I would use a ready solution to save time and money.

You also might find useful on [how to take screenshots with Puppeteer](/blog/how-take-a-screenshot-with-puppeteer).

Have a nice day 👋

Read more Puppeteer guides

--------------------------

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

[View all posts](/blog/tags/puppeteer-guides/)

#### [How to take bulk screenshots with Puppeteer](/blog/bulk-screenshots-with-puppeteer/)

Learn how to take screenshots of multiple URLs with Puppeteer, including concurrency management, error handling, retries, and proxy support.

Read more

#### [How to render screenshots with different emoji styles in Puppeteer](/blog/emojis/)

Learn how to render screenshots with different emoji styles in Puppeteer using emoji-js in a few lines of code.

Read more

#### [How to Take Full Page Screenshots with Playwright in Python](/blog/playwright-python-full-page-website-screenshots/)

Learn how to capture full page screenshots with Playwright in Python. Master the full\_page parameter, handle infinite scroll pages, lazy-loaded images, and maximum size limits.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/copy-page-button-in-docs
----

Added a "copy page" button in documentation

===========================================

You can now copy the page content as Markdown for LLMs and more.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Dec 6, 2025

We have added a new “copy page” button in documentation that allows you to copy the page content as Markdown for LLMs and more.

It allows to process the documentation content faster and more efficiently.

For example, check out our [errors](/docs/errors/) page:

[](/docs/errors/)

If you have any questions, suggestions, or feedback, please [contact us](mailto:support@screenshotone.com).

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [ScreenshotOne on the Postman Public API Network](/changelog/postman-public-collections/)

You can now play with the ScreenshotOne API in Postman using many examples as starting points for integrations.

Read more →

1 min read

#### [Added an Above-the-Fold Checker Tool](/changelog/above-the-fold-checker/)

A new ScreenshotOne tool to capture what users see before the first scroll.

Read more →

1 min read

#### [Fixed a validation issue in the playground](/changelog/fixed-a-playground-issue/)

We fixed a validation issue in the ScreenshotOne playground caused by selector scroll into view.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/fail-if-content-missing
----

Fail rendering if the content is missing a string

=================================================

There is a set of use cases when you want to fail screenshot rendering and retry it if the content of the page is missing a string.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Feb 2, 2025

For example:

1.  If you use residential rotating proxies and a site blocks you with some specific test, you might want to retry the request instead of getting the successful screenshot of the page with the CAPTCHA or an error.

2.  Setting `fail_if_content_missing=<some string that present in the working page content>` for your screenshot requests allows you to automatically ignore captures showing “Coming Soon” on a product page, ensuring you only get notified when the page updates to show the product is available for purchase.

3.  To focus monitoring on actual uptime and avoid capturing screenshots during nightly maintenance, configure your requests with `fail_if_content_missing=<some string that present in the working page content>`, thereby skipping any maintenance messages displayed on your application’s homepage.

You don’t pay for failed and cached screenshots with ScreenshotOne.

That’s exactly what you need the option `fail_if_content_missing` for.

Let’s quickly see how it works and how you can use it. Let’s first render the example.com page:

    1https://api.screenshotone.com/take?url=https://example.com&fail_if_content_missing=example+domain&access_key=<your access key>

The result is:

As you might notice, the match is case insensitive, it is done for simplicity.

Now, let’s try to fail it:

    1https://api.screenshotone.com/take?fail_if_content_missing=some+random+string+to+fail&url=https://example.com&access_key=<your access key></your>

The result is:

    1{2    "is_successful": false,3    "error_message": "The page content is missing the requested string `some random string to fail` by the `fail_if_content_missing` option. If it seems to be a mistake or not what you expected, please, reach out to `support@screenshotone.com` as quickly as possible, and will assist and try to resolve your problem.",4    "error_code": "content_missing_requested_string"5}

It works!

Also check out the [fail\_if\_content\_contains](/docs/options/#fail_if_content_contains) option.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Rendering errors in webhooks](/changelog/screenshotone-webhook-errors/)

Check out how to get notified about rendering errors when using webhooks.

Read more →

1 min read

#### [Include shadow DOM when requesting the page content](/changelog/include-shadow-dom/)

A new version of the ScreenshotOne API has been just deployed. It allows you to include the shadow DOM contents when requesting the page content.

Read more →

1 min read

#### [Screenshot URLs are now available in the response](/changelog/screenshot-url/)

You can now get a screenshot URL in the response of the API call.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/tags/customer-stories/4
----

Customer Stories

----------------

Customer stories and case studies from teams using ScreenshotOne.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [SEOBot uses ScreenshotOne API to generate screenshots for articles](/blog/seobot-automates-screenshot-generation-for-articles/)

Customers can your product in unpredictable and surprising ways. SEOBot now uses ScreenshotOne API to enhance its articles with screenshots, making content more engaging and visually appealing.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [John Rush](/contributors/john-rush/)

Published on

Feb 27, 2024

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Ilias Ism, a founder of the MagicSpace SEO agency, uses ScreenshotOne daily](/blog/how-ilias-ism-a-founder-of-the-magicspace-seo-agency-uses-screenshotone-daily/)

We would love to share a quick review of ScreenshotOne by Ilias Ism, a founder of MagicSpace SEO agency and OG Image Generator on how he uses the API daily to generate screenshots and automate regular tasks associated with screenshots.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Dec 5, 2023

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Heart-touching feedback from Gregory](/blog/heart-touching-feedback-from-gregory/)

Daily and nightly, I work on improving the quality and performance of ScreenshotOne (your friendly screenshot API) and ensuring I help customers solve their problems and prosper.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Nov 20, 2022

•

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/puppeteer-versus-playwright
----

Puppeteer versus Playwright

===========================

When to use Playwright and when to use Puppeteer.

[Blog post](/blog/) 2 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

May 6, 2024

#### Tags

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Playwright guides](/blog/tags/playwright-guides/)

[Playwright](/blog/playwright/) is the more robust and flexible option for general-purpose web automation and testing, while [Puppeteer](/blog/puppeteer/) remains a solid choice for Chrome/Chromium-centric projects or when developer familiarity is a key factor.

Playwright

----------

[](/blog/playwright/)

[Playwright](/blog/playwright/), a web automation framework, was introduced by Microsoft in January 2020. The development team behind Playwright had previously worked on similar projects like Puppeteer at Google.

Since its inception, Playwright has been actively maintained and has experienced rapid growth and widespread adoption within the web testing community.

Puppeteer

---------

[](/blog/puppeteer/)

[Puppeteer](\(/blog/puppeteer/\)) is an open-source project that was initially developed and released by the Chrome DevTools team at Google in 2017. While Puppeteer is owned by Google, the current development and contributions come from developers all over the world, not just those affiliated with Google.

It is basically a Node.js library which provides a high-level API to control Chrome/Chromium over the DevTools Protocol.

When to use Playwright

----------------------

[Playwright](/blog/playwright/) is generally the better choice in the following scenarios:

*   If you need to automate websites across multiple browsers (Chrome, Firefox, Safari, etc.), as Playwright provides cross-browser support out of the box.

*   If you require parallel test execution, as Playwright supports running multiple tests concurrently.

*   If you prefer to use a language other than just JavaScript, as Playwright supports multiple programming languages like Python, Java, and C#, while Puppeteer is JavaScript-only.

*   If you need more advanced browser capabilities like multi-context browsing and browser extension support, which Playwright offers.

When to use Puppeteer

---------------------

[Puppeteer](/blog/puppeteer/) may be the better choice in these cases:

*   If you are only targeting Chrome/Chromium-based browsers and don’t need cross-browser support.

*   If you have a limited time frame and need to leverage Puppeteer’s more established community, documentation, and ecosystem.

*   If you already have developers familiar with Puppeteer and don’t want to invest in learning a new tool.

Code examples

-------------

Both libraries have similar APIs, with a few exceptions.

### Playwright

An example of rendering screenshots with Playwright:

    1const { chromium } = require("playwright");2

    3(async () => {4    const browser = await chromium.launch();5    const page = await browser.newPage();6

    7    await page.goto("https://www.example.com");8

    9    await page.screenshot({ path: "example.com.png" });10

    11    await browser.close();12})();

### Puppeteer

An example of rendering screenshots with Puppeteer:

    1import puppeteer from "puppeteer";2

    3(async () => {4    const browser = await puppeteer.launch();5    const page = await browser.newPage();6    await page.goto("https://example.com");7

    8    await page.screenshot({ path: "example.com.png" });9

    10    await browser.close();11})();

### The key difference

The main difference is that Playwright has a more powerful and intuitive API compared to Puppeteer, with features like automatic waiting and parallel test execution. Because of its design philosophy as a testing framework.

### Summary

[Playwright](/blog/playwright/) offers robust and flexible web automation across multiple browsers and supports several programming languages, making it ideal for complex, multi-browser testing scenarios.

But [Puppeteer](/blog/puppeteer/) is tailored for Chrome/Chromium browsers and benefits from a strong community and extensive documentation, making it suitable for projects with these specific needs.

The choice between Playwright and Puppeteer depends on the browser requirements and the programming environment of the project, with Playwright providing more advanced features like parallel test execution and multi-context browsing.

Read more Puppeteer guides

--------------------------

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

[View all posts](/blog/tags/puppeteer-guides/)

#### [Playwright "Execution context was destroyed": how to fix navigation and page.evaluate errors](/blog/playwright-execution-context-was-destroyed-most-likely-because-of-a-navigation/)

Fix the Playwright "Execution context was destroyed, most likely because of a navigation" error after click, form submit, redirect, reload, or page.evaluate.

Read more

#### [page.waitForTimeout is not a function in Puppeteer](/blog/page-waitfortimeout-is-not-a-function-in-puppeteer/)

Puppeteer removed page.waitForTimeout(). Learn why the error happens and which modern alternatives to use instead.

Read more

#### [How to Take Full Page Screenshots with Playwright in Python](/blog/playwright-python-full-page-website-screenshots/)

Learn how to capture full page screenshots with Playwright in Python. Master the full\_page parameter, handle infinite scroll pages, lazy-loaded images, and maximum size limits.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/website-monitoring
----

Automate Website Screenshots

1 min read

Website Monitoring

==================

Monitor website changes, or even errors. And notify your customers if needed.

For companies in industries where website uptime and observability are critical, maintaining a visual record of website states is essential.

This need can be effectively met by leveraging a screenshot API to periodically capture website snapshots, ensuring an accurate visual history of the site’s performance and availability.

Why Choose ScreenshotOne API?

-----------------------------

The ScreenshotOne API allows automating website snapshots.

It can be used for [monitoring website changes](/blog/monitoring-website-changes/). Additionally, when an error occurs, a screenshot of the error page can be taken.

Value and Time Savings

----------------------

By using ScreenshotOne API, companies can significantly reduce the time invested in establishing and building website rendering services.

It offers a straightforward, reliable, and cost-effective solution for website screenshotting including error pages, allowing businesses to focus on their core activities rather than the complexities of screenshotting and handling all the possible corner cases associated with it.

That was a lot of work to get rendering screenshots work right (there's a lot of edge cases in my case) and I just opted for ScreenshotOne because of the pricing and great API.

Bjarn Bronsveld

Founder, [Spectate](https://spectate.net/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/unveil-the-power-of-automation-with-screenshotone-and-zapier
----

Unveil the Power of Automation with ScreenshotOne and Zapier

============================================================

I am thrilled to announce an exciting update for the ScreenshotOne users – the much-anticipated integration of ScreenshotOne with Zapier. This powerful combination is here to enhance your automation journey and expand your workflow capabilities to new heights.

[Blog post](/blog/) 2 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jun 1, 2023

ScreenshotOne is known for its intuitive screenshot API that enables businesses to render websites into images, PDFs, and more with simple API calls. Now, by partnering with [Zapier](https://zapier.com/apps/screenshotone/integrations), we’re supercharging your access to ScreenshotOne’s features, connecting them to over 5,000 apps available on the Zapier platform.

The Power of Integration

------------------------

The integration of ScreenshotOne with Zapier allows you to seamlessly include screenshot functionalities in your workflows, enhancing productivity, saving time, and reducing errors. Here’s why you should be as excited about this integration as we are:

### 1\. Powerful Automation

Automate your screenshot tasks based on triggers and actions in thousands of other apps. Get a PDF of a webpage every time a new blog post goes live or capture screenshots of competitors’ homepages weekly – the possibilities are endless!

### 2\. Scalability

No matter the size of your business, this integration scales with you. Whether you’re taking a dozen screenshots a day or thousands, we’ve got you covered.

### 3\. Flexibility

You have the power to decide what triggers a screenshot and what happens after one is taken. Tailor your Zapier workflows to perfectly fit your needs.

### 4\. Efficiency

The Zapier integration streamlines your workflow by automatically creating images or PDFs in response to predefined triggers.

### 5\. Quality and Precision

ScreenshotOne’s superior rendering capability ensures you get accurate, high-quality screenshots every single time.

Exploring the Use Cases

-----------------------

The Zapier-ScreenshotOne integration can find a place in countless scenarios, irrespective of your industry. Let’s look at a few potential use cases:

### 1\. Content Creators and Marketers

Automatically capture and archive website changes, track competitor websites, or create visual content for social media or blog posts.

### 2\. Developers and Product Managers

Easily document changes for client reports, bug tracking, or user testing without manually taking and managing screenshots.

### 3\. E-Commerce Businesses

Keep track of product listings, price changes, or customer reviews across multiple websites by automating screenshots of specific pages.

### 4\. Researchers and Analysts

Automate capture of online articles, social media posts, or public database information for analysis or reference.

This is just the tip of the iceberg. I can’t wait to see how you will use this integration to boost your workflow!

It’s Time to Start Zapping!

---------------------------

You can sign up now and start exploring the countless possibilities this integration brings to your workflow.

I believe the integration of ScreenshotOne with Zapier will not only bring efficiency but also a new level of creativity to your business. So go ahead, make your workday more productive, efficient, and fun. Let’s start ‘Zapping’ with ScreenshotOne and Zapier!

Read more posts

---------------

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

[View all posts](/blog/)

#### [A complete guide on how to take full page screenshots with Puppeteer, Playwright or Selenium](/blog/a-complete-guide-on-how-to-take-full-page-screenshots-with-puppeteer-playwright-or-selenium/)

You can take a full page screenshot with Pupeeter by specifying the \`fullPage\` parameter as true when taking a screenshot. But there is a caveat. If a site has lazy-loaded images, they won't be rendered. Let's examine how to fix the issue and trigger lazy image loading with Puppeteer.

Read more

#### [Rendering screenshot with Browserless](/blog/browserless/)

A few words about what is Browserless, when to use it, and if it is suitable for screenshots or not.

Read more

#### [ScreenshotOne November 2025 updates](/blog/screenshotone-november-2025-updates/)

Error metrics in the dashboard, Postman Public API Network, and Landing Gallery customer story.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/errors/usage-quota-exceeded
----

[Skip to content](#_top)

Usage Quota Exceeded

====================

Copy page

It is an API error returned when the monthly usage quota has been exceeded:

    1{2    "is_successful": false,3    "error_code": "screenshots_limit_reached",4    "error_message": "The usage quota has been exceeded. Please, either upgrade to a plan with more quota or change the maximum allowed limit (if possible) in the ScreenshotOne dashboard. If it is a mistake, please, reach out at `support@screenshotone.com.`",5    "documentation_url": "https://screenshotone.com/docs/usage-quota-exceeded/"6}

Reasons and how to fix

----------------------

There is a few ways on how to fix the error:

1.  If you use a free plan, you need to upgrade to a paid plan. You can do that at [the Dashboard Billing page](https://dash.screenshotone.com/billing).

2.  If you are already a paying customer, please, consider upgrade to a higher plan.

3.  Or you can [request extra quota](/docs/charging-extra/).

Reach out to support

--------------------

If nothing helps you, please, reach out to `support@screenshotone.com` and we will try to help you as fast as possible.

----
url: https://screenshotone.com/docs/errors/invalid-cookie-parameter
----

[Skip to content](#_top)

Invalid Cookie Parameter

========================

Copy page

It is an API error returned when the `cookies` parameter is invalid.

    1{2    "is_successful": false,3    "error_message": "The `cookies` parameters you provided are invalid. Please, consider providing different values and adhere to the format specified in the ScreenshotOne documentation.",4    "error_code": "invalid_cookie_parameter",5    "documentation_url": "https://screenshotone.com/docs/errors/invalid-cookie-parameter/"6}

Reasons and how to fix

----------------------

### The format of the parameter is invalid

Make sure you adhere to the format specified in the [ScreenshotOne options documentation](https://screenshotone.com/docs/options/#cookies):

    1cookies=name1=val1; Domain=example.com; Secure; HttpOnly

It is not for demonstration purposes, but the string must be URL-encoded.

If you need to specify multiple cookies, you can do it like this:

    1cookies=name1=val1; Domain=example.com; Secure; HttpOnly&cookies=name2=val2; Domain=example.com; Secure; HttpOnly

Reach out to support

--------------------

If you continue to face issues, please reach out to `support@screenshotone.com`, and we will assist you as soon as possible.

----
url: https://screenshotone.com/blog/using-ai-to-block-banners
----

Using AI to block banners

=========================

First successful attempts to block banners on websites using AI before rendering screenshots.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Oct 25, 2024

[Blocking banners when rendering screenshots is really hard](/blog/how-to-hide-cookie-banners-when-taking-a-screenshot-with-puppeteer/).

ScreenshotOne API does it for you automatically by using different sophisticated techniques. But in case, if nothing works, what to do?

Ask AI!

 Sorry, your browser doesn't support embedded videos.

I already built a simple tool that allows me to do that. Now, in case if a customer reaches to support with a problem that some banner is not blocked, I can quickly use the tool to fix the issue.

And response time will be shortened from hours to minutes.

Will be it part of the API itself? It is early to tell now. But I can see it definitely will be useful for some customers.

If you have any questions or suggestions, please reach out at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Use cases in the ScreenshotOne playground](/changelog/improved-playground/)

Having documentation and code examples is great, but not enough to allow developers to quickly integrate the API and assess all available features of the ScreenshotOne API.

Read more →

1 min read

#### [Documentation for LLMs](/changelog/docs-for-llms/)

ScreenshotOne now supports documentation format specifically targeted for LLMs—llms.txt and llms-full.txt.

Read more →

1 min read

#### [Improved full page screenshot algorithm](/changelog/fixed-a-corner-case-for-full-page-screenshots/)

We fixed issues with full page screenshots when the viewport was overridden together with the device option.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/how-to-render-screenshots-with-playwright
----

How to render screenshots with Playwright

=========================================

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

[Blog post](/blog/) 10 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Apr 29, 2025

#### Tags

[Playwright guides](/blog/tags/playwright-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

Making screenshots of the websites with [Playwright](/blog/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:

    1"use strict";2

    3const { chromium } = require('playwright');4

    5(async () => {6    const browser = await chromium.launch();7    try {8        const page = await browser.newPage();9        await page.goto("https://github.com");10        await page.screenshot({ path: "github.png" });11    } catch (e) {12        console.log(e);13    } finally {14        await browser.close();15    }16})();

The result is a screenshot of the GitHub website:

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](https://en.wikipedia.org/wiki/Retina_display) you can change the viewport properties `width`, `height` and `deviceScaleFactor`:

    1"use strict";2

    3const { chromium } = require('playwright');4

    5(async () => {6    const browser = await chromium.launch();7

    8    try {9        const page = await browser.newPage();10

    11        await page.setViewportSize({12            width: 2880, // default: 80013            height: 1800, // default: 60014            deviceScaleFactor: 2, // default: 115        });16

    17        await page.goto("https://apple.com");18        await page.screenshot({ path: "apple.com.png" });19    } catch (e) {20        console.log(e);21    } finally {22        await browser.close();23    }24})();

That’s called pixel-perfect screenshots.

### Full-page screenshots

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

    1"use strict";2

    3const { chromium } = require('playwright');4

    5(async () => {6    const browser = await chromium.launch();7

    8    try {9        const page = await browser.newPage();10        await page.goto("https://apple.com");11        await page.screenshot({ path: "apple.com.png", fullPage: true });12    } catch (e) {13        console.log(e);14    } finally {15        await browser.close();16    }17})();

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](/blog/take-a-full-page-screenshot-with-playwright/).

### Wait until the page is completely loaded

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

    1"use strict";2

    3const { chromium } = require('playwright');4

    5(async () => {6    const browser = await chromium.launch({});7

    8    try {9        const page = await browser.newPage();10

    11        await page.goto("https://apple.com/", {12            waitUntil: "networkidle",13        });14

    15        await page.screenshot({ path: "apple.com.png" });16    } catch (e) {17        console.log(e);18    } finally {19        await browser.close();20    }21})();

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](/blog/playwright-wait-until-the-page-is-ready/).

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

    1"use strict";2

    3const { chromium } = require('playwright');4

    5(async () => {6    const browser = await chromium.launch({});7

    8    try {9        const page = await browser.newPage();10

    11        await page.goto("https://example.com/", {12            waitUntil: "networkidle",13        });14

    15        const selector = "div";16        await page.waitForSelector(selector, {17            state: "visible",18        });19

    20        await page.screenshot({ path: "example.com.png" });21    } catch (e) {22        console.log(e);23    } finally {24        await browser.close();25    }26})();

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:

    1"use strict";2

    3const { chromium } = require('playwright');4

    5(async () => {6    const browser = await chromium.launch();7

    8    try {9        const page = await browser.newPage();10        await page.goto("https://apple.com");11        await page.screenshot({12            path: "apple.com.png",13            clip: {14                x: 100,15                y: 100,16                width: 800,17                height: 800,18            },19        });20    } catch (e) {21        console.log(e);22    } finally {23        await browser.close();24    }25})();

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:

    1"use strict";2

    3const { chromium } = require('playwright');4

    5(async () => {6    const browser = await chromium.launch();7

    8    try {9        const page = await browser.newPage();10        await page.goto("https://example.com");11

    12        const selector = "body > div:first-child";13        await page.waitForSelector(selector);14        const element = await page.$(selector);15

    16        await element.screenshot({17            path: "example.com.png",18        });19    } catch (e) {20        console.log(e);21    } finally {22        await browser.close();23    }24})();

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](/docs/options/#selector).

### Screenshots with transparent background

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

    1"use strict";2

    3const { chromium } = require('playwright');4

    5(async () => {6    const browser = await chromium.launch();7

    8    try {9        const page = await browser.newPage();10        await page.goto("https://example.com");11

    12        await page.screenshot({13            path: "example.com.png",14            omitBackground: true,15        });16    } catch (e) {17        console.log(e);18    } finally {19        await browser.close();20    }21})();

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:

    1"use strict";2

    3const { chromium } = require('playwright');4

    5(async () => {6    const browser = await chromium.launch();7

    8    try {9        const page = await browser.newPage();10        await page.goto("https://example.com");11

    12        await page.evaluate(() => {13            document.body.style.background = "transparent";14        });15

    16        await page.screenshot({17            path: "example.com.png",18            omitBackground: true,19        });20    } catch (e) {21        console.log(e);22    } finally {23        await browser.close();24    }25})();

### 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](https://en.wikipedia.org/wiki/Base64) encoding format:

    1"use strict";2

    3const { chromium } = require('playwright');4

    5(async () => {6    const browser = await chromium.launch({});7

    8    try {9        const page = await browser.newPage();10        await page.goto("https://example.com/");11

    12        const base64 = await page.screenshot({ encoding: "base64" });13        console.log(base64);14    } catch (e) {15        console.log(e);16    } finally {17        await browser.close();18    }19})();

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:

    1"use strict";2

    3const { chromium } = require('playwright');4

    5(async () => {6    const browser = await chromium.launch();7    try {8        const page = await browser.newPage();9        await page.goto("https://example.com");10        await page.screenshot({11            path: "example.jpg",12            type: "jpeg",13            quality: 100,14        });15    } catch (e) {16        console.log(e);17    } finally {18        await browser.close();19    }20})();

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](/blog/taking-screenshots-with-playwright-in-gif-jp2-tiff-avif-heif-or-svg-format).

### Blocking ads and trackers when using Playwright

In our [screenshot API](/), you can block ads by setting [blockAds=true](/docs/options/#block_ads).

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:

    1"use strict";2

    3const { chromium } = require('playwright-extra');4

    5const AdblockerPlugin = require('playwright-extra-plugin-adblocker');6chromium.use(AdblockerPlugin());7

    8(async () => {9    const browser = await chromium.launch();10

    11    try {12        const page = await browser.newPage(); // ads are blocked automatically13

    14        await page.goto("https://www.example.com");15

    16        await page.screenshot({17            path: "example.com.png",18            fullPage: true,19        });20    } catch (e) {21        console.log(e);22    } finally {23        await browser.close();24    }25})();

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:

    1chromium.use(2    AdblockerPlugin({3        blockTrackers: true, // default: false4    })5);

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:

    1"use strict";2

    3const { chromium } = require('playwright');4

    5(async () => {6    const options = {7        args: [8            '--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"',9        ],10        headless: true,11    };12

    13    const browser = await chromium.launch(options);14    try {15        const page = await browser.newPage();16        await page.goto("https://www.example.com");17

    18        await page.screenshot({19            path: "example.com.png",20            fullPage: true,21        });22    } catch (e) {23        console.log(e);24    } finally {25        await browser.close();26    }27})();

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:

    1"use strict";2

    3const { chromium } = require('playwright-extra');4

    5const StealthPlugin = require('playwright-extra-plugin-stealth');6chromium.use(StealthPlugin());7

    8(async () => {9    const browser = await chromium.launch();10

    11    try {12        const page = await browser.newPage();13        await page.evaluateOnNewDocument(() => {14            const newProto = navigator.__proto__;15            delete newProto.webdriver;16            navigator.__proto__ = newProto;17        });18

    19        await page.goto("https://bot.sannysoft.com");20        await page.waitForTimeout(5000);21        await page.screenshot({ path: "stealth.png", fullPage: true });22    } catch (e) {23        console.log(e);24    } finally {25        await browser.close();26    }27})();

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:

    1"use strict";2

    3const { chromium } = require('playwright');4

    5(async () => {6    const browser = await chromium.launch();7

    8    try {9        const page = await browser.newPage();10

    11        await page.setExtraHTTPHeaders({12            'Authorization': 'Basic ' + Buffer.from('YOUR_BASIC_AUTH_USERNAME:YOUR_BASIC_AUTH_PASSWORD').toString('base64')13        });14

    15        await page.goto("https://example.com");16        await page.screenshot({ path: "example.png" });17    } catch (e) {18        console.log(e);19    } finally {20        await browser.close();21    }22})();

### 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](https://github.com/googlefonts/noto-fonts) published under [SIL Open Font License (OFL) v1.1](http://scripts.sil.org/OFL).

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](https://www.selenium.dev/documentation/webdriver/browser/windows/#takescreenshot) protocol.

2.  The second one is [taking screenshots with Puppeteer](/blog/how-to-take-a-screenshot-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](/comparisons/playwright-alternative-for-screenshots/).

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](/blog/tags/playwright-guides/)

#### [Puppeteer waitUntil: how to wait for page load](/blog/puppeteer-wait-until-the-page-is-ready/)

Join me in exploring how to find the ideal wait time or event of when to take the page screenshot with Puppeteer.

Read more

#### [How to add custom styles to a page in Puppeteer](/blog/how-to-add-custom-styles-to-a-page-in-puppeteer/)

To add custom styles to any page use Puppeteer's page method \`page.addStyleTag(options)\`. Let's discover how it works quickly.

Read more

#### [Take a screenshot "from the surface" in Puppeteer and Chrome DevTools Protocol](/blog/take-a-screenshot-from-the-surface-in-puppeteer-and-chrome-devtools-protocol/)

Let's talk about the fromSurface parameter introduced in Chrome DevTools Protocol which will soon be supported by Puppeteer or even supported now at the time when you are reading the post.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/12
----

Automate Website Screenshots

----------------------------

Guides, Product Updates, and Helpful Resources from ScreenshotOne.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [Capture beyond viewport in Puppeteer and Chrome DevTools Protocol](/blog/capture-beyond-viewport-in-puppeteer-and-chrome-devtools-protocol/)

Let's talk about the captureBeyondViewport parameter introduced in Chrome DevTools Protocol which will soon be supported by Puppeteer or even supported now at the time when you are reading the post.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 1, 2023

•

3 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots in Python](/blog/how-to-take-website-screenshots-in-python/)

With Python, you can take website screenshots in multiple ways. But the best way to do it depends solely on your needs and your use case. Let's quickly examine all the options.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Mar 18, 2024

•

8 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots in Ruby](/blog/how-to-take-website-screenshots-in-ruby/)

Let's examine what Ruby proposes for us to render HTML or URL as a screenshot dynamically.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Dec 15, 2022

•

5 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [How to record videos with Puppeteer](/blog/how-to-record-videos-with-puppeteer/)

Let's quickly record a video with Puppeteer and see what upsides and downsides the native Puppeteer method of screencasting has. And how they can be tackled.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Apr 9, 2024

•

6 min read

#### [Open Graph images](/blog/open-graph-images/)

You can control the preview image rendered when your site is shared on social media, messengers, or apps that support the Open Graph protocol.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jan 21, 2026

•

12 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [What is a screenshot or HTML rendering API?](/blog/what-is-a-screenshot-or-html-rendering-api/)

A screenshot API or a screenshot as a service is usually a cloud or a remote server service that provides the ability to render any website, HTML, Markdown, or even PDF by making a request to the service, be it over HTTP, TCP, or any other protocol.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Nov 27, 2022

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Heart-touching feedback from Gregory](/blog/heart-touching-feedback-from-gregory/)

Daily and nightly, I work on improving the quality and performance of ScreenshotOne (your friendly screenshot API) and ensuring I help customers solve their problems and prosper.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Nov 20, 2022

•

1 min read

#### [Building a website directory with Next.js, Tailwind CSS, and Prisma](/blog/building-a-website-directory-with-nextjs-tailwind-css-and-prisma/)

See how easy it is to build a website directory with screenshots with Next.js, Tailwind CSS, and Prisma.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Nov 17, 2022

•

14 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/contributors/valerio-barbera
----

Valerio Barbera

---------------

View all Changelog

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [Puppeteer Performance Monitoring with Inspector](/blog/puppeteer-performance-monitoring-with-inspector/)

In this article I'll show you how to monitor performance and errors of a browser automation script written with Puppeteer.

Written by

[Valerio Barbera](/contributors/valerio-barbera/)

Published on

Jun 13, 2023

•

5 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/integrations/clay
----

Integrations

1 min read

Clay

====

Generate website screenshots inside Clay to qualify leads, assess content, and enrich rows with visual context automatically.

No-Code Automation

[Clay](https://clay.com/) is a powerful data-automation tool that lets teams enrich, filter, and transform leads from hundreds of sources without writing code. With Clay, you can build dynamic workflows that connect CRMs, APIs, and enrichment tools in minutes.

[](https://www.clay.com/integrations/data-provider/screenshotone)

Integration with [ScreenshotOne](/) lets you automatically generate high-quality website screenshots inside your Clay tables—perfect for lead research, prospecting, directory building, and any workflow where visual context matters.

Resources

---------

*   [ScreenshotOne on Clay](https://www.clay.com/integrations/data-provider/screenshotone)

*   [Documentation](https://screenshotone.com/docs/no-code/clay/)

*   [A guide on how to use AI screenshot analysis with ScreenshotOne and Clay to find customers](https://screenshotone.com/blog/ai-screenshot-analysis-for-finding-customers/)

ScreenshotOne made it possible to ship dynamic meta images for my MVP customers without spending weeks building the support myself. Works like a charm. The caching is the icing on the cake.

Sukh

Founder, Engyne.ai

Check more Integrations

-----------------------

No-code tools, AI, code libraries, and more.

[Check more Integrations](/integrations/)

Code API

### SDK and Code Examples

Use the SDKs and code examples to take screenshots in your own code.

[Read more →](/integrations/code/)

No-Code Automation

### n8n

Use ScreenshotOne in n8n workflows to render website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

[Read more →](/integrations/n8n/)

No-Code Automation

### Make

Use ScreenshotOne with Make to automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

[Read more →](/integrations/make/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/agents
----

[What's new API error insights API error insights in the dashboard](/changelog/error-metrics/)

The screenshot API for AI agents

================================

Give AI agents reliable screenshots of web pages so they can inspect, compare, verify, and act with visual context.

[Start rendering for free →](https://dash.screenshotone.com/sign-up)

> ScreenshotOne is the best product on the market - and that's before you take into account how responsive and easy Dmytro is to work with.

> 

> Any time we've found a rare edge case, it's been resolved in hours.

> 

> Great company, great founder - can't say enough!

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/no-code/bubble
----

[Skip to content](#_top)

How to render website screenshots with Bubble

=============================================

Copy page

Bubble is a full-stack no-code app builder. It is a platform, where you can design, build, and launch fully functional web and mobile applications. They also handle all the technical details, like servers, integrations, and security.

In case if you are going to build a website directory or your application needs website screenshots, you can use ScreenshotOne to do that for you.

Community Plugins and Integrations

----------------------------------

To integrate ScreenshotOne with Bubble for rendering website screenshots, you can use [a ScreenshotOne plugin for Bubble provided Revido](https://bubble.io/plugin/screenshotone-1732272787355x675035896606359600).

The plugin is developed and supported by [Revido—a company that build products for their customers through low-code](https://revido.co).

----
url: https://screenshotone.com/docs/errors/access-key-required
----

[Skip to content](#_top)

Access Key Required

===================

Copy page

It is an API error returned when the access key parameter is missing in the request.

    1{2    "is_successful": false,3    "error_code": "access_key_required",4    "error_message": "The `access_key` parameter is required. Please, check out the access dashboard page to get the access key—https://dash.screenshotone.com/access.",5    "documentation_url": "https://screenshotone.com/docs/errors/access-key-required/"6}

Reasons and how to fix

----------------------

### Missing Access Key Parameter

The most common reason for the “access\_key\_required” error is that the `access_key` parameter is not included in the request. This is mandatory for authenticating and authorizing the API request.

To fix this, ensure that you include the `access_key` parameter in your API request. You can obtain your access key from the [access dashboard page](https://dash.screenshotone.com/access).

### Misconfigured Request

Sometimes, a request might be misconfigured, leading to the `access_key` parameter being omitted.

To fix this, review the configuration of your API client or the code that constructs the request to ensure that the `access_key` parameter is always included.

### Typographical Errors

A typo or incorrect parameter name might lead to the `access_key` not being recognized by the API.

To fix this, double-check the parameter name in your request to ensure it is spelled correctly as `access_key`.

### Programmatic Issues

If you are dynamically generating requests (e.g., through a script or application), there might be a bug causing the `access_key` to be omitted.

To fix this, debug your script or application to ensure the `access_key` is being properly set and included in every API request.

Reach out to support

--------------------

If you continue to face issues, please reach out to `support@screenshotone.com`, and we will assist you as soon as possible.

----
url: https://screenshotone.com/changelog/improved-errors
----

Improved errors

===============

Now, errors will have relevant documentation links. It will be also possible to see why some requests failed in the dashboard and get recommendations on how to address the issue.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

May 1, 2024

The goal of the new improvement is to make the API self-service as much as possible and to reduce the support load.

It will help ScreenshotOne customers to get unstuck and not wait for the support team to answer questions and analyze the problem themselves quickly.

Also, a reduced support load will help ScreenshotOne to provide better services and more delightful features.

Documentation links in the response

-----------------------------------

Since now you can the documentation URL in the error response. It will allow users to check how to handle the error straight away:

Improved history

----------------

In the dashboard request log, users will also see an error and it is a link to the dedicated documentation page:

Next

----

There is a lot to do, still:

1.  Today, only a handful of errors are covered. But it is a good start and a solid foundation. The goal is to cover all errors.

2.  Send an email when the error is encountered for the first time with help on how to handle it.

3.  Automatically analyze the error and what caused it and provide code examples on how to fix it.

4.  More analytics of error rate by error types.

Any more ideas or best practices you can share? Feel free to reach out and share at `hey@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [More algorithms for screenshots by selectors](/changelog/selector-algorithm/)

We added more algorithms for screenshots by selectors.

Read more →

1 min read

#### [ScreenshotOne integration with Dirstarter](/changelog/dirstarter-integration/)

Build a directory with Dirstarter and add website screenshots automatically with ScreenshotOne.

Read more →

1 min read

#### [Available in Context7](/changelog/available-in-context7/)

ScreenshotOne documentation is now available in Context7.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/7
----

Automate Website Screenshots

----------------------------

Guides, Product Updates, and Helpful Resources from ScreenshotOne.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [Automating screenshots for directory websites with ScreenshotOne](/blog/directify-feedback/)

How and why "Directify" used ScreenshotOne to automate screenshots for directory websites.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Sergey Karakhanyan](/contributors/sergey-karakhanyan/)

Published on

Dec 15, 2024

•

2 min read

#### [Blast Banners with ScreenshotOne](/blog/blast-banners/)

A funny game built on top of ScreenshotOne API.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Oct 29, 2024

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Branding 5 uses ScreenshotOne for competitor analysis](/blog/how-branding5-uses-screenshotone/)

If you are interested in diving deeper into the Branding 5 use case and discover if ScreenshotOne might be useful for you, too, keep reading.

Written by

[Matthias Neumayer](/contributors/matthias-neumayer/), [Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Oct 4, 2024

•

2 min read

[Engineering](/blog/tags/engineering/)

#### [Cloudflare Workers as an API gateway](/blog/cloudflare-workers/)

Check out how ScreenshotOne relies on Cloudflare Workers as an API gateway to enhance performance, reliability, and cost-efficiency.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Aug 3, 2024

•

7 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Spectate uses ScreenshotOne to improve incident observability](/blog/how-spectate-uses-screenshotone/)

If you are interested in diving deeper into the Spectate use case and discover if ScreenshotOne might be useful for you, too, keep reading.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Bjarn Bronsveld](/contributors/bjarn-bronsveld/)

Published on

Jul 21, 2024

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How GetWebsite.Report uses ScreenshotOne for screenshot automation tasks](/blog/how-website-report-uses-screenshotone/)

If you are interested in diving deeper into the GetWebsite.Report use case and discover if ScreenshotOne might be useful for you, too, keep reading.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jun 4, 2024

•

2 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How FounderPal uses ScreenshotOne for landing page analysis](/blog/how-founderpal-uses-screenshotone/)

If you are interested in diving deeper into the FounderPal use case and discover if ScreenshotOne might be useful for you, too, keep reading.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jun 2, 2024

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Boosting email CTR for "Bridesmaid For Hire" with ScreenshotOne](/blog/braidsmade-for-hire-case-study/)

How and why "Bridesmaid for Hire" used ScreenshotOne to boost their email campaign CTR.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

May 21, 2024

•

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/courses-hand-outs-and-certification-documents
----

Automate Website Screenshots

1 min read

Course handouts and certification PDFs

======================================

Generate course handouts and certification PDFs from HTML templates.

When a learner clicks “Complete module,” you want two things to happen instantly:

1.  **A branded certificate** slides into their inbox, ready to share on LinkedIn.

2.  **A printable workbook** drops into their downloads so they can revise offline.

With [**ScreenshotOne’s PDF Generation API**](/pdf-generation-api/), both files are created on‑the‑fly—no manual design work, no waiting for batch jobs.

How it works

------------

1.  **Design once in HTML/CSS** Build a certificate or workbook page with your logo, colors, and dynamic placeholders (`{{name}}`, `{{course}}`, `{{date}}`, etc.).

2.  **Call the API when the learner finishes**

    Terminal window

        1curl -X POST https://api.screenshotone.com/take \2  -d '{3    "url": "https://example.com/certificate",4    "format": "pdf",5    "access_key": "<your access key>"6  }'

3.  **Deliver immediately** Pipe the returned PDF to email, cloud storage, or a “Download workbook” button in your UI.

Why teams ship faster with ScreenshotOne

----------------------------------------

*   **Pixel‑perfect branding** – Every PDF mirrors the web version exactly, so marketing sign‑off is automatic.

*   **Zero maintenance** – No headless browsers or Puppeteer scripts to babysit; the API scales for peak course completions.

*   **Global performance** – CDN‑backed rendering means certificates reach learners worldwide in seconds.

*   **Usage‑based pricing** – Pay only for the PDFs you generate; free tier ideal for early‑stage courses.

Result

------

Your learners get instant, professional‑looking proof of achievement. You stay focused on creating content—ScreenshotOne handles the PDFs.

We thought making a screenshot tool for our AI agents would be simple. But we faced countless unexpected problems.

So, we ditched the idea and chose ScreenshotOne API instead. It saved us lots of time and it just works!

John Rush

Founder, [Unicorn Platform](https://unicornplatform.com)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/integrations/postman-api-network
----

Integrations

1 min read

Postman

=======

You can use the Postman Collections provided by ScreenshotOne to play with the API and get started quickly.

Low-Code Code API

Resources

---------

*   [ScreenshotOne on the Postman API Network](https://www.postman.com/screenshotone/screenshotone-s-workspace/overview)

Kudos to the team for building ScreenshotOne. It's been more than 4 months now, and there's hardly been an outage/downtime.

ScreenshotOne handled even the rarest of edge cases where websites were loading slowly, which I found other products in the market failed to do.

Lastly, the support has been extremely top-notch, which is like a cherry on top.

Sankeerth Julapally

Founder, [GetWebsite.Report](https://screenshotone.com/blog/how-website-report-uses-screenshotone/)

Check more Integrations

-----------------------

No-code tools, AI, code libraries, and more.

[Check more Integrations](/integrations/)

No-Code Automation

### Zapier

Automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos in Zapier.

[Read more →](/integrations/zapier/)

Code API

### SDK and Code Examples

Use the SDKs and code examples to take screenshots in your own code.

[Read more →](/integrations/code/)

No-Code Automation

### Make

Use ScreenshotOne with Make to automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

[Read more →](/integrations/make/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/screenshots-and-law
----

Is it legal to screenshot websites?

===================================

A few thoughts on the topic of screenshots and law.

[Blog post](/blog/) 3 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jul 22, 2025

The post is not a legal advice. It is rather a few thoughts on the topic of screenshots and law.

Get a professional advice

-------------------------

Consult with a lawyer or a legal expert to get a professional advice on your specific use case. ScreenshotOne doesn’t take responsibility for the legality of your use case. ScreenshotOne is a tool to screenshot, and how it is used is up to you. Do not use it for illegal purposes or violate any law in any way in any jurisdiction.

Laws around screenshots can vary widely between jurisdictions. What’s legal in one country might be illegal in another. For example, the EU’s GDPR or California’s CCPA may apply to screenshots that contain personal data, even if you’re not based in those regions.

Depends on the use case

-----------------------

If you are going to screenshot your website and resources under your control, there might be no questions at all, but what if you are going to screenshot a website that is not under your control? And basically any random public website?

Misusing screenshots, especially for commercial use, defamation, or copyright infringement, can result in takedown requests, account suspensions, DMCA notices, or even lawsuits.

Always respect Terms and Services

---------------------------------

Legal issues aren’t just about copyright law – websites have Terms of Service (ToS) that may restrict automated access, scraping, or screenshots. When you use a site (especially if you click “agree” to something), you may be entering a contract. Breaching those terms can lead to consequences from the website owner, ranging from revoked access to legal action for damages.

Always respect the Terms and Services of the website you are screenshotting. If it is prohibited by the website Terms of Service, don’t do it.

Responsible use of automation tools

-----------------------------------

If you’re automating screenshots,remember that automated bots can be detected and blocked. Excessive requests might be seen as scraping or abuse, even if you’re only capturing visuals. Use rate limits and avoid interfering with site performance.

Respect copyright and get permission if needed

----------------------------------------------

If you want to use a screenshot in a way that doesn’t clearly fall under fair use or an exception, consider reaching out for permission. Many site owners will be fine with you showing a snapshot of their site (it can even be free publicity), especially if you credit them. When in doubt, it’s safer to ask. This is particularly true for using screenshots in commercial materials (e.g., in marketing or in-app assets). And obviously, never try to pass off someone else’s web content as your own.

Keep in mind that “fair use” is a legal defense, not a right. Just because your use feels fair doesn’t mean a court will agree. Commercial intent, amount of content copied, and the effect on the original work’s value all matter.

Protect personal data

---------------------

Treat any personal information in screenshots as you would any sensitive data. That means storing it securely (encrypted if appropriate), limiting who can see it, and not keeping it longer than necessary.

If you’re going to publish a screenshot containing someone’s data, consider anonymizing it. For instance, hide usernames or faces unless they are central to the story.

Always follow privacy laws for the regions your project touches.

Conclusion

----------

In short, take screenshots responsibly. Think about copyright, contracts, privacy, and ethics. It is not enough to think about what’s technically possible. Follow the laws and regulations.

Read more posts

---------------

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

[View all posts](/blog/)

#### [OpenAI 4o image generation and marketing opportunities](/blog/openai-4o-marketing-opportunities/)

OpenAI 4o image generation is a really good model that can change the way you automate marketing

Read more

#### [OpenClaw with Playwright or Puppeteer: how to install browser support](/blog/openclaw-playwright-puppeteer/)

A practical guide to OpenClaw browser automation, why Playwright is the documented path, where Puppeteer fits, how to make screenshots, and when ScreenshotOne is the better choice for screenshot-only flows.

Read more

#### [Unveil the Power of Automation with ScreenshotOne and Zapier](/blog/unveil-the-power-of-automation-with-screenshotone-and-zapier/)

I am thrilled to announce an exciting update for the ScreenshotOne users – the much-anticipated integration of ScreenshotOne with Zapier. This powerful combination is here to enhance your automation journey and expand your workflow capabilities to new heights.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/errors/name-not-resolved
----

[Skip to content](#_top)

Name Not Resolved

=================

Copy page

It is an API error returned when the domain name of the requested URL cannot be resolved.

    1{2    "is_successful": false,3    "error_code": "name_not_resolved",4    "error_message": "Usually, the error happens when the domain name of the requested URL is not resolved. If you are trying to take a screenshot of a new site, please, wait a bit until the DNS records are refreshed.",5    "documentation_url": "https://screenshotone.com/docs/errors/name-not-resolved/"6}

Reasons and how to fix

----------------------

### Unresolved Domain Name

The most common reason for the “name\_not\_resolved” error is that the domain name of the requested URL cannot be resolved to an IP address. This often occurs with new domains or recently updated DNS records.

To fix this, you can:

1.  **Wait for the DNS propagation if it is your website**: If you are trying to take a screenshot of a new site, wait for the DNS records to propagate fully. This can take anywhere from a few minutes to 48 hours.

2.  **Or check DNS configuration**: Ensure that the DNS configuration for the domain is correct and that the records are properly set up.

### Temporary DNS Issues

Temporary DNS issues can also cause the “name\_not\_resolved” error. These can be due to network problems, DNS server issues, or other transient conditions.

To fix this, consider simply retrying the request after a short wait

### Incorrect Domain Name

If the domain name is incorrectly typed or does not exist, the API will not be able to resolve it.

To fix this, verify that the domain name in the request is correct and exists.

Reach out to support

--------------------

If you continue to face issues or need further assistance, please reach out to `support@screenshotone.com`, and we will assist you as soon as possible.

----
url: https://screenshotone.com/docs/organizations
----

[Skip to content](#_top)

Organizations and Roles

=======================

Copy page

Organizations are the core unit for managing your ScreenshotOne account. Every user belongs to one organization, and all billing, API access, and resources are scoped to the organization level.

Roles

-----

There are three roles in an organization:

### Owner

The owner has full control over the organization:

*   Full access to billing, invoices, and subscription management

*   Can invite and remove members

*   Can change member roles

*   Can transfer ownership to another member

*   Can delete the organization

*   Can configure notifications

Every organization has exactly one owner. When you sign up, you automatically become the owner of your organization.

### Admin

Admins are trusted team members who can help manage the organization:

*   Can view and manage billing information

*   Can invite and remove members

*   Can change member roles (promote/demote between admin and developer)

*   Can edit organization settings

*   Can configure notifications

*   **Cannot** transfer ownership

*   **Cannot** delete the organization

Use the admin role for team leads, managers, or anyone who needs to manage the team without having full control.

### Developer

Developers have access to everything needed to integrate with ScreenshotOne:

*   Can view and manage API keys

*   Can view request logs and screenshot history

*   Can access the playground

*   Can configure S3 storage

*   Can view organization members (read-only)

*   **Cannot** manage members or invites

*   **Cannot** view billing or payment information

*   **Cannot** change organization settings

Use the developer role for engineers and team members who need to work with the API but don’t need administrative access.

Managing Your Team

------------------

### Inviting Members

1.  Go to the **Organization** page

2.  Click **Invite new member**

3.  Enter the email address

4.  Select a role (Developer or Admin)

5.  Click **Invite**

The invited user will receive an email with instructions to join. They can sign in (or sign up if new to ScreenshotOne) to accept the invitation.

**Note:** You cannot invite users who already have an active subscription or are owners of another organization with members.

### Changing Roles

1.  Go to the **Organization** page

2.  Find the member in the list

3.  Click **Change role**

4.  Select the new role (Developer or Admin)

5.  Click **Change Role**

Only owners and admins can change roles. You cannot change the owner’s role or your own role.

### Removing Members

1.  Go to the **Organization** page

2.  Find the member in the list

3.  Click **Remove member**

4.  Confirm the removal

When a member is removed, they are moved to their own organization with fresh API keys. **Important:** They may still have copies of your API keys. Consider regenerating your keys after removing a member.

### Transferring Ownership

If you need to transfer ownership to another member:

1.  Go to the **Organization** page

2.  Find the member who will become the new owner

3.  Click **Transfer ownership**

4.  Confirm the transfer

After transfer, you will become a developer in the organization. Only the owner can transfer ownership, and only if no members have active legacy subscriptions.

Common Use Cases

----------------

### Small Team

*   **Owner**: Founder or team lead (handles billing)

*   **Developers**: Engineers working on the integration

### Medium Team

*   **Owner**: Finance or operations (manages billing)

*   **Admins**: Team leads (manage their developers)

*   **Developers**: Engineers

### Enterprise

*   **Owner**: Account administrator

*   **Admins**: Department heads or project managers

*   **Developers**: Development teams

FAQ

---

**Can I have multiple owners?** No, each organization has exactly one owner. Use the admin role for additional people who need management access.

**What happens to removed members?** They get their own organization with a free plan and new API keys. They lose access to your organization’s resources immediately.

**Can developers see billing information?** No, only owners and admins can view billing, invoices, and subscription details.

**Can admins change the subscription?** Yes, admins have full access to billing and can change plans, update payment methods, and manage the subscription.

**What if I need help?** Contact us at [support@screenshotone.com](mailto:support@screenshotone.com) or use the support chat. We’re happy to help with any organization-related questions.

----
url: https://screenshotone.com/blog/how-to-hide-cookie-banners-when-taking-a-screenshot-with-puppeteer
----

How to hide cookie banners when taking a screenshot with Puppeteer

==================================================================

When taking a screenshot, you want to ensure that you take a clean screenshot without cookie banners or cookie consent forms. And in this article, I will share with you how you can do it when using Puppeteer.

[Blog post](/blog/) 11 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Nov 12, 2024

#### Tags

[Puppeteer guides](/blog/tags/puppeteer-guides/)

There are many tactics on how you can block cookie banners:

*   writing [a custom solution for every site](#a-custom-logic-for-every-site);

*   writing [custom but generic solutions for every site](#a-custom-but-generic-logic-for-every-site) and update them periodically;

*   using [cookie blocking rule lists](#block-cookie-banners-with-easylist-filter-lists-rules);

*   using [automatic cookie consent libraries](#automatic-cookie-consent-libraries);

*   [combining cookie blocking rule lists and automatic cookie consent library (**recommended**)](#recommended-combining-automatic-cookie-consent-libraries-and-blocking-by-rule-lists);

*   or using [extensions](#extensions).

You can skip dealing with cookie popups when using Puppeteer and instead try [a straightforward screenshot API](/) that can already do it for you with [the block cookie banners parameter](/docs/options/#block_cookie_banners).

A custom logic for every site

-----------------------------

You are lucky if you take screenshots only for a small group of sites. You can use a simple trick to disable cookie popups and banners on site.

Let’s do it for StackOverflow as an example. Let’s first take a screenshot of the site and see if there is a cookie banner:

    1const puppeteer = require('puppeteer');2

    3(async () => {4    const browser = await puppeteer.launch({ headless: true });5    try {6        const page = await browser.newPage();7

    8        await page.setViewport({ width: 1280, height: 1024 });9        await page.goto('https://stackoverflow.com/', { waitUntil: ['load', 'domcontentloaded'] });10

    11        await page.screenshot({ type: 'png', path: 'screenshot.png'});12    } catch (e) {13        console.log(e)14    } finally {15        await browser.close();16    }17})();

In the bottom left corner, you can see a cookie consent:

And it is fairly easy to block. We can apply `display: none !important` to `.js-consent-banner` class or to click on “Accept all cookies”. You can use Chromium DevTools to debug and to see which classes you need to block or on which buttons you need to click:

I would accept all cookies to make sure that the site is functioning correctly:

    1const puppeteer = require('puppeteer');2

    3(async () => {4    const browser = await puppeteer.launch({ headless: true });5    try {6        const page = await browser.newPage();7

    8        await page.setViewport({ width: 1280, height: 1024 });9        await page.goto('https://stackoverflow.com/', { waitUntil: ['load', 'domcontentloaded'] });10

    11        // to hide banner:12        // await page.waitForSelector('.js-consent-banner', { visible: true });13        // await page.addStyleTag({14        //     content: '.js-consent-banner { display: none !important; }',15        // });16

    17        // or click to "Accept all cookies"18        await page.waitForSelector('.js-accept-cookies', { visible: true });19        await page.click('.js-accept-cookies');20

    21        await page.screenshot({ type: 'png', path: 'screenshot.png' });22    } catch (e) {23        console.log(e)24    } finally {25        await browser.close();26    }27})();

The result is that there is no cookie banner in both cases:

I recommend always accepting all cookies because some sites can even block you if you don’t accept them.

But what if you need to take screenshots of more than one site?

A custom, but generic logic for every site

------------------------------------------

You can write quite generic code that might work in many cases. Since mostly any cookie consent has a button like “Accept all cookies”, “Accept” or “Allow”. The only downside is that you might accidentally click on another button, or the button title might not be in English, and you need to adopt it. And every case is different. You will always find a corner case.

Let’s look at [the CookieBot site](https://www.cookiebot.com/en):

Let’s close allow all cookies for the CookieBot site:

    1const puppeteer = require('puppeteer');2

    3(async () => {4    const browser = await puppeteer.launch({ headless: true });5    try {6        const page = await browser.newPage();7

    8        await page.setViewport({ width: 1280, height: 1024 });9        await page.goto('https://www.cookiebot.com/en', { waitUntil: ['load', 'domcontentloaded', 'networkidle0'] });10

    11        await page.waitForSelector('#CybotCookiebotDialogBodyLevelButtonLevelOptinAllowAll', { visible: true });12        await page.click('#CybotCookiebotDialogBodyLevelButtonLevelOptinAllowAll');13

    14        await page.screenshot({ type: 'png', path: 'screenshot.png' });15    } catch (e) {16        console.log(e)17    } finally {18        await browser.close();19    }20})();

And the result is:

How do we generalize the code? To both close the banner for StackOverflow, CookieBot, and new sites?

The most common thing between all cookie banners is a link or a button containing “Accept all cookies” or “Allow all” text that you might click to close the banner.

So, we can search for all buttons or links with such text and try to click on them if found. Let’s try to close the banner now for both the StackOverflow and the CookieBot site:

    1const puppeteer = require('puppeteer');2

    3(async () => {4    const browser = await puppeteer.launch({ headless: true });5    try {6        const page = await browser.newPage();7

    8        await page.setViewport({ width: 1280, height: 1024 });9        await page.goto('https://cookiebot.com', { waitUntil: ['load', 'domcontentloaded', 'networkidle0'] });10

    11        await page.evaluate(_ => {12            const selector = 'a[id*=cookie i], a[class*=cookie i], button[id*=cookie i] , button[class*=cookie i]';13            const expectedText = /^(Accept|Accept all cookies|Accept all|Allow|Allow all|Allow all cookies|OK)$/gi;14            const elements = document.querySelectorAll(selector);15            for (const element of elements) {16                if (element.textContent.trim().match(expectedText)) {17                    element.click();18                    return;19                }20            }21        });22

    23        await page.screenshot({ type: 'png', path: 'screenshot.png' });24    } catch (e) {25        console.log(e)26    } finally {27        await browser.close();28    }29})();

The code works well both for StackOverflow and CookieBot. Let’s test on a new site that we haven’t seen before — the [Hetzner](https://www.hetzner.com/) site:

It works, but since Hetzner animates closing the cookie banner, we need to add a delay to wait before taking a screenshot:

    1const puppeteer = require('puppeteer');2

    3(async () => {4    const browser = await puppeteer.launch({ headless: true });5    try {6        const page = await browser.newPage();7

    8        await page.setViewport({ width: 1280, height: 1024 });9        await page.goto('https://www.hetzner.com/', { waitUntil: ['load', 'domcontentloaded', 'networkidle0'] });10

    11        await page.evaluate(_ => {12            const selector = 'a[id*=cookie i], a[class*=cookie i], button[id*=cookie i] , button[class*=cookie i]';13            const expectedText = /^(Accept|Accept all cookies|Accept all|Allow|Allow all|Allow all cookies|Ok)$/gi;14            const elements = document.querySelectorAll(selector);15            for (const element of elements) {16                if (element.textContent.trim().match(expectedText)) {17                    element.click();18                    break;19                }20            }21        });22

    23        await wait(2000);24

    25        await page.screenshot({ type: 'png', path: 'screenshot.png' });26    } catch (e) {27        console.log(e)28    } finally {29        await browser.close();30    }31})();32

    33async function wait(delay) {34    return new Promise(function (resolve, reject) {35        setTimeout(resolve, delay);36    });37}

And the result is:

But, now you get the idea. You will need to hack the script repeatedly for all the new sites. Let’s take a screenshot of [the London Stock Exchange](https://www.londonstockexchange.com/):

As you see, the banner is not closed. We can try a new approach for closing it by finding all the buttons that contain the text we search for, but without the word “cookie” in their attributes:

    1const puppeteer = require('puppeteer');2

    3(async () => {4    const browser = await puppeteer.launch({ headless: true });5    try {6        const page = await browser.newPage();7

    8        await page.setViewport({ width: 1280, height: 1024 });9

    10        await page.goto('https://www.londonstockexchange.com/', { waitUntil: ['load', 'domcontentloaded', 'networkidle0'] });11

    12        await page.evaluate(_ => {13            const expectedText = /^(Accept|Accept all cookies|Accept all|Allow|Allow all|Allow all cookies|Ok)$/gi;14            const clickAccept = (selector) => {15                const elements = document.querySelectorAll(selector);16                for (const element of elements) {17                    if (element.textContent.trim().match(expectedText)) {18                        element.click();19                        return true;20                    }21                }22

    23                return false;24            }25

    26            if (clickAccept('a[id*=cookie i], a[class*=cookie i], button[id*=cookie i] , button[class*=cookie i]')) {27                return;28            }29

    30            // a second try31            clickAccept('a, button');32        });33

    34        await wait(2000);35

    36        await page.screenshot({ type: 'png', path: 'screenshot.png' });37    } catch (e) {38        console.log(e)39    } finally {40        await browser.close();41    }42})();43

    44async function wait(delay) {45    return new Promise(function (resolve, reject) {46        setTimeout(resolve, delay);47    });48}

Let’s execute it:

As you see, it works, but the code is computational heavy now, and it might click the button that we don’t expect to be clicked.

Let’s try another site — [DigitalOcean](https://www.digitalocean.com/), but first, we need to check that it renders a cookie popup:

At the bottom you see a popup. And now, let’s try to execute the latest code that remove banners and check if it works:

And it works perfectly! But there is a new corner case —languages! Look at [Börse Frankfurt](https://www.boerse-frankfurt.de/):

Let’s add button text in German:

    1const puppeteer = require('puppeteer');2

    3(async () => {4    const browser = await puppeteer.launch({ headless: true });5    try {6        const page = await browser.newPage();7

    8        await page.setViewport({ width: 1280, height: 1024 });9

    10        await page.goto('https://www.boerse-frankfurt.de/', { waitUntil: ['load', 'domcontentloaded'] });11

    12        await page.evaluate(_ => {13            const expectedText = /^(Akzeptieren|Accept|Accept all cookies|Accept all|Allow|Allow all|Allow all cookies|Ok)$/gi;14            const clickAccept = (selector) => {15                const elements = document.querySelectorAll(selector);16                for (const element of elements) {17                    if (element.textContent.trim().match(expectedText)) {18                        element.click();19                        return true;20                    }21                }22

    23                return false;24            }25

    26            if (clickAccept('a[id*=cookie i], a[class*=cookie i], button[id*=cookie i] , button[class*=cookie i]')) {27                return;28            }29

    30            // a second try31            clickAccept('a, button');32        });33

    34        await wait(2000);35

    36        await page.screenshot({ type: 'png', path: 'screenshot.png' });37    } catch (e) {38        console.log(e)39    } finally {40        await browser.close();41    }42})();43

    44async function wait(delay) {45    return new Promise(function (resolve, reject) {46        setTimeout(resolve, delay);47    });48}

And voila:

It works. It is a constant headache to adapt the code to all corner cases and all possible cookie banners.

In [ScreenshotOne screenshot API](/), the problem is already solved, and the code is constantly updated to hide all cookie consents, including all found corner cases.

Block cookie banners with EasyList filter lists rules

-----------------------------------------------------

The [EasyList site](https://easylist.to/) provides a list of rules that were originally designed for [AdBlock](https://web.archive.org/web/20200430081315/http://adblock.mozdev.org/), but thanks to [Puppeteer AdBlocker library](https://github.com/ghostery/adblocker/blob/master/packages/adblocker-puppeteer/README.md), these lists can be used from Puppeteer to block not only ads but cookies banners, GDPR overlay windows, privacy-related notices, Social Media content, in-page pop-ups and other annoyances.

Let’s install the library:

Terminal window

    1npm install --save @cliqz/adblocker-puppeteer cross-fetch

The library requires [cross-fetch](https://www.npmjs.com/package/cross-fetch) as a dependency to download blocking lists.

And try to apply it and take a screenshot for StackOverflow:

    1const puppeteer = require('puppeteer');2const { PuppeteerBlocker } = require('@cliqz/adblocker-puppeteer');3const fetch = require('cross-fetch');4

    5(async () => {6    const blocker = await PuppeteerBlocker.fromLists(fetch, [7        'https://secure.fanboy.co.nz/fanboy-cookiemonster.txt'8    ]);9

    10    const browser = await puppeteer.launch({ headless: true });11    try {12        const page = await browser.newPage();13        await blocker.enableBlockingInPage(page);14

    15        await page.setViewport({ width: 1280, height: 1024 });16

    17        await page.goto('https://stackoverflow.com/', { waitUntil: ['load', 'domcontentloaded', 'networkidle0'] });18

    19        await page.screenshot({ type: 'png', path: 'screenshot.png' });20    } catch (e) {21        console.log(e)22    } finally {23        await browser.close();24    }25})();

It works:

And now let’s try to apply it to CookieBot site:

As you see, it does not work. Using blocking lists is not as effective as using extensions. But there is a solution — a library for blocking CMP (consent management platform) banners!

Automatic cookie consent libraries

----------------------------------

In the case of popups like CookieBot, they are widely known as CMP (consent management platform), and there is a lot of them.

To our luck, there is a library that has support for Puppeteer — [autoconsent](https://www.npmjs.com/package/@duckduckgo/autoconsent/v/1.0.8). The library supports major CMP and allows auto-consent or opt-out.

Install the library:

Terminal window

    1npm i @duckduckgo/autoconsent@1.0.8

And let’s apply it and test with CookieBot:

    1const puppeteer = require('puppeteer');2

    3const autoconsent = require('@duckduckgo/autoconsent/dist/autoconsent.puppet.js');4const extraRules = require('@duckduckgo/autoconsent/rules/rules.json');5

    6const consentomatic = extraRules.consentomatic;7const rules = [8    ...autoconsent.rules,9    ...Object.keys(consentomatic).map(name => new autoconsent.ConsentOMaticCMP(`com_${name}`, consentomatic[name])),10    ...extraRules.autoconsent.map(spec => autoconsent.createAutoCMP(spec)),11];12

    13(async () => {14    const browser = await puppeteer.launch({ headless: true });15    try {16        const page = await browser.newPage();17

    18        await page.setViewport({ width: 1280, height: 1024 });19

    20        page.once('load', async () => {21            const tab = autoconsent.attachToPage(page, 'https://cookiebot.com/', rules, 10);22            try {23                await tab.checked;24                await tab.doOptIn();25            } catch (e) {26                console.warn(`CMP error`, e);27            }28        });29

    30        await page.goto('https://cookiebot.com/', { waitUntil: ['load', 'domcontentloaded', 'networkidle0'] });31

    32        await page.screenshot({ type: 'png', path: 'screenshot.png' });33    } catch (e) {34        console.log(e)35    } finally {36        await browser.close();37    }38})();

And it works like a charm:

(Recommended) Combining automatic cookie consent libraries and blocking by rule lists

-------------------------------------------------------------------------------------

It won’t be a bulletproof solution, but it might be the best one to combine blocking by lists and auto-consent:

    1const puppeteer = require('puppeteer');2const { PuppeteerBlocker } = require('@cliqz/adblocker-puppeteer');3const fetch = require('cross-fetch');4

    5const autoconsent = require('@duckduckgo/autoconsent/dist/autoconsent.puppet.js');6const extraRules = require('@duckduckgo/autoconsent/rules/rules.json');7

    8const consentomatic = extraRules.consentomatic;9const rules = [10    ...autoconsent.rules,11    ...Object.keys(consentomatic).map(name => new autoconsent.ConsentOMaticCMP(`com_${name}`, consentomatic[name])),12    ...extraRules.autoconsent.map(spec => autoconsent.createAutoCMP(spec)),13];14

    15(async () => {16    const blocker = await PuppeteerBlocker.fromLists(fetch, [17        'https://secure.fanboy.co.nz/fanboy-cookiemonster.txt'18    ]);19

    20    const browser = await puppeteer.launch({ headless: true });21    try {22        const page = await browser.newPage();23        await blocker.enableBlockingInPage(page);24

    25        await page.setViewport({ width: 1280, height: 1024 });26

    27        page.once('load', async () => {28            const tab = autoconsent.attachToPage(page, 'https://cookiebot.com/', rules, 10);29            try {30                await tab.checked;31                await tab.doOptIn();32            } catch (e) {33                console.warn(`CMP error`, e);34            }35        });36

    37        await page.goto('https://cookiebot.com/', { waitUntil: ['load', 'domcontentloaded', 'networkidle0'] });38

    39        await page.screenshot({ type: 'png', path: 'screenshot.png' });40    } catch (e) {41        console.log(e)42    } finally {43        await browser.close();44    }45})();

In addition to this solution, you will need to make sure that you support customizations for sites that are not covered by this solution.

Extensions

----------

You can use Chrome Extensions with Puppeteer, and the “I don’t care about cookies” extension is constantly updated and is supported by the author.

I don’t use it because it is a protected GPLv3 license, and I recommend having a consultation with lawyers or receiving permission from the author to use it in commercial code.

Using AI to block cookie banners

--------------------------------

[ScreenshotOne is using AI to block cookie banners](https://screenshotone.com/blog/using-ai-to-block-banners/).

Yes, yes, and you can do it, too. If you are OK to have slower performance when rendering, you can send HTML and screenshot to AI, and ask it to return you code that will remove cookie banners. Then you can execute it and take a screenshot again.

ScreenshotOne API

-----------------

In [ScreenshotOne (URL or HTML to image or PDF API)](/) there is already [a simple option you need to specify to block cookie banners](/docs/options/#block_cookie_banners). And nothing more. The API is ready to handle most cookie banners and is constantly updated to support new cases.

Summary

-------

If you have enough time, money, and energy to deal with all the corner cases, go with [combining automatic cookie consent libraries and blocking by rule lists](#recommended-combining-automatic-cookie-consent-libraries-and-blocking-by-rule-lists).

Otherwise, you can start using [ScreenshotOne API for free](/) to see if it suits you well. This way, you delegate all the headaches of dealing with cookie banners to [ScreenshotOne](/).

Have a nice day 👋 and you also might find helpful:

*   [the complete guide on how to take a screenshot with Puppeteer](/blog/how-take-a-screenshot-with-puppeteer);

*   [how to hide chat widgets when taking a screenshot with Puppeteer](/blog/how-to-hide-chat-widgets-when-taking-a-screenshot-with-puppeteer)

Read more Puppeteer guides

--------------------------

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

[View all posts](/blog/tags/puppeteer-guides/)

#### [How to use proxy per page with Puppeteer](/blog/how-to-use-proxy-per-page-with-puppeteer/)

It is easy to use proxy globally for the puppeteer instance, but there is a trick to use proxy on a per-page basis.

Read more

#### [page.waitForTimeout is not a function in Puppeteer](/blog/page-waitfortimeout-is-not-a-function-in-puppeteer/)

Puppeteer removed page.waitForTimeout(). Learn why the error happens and which modern alternatives to use instead.

Read more

#### [How to take bulk screenshots with Puppeteer](/blog/bulk-screenshots-with-puppeteer/)

Learn how to take screenshots of multiple URLs with Puppeteer, including concurrency management, error handling, retries, and proxy support.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/mss-python-screen-capture
----

How to Take Screenshots with Python MSS

=======================================

Complete guide to the MSS Python screen capture library. Learn installation, capturing monitors, regions, performance optimization, and common errors like xgetimage() failed.

[Blog post](/blog/) 4 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jan 15, 2026

#### Tags

[Desktop screen capture](/blog/tags/desktop-screen-capture/)

[Python MSS](https://pypi.org/project/mss/) stands for Multiple Screen Shot, and it lives up to the name. It handles multi-monitor setups natively, runs on Windows, macOS, and Linux, and delivers solid performance.

[](https://pypi.org/project/mss/)

If you want to save time, [I shared all the code examples in the open GitHub repository](https://github.com/screenshotone/python-mss-examples).

Installation and Basic Usage

----------------------------

Install the library using `pip`:

Terminal window

    1pip install mss

And then:

    1import mss2

    3with mss.mss() as sct:4    # Capture the first monitor5    screenshot = sct.grab(sct.monitors[1])6

    7    # Save to file8    mss.tools.to_png(screenshot.rgb, screenshot.size, output='screenshot.png')

Understanding Monitors

----------------------

mss uses an index system for monitors:

    1import mss2

    3with mss.mss() as sct:4    # monitors[0] = all monitors combined5    # monitors[1] = first monitor6    # monitors[2] = second monitor (if exists)7

    8    for i, monitor in enumerate(sct.monitors):9        print(f"Monitor {i}: {monitor}")

Output:

    1Monitor 0: {'left': 0, 'top': 0, 'width': 3840, 'height': 1080}2Monitor 1: {'left': 0, 'top': 0, 'width': 1920, 'height': 1080}3Monitor 2: {'left': 1920, 'top': 0, 'width': 1920, 'height': 1080}

Capturing Specific Monitors

---------------------------

    1import mss2

    3with mss.mss() as sct:4    # First monitor5    first_monitor = sct.grab(sct.monitors[1])6

    7    # Second monitor8    second_monitor = sct.grab(sct.monitors[2])9

    10    # All monitors combined11    all_monitors = sct.grab(sct.monitors[0])

Capturing Specific Regions

--------------------------

Define a region with a dictionary:

    1import mss2

    3with mss.mss() as sct:4    region = {5        'left': 100,    # X coordinate6        'top': 100,     # Y coordinate7        'width': 500,   # Width in pixels8        'height': 500   # Height in pixels9    }10

    11    screenshot = sct.grab(region)12    mss.tools.to_png(screenshot.rgb, screenshot.size, output='region.png')

Saving Screenshots

------------------

### To PNG File

    1import mss2

    3with mss.mss() as sct:4    screenshot = sct.grab(sct.monitors[1])5    mss.tools.to_png(screenshot.rgb, screenshot.size, output='screenshot.png')

### To PIL Image

    1import mss2from PIL import Image3

    4with mss.mss() as sct:5    screenshot = sct.grab(sct.monitors[1])6

    7    # Convert BGRA to RGB8    img = Image.frombytes('RGB', screenshot.size, screenshot.bgra, 'raw', 'BGRX')9    img.save('screenshot.png')

### To NumPy Array

    1import mss2import numpy as np3

    4with mss.mss() as sct:5    screenshot = sct.grab(sct.monitors[1])6    img_array = np.array(screenshot)  # BGRA format7

    8    # Convert to RGB if needed9    rgb_array = img_array[:, :, :3][:, :, ::-1]  # Remove alpha, BGR to RGB

Understanding Color Formats

---------------------------

mss returns BGRA (Blue, Green, Red, Alpha) format:

    1import mss2

    3with mss.mss() as sct:4    screenshot = sct.grab(sct.monitors[1])5

    6    # Raw bytes (BGRA)7    bgra_bytes = screenshot.bgra8

    9    # RGB bytes (for saving)10    rgb_bytes = screenshot.rgb11

    12    # Size tuple13    width, height = screenshot.size

### BGRA to RGB Conversion

    1import mss2import numpy as np3

    4with mss.mss() as sct:5    screenshot = sct.grab(sct.monitors[1])6

    7    # Method 1: Using numpy8    bgra = np.array(screenshot)9    rgb = bgra[:, :, [2, 1, 0]]  # Swap B and R channels10

    11    # Method 2: Using PIL12    from PIL import Image13    img = Image.frombytes('RGB', screenshot.size, screenshot.bgra, 'raw', 'BGRX')

Performance Optimization

------------------------

### Reuse the mss Instance

    1import mss2

    3# Bad: Creating new instance each time4for i in range(100):5    with mss.mss() as sct:6        screenshot = sct.grab(sct.monitors[1])7

    8# Good: Reuse instance9with mss.mss() as sct:10    for i in range(100):11        screenshot = sct.grab(sct.monitors[1])

### Capture Only What You Need

    1import mss2

    3with mss.mss() as sct:4    # Capturing a smaller region is faster5    small_region = {'left': 0, 'top': 0, 'width': 100, 'height': 100}6    screenshot = sct.grab(small_region)

### Benchmark

    1import mss2import time3

    4with mss.mss() as sct:5    monitor = sct.monitors[1]6

    7    start = time.time()8    frames = 09

    10    while time.time() - start < 5:11        sct.grab(monitor)12        frames += 113

    14    fps = frames / 515    print(f"FPS: {fps:.1f}")

Typical results: 30-60 FPS depending on resolution and system.

Continuous Capture

------------------

    1import mss2import time3

    4def record_screen(duration_seconds, output_dir='frames'):5    import os6    os.makedirs(output_dir, exist_ok=True)7

    8    frames = []9

    10    with mss.mss() as sct:11        monitor = sct.monitors[1]12        start = time.time()13

    14        while time.time() - start < duration_seconds:15            screenshot = sct.grab(monitor)16            frames.append(screenshot)17

    18    # Save frames19    for i, frame in enumerate(frames):20        mss.tools.to_png(frame.rgb, frame.size, output=f'{output_dir}/frame_{i:05d}.png')21

    22    print(f"Captured {len(frames)} frames")23    return frames24

    25record_screen(2)  # Record 2 seconds

Common Errors and Solutions

---------------------------

### ScreenShotError: xgetimage() failed

This error occurs on Linux when the X display isn’t accessible.

**Solution 1**: Set the DISPLAY variable

Terminal window

    1export DISPLAY=:02python your_script.py

**Solution 2**: Use Xvfb for headless servers

Terminal window

    1apt-get install xvfb2xvfb-run python your_script.py

**Solution 3**: Check display access in code

    1import os2import mss3

    4# Ensure DISPLAY is set5if 'DISPLAY' not in os.environ:6    os.environ['DISPLAY'] = ':0'7

    8with mss.mss() as sct:9    screenshot = sct.grab(sct.monitors[1])

### Import Error on Linux

Terminal window

    1# Install required system dependencies2apt-get install python3-xlib

MSS vs DXcam

------------

Feature

MSS

DXcam

Platform

Windows, macOS, Linux

Windows only

FPS

30-60

240+

Multi-monitor

Excellent

Good

Dependencies

Pure Python

DirectX

Best for

Cross-platform

Gaming

**Use MSS when**: You need cross-platform support or don’t need extreme performance.

**Use [DXcam](/blog/dxcam-python-screenshots/) when**: You are on Windows and need maximum FPS.

However, consider that DXcam is not actively maintained at the moment of writing the guide.

Complete Example

----------------

    1import mss2import time3from PIL import Image4from pathlib import Path5

    6class ScreenCapture:7    def __init__(self, output_dir='captures'):8        self.output_dir = Path(output_dir)9        self.output_dir.mkdir(exist_ok=True)10

    11    def capture_monitor(self, monitor_index=1, filename='screenshot.png'):12        """Capture a specific monitor."""13        with mss.mss() as sct:14            if monitor_index >= len(sct.monitors):15                raise ValueError(f"Monitor {monitor_index} not found")16

    17            screenshot = sct.grab(sct.monitors[monitor_index])18            output_path = self.output_dir / filename19            mss.tools.to_png(screenshot.rgb, screenshot.size, output=str(output_path))20            return output_path21

    22    def capture_region(self, left, top, width, height, filename='region.png'):23        """Capture a specific region."""24        region = {'left': left, 'top': top, 'width': width, 'height': height}25

    26        with mss.mss() as sct:27            screenshot = sct.grab(region)28            output_path = self.output_dir / filename29            mss.tools.to_png(screenshot.rgb, screenshot.size, output=str(output_path))30            return output_path31

    32    def list_monitors(self):33        """List available monitors."""34        with mss.mss() as sct:35            return sct.monitors36

    37# Usage38capture = ScreenCapture()39print("Monitors:", capture.list_monitors())40capture.capture_monitor(1, 'monitor1.png')41capture.capture_region(0, 0, 500, 500, 'region.png')

Run the script with:

Terminal window

    1python record_screen.py

Results on my machine:

For the first monitor:

For the region:

Summary

-------

Python MSS is the best general-purpose screen capture library for Python:

1.  Cross-platform (Windows, macOS, Linux)

2.  Fast enough for most use cases (30-60 FPS)

3.  Native multi-monitor support

4.  Simple API with no complex dependencies

For website screenshots check out our [guide on website screenshots with Python](/blog/how-to-take-website-screenshots-in-python/) or use [Playwright](/blog/playwright-python-screenshots/).

Frequently Asked Questions

--------------------------

If you read the article, but still have questions. Please, check the most frequently asked. And if you still have questions, feel free reach out at [support@screenshotone.com](mailto:support@screenshotone.com).

### Is MSS faster than DXcam for screen capture?

No, DXcam is faster (240+ FPS vs 30-60 FPS), but it only works on Windows. mss is the best choice for cross-platform code or when you don't need extreme performance.

### How to fix MSS ScreenShotError xgetimage() failed?

This error occurs on Linux when the display isn't accessible. Make sure DISPLAY environment variable is set, or run with a display server. For headless servers, use Xvfb.

### What format does MSS grab() return?

MSS returns a ScreenShot object with BGRA pixel data. Use screenshot.rgb for RGB data, or convert with PIL/numpy for other formats.

Read more Desktop screen capture

--------------------------------

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

[View all posts](/blog/tags/desktop-screen-capture/)

#### [How to Capture Desktop Screenshots in Python](/blog/python-screen-capture/)

Complete guide to desktop screen capture in Python. Compare Python MSS, DXcam, PyAutoGUI for capturing monitors, windows, and screen regions.

Read more

#### [How to Capture Desktop Screen with DXcam in Python](/blog/dxcam-python-screenshots/)

Complete guide to DXcam, the fastest Python screen capture library. Learn high-FPS capture, video mode, region capture, and DXcam vs Python MSS performance comparison.

Read more

#### [How to Take Screenshots with PyAutoGUI in Python](/blog/pyautogui-python-screenshots/)

Complete guide to taking screenshots with PyAutoGUI in Python. Learn screenshot(), region parameters, locateOnScreen(), and common errors with ImageNotFoundException.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/how-to-take-screenshots-of-social-media-pages
----

Rendering screenshots of social media pages

===========================================

Social media platforms often restrict automation, but with the right tools and care for compliance, capturing screenshots is possible.

[Blog post](/blog/) 2 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Jul 4, 2025

#### Tags

[Screenshot rendering](/blog/tags/screenshot-rendering/)

Requirements

------------

### A screenshot API

First of all, you need access to any screenshot API, but I will use the ScreenshotOne API as an example in this tutorial. It requires a bit of coding skills or you can use [our Zapier integration](https://zapier.com/apps/screenshotone/integrations). Also, you can reach out to us at [hey@screenshotone.com](mailto:hey@screenshotone.com) and we can see if we can render screenshots for you.

[Sign up](https://dash.screenshotone.com/sign-up) to the ScreenshotOne API and get the access key to send API requests like:

    1https://api.screenshotone.com/take?access_key=<your access key>&url=https://example.com

### Residential proxies

Social media often block requests that come from servers and not from computers that have IP addresses like regular users. To bypass that limitation, it is recommended to use residential proxies. There is a huge variety of proxy providers you can choose from, e.g. [Smartproxy](https://smartproxy.com/), [Geonode](https://geonode.com/), and others.

When you use them, almost all the requests you send look like you sent them from the regular home computer. The ScreenshotOne API supports specifying proxies with [the proxy option](https://screenshotone.com/docs/options/#proxy).

Sign up to one of the proxy providers and get the link to an HTTP proxy, we can use it in the API request like: [https://api.screenshotone.com/take?access\_key=](https://api.screenshotone.com/take?access_key=)&proxy=&url=[https://example.com](https://example.com)

### Authentication and cookies

Having proxies is not enough. Some social media websites will block rendering screenshots of profiles and company pages even for residential proxies and will require a user to log in.

In such cases, social media platforms require user authentication. Accessing content this way often falls under strict terms of service, and attempting to bypass these controls may be unlawful or against the platform’s policies. Always ensure your actions comply with applicable legal and contractual obligations.

Screenshot of social media profiles

-----------------------------------

Once you have a ScreenshotOne access key, residential proxy access, and can fetch a cookie for any website, we can go and make screenshots for them.

In some cases, residential proxies may help simulate typical user access, which might reduce the likelihood of blocks. However, this does not guarantee compliance with platform terms of service.

And don’t forget to block cookie cookie banners by using block\_cookie\_banners and block\_banners\_by\_heuristics:

    1https://api.screenshotone.com?proxy=<your rotating residential proxy URL>&url=<a social media URL>&block_banners_by_heuristics=true&block_cookie_banners=true

Is it legal to scrape or screenshot social media profiles?

----------------------------------------------------------

In general, the legality of scraping or screenshotting social media profiles depends on local laws, the purpose of data use, and the social media platform’s terms of service.

Laws vary by region, with areas like the EU having strict data protection regulations. Using scraped data, especially for commercial purposes without consent, often breaches legal and ethical boundaries. Also, automated scraping may violate a platform’s terms, leading to potential legal consequences.

ScreenshotOne provides technical infrastructure for screenshot rendering. The responsibility for ensuring lawful use of the tool lies entirely with the user. Users must comply with all applicable laws and third-party terms of service when using ScreenshotOne.

It’s essential to adhere to local laws and seek legal advice if necessary. Always consider the legal implications of scraping, or screenshotting social media content.

Summary

-------

Capturing screenshots of social media pages is achievable with the right combination of tools and compliance considerations.

If you have questions, feedback, or encounter issues, please reach out to us at [support@screenshotone.com](mailto:support@screenshotone.com).

Read more Screenshot rendering

------------------------------

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

[View all posts](/blog/tags/screenshot-rendering/)

#### [How to render HTML with Puppeteer](/blog/how-to-render-html-with-puppeteer/)

Use Puppeteer or screenshot API to generate the Open Graph protocol images, bills, receipts, or invoices PDF or PNG files from the HTML templates.

Read more

#### [Website Screenshots with Selenium in Python](/blog/selenium-python-screenshots/)

Complete guide to taking screenshots with Selenium in Python. Learn save\_screenshot(), element screenshots, full page workarounds, and headless mode setup.

Read more

#### [How to take website screenshots with C# (.NET)](/blog/how-to-take-website-screenshots-with-csharp-dotnet/)

The article examines how you can take screenshots of any URL with C# (.NET) by using PuppeteerSharp, or screenshot API as a service.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/pdfs/example.com.pdf
----

E x a mpl e   D om ai n  T hi s   d om ai n   i s   f or   us e   i n   i llustr a t i v e   e x a mpl e s   i n   d o c um e nts .   Y ou   m a y   us e   t hi s   d om ai n   i n   l i t e r a tur e  w i t h out   pr i or   c oor di n a t i on   or   a s ki n g   f or   p e rm i ss i on .  M or e   i n f orm a t i on ...

----
url: https://screenshotone.com/contributors/john-rush
----

John Rush

---------

View all Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [SEOBot uses ScreenshotOne API to generate screenshots for articles](/blog/seobot-automates-screenshot-generation-for-articles/)

Customers can your product in unpredictable and surprising ways. SEOBot now uses ScreenshotOne API to enhance its articles with screenshots, making content more engaging and visually appealing.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [John Rush](/contributors/john-rush/)

Published on

Feb 27, 2024

•

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/9
----

Changes and updates

-------------------

Stay updated with the latest information about new features, bug fixes, and optimizations at ScreenshotOne

### Product updates in the last 12 months

Oct 25, 2024

#### [Using AI to block banners](/changelog/using-ai-to-block-banners/)

First successful attempts to block banners on websites using AI before rendering screenshots.

Read more →

1 min read

Oct 15, 2024

#### [Set locale and language of the browser](/changelog/language-and-locale/)

A new version of the ScreenshotOne API has been just deployed. It allows you to set both locale and language of the browser when rendering screenshots with one simple option.

Read more →

1 min read

Oct 13, 2024

#### [Stop scrolling screenshots when a given selector is visible](/changelog/animated-scrolling-till-selector/)

New options were added to the ScreenshotOne API to stop scrolling screenshots when a given selector is reached.

Read more →

1 min read

Aug 27, 2024

#### [Improved the behavior and stability of the "scroll\_into\_view" option](/changelog/improved-scroll-into-view/)

Before the change, there was a subset of cases when the rendering requests were failing when using the scroll\_into\_view option. Now, it is improved and will make rendering more stable.

Read more →

1 min read

Aug 2, 2024

#### [Get the HTTP response status code and headers with screenshots](/changelog/http-response-metadata/)

On rare occasions, you might need to get the HTTP status code and headers of the target host. It is pretty easy to do now.

Read more →

1 min read

Jul 30, 2024

#### [Better error coverage and documentation](/changelog/all-errors-are-covered/)

Since a few months ago, it has been possible to check errors in the dashboard request log and get explanations and more details in the documentation. But!

Read more →

1 min read

Jul 29, 2024

#### [Improved API request log](/changelog/introducing-request-log/)

A new and improved request log has been deployed. That is a good beginning of the week! Check out why.

Read more →

1 min read

Jul 20, 2024

#### [ScreenshotOne is now integrated into Summit](/changelog/summit-integration/)

The ScreenshotOne screenshot API is now natively integrated into Summit and you can perform anything on top of the powerful screenshot automation and Summit models—only the sky is the limit.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/contributors/dmytro-krasun/6
----

Dmytro Krasun

-------------

With more than a decade of experience in software engineering, I share the best practices and solutions you can apply to your problems in the space of headless browsers. You can also find me on [Twitter](https://twitter.com/DmytroKrasun) and [LinkedIn](https://www.linkedin.com/in/dmytrokrasun)

View all Changelog

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Why and how to choose a screenshot API](/blog/why-and-how-to-choose-a-screenshot-api/)

You don't need a screenshot API if it is a one-off task for you and you can use some library for screenshotting.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 20, 2024

•

6 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [3 best screenshot APIs in 2026](/blog/best-screenshot-apis/)

The truth is, that there is no single best screenshot API that fits everyone. But some APIs stand out and shine when compared to others. Also, it depends on your use case and needs which must be included in considering what API to use.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jan 6, 2026

•

7 min read

#### [Rendering screenshot with Browserless](/blog/browserless/)

A few words about what is Browserless, when to use it, and if it is suitable for screenshots or not.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

May 6, 2024

•

4 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Stagetimer automates Open Graph image generation](/blog/how-stagetimer-automates-og-image-generation/)

We would love to share a quick review of ScreenshotOne by Lukas Hermann, a co-founder of Stagetimer on how he uses the API daily to generate screenshots and automate regular tasks associated with screenshots.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Lukas Hermann](/contributors/lukas-hermann/)

Published on

Mar 5, 2024

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Elias Stråvik uses GPT-4 Vision and Zapier for landing page feedback automation](/blog/generating-landing-page-feedback-with-vision/)

A quick review of ScreenshotOne by Elias Stråvik, a founder of Roast as A Service on how he uses the ScreenshotOne daily to automate regular tasks associated with screenshots.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Elias Stravik](/contributors/elias-stravik/)

Updated on

Mar 4, 2024

•

1 min read

[Customer stories](/blog/tags/customer-stories/)

#### [SEOBot uses ScreenshotOne API to generate screenshots for articles](/blog/seobot-automates-screenshot-generation-for-articles/)

Customers can your product in unpredictable and surprising ways. SEOBot now uses ScreenshotOne API to enhance its articles with screenshots, making content more engaging and visually appealing.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [John Rush](/contributors/john-rush/)

Published on

Feb 27, 2024

•

1 min read

#### [ScreenshotOne is featured in the Cloudflare "Built With" series](/blog/screenshotone-and-cloudflare/)

The Cloudflare platform is at the core of ScreenshotOne—it is used for caching, API gateway, storage for screenshots, and many other functions. It was an opportunity to learn about the company from a closer distance.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Aug 3, 2024

•

1 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Rendering screenshots of social media pages](/blog/how-to-take-screenshots-of-social-media-pages/)

Social media platforms often restrict automation, but with the right tools and care for compliance, capturing screenshots is possible.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jul 4, 2025

•

2 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Ilias Ism, a founder of the MagicSpace SEO agency, uses ScreenshotOne daily](/blog/how-ilias-ism-a-founder-of-the-magicspace-seo-agency-uses-screenshotone-daily/)

We would love to share a quick review of ScreenshotOne by Ilias Ism, a founder of MagicSpace SEO agency and OG Image Generator on how he uses the API daily to generate screenshots and automate regular tasks associated with screenshots.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Dec 5, 2023

•

1 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [Comparing Puppeteer versus Selenium for rendering website screenshots](/blog/comparing-puppeteer-versus-selenium-for-rendering-website-screenshots/)

When comparing Puppeteer, Selenium, and ScreenshotOne for rendering screenshots, it's crucial to understand the distinct capabilities and use cases of each tool.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Oct 5, 2023

•

2 min read

#### [Using Clobbr to quickly load test the ScreenshotOne API](/blog/using-clobbr-to-quickly-load-test-the-screenshotone-api/)

Google Cloud gives $300 in credits for 3 months for experimenting. And I decided to give it a try, but not because of the free credits.

Written by

[Dan Mindru](/contributors/dan-mindru/), [Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Sep 23, 2023

•

3 min read

#### [Alexander Schnebel about how he uses ScreenshotOne in Productglowup](/blog/alexander-schnebel-about-how-he-uses-screenshotone-in-productglowup/)

I had a great chat with Alexander Schnebel, the fullstack software engineer behind Productglowup.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jul 23, 2023

•

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/pipedream-integration
----

ScreenshotOne is available on Pipedream

=======================================

Automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos in Pipedream.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Dec 8, 2025

[ScreenshotOne Pipedream integration is now available](/integrations/pipedream/).

With Pipedream and ScreenshotOne, you can:

*   render website screenshots;

*   PDFs from HTML or URLs;

*   scrolling screenshots and videos;

*   HTML and Markdown to images;

*   and more…

All as part of your workflows in [Pipedream](https://pipedream.com/)—a powerful developer-first automation platform.

If you have any questions or need any assistance, please, reach out at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Improved uploading and error handling to S3-compatible storage](/changelog/improved-storage-upload/)

Today, the new version of ScreenshotOne API was deployed to production that enables a retries mechanism when uploading to an S3 storage and more granular error handling.

Read more →

1 min read

#### [Documentation for LLMs](/changelog/docs-for-llms/)

ScreenshotOne now supports documentation format specifically targeted for LLMs—llms.txt and llms-full.txt.

Read more →

1 min read

#### [Failed payment alerts in the dashboard](/changelog/failed-payment-alerts/)

Starting today, you will see an alert in the dashboard when a payment fails.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/better-and-more-extensible-pdf-rendering
----

Better and more extensible PDF rendering

========================================

ScreenshotOne supports PDF rendering for a long time but it was used till recently by a small group of customers. Growing demand in PDF rendering required updating the API. And today, we introduce new options for PDF customization.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Feb 2, 2024

We have added a possibility to render the website as a page PDF, it is essentially the equivalent of the full-page screenshot, but as a PDF with one page only. Use the [pdf\_fit\_one\_page](https://screenshotone.com/docs/options/#pdf_print_background) option to achieve that.

And you can force our PDF API (now we call it so) to render graphics, which is not enabled by default. Most of our current customers use PDF rendering without graphics. Use the [pdf\_print\_background](https://screenshotone.com/docs/options/#pdf_print_background) option to achieve that.

Happy to share the updates and more soon to come!

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Choose the format of the page content returned by the ScreenshotOne API](/changelog/metadata-content-format/)

Now you can choose the format of the page content returned by ScreenshotOne API with the metadata\_content\_format option.

Read more →

1 min read

#### [Change organization owner for already subscribed customers](/changelog/change-ownership-for-subscribed/)

Starting today, you can change organization owner for already subscribed customers.

Read more →

1 min read

#### [I migrated to Google Cloud](/changelog/i-migrated-to-google-cloud/)

Google Cloud gives $300 in credits for 3 months for experimenting. And I decided to give it a try, but not because of the free credits.

Read more →

4 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/ai-vision-web-page-analysis
----

Automate Website Screenshots

1 min read

AI Vision For Analyzing Web Pages

=================================

Use AI to extract insights from web page visuals for enhanced content strategy and market analysis.

ScreenshotOne [supports OpenAI GPT-4 vision integration](/blog/support-of-the-openai-gpt-vision-api-in-screenshotone/) for a long time.

It made possible to capture web pages and then use the vision API to analyze these images for content, design, and layout insights.

This powerful combination allows for an in-depth understanding of how web pages are structured and how they can be optimized for better performance.

Small companies can benefit from this approach by gaining insights into competitors’ web strategies, identifying trends, and optimizing their own content for better engagement and SEO. For example, you can read about [how ScreenshotOne helps automating landing page analysis for Roast as a Service](/blog/generating-landing-page-feedback-with-vision/).

The advantage of using ScreenshotOne API for this purpose is significant, as it offers a streamlined process for capturing and analyzing web page screenshots, saving businesses time and resources compared to in-house development.

There are already companies providing that landing page evaluation as a product, if you are curious, read more about [how FounderPal uses ScreenshotOne for automated landing page evaluation with AI](/blog/how-founderpal-uses-screenshotone/).

Integrated ScreenshotOne in my production app within minutes. Flexible API that has fit every use case I've thrown at it.

Tim Wheeler

Maker, [BotRoast.io](https://www.botroast.io/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

### AI Agents With Browser Observation

Give AI agents reliable screenshots of web pages so they can inspect, compare, and act with visual context.

[Read more →](/use-cases/ai-agents/)

### Landing Page Evaluation with AI

Automate landing page roasting for your customers or yourself with modern technologies like OpenAI Vision.

[Read more →](/use-cases/ai-landing-page-roasting/)

### Screenshots for NemoClaw Agents

Use ScreenshotOne with NemoClaw to capture website screenshots for enterprise AI agents, browser verification, secure reporting, and visual audit trails.

[Read more →](/use-cases/nemoclaw-agents/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/guides
----

[Skip to content](#_top)

Guides

======

Copy page

Check out our collection of guides to help you get the most out of ScreenshotOne:

*   [How to handle API errors](/docs/guides/how-to-handle-api-errors/)

*   [How to use proxies](/docs/guides/how-to-use-proxies/)

*   [How to optimize for performance](/docs/guides/performance/)

*   [How to screenshot authenticated pages](/docs/guides/authenticated-pages/)

*   [How to take full-page screenshots](/docs/guides/full-page-screenshots/)

*   [How to bypass CAPTCHAs](/docs/guides/how-to-bypass-captchas/)

*   [Upload to any S3 storage](/docs/guides/upload-to-s3/)

*   [How to screenshot an area of a site](/docs/guides/how-to-screenshot-an-area-of-a-site/)

*   [Translate and screenshot a website](/docs/guides/how-to-translate-and-render-a-website-as-a-screenshot/)

*   [How to customize websites](/docs/guides/how-to-customize-any-website-before-screenshotting/)

*   [Fail rendering if the content contains a string](/docs/guides/fail-if-content-contains/)

*   [Render Google Slides as scrolling screenshots](/docs/guides/google-slides-as-scrolling-screenshots/)

*   [Screenshot Google Documents](/docs/guides/screenshot-google-docs/)

*   [Emojis](/docs/guides/emojis/)

*   [How to detect website fonts](/docs/guides/how-to-detect-website-fonts/)

*   [How to take screenshots of multiple URLs](/docs/guides/bulk-screenshots/)

----
url: https://screenshotone.com/docs/errors/access-key-invalid
----

[Skip to content](#_top)

Access Key Invalid

==================

Copy page

It is an API error returned when the provided access key is invalid or incorrect.

    1{2    "is_successful": false,3    "error_code": "access_key_invalid",4    "error_message": "The `access_key` parameter is set, but it is not correct. Please, check out the access dashboard page to get the access key—https://dash.screenshotone.com/access.",5    "documentation_url": "https://screenshotone.com/docs/errors/access-key-invalid/"6}

Reasons and how to fix

----------------------

### Incorrect Access Key

One common reason for the “access\_key\_invalid” error is using an incorrect access key. This can happen if the key is copied incorrectly or if an old key is being used.

To fix this, ensure you are using the correct access key by visiting the [access dashboard page](https://dash.screenshotone.com/access) and copying the key directly from there.

### Typographical Errors

Typos in the access key parameter can also lead to this error. This includes extra spaces, missing characters, or incorrect case sensitivity.

To fix this, carefully check and re-enter the access key, ensuring there are no typographical errors. Copy-pasting the key directly from the dashboard is recommended.

### Misconfigured Environment

In some cases, the environment where the API request is being made might be misconfigured, leading to the wrong access key being used.

To fix this, review your environment configuration settings to ensure the correct access key is being used in the appropriate environment (e.g., development, staging, production).

Reach out to support

--------------------

If you continue to face issues, please reach out to `support@screenshotone.com`, and we will assist you as soon as possible.

----
url: https://screenshotone.com/contributors/lukas-hermann
----

Lukas Hermann

-------------

View all Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [How Stagetimer automates Open Graph image generation](/blog/how-stagetimer-automates-og-image-generation/)

We would love to share a quick review of ScreenshotOne by Lukas Hermann, a co-founder of Stagetimer on how he uses the API daily to generate screenshots and automate regular tasks associated with screenshots.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Lukas Hermann](/contributors/lukas-hermann/)

Published on

Mar 5, 2024

•

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/email-marketing
----

Automate Website Screenshots

1 min read

Dynamic Email Campaign Previews

===============================

Automatically generate and embed website screenshots in email marketing campaigns.

For small companies looking to enhance their email marketing efforts, incorporating dynamic content such as live website screenshots can significantly increase engagement rates. Utilizing a website screenshot API like ScreenshotOne offers a streamlined solution for this need.

[Read more about how and why “Bridesmaid for Hire” used ScreenshotOne to boost their email campaign CTR.](/blog/braidsmade-for-hire-case-study/)

Why Use ScreenshotOne for Email Campaigns?

------------------------------------------

ScreenshotOne API simplifies the process of capturing up-to-date website visuals, allowing developers to easily embed these images into email newsletters or promotional materials. This approach ensures recipients receive the most current content, making emails more appealing and relevant.

Value and Time Savings

----------------------

By leveraging a screenshot API, companies save on the substantial time and resources that would otherwise be spent developing an in-house solution or manually updating email content. ScreenshotOne provides high-quality, timely screenshots with minimal latency, ensuring your email campaigns are enhanced without significant overhead.

ScreenshotOne is a really helpful service provider. All that I need for my work is combined here.

Service is comfortable, fast, and consistent. It has a nice support service that always stays active to problems of users and has an immediate response time.

I really appreciate and recommend ScreenshotOne to everyone.

Alexandr Bezhan

Chief Product Officer, [AMS Pilot](https://www.amspilot.com/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/dirstarter-integration
----

ScreenshotOne integration with Dirstarter

=========================================

Build a directory with Dirstarter and add website screenshots automatically with ScreenshotOne.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Dec 10, 2025

ScreenshotOne is [integrated with Dirstarter](/integrations/dirstarter/)—a complete, customizable Next.js directory template.

With Dirstarter and ScreenshotOne, you can:

*   automatically capture website screenshots for your directory listings;

*   launch unlimited directories with the one-time purchase template;

*   customize the design to match your brand;

*   accept payments with built-in Stripe integration;

*   benefit from SEO optimization out of the box.

Check out [Dirstarter documentation](https://dirstarter.com/docs/integrations/media) for more details on how to set up the integration.

If you have any questions or need any assistance, please, reach out at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Improved blocking of banners for specific websites](/changelog/improved-banner-blocking-for-specific-websites/)

We just released an updated version of our algorithm to block banners for specific websites by heuristics.

Read more →

1 min read

#### [Added a "copy page" button in documentation](/changelog/copy-page-button-in-docs/)

You can now copy the page content as Markdown for LLMs and more.

Read more →

1 min read

#### [Async, Webhooks, and Extra Limits](/changelog/async-webhooks-and-extra-limits/)

May was a great month and full of new and exciting updates. Let's check them out quickly.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/emojis
----

How to render screenshots with different emoji styles in Puppeteer

==================================================================

Learn how to render screenshots with different emoji styles in Puppeteer using emoji-js in a few lines of code.

[Blog post](/blog/) 2 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Apr 4, 2025

#### Tags

[Puppeteer guides](/blog/tags/puppeteer-guides/)

When working with Puppeteer for web scraping or screenshot generation, you might need to render pages with different emoji styles rather than the default emoji style provided by the browser.

There are many emoji libraries that can help with this. For example, [emoji-js](https://www.npmjs.com/package/emoji-js) is a popular library that can be used to render emojis in different styles.

> **Note:** Whatever emoji library or style you decide to use, make sure you do not violate any license of the emoji set.

> 

> For example, if you use [emojis provided by Twitter](https://github.com/twitter/twemoji), you must follow their license requirements.

Using emoji-js with Puppeteer

-----------------------------

Here’s how you can use Puppeteer to replace emojis on a page with a different style (like Twitter emojis):

    1const puppeteer = require("puppeteer");2

    3async function takeScreenshotWithCustomEmojis(url, outputPath) {4    const browser = await puppeteer.launch();5    const page = await browser.newPage();6

    7    await page.goto(url, { waitUntil: "networkidle2" });8

    9    // replace emojis with different style10    await page.evaluate(() => {11        return new Promise((resolve) => {12            const script = document.createElement("script");13            script.src = "https://cdn.jsdelivr.net/npm/emoji-js@3.8.1/lib/emoji.min.js";14            script.crossOrigin = "anonymous";15            script.onload = () => {16                // change to the emoji set you want to use17                const img_set = "twitter";18

    19                const emoji = new window.EmojiConvertor();20

    21                emoji.img_sets[img_set].path =22                    `https://cdn.jsdelivr.net/npm/emoji-datasource-${img_set}@15.1.2/img/${img_set}/64/`;23                emoji.img_sets[img_set].sheet =24                    `https://cdn.jsdelivr.net/npm/emoji-datasource-${img_set}@15.1.2/img/${img_set}/sheets/64.png`;25                emoji.img_set = img_set;26                emoji.replace_mode = "img";27

    28                // Recursively iterate through DOM and replace emojis only in text nodes29                function replaceEmojisInTextNodes(node) {30                    if (node.nodeType === Node.TEXT_NODE) {31                        if (node.textContent && node.textContent.trim()) {32                            const span = document.createElement("span");33                            const replaced = emoji.replace_unified(node.textContent);34                            span.innerHTML = replaced;35

    36                            if (replaced.trim() !== node.textContent.trim()) {37                                const parent = node.parentNode;38                                if (parent) {39                                    while (span.firstChild) {40                                        parent.insertBefore(span.firstChild, node);41                                    }42                                    parent.removeChild(node);43                                }44                            }45                        }46                    } else if (node.nodeType === Node.ELEMENT_NODE) {47                        if (node.tagName === "SCRIPT" || node.tagName === "STYLE") {48                            return;49                        }50

    51                        const childNodes = Array.from(node.childNodes);52                        childNodes.forEach((child) => replaceEmojisInTextNodes(child));53                    }54                }55

    56                replaceEmojisInTextNodes(document.body);57                resolve();58            };59

    60            document.body.appendChild(script);61        });62    });63

    64    await page.screenshot({ path: outputPath });65

    66    await browser.close();67    console.log(`Screenshot saved to ${outputPath}`);68}69

    70takeScreenshotWithCustomEmojis("https://example.com", "screenshot-with-custom-emojis.png").catch(71    (err) => console.error("Error taking screenshot:", err)72);

ScreenshotOne API

-----------------

If you decide to go with [the ScreenshotOne API for rendering screenshots](https://screenshotone.com/), you can just apply the scripts from above as a simple API `scripts` parameter:

    1https://api.screenshotone.com/take?access_key=<your_access_key>&url=https://example.com&scripts=const%20stylesheet%20%3D%20document.createElement%28%27link%27%29%3B%0Astylesheet.href%20%3D%20%27https%3A%2F%2Fcdn.jsdelivr.net%2Fnpm%2Femoji-js%403.8.1%2Flib%2Femoji.min.css%27%3B%0Astylesheet.rel%20%3D%20%27stylesheet%27%3B%0Adocument.head.appendChild%28stylesheet%29%3B%0A%0Aconst%20script%20%3D%20document.createElement%28%27script%27%29%3B%0Ascript.onload%20%3D%20%28%29%20%3D%3E%20%7B%0A%20%20%20%20%2F%2F%20change%20to%20one%20you%20are%20interested%20in%2C%20%0A%20%20%20%20%2F%2F%20check%20the%20library%20documentation%20for%20the%20list%20of%20available%20emoji%20sets%0A%20%20%20%20const%20img_set%20%3D%20%27apple%27%3B%0A%0A%20%20%20%20const%20emoji%20%3D%20new%20window.EmojiConvertor%28%29%3B%20%20%20%20%0A%20%20%20%20%0A%20%20%20%20emoji.img_sets%5Bimg_set%5D.path%20%3D%20%60https%3A%2F%2Fcdn.jsdelivr.net%2Fnpm%2Femoji-datasource-%24%7Bimg_set%7D%4015.1.2%2Fimg%2F%24%7Bimg_set%7D%2F64%2F%60%3B%0A%20%20%20%20emoji.img_sets%5Bimg_set%5D.sheet%20%3D%20%60https%3A%2F%2Fcdn.jsdelivr.net%2Fnpm%2Femoji-datasource-%24%7Bimg_set%7D%4015.1.2%2Fimg%2F%24%7Bimg_set%7D%2Fsheets%2F64.png%60%3B%0A%20%20%20%20emoji.img_set%20%3D%20img_set%3B%0A%0A%20%20%20%20emoji.replace_mode%20%3D%20%27img%27%3B%0A%0A%20%20%20%20function%20replaceEmojisInTextNodes%28node%29%20%7B%0A%20%20%20%20%20%20%20%20if%20%28node.nodeType%20%3D%3D%3D%20Node.TEXT_NODE%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20%28node.textContent%20%26%26%20node.textContent.trim%28%29%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20const%20span%20%3D%20document.createElement%28%27span%27%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20const%20replaced%20%3D%20emoji.replace_unified%28node.textContent%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20span.innerHTML%20%3D%20replaced%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20%28replaced.trim%28%29%20%21%3D%3D%20node.textContent.trim%28%29%29%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20const%20parent%20%3D%20node.parentNode%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20%28parent%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20while%20%28span.firstChild%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20parent.insertBefore%28span.firstChild%2C%20node%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20parent.removeChild%28node%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%20else%20if%20%28node.nodeType%20%3D%3D%3D%20Node.ELEMENT_NODE%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20%28node.tagName%20%3D%3D%3D%20%27SCRIPT%27%20%7C%7C%20node.tagName%20%3D%3D%3D%20%27STYLE%27%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20const%20childNodes%20%3D%20Array.from%28node.childNodes%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20childNodes.forEach%28child%20%3D%3E%20replaceEmojisInTextNodes%28child%29%29%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20replaceEmojisInTextNodes%28document.body%29%3B%0A%7D%3B%0A%0Ascript.src%20%3D%20%27https%3A%2F%2Fcdn.jsdelivr.net%2Fnpm%2Femoji-js%403.8.1%2Flib%2Femoji.min.js%27%3B%0Ascript.crossOrigin%20%3D%20%27anonymous%27%3B%0A%0Adocument.body.appendChild%28script%29%3B

There is [a guide on how to render screenshots with different emoji styles in the ScreenshotOne API docs](/docs/guides/emojis).

Conclusion

----------

Using `emoji-js` with Puppeteer is a simple way to render screenshots with different emoji styles and can be accomplished in a few lines of code.

As an alternative to Puppeteer, you can use the ScreenshotOne API to render screenshots with different emoji styles, and doing the same but with just one simple API option.

If you have any questions or suggestions, and decide to go with the ScreenshotOne API for screenshot generation, please let us know at `support@screenshotone.com`.

Read more Puppeteer guides

--------------------------

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

[View all posts](/blog/tags/puppeteer-guides/)

#### [Puppeteer Performance Monitoring with Inspector](/blog/puppeteer-performance-monitoring-with-inspector/)

In this article I'll show you how to monitor performance and errors of a browser automation script written with Puppeteer.

Read more

#### [Puppeteer waitUntil: how to wait for page load](/blog/puppeteer-wait-until-the-page-is-ready/)

Join me in exploring how to find the ideal wait time or event of when to take the page screenshot with Puppeteer.

Read more

#### [How to take bulk screenshots with Puppeteer](/blog/bulk-screenshots-with-puppeteer/)

Learn how to take screenshots of multiple URLs with Puppeteer, including concurrency management, error handling, retries, and proxy support.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/company-information-management
----

Update your company information in the dashboard

================================================

Starting today, you can update your company information in the dashboard. It includes updating the address, tax number, company number, and company name.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Nov 12, 2024

For tax purposes, VAT return, and other legal documents, you can update your company information [directly in the dashboard](https://dash.screenshotone.com/billing/company), without requesting a support ticket.

If you have any questions or suggestions, feel free to contact us at [support@screenshotone.com](mailto:support@screenshotone.com).

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [ScreenshotOne API supports GPU Rendering](/changelog/screenshotone-api-supports-gpu-rendering/)

From today ScreenshotOne supports GPU rendering for both regular and animated website screenshots. The API now leverages the latest in graphics processing technology to bring your screenshot needs to a whole new level.

Read more →

2 min read

#### [Improved blocking of banners and popups](/changelog/improved-blocking-of-banners-and-popups/)

Improved generic algorithm to bypass blockers and better banner exclusion heuristics.

Read more →

1 min read

#### [Improved uploading and error handling to S3-compatible storage](/changelog/improved-storage-upload/)

Today, the new version of ScreenshotOne API was deployed to production that enables a retries mechanism when uploading to an S3 storage and more granular error handling.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/how-founderpal-uses-screenshotone
----

How FounderPal uses ScreenshotOne for landing page analysis

===========================================================

If you are interested in diving deeper into the FounderPal use case and discover if ScreenshotOne might be useful for you, too, keep reading.

[Customer story](/blog/tags/customer-stories/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jun 2, 2024

[FounderPal](https://founderpal.ai/) positions itself as a marketing co-pilot—from analyzing your ideal customer to generating a unique value proposition for one-person businesses.

They use ScreenshotOne to analyze and give automated feedback on landing pages for their customers.

FounderPal and ScreenshotOne

----------------------------

Here is what Dan Kulkov a co-founder shared with us about their integration with ScreenshotOne:

### How did you discover ScreenshotOne?

> I have been following Dmytro for a few years already. He is the opposite of most solopreneurs. He is 100% focused on building the best product without any distractions. This reputation made a purchase of his product a no-brainer.

### Did you check any alternatives?

> The alternative of ScreenshotOne is to spend 20 hours figuring this out, waste your time, and end up buying it later. I decided to take a shortcut and buy it right away.

### How does it help you in your business

> We use ScreenshotOne in [Marketing Strategy Generator](https://founderpal.ai/). Our customers want to get their landing page roasted — that’s when website screenshots come in handy. We added this major feature in days and it increased our revenue instantly — only possible thanks to ScreenshotOne.

### Anything you would like to add?

> Last thing — I appreciate the fast customer support. Building the product, doing marketing is hard enough. But Dmytro still manages to solve my problems fast. Thank you!

More Examples and Use Cases

---------------------------

You might be also interested in how [SpyFu uses ScreenshotOne for RivalFlowAI for competitive content analysis with AI](/blog/rivalflowai-by-spyfu/).

ScreenshotOne supports a huge variety of uses including but not only:

*   [Automating Open Graph image generation](/use-cases/open-graph-images/).

*   [Generating personalized videos](/use-cases/automate-personalized-videos/).

*   [Rendering site thumbnails for search previews](/use-cases/preview-search-results/)

And [many more](/use-cases/).

Read more customer stories

--------------------------

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

[View all posts](/blog/tags/customer-stories/)

#### [Why Promptwatch wins in the AI search space](/blog/promptwatch/)

About how Promptwatch uses ScreenshotOne to automate website screenshots and why that matters.

Read more

#### [How Stagetimer automates Open Graph image generation](/blog/how-stagetimer-automates-og-image-generation/)

We would love to share a quick review of ScreenshotOne by Lukas Hermann, a co-founder of Stagetimer on how he uses the API daily to generate screenshots and automate regular tasks associated with screenshots.

Read more

#### [How Landing Gallery uses ScreenshotOne to automate screenshot generation](/blog/landing-gallery/)

How and why "Landing Gallery" uses ScreenshotOne to automate screenshot generation for their landing page inspiration platform.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/website-screenshot
----

A Simple Website Screenshot Tool by ScreenshotOne

=================================================

A few words about why to launch yet another website screenshotting tool.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

May 6, 2024

In order to allow potential customers to quickly assess the quality of our API, a simple [website screenshot tool](/tools/website-screenshot/) has been developed and launched today:

[](/tools/website-screenshot/)

It showcases only the simple subset of features available by ScreenshotOne but allows potential users to quickly asses the API performance and quality.

[Check it out](/tools/website-screenshot/) and share any feedback or issues at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Improved favicon detection for metadata\_icon](/changelog/improved-metadata-icon-detection/)

Improved \`metadata\_icon\` to check common favicon link variants more reliably.

Read more →

1 min read

#### [New organization role](/changelog/new-organization-role/)

Allow other members to manage your organization without transferring ownership.

Read more →

1 min read

#### [Navigate Pages when recording Scrolling Screenshots](/changelog/scrolling-screenshots-navigation/)

You can record a page navigation when recording scrolling screenshot video. It allows render less boring and more engaging videos.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/improved-code-examples-in-playground
----

Better code examples in the playground

======================================

Improved code examples in the playground and added all official supported ScreenshotOne SDKs.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Apr 9, 2025

The goal is to make integration with ScreenshotOne as easy as possible for new customers:

 Sorry, your browser doesn't support embedded videos.

And for existing customers to check on new options and how they look in their language of choice.

If you have any questions or noticed any issues, please contact us at [support@screenshotone.com](mailto:support@screenshotone.com).

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Improved webhooks documentation and playground](/changelog/improved-webhooks-documentation-and-playground/)

We improved the webhooks documentation and playground.

Read more →

1 min read

#### [Added an Above-the-Fold Checker Tool](/changelog/above-the-fold-checker/)

A new ScreenshotOne tool to capture what users see before the first scroll.

Read more →

1 min read

#### [Stop scrolling screenshots when a given selector is visible](/changelog/animated-scrolling-till-selector/)

New options were added to the ScreenshotOne API to stop scrolling screenshots when a given selector is reached.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/outrank
----

How Outrank enriches content generation with ScreenshotOne

==========================================================

A short story about how and why Outrank uses ScreenshotOne for screenshot generation to enrich SEO content.

[Customer story](/blog/tags/customer-stories/) 1 min read

#### Written by

[Eugene Zolotarenko](/contributors/eugene-zolotarenko/), [Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jun 29, 2025

Outrank as a content generation platform

----------------------------------------

[Outrank](https://www.outrank.so/) is a platform that helps you grow organic traffic on auto-pilot. It helps to build and generate SEO-optimized content and get backlinks to your website.

[](https://www.outrank.so/)

It uses a simple and effective approach to content generation:

1.  It runs deep analysis of your business. Outrank explores your niche, competitors, and target audience. Discover hidden keywords with high traffic potential and low competition.

2.  It create a strategic content plan where each day focuses on a key phrase with the highest potential for your business.

3.  Outrank creates and publish SEO-optimized articles based on selected keywords daily. Your blog grows automatically while you focus on your business.

Using screenshots to enrich content

-----------------------------------

[ScreenshotOne as one the best screenshot APIs](https://screenshotone.com/) is used by Eugene Zolotarenko (Outrank co-founder) to generate screenshots for the content:

1.  It makes content that contains links to websites more engaging and appealing to readers.

2.  It also helps to rank images on Google.

3.  Pages and blog posts with relevant screenshots might convert better.

4.  Differentiate from competitors. If competitors are using only text and stock illustrations, screenshots make your content stand out as more credible.

And many more reasons.

Feedback

--------

Eugene as technical co-founder of Outrank, is responsible for the technical side of the product, and was integrating ScreenshotOne into the product:

> Using the API was very simple, I just gave the docs to Cursor. Although something in the API didn’t work when I started using it. I wrote to the support and they helped to resolve the issue in 30 mins I think.

It is an honest and unpolished feedback. Not everything went smoothly. But ScreenshotOne support team helped to resolve the issue he experienced as fast as possible, and updated the product and our documentation to not encounter it again.

Read more customer stories

--------------------------

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

[View all posts](/blog/tags/customer-stories/)

#### [ScreenshotOne took away one major complexity off the Supawrite plate](/blog/supawrite/)

A short story about how ScreenshotOne helps a content marketing platform automate their screenshot workflow.

Read more

#### [How Typeshare uses ScreenshotOne for image generation](/blog/how-typeshare-uses-screenshotone/)

Typeshare is a digital writing platform designed to enhance the writing experience by offering a suite of tools aimed at reducing common barriers writers face.

Read more

#### [How Stagetimer automates Open Graph image generation](/blog/how-stagetimer-automates-og-image-generation/)

We would love to share a quick review of ScreenshotOne by Lukas Hermann, a co-founder of Stagetimer on how he uses the API daily to generate screenshots and automate regular tasks associated with screenshots.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/supawrite
----

ScreenshotOne took away one major complexity off the Supawrite plate

====================================================================

A short story about how ScreenshotOne helps a content marketing platform automate their screenshot workflow.

[Customer story](/blog/tags/customer-stories/) 1 min read

#### Written by

[Daniel Kempe](/contributors/daniel-kempe/)

#### Published on

Dec 2, 2025

The post is written by Daniel Kempe (and published as-is), the founder of Supawrite and shares how he uses ScreenshotOne to automate screenshot workflow for his content marketing platform.

Supawrite

---------

[Supawrite](https://supawrite.com) manages your entire blog, from seo and keyword research, to writing, creating images (and generating screenshots of course) and publishing.

It can post directly to WordPress and Shopify:

[](https://supawrite.com)

I found ScreenshotOne on X initially, but signed up via a Google search after trying to implement my own infrastructure.

ScreenshotOne over building myself

----------------------------------

I tried to build my own screenshotting implementation, and although it worked, I knew it wouldn’t be scalable over time. I didn’t want to manage this infrastructure going forward, so opted for a proven API instead.

I’m a vibe coder, so the integration was done in seconds and it just worked straight away.

Testimonails

------------

Including screenshots of tools and websites mentioned in blogs is a fundamental requirement, so automating this entire process wasn’t an easy process. The ScreenshotOne API took away one major complexity off my plate for a reasonable cost.

Read more customer stories

--------------------------

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

[View all posts](/blog/tags/customer-stories/)

#### [SEOBot uses ScreenshotOne API to generate screenshots for articles](/blog/seobot-automates-screenshot-generation-for-articles/)

Customers can your product in unpredictable and surprising ways. SEOBot now uses ScreenshotOne API to enhance its articles with screenshots, making content more engaging and visually appealing.

Read more

#### [Automating screenshots for directory websites with ScreenshotOne](/blog/directify-feedback/)

How and why "Directify" used ScreenshotOne to automate screenshots for directory websites.

Read more

#### [Taking care of WordPress Sites with ScreenshotOne](/blog/kinsta/)

How Kinsta uses ScreenshotOne to deliver reliable automatic updates.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/fixed-a-corner-case-for-full-page-screenshots
----

Improved full page screenshot algorithm

=======================================

We fixed issues with full page screenshots when the viewport was overridden together with the device option.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Oct 16, 2025

In cases where you specified both device and viewport options together, the full page screenshot algorithm was not working correctly.

For example:

    1https://api.screenshotone.com/take?device=iphone_13_pro_max&viewport_width=1024&...

That led to internal application errors.

Now, the full page screenshot algorithm is working correctly.

If you have any feedback, please reach out to us at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Set PDF margins](/changelog/pdf-margin/)

Now you can set PDF margins for the resulting PDF file.

Read more →

1 min read

#### [Remove organization members](/changelog/remove-organization-member/)

Improvements to the organization management.

Read more →

1 min read

#### [Playground Presets](/changelog/playground-presets/)

You can now create and save presets in the ScreenshotOne Playground!

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/all-errors-are-covered
----

Better error coverage and documentation

=======================================

Since a few months ago, it has been possible to check errors in the dashboard request log and get explanations and more details in the documentation. But!

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jul 30, 2024

The problem was that not every possible error was covered and sometimes ScreenshotOne users couldn’t find more information about unknown errors.

Since today, every possible error has been covered in the API and will be shown in [the request log](dash.screenshotone.com/logs).

In case, a new error type appears, we will add it to [the error documentation](https://screenshotone.com/docs/errors/) and to the request log.

Enjoy! And thanks for being a ScreenshotOne customer.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Improved webhooks documentation and playground](/changelog/improved-webhooks-documentation-and-playground/)

We improved the webhooks documentation and playground.

Read more →

1 min read

#### [Added an Above-the-Fold Checker Tool](/changelog/above-the-fold-checker/)

A new ScreenshotOne tool to capture what users see before the first scroll.

Read more →

1 min read

#### [Proxy option in the ScreenshotOne Playground](/changelog/proxy-option-in-playground/)

You can now take screenshots with a proxy in the ScreenshotOne Playground.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/tags/screenshot-rendering/3
----

Screenshot Rendering

--------------------

Best practices for rendering reliable website screenshots.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots in Ruby](/blog/how-to-take-website-screenshots-in-ruby/)

Let's examine what Ruby proposes for us to render HTML or URL as a screenshot dynamically.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Dec 15, 2022

•

5 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [What is a screenshot or HTML rendering API?](/blog/what-is-a-screenshot-or-html-rendering-api/)

A screenshot API or a screenshot as a service is usually a cloud or a remote server service that provides the ability to render any website, HTML, Markdown, or even PDF by making a request to the service, be it over HTTP, TCP, or any other protocol.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Nov 27, 2022

•

1 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to hide chat widgets when taking a screenshot with Puppeteer](/blog/how-to-hide-chat-widgets-when-taking-a-screenshot-with-puppeteer/)

When you want to take chat widgets, there are annoying chat widgets that you would love to hide. It is easy to do.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jul 28, 2022

•

1 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to create a site thumbnail with Puppeteer](/blog/how-to-create-a-site-thumbnail-with-puppeteer/)

We can consider the screenshot of URL or HTML as a thumbnail, but I write about the thumbnail of a screenshot. How do you take a screenshot within the defined viewport but with different image width and height? Resize!

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jul 17, 2022

•

3 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Taking screenshots with Puppeteer in GIF, JP2, TIFF, AVIF, HEIF, or SVG format](/blog/taking-screenshots-with-puppeteer-in-gif-jp2-tiff-avif-heif-or-svg-format/)

Puppeteer, by default, supports only four formats for taking screenshots or rendering HTML: PNG, JPEG, WebP, and PDF. But what if you want it to take it in a different format like GIF, JP2, TIFF, AVIF, HEIF, or SVG?

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jul 17, 2022

•

6 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Puppeteer waitUntil: how to wait for page load](/blog/puppeteer-wait-until-the-page-is-ready/)

Join me in exploring how to find the ideal wait time or event of when to take the page screenshot with Puppeteer.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Mar 13, 2026

•

8 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Uploading website screenshots to any S3-compatible storage](/blog/uploading-website-screenshots-to-any-s3-compatible-storage/)

In this note, I share how I take website screenshots or render HTML and upload the resulted images or PDF to any S3-compatible storage like Amazon S3, Cloudflare R2, or Backblaze B2.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jul 12, 2022

•

2 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to render HTML with Puppeteer](/blog/how-to-render-html-with-puppeteer/)

Use Puppeteer or screenshot API to generate the Open Graph protocol images, bills, receipts, or invoices PDF or PNG files from the HTML templates.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Mar 13, 2026

•

3 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/make-conference
----

ScreenshotOne made it to the official Make conference

=====================================================

One of our friends noticed ScreenshotOne at the official Make conference

[Blog post](/blog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Oct 16, 2025

ScreenshotOne is the best screenshot API for developers and makers and when it comes to [automating screenshots with no-code platforms like Make](/docs/no-code/make/).

And ScreenshotOne made it to the Make official conference.

On the photo, you can see [Shubham Sharma](https://www.shubham-sharma.fr) showing [the ScreenshotOne dashboard](https://dash.screenshotone.com/):

The photo was shared by our friend, Samuel Op den Orth, a co-founder of [Coding Delta](https://codingdelta.com).

Shubham Sharma was sharing his experience with ScreenshotOne and how he uses it to automate screenshots with Make for complex workflows.

In case if you want to do the same, you can start today from [our documentation for Make integration](/docs/no-code/make/).

Read more posts

---------------

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

[View all posts](/blog/)

#### [Lessons learned from the AWS disruption](/blog/lessons-from-the-aws-us-east-1-disruption/)

Sharing thoughts and lessons learned from the AWS (us-east-1) disruption, including impact on ScreenshotOne.

Read more

#### [How to build a Programmatic SEO site with automated website screenshots using ScreenshotOne, Airtable, and Launchman](/blog/how-to-build-a-programmatic-seo-site-with-automated-website-screenshots-using-screenshotone-airtable-and-launchman/)

Programmatic SEO is a great growth hacking strategy where you create a large number of content pages that rank for long-tailed keywords on Google.

Read more

#### [How to set a time zone in Puppeteer for page](/blog/how-to-set-a-time-zone-in-puppeteer-for-page/)

Puppeteer allows changing the time zone on a per-page basis. In automation testing, you can use it to test how the website behaves for different time zones. Or you can use it for scrapping to imitate the user from the expected time zone by the site.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/viewport-devices
----

[Skip to content](#_top)

Devices

=======

Copy page

Instead of manually specifying viewport parameters like width and height, you can specify a device to use for emulation. In addition, other parameters of the viewport, including the user agent, will be set automatically.

The [viewport\_device](/docs/options/#viewport_device) option sets the next options for you: [viewport\_width](/docs/options/#viewport_width), [viewport\_height](/docs/options/#viewport_height), [device\_scale\_factor](/docs/options/#device_scale_factor), [viewport\_mobile](/docs/options/#viewport_mobile), [viewport\_has\_touch](/docs/options/#viewport_has_touch), [viewport\_landscape](/docs/options/#viewport_landscape). You can change these options and override the ones set by the `viewport_device` option.

API does not use an actual device to take a screenshot. It is emulation that works in most cases.

Use the `id` property of the device as the [viewport\_device](/docs/options/#viewport_device) option, e.g. `viewport_device=galaxy_s9+_landscape`.

You can get the list of supported devices by:

    1GET https://api.screenshotone.com/devices?access_key=<YOUR ACCESS KEY>`2

    3[4    {5        "id": "iphone_13_pro_max_landscape",6        "name": "iPhone 13 Pro Max landscape",7        "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Mobile/15E148 Safari/604.1",8        "viewport": {9            "width": 926,10            "height": 428,11            "deviceScaleFactor": 3,12            "isMobile": true,13            "hasTouch": true,14            "isLandscape": true15        }16    },17    // ... many devices ...18    {19        "id": "galaxy_s9+",20        "name": "Galaxy S9+",21        "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36",22        "viewport": {23            "width": 320,24            "height": 658,25            "deviceScaleFactor": 4.5,26            "isMobile": true,27            "hasTouch": true,28            "isLandscape": false29        }30    },31    {32        "id": "galaxy_s9+_landscape",33        "name": "Galaxy S9+ landscape",34        "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36",35        "viewport": {36            "width": 658,37            "height": 320,38            "deviceScaleFactor": 4.5,39            "isMobile": true,40            "hasTouch": true,41            "isLandscape": true42        }43    },44    // ... many devices ...45]

Devices

-------

The list of devices returned by API is dynamic and continuously updated. But there is a snapshot of all supported devices if you want to take a quick look (**don’t rely on it solely, use the API method** `GET /devices` **instead**):

Device (id)

Viewport (scale)

Mobile

Touch

Landscape

User Agent

Blackberry PlayBook (blackberry\_playbook)

600x1024 (1)

Yes

Yes

No

Mozilla/5.0 (PlayBook; U; RIM Tablet OS 2.1.0; en-US) AppleWebKit/536.2+ (KHTML like Gecko) Version/7.2.1.0 Safari/536.2+

Blackberry PlayBook landscape (blackberry\_playbook\_landscape)

1024x600 (1)

Yes

Yes

Yes

Mozilla/5.0 (PlayBook; U; RIM Tablet OS 2.1.0; en-US) AppleWebKit/536.2+ (KHTML like Gecko) Version/7.2.1.0 Safari/536.2+

BlackBerry Z30 (blackberry\_z30)

360x640 (2)

Yes

Yes

No

Mozilla/5.0 (BB10; Touch) AppleWebKit/537.10+ (KHTML, like Gecko) Version/10.0.9.2372 Mobile Safari/537.10+

BlackBerry Z30 landscape (blackberry\_z30\_landscape)

640x360 (2)

Yes

Yes

Yes

Mozilla/5.0 (BB10; Touch) AppleWebKit/537.10+ (KHTML, like Gecko) Version/10.0.9.2372 Mobile Safari/537.10+

Galaxy Note 3 (galaxy\_note\_3)

360x640 (3)

Yes

Yes

No

Mozilla/5.0 (Linux; U; Android 4.3; en-us; SM-N900T Build/JSS15J) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30

Galaxy Note 3 landscape (galaxy\_note\_3\_landscape)

640x360 (3)

Yes

Yes

Yes

Mozilla/5.0 (Linux; U; Android 4.3; en-us; SM-N900T Build/JSS15J) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30

Galaxy Note II (galaxy\_note\_ii)

360x640 (2)

Yes

Yes

No

Mozilla/5.0 (Linux; U; Android 4.1; en-us; GT-N7100 Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30

Galaxy Note II landscape (galaxy\_note\_ii\_landscape)

640x360 (2)

Yes

Yes

Yes

Mozilla/5.0 (Linux; U; Android 4.1; en-us; GT-N7100 Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30

Galaxy S III (galaxy\_s\_iii)

360x640 (2)

Yes

Yes

No

Mozilla/5.0 (Linux; U; Android 4.0; en-us; GT-I9300 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30

Galaxy S III landscape (galaxy\_s\_iii\_landscape)

640x360 (2)

Yes

Yes

Yes

Mozilla/5.0 (Linux; U; Android 4.0; en-us; GT-I9300 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30

Galaxy S5 (galaxy\_s5)

360x640 (3)

Yes

Yes

No

Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36

Galaxy S5 landscape (galaxy\_s5\_landscape)

640x360 (3)

Yes

Yes

Yes

Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36

Galaxy S8 (galaxy\_s8)

360x740 (3)

Yes

Yes

No

Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36

Galaxy S8 landscape (galaxy\_s8\_landscape)

740x360 (3)

Yes

Yes

Yes

Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36

Galaxy S9+ (galaxy\_s9+)

320x658 (4.5)

Yes

Yes

No

Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36

Galaxy S9+ landscape (galaxy\_s9+\_landscape)

658x320 (4.5)

Yes

Yes

Yes

Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36

Galaxy Tab S4 (galaxy\_tab\_s4)

712x1138 (2.25)

Yes

Yes

No

Mozilla/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Safari/537.36

Galaxy Tab S4 landscape (galaxy\_tab\_s4\_landscape)

1138x712 (2.25)

Yes

Yes

Yes

Mozilla/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Safari/537.36

iPad (ipad)

768x1024 (2)

Yes

Yes

No

Mozilla/5.0 (iPad; CPU OS 11\_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1

iPad landscape (ipad\_landscape)

1024x768 (2)

Yes

Yes

Yes

Mozilla/5.0 (iPad; CPU OS 11\_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1

iPad (gen 6) (ipad\_gen\_6)

768x1024 (2)

Yes

Yes

No

Mozilla/5.0 (iPad; CPU OS 12\_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Mobile/15E148 Safari/604.1

iPad (gen 6) landscape (ipad\_gen\_6\_landscape)

1024x768 (2)

Yes

Yes

Yes

Mozilla/5.0 (iPad; CPU OS 12\_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Mobile/15E148 Safari/604.1

iPad (gen 7) (ipad\_gen\_7)

810x1080 (2)

Yes

Yes

No

Mozilla/5.0 (iPad; CPU OS 12\_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Mobile/15E148 Safari/604.1

iPad (gen 7) landscape (ipad\_gen\_7\_landscape)

1080x810 (2)

Yes

Yes

Yes

Mozilla/5.0 (iPad; CPU OS 12\_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Mobile/15E148 Safari/604.1

iPad Mini (ipad\_mini)

768x1024 (2)

Yes

Yes

No

Mozilla/5.0 (iPad; CPU OS 11\_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1

iPad Mini landscape (ipad\_mini\_landscape)

1024x768 (2)

Yes

Yes

Yes

Mozilla/5.0 (iPad; CPU OS 11\_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1

iPad Pro (ipad\_pro)

1024x1366 (2)

Yes

Yes

No

Mozilla/5.0 (iPad; CPU OS 11\_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1

iPad Pro landscape (ipad\_pro\_landscape)

1366x1024 (2)

Yes

Yes

Yes

Mozilla/5.0 (iPad; CPU OS 11\_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1

iPad Pro 11 (ipad\_pro\_11)

834x1194 (2)

Yes

Yes

No

Mozilla/5.0 (iPad; CPU OS 12\_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Mobile/15E148 Safari/604.1

iPad Pro 11 landscape (ipad\_pro\_11\_landscape)

1194x834 (2)

Yes

Yes

Yes

Mozilla/5.0 (iPad; CPU OS 12\_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Mobile/15E148 Safari/604.1

iPhone 4 (iphone\_4)

320x480 (2)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 7\_1\_2 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 Mobile/11D257 Safari/9537.53

iPhone 4 landscape (iphone\_4\_landscape)

480x320 (2)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 7\_1\_2 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 Mobile/11D257 Safari/9537.53

iPhone 5 (iphone\_5)

320x568 (2)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 10\_3\_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1

iPhone 5 landscape (iphone\_5\_landscape)

568x320 (2)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 10\_3\_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1

iPhone 6 (iphone\_6)

375x667 (2)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 11\_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1

iPhone 6 landscape (iphone\_6\_landscape)

667x375 (2)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 11\_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1

iPhone 6 Plus (iphone\_6\_plus)

414x736 (3)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 11\_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1

iPhone 6 Plus landscape (iphone\_6\_plus\_landscape)

736x414 (3)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 11\_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1

iPhone 7 (iphone\_7)

375x667 (2)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 11\_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1

iPhone 7 landscape (iphone\_7\_landscape)

667x375 (2)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 11\_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1

iPhone 7 Plus (iphone\_7\_plus)

414x736 (3)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 11\_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1

iPhone 7 Plus landscape (iphone\_7\_plus\_landscape)

736x414 (3)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 11\_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1

iPhone 8 (iphone\_8)

375x667 (2)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 11\_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1

iPhone 8 landscape (iphone\_8\_landscape)

667x375 (2)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 11\_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1

iPhone 8 Plus (iphone\_8\_plus)

414x736 (3)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 11\_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1

iPhone 8 Plus landscape (iphone\_8\_plus\_landscape)

736x414 (3)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 11\_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1

iPhone SE (iphone\_se)

320x568 (2)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 10\_3\_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1

iPhone SE landscape (iphone\_se\_landscape)

568x320 (2)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 10\_3\_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1

iPhone X (iphone\_x)

375x812 (3)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 11\_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1

iPhone X landscape (iphone\_x\_landscape)

812x375 (3)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 11\_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1

iPhone XR (iphone\_xr)

414x896 (3)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 12\_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1

iPhone XR landscape (iphone\_xr\_landscape)

896x414 (3)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 12\_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1

iPhone 11 (iphone\_11)

414x828 (2)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 13\_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Mobile/15E148 Safari/604.1

iPhone 11 landscape (iphone\_11\_landscape)

828x414 (2)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 13\_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Mobile/15E148 Safari/604.1

iPhone 11 Pro (iphone\_11\_pro)

375x812 (3)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 13\_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Mobile/15E148 Safari/604.1

iPhone 11 Pro landscape (iphone\_11\_pro\_landscape)

812x375 (3)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 13\_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Mobile/15E148 Safari/604.1

iPhone 11 Pro Max (iphone\_11\_pro\_max)

414x896 (3)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 13\_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Mobile/15E148 Safari/604.1

iPhone 11 Pro Max landscape (iphone\_11\_pro\_max\_landscape)

896x414 (3)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 13\_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Mobile/15E148 Safari/604.1

iPhone 12 (iphone\_12)

390x844 (3)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 14\_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Mobile/15E148 Safari/604.1

iPhone 12 landscape (iphone\_12\_landscape)

844x390 (3)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 14\_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Mobile/15E148 Safari/604.1

iPhone 12 Pro (iphone\_12\_pro)

390x844 (3)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 14\_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Mobile/15E148 Safari/604.1

iPhone 12 Pro landscape (iphone\_12\_pro\_landscape)

844x390 (3)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 14\_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Mobile/15E148 Safari/604.1

iPhone 12 Pro Max (iphone\_12\_pro\_max)

428x926 (3)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 14\_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Mobile/15E148 Safari/604.1

iPhone 12 Pro Max landscape (iphone\_12\_pro\_max\_landscape)

926x428 (3)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 14\_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Mobile/15E148 Safari/604.1

iPhone 12 Mini (iphone\_12\_mini)

375x812 (3)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 14\_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Mobile/15E148 Safari/604.1

iPhone 12 Mini landscape (iphone\_12\_mini\_landscape)

812x375 (3)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 14\_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Mobile/15E148 Safari/604.1

iPhone 13 (iphone\_13)

390x844 (3)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 15\_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Mobile/15E148 Safari/604.1

iPhone 13 landscape (iphone\_13\_landscape)

844x390 (3)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 15\_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Mobile/15E148 Safari/604.1

iPhone 13 Pro (iphone\_13\_pro)

390x844 (3)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 15\_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Mobile/15E148 Safari/604.1

iPhone 13 Pro landscape (iphone\_13\_pro\_landscape)

844x390 (3)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 15\_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Mobile/15E148 Safari/604.1

iPhone 13 Pro Max (iphone\_13\_pro\_max)

428x926 (3)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 15\_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Mobile/15E148 Safari/604.1

iPhone 13 Pro Max landscape (iphone\_13\_pro\_max\_landscape)

926x428 (3)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 15\_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Mobile/15E148 Safari/604.1

iPhone 13 Mini (iphone\_13\_mini)

375x812 (3)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 15\_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Mobile/15E148 Safari/604.1

iPhone 13 Mini landscape (iphone\_13\_mini\_landscape)

812x375 (3)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 15\_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Mobile/15E148 Safari/604.1

iPhone 14 (iphone\_14)

390x663 (3)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 16\_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1

iPhone 14 landscape (iphone\_14\_landscape)

750x340 (3)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 16\_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1

iPhone 14 Plus (iphone\_14\_plus)

428x745 (3)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 16\_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1

iPhone 14 Plus landscape (iphone\_14\_plus\_landscape)

832x378 (3)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 16\_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1

iPhone 14 Pro (iphone\_14\_pro)

393x659 (3)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 16\_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1

iPhone 14 Pro landscape (iphone\_14\_pro\_landscape)

734x343 (3)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 16\_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1

iPhone 14 Pro Max (iphone\_14\_pro\_max)

430x739 (3)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 16\_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1

iPhone 14 Pro Max landscape (iphone\_14\_pro\_max\_landscape)

814x380 (3)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 16\_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1

iPhone 15 (iphone\_15)

393x659 (3)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 17\_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1

iPhone 15 landscape (iphone\_15\_landscape)

734x343 (3)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 17\_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1

iPhone 15 Plus (iphone\_15\_plus)

430x739 (3)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 17\_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1

iPhone 15 Plus landscape (iphone\_15\_plus\_landscape)

814x380 (3)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 17\_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1

iPhone 15 Pro (iphone\_15\_pro)

393x659 (3)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 17\_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1

iPhone 15 Pro landscape (iphone\_15\_pro\_landscape)

734x343 (3)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 17\_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1

iPhone 15 Pro Max (iphone\_15\_pro\_max)

430x739 (3)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 17\_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1

iPhone 15 Pro Max landscape (iphone\_15\_pro\_max\_landscape)

814x380 (3)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 17\_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1

iPhone 16 (iphone\_16)

393x659 (3)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 17\_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1

iPhone 16 landscape (iphone\_16\_landscape)

734x343 (3)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 17\_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1

iPhone 16 Plus (iphone\_16\_plus)

430x739 (3)

Yes

Yes

No

Mozilla/5.0 (iPhone; CPU iPhone OS 17\_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1

iPhone 16 Plus landscape (iphone\_16\_plus\_landscape)

814x380 (3)

Yes

Yes

Yes

Mozilla/5.0 (iPhone; CPU iPhone OS 17\_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1

JioPhone 2 (jiophone\_2)

240x320 (1)

Yes

Yes

No

Mozilla/5.0 (Mobile; LYF/F300B/LYF-F300B-001-01-15-130718-i;Android; rv:48.0) Gecko/48.0 Firefox/48.0 KAIOS/2.5

JioPhone 2 landscape (jiophone\_2\_landscape)

320x240 (1)

Yes

Yes

Yes

Mozilla/5.0 (Mobile; LYF/F300B/LYF-F300B-001-01-15-130718-i;Android; rv:48.0) Gecko/48.0 Firefox/48.0 KAIOS/2.5

Kindle Fire HDX (kindle\_fire\_hdx)

800x1280 (2)

Yes

Yes

No

Mozilla/5.0 (Linux; U; en-us; KFAPWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.13 Safari/535.19 Silk-Accelerated=true

Kindle Fire HDX landscape (kindle\_fire\_hdx\_landscape)

1280x800 (2)

Yes

Yes

Yes

Mozilla/5.0 (Linux; U; en-us; KFAPWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.13 Safari/535.19 Silk-Accelerated=true

LG Optimus L70 (lg\_optimus\_l70)

384x640 (1.25)

Yes

Yes

No

Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/75.0.3765.0 Mobile Safari/537.36

LG Optimus L70 landscape (lg\_optimus\_l70\_landscape)

640x384 (1.25)

Yes

Yes

Yes

Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/75.0.3765.0 Mobile Safari/537.36

Microsoft Lumia 550 (microsoft\_lumia\_550)

640x360 (2)

Yes

Yes

No

Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 550) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/14.14263

Microsoft Lumia 950 (microsoft\_lumia\_950)

360x640 (4)

Yes

Yes

No

Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/14.14263

Microsoft Lumia 950 landscape (microsoft\_lumia\_950\_landscape)

640x360 (4)

Yes

Yes

Yes

Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/14.14263

Nexus 10 (nexus\_10)

800x1280 (2)

Yes

Yes

No

Mozilla/5.0 (Linux; Android 6.0.1; Nexus 10 Build/MOB31T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Safari/537.36

Nexus 10 landscape (nexus\_10\_landscape)

1280x800 (2)

Yes

Yes

Yes

Mozilla/5.0 (Linux; Android 6.0.1; Nexus 10 Build/MOB31T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Safari/537.36

Nexus 4 (nexus\_4)

384x640 (2)

Yes

Yes

No

Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36

Nexus 4 landscape (nexus\_4\_landscape)

640x384 (2)

Yes

Yes

Yes

Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36

Nexus 5 (nexus\_5)

360x640 (3)

Yes

Yes

No

Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36

Nexus 5 landscape (nexus\_5\_landscape)

640x360 (3)

Yes

Yes

Yes

Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36

Nexus 5X (nexus\_5x)

412x732 (2.625)

Yes

Yes

No

Mozilla/5.0 (Linux; Android 8.0.0; Nexus 5X Build/OPR4.170623.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36

Nexus 5X landscape (nexus\_5x\_landscape)

732x412 (2.625)

Yes

Yes

Yes

Mozilla/5.0 (Linux; Android 8.0.0; Nexus 5X Build/OPR4.170623.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36

Nexus 6 (nexus\_6)

412x732 (3.5)

Yes

Yes

No

Mozilla/5.0 (Linux; Android 7.1.1; Nexus 6 Build/N6F26U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36

Nexus 6 landscape (nexus\_6\_landscape)

732x412 (3.5)

Yes

Yes

Yes

Mozilla/5.0 (Linux; Android 7.1.1; Nexus 6 Build/N6F26U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36

Nexus 6P (nexus\_6p)

412x732 (3.5)

Yes

Yes

No

Mozilla/5.0 (Linux; Android 8.0.0; Nexus 6P Build/OPP3.170518.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36

Nexus 6P landscape (nexus\_6p\_landscape)

732x412 (3.5)

Yes

Yes

Yes

Mozilla/5.0 (Linux; Android 8.0.0; Nexus 6P Build/OPP3.170518.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36

Nexus 7 (nexus\_7)

600x960 (2)

Yes

Yes

No

Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MOB30X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Safari/537.36

Nexus 7 landscape (nexus\_7\_landscape)

960x600 (2)

Yes

Yes

Yes

Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MOB30X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Safari/537.36

Nokia Lumia 520 (nokia\_lumia\_520)

320x533 (1.5)

Yes

Yes

No

Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 520)

Nokia Lumia 520 landscape (nokia\_lumia\_520\_landscape)

533x320 (1.5)

Yes

Yes

Yes

Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 520)

Nokia N9 (nokia\_n9)

480x854 (1)

Yes

Yes

No

Mozilla/5.0 (MeeGo; NokiaN9) AppleWebKit/534.13 (KHTML, like Gecko) NokiaBrowser/8.5.0 Mobile Safari/534.13

Nokia N9 landscape (nokia\_n9\_landscape)

854x480 (1)

Yes

Yes

Yes

Mozilla/5.0 (MeeGo; NokiaN9) AppleWebKit/534.13 (KHTML, like Gecko) NokiaBrowser/8.5.0 Mobile Safari/534.13

Pixel 2 (pixel\_2)

411x731 (2.625)

Yes

Yes

No

Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36

Pixel 2 landscape (pixel\_2\_landscape)

731x411 (2.625)

Yes

Yes

Yes

Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36

Pixel 2 XL (pixel\_2\_xl)

411x823 (3.5)

Yes

Yes

No

Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36

Pixel 2 XL landscape (pixel\_2\_xl\_landscape)

823x411 (3.5)

Yes

Yes

Yes

Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36

Pixel 3 (pixel\_3)

393x786 (2.75)

Yes

Yes

No

Mozilla/5.0 (Linux; Android 9; Pixel 3 Build/PQ1A.181105.017.A1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36

Pixel 3 landscape (pixel\_3\_landscape)

786x393 (2.75)

Yes

Yes

Yes

Mozilla/5.0 (Linux; Android 9; Pixel 3 Build/PQ1A.181105.017.A1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36

Pixel 4 (pixel\_4)

353x745 (3)

Yes

Yes

No

Mozilla/5.0 (Linux; Android 10; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Mobile Safari/537.36

Pixel 4 landscape (pixel\_4\_landscape)

745x353 (3)

Yes

Yes

Yes

Mozilla/5.0 (Linux; Android 10; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Mobile Safari/537.36

Pixel 4a (5G) (pixel\_4a\_5g)

353x745 (3)

Yes

Yes

No

Mozilla/5.0 (Linux; Android 11; Pixel 4a (5G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4812.0 Mobile Safari/537.36

Pixel 4a (5G) landscape (pixel\_4a\_5g\_landscape)

745x353 (3)

Yes

Yes

Yes

Mozilla/5.0 (Linux; Android 11; Pixel 4a (5G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4812.0 Mobile Safari/537.36

Pixel 5 (pixel\_5)

393x851 (3)

Yes

Yes

No

Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4812.0 Mobile Safari/537.36

Pixel 5 landscape (pixel\_5\_landscape)

851x393 (3)

Yes

Yes

Yes

Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4812.0 Mobile Safari/537.36

Moto G4 (moto\_g4)

360x640 (3)

Yes

Yes

No

Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4812.0 Mobile Safari/537.36

Moto G4 landscape (moto\_g4\_landscape)

640x360 (3)

Yes

Yes

Yes

Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4812.0 Mobile Safari/537.36

----
url: https://screenshotone.com/contributors/klaas-foppen
----

Klaas Foppen

------------

View all Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [Why Promptwatch wins in the AI search space](/blog/promptwatch/)

About how Promptwatch uses ScreenshotOne to automate website screenshots and why that matters.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Klaas Foppen](/contributors/klaas-foppen/)

Updated on

Feb 11, 2026

•

3 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/makeadir-feedback
----

Integrating ScreenshotOne into the directory management platform

================================================================

How and why "Make a Directory" used ScreenshotOne to automate screenshots for directory websites.

[Customer story](/blog/tags/customer-stories/) 3 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Bohdan Shulha](/contributors/bohdan-shulha/)

#### Published on

Dec 23, 2024

[“Make a Directory”](https://makeadir.com/) is a no-code platform that allows you to create directory websites.

Their goal was to automate screenshot generation for directory websites—it was a feature requested by their customers.

Challenge

---------

“Make a Directory” allows to spin a new directory website in minutes. But when it comes to listing website, customers had to manually take screenshots of their listings or didn’t have an option to do it, all.

They choose ScreenshotOne to help with that and let’s check out their feedback.

ScreenshotOne as a Solution and Results

---------------------------------------

A few words by Bohdan Shulha, a maker behind [“Make a Directory”](https://makeadir.com/):

1.  **How did you discover ScreenshotOne?**

> I am a fan of Build in Public community on X, and met Dmytro here, who’s been building ScreenshotOne and shared his experiences.

2.  **Did you check any alternatives?**

> Yes, of course. I’ve been thinking of crafting my own screenshotter tool with help of Clouflare Workers, but once I examined my use case deeper, I understood that I’d have to re-implement ScreenshotOne, which was in active development for a long time already and it turned out to be fairly complex task.

> 

> Before sticking up to ScreenshotOne, I did a market research on similar tools, but, overall, the choice was made mostly by Dmytro’s attitude and openness. I knew I can always get help directly from a founder if I need it and it simply bought me.

3.  **How was the integration process?**

> I wouldn’t say I even noticed an integration process at all, because it was extremely easy and quick. I signed up to ScreenshotOne, made two or three adjustments on the configuration control panel and copy-pasted the generated string into the codebase. Voila!

4.  **What is your application about?**

> It started as a SaaS for directory builders. Anyone could create a simple directory and add as much listings as they need, without any limitations.

> 

> Today it is much more of that - recently we released a page builder allowing to not only create custom content pages, but also modify any of the system pages (categories, listings, blog - literally anything).

> 

> It means that today you can create any website you want (content-based, of course) using a simple UX.

> 

> Best SEO practices implemented by the platform and AI-powered content writing tool will help you to grow the website naturally.

5.  **How does it help you and your customers in your business?**

> The platform focuses on websites when a “share” functionality is expected to be used a lot. Today it is not enough to provide text description to the shared link - people are much more likely would interact with an image. I use ScreenshotOne to generate Open Graph images out of the live content of the website.

> 

> In the upcoming releases, it will be doing automated screenshots for listings added to the platform, which would allow to save another 10-15 minutes per listing.

6.  **Anything you would like to add?**

> Being non-VC backed has it’s own challenges, but as Dmytro’s hands are not tied by investors, he’s able to deliver excellent product development performance and support.

> 

> I will recommend ScreenshotOne to anyone who needs to complete similar tasks.

Conclusion

----------

By integrating ScreenshotOne, “Make a Directory” successfully automated screenshot generation for directory websites, providing an almost seamless experience for their customers.

More Examples and Use Cases

---------------------------

You might be also interested in how [SpyFu uses ScreenshotOne for RivalFlowAI for competitive content analysis with AI](/blog/rivalflowai-by-spyfu/).

ScreenshotOne supports a huge variety of uses including but not only:

*   [Automating Open Graph image generation](/use-cases/open-graph-images/).

*   [Generating personalized videos](/use-cases/automate-personalized-videos/).

*   [Rendering site thumbnails for search previews](/use-cases/preview-search-results/)

And [many more](/use-cases/).

Read more customer stories

--------------------------

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

[View all posts](/blog/tags/customer-stories/)

#### [How Landing Gallery uses ScreenshotOne to automate screenshot generation](/blog/landing-gallery/)

How and why "Landing Gallery" uses ScreenshotOne to automate screenshot generation for their landing page inspiration platform.

Read more

#### [Why Promptwatch wins in the AI search space](/blog/promptwatch/)

About how Promptwatch uses ScreenshotOne to automate website screenshots and why that matters.

Read more

#### [How RivalFlowAI uses ScreenshotOne to help its customers improve existing content](/blog/rivalflowai-by-spyfu/)

RivalFlowAI is a new product by SpyFu, launched in 2023. The product helps to improve existing content with AI by finding the missing pieces your page needs to rank.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/how-to-block-requests-with-puppeteer
----

How to block requests with Puppeteer

====================================

Puppeteer allows blocking any outgoing requests while loading the page. Whether you want to block ads, tracking scripts, or different types of resources, it is relatively easy to do with Puppeteer.

[Blog post](/blog/) 3 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Jul 14, 2022

#### Tags

[Puppeteer guides](/blog/tags/puppeteer-guides/)

If you want to speed up scrapping or make screenshots faster, you can disable all the requests that do not make any crucial impact on the results.

Puppeteer allows blocking any outgoing requests while loading the page. Whether you want to block ads, tracking scripts, or different types of resources, it is relatively easy to do with Puppeteer.

A full example of blocking requests

-----------------------------------

Let’s start with a fully working example on how to intercept and block requests in Puppeteer:

    1const puppeteer = require('puppeteer');2const wildcardMatch = require('wildcard-match');3

    4const blockRequest = wildcardMatch(['*.css', '*.js'], { separator: false });5

    6(async () => {7    const browser = await puppeteer.launch({});8    try {9

    10        const page = await browser.newPage();11        page.setRequestInterception(true);12

    13        page.on('request', (request) => {14            if (blockRequest(request.url())) {15                const u = request.url();16                console.log(`request to ${u.substring(0, 50)}...${u.substring(u.length - 5)} is aborted`);17

    18                request.abort();19

    20                return;21            }22

    23            request.continue();24        });25

    26        await page.goto('https://screenshotone.com/');27    } catch (e) {28        console.log(e)29    } finally {30        await browser.close();31    }32})();

The result is:

    1request to https://screenshotone.com/main.7a76b580aa30ffecb0b...f.css is aborted2request to https://screenshotone.com/js/bootstrap.min.592b9fa...ab.js is aborted3request to https://screenshotone.com/js/highlight.min.e13cfba...5f.js is aborted4request to https://screenshotone.com/main.min.dabf7f45921a731...45.js is aborted

Sorry, but I won’t show you the resulting screenshot of the site because it looks awful without CSS and JS.

A step-by-step explanation

--------------------------

The most crucial step is not to forget to enable request interception before sending any request:

    1// ...2const page = await browser.newPage();3page.setRequestInterception(true);4// ...

Otherwise, the trick won’t work.

After request interception is enabled, you can listen to any new outgoing request while the page is being loaded and decide on a per-request basis whether to block the request or not.

If you want to block all requests to [www.google-analytics.com](http://www.google-analytics.com) to speed up the site loading and to avoid tracking, then just filter requests based on the domain substring:

    1page.on('request', (request) => {2    if (request.url().includes('www.google-analytics.com')) {3        request.abort();4

    5        return;6

    7    }8

    9    request.continue();10});

The better option is to parse URL, extract domain, and filter based on the domain name:

    1page.on('request', (request) => {2    const domain = url.parse(request.url(), false).hostname;3    if (domain == 'www.google-analytics.com') {4        request.abort();5

    6        return;7    }8

    9    request.continue();10});

Because you might have an URL that accidentally might include `www.google-analytics.com`.

Blocking requests by resource type

----------------------------------

If you need to block a set of requests by the resource type, like images or stylesheets, regardless of the extension and URL pattern, you can use the `request.resourceType()` method to test against blocking resource type:

    1const puppeteer = require('puppeteer');2

    3(async () => {4    const browser = await puppeteer.launch({});5    try {6        const page = await browser.newPage();7        page.setRequestInterception(true);8

    9        page.on('request', (request) => {10            if (request.resourceType() == "stylesheet" || request.resourceType() == "script") {11                const u = request.url();12                console.log(`request to ${u.substring(0, 50)}...${u.substring(u.length - 5)} is aborted`);13

    14                request.abort();15

    16                return;17            }18

    19            request.continue();20        });21

    22        await page.goto('https://screenshotone.com/');23    } catch (e) {24        console.log(e)25    } finally {26        await browser.close();27    }28})();

The result is the same as for the initial example:

    1request to https://screenshotone.com/main.7a76b580aa30ffecb0b...f.css is aborted2request to https://screenshotone.com/js/bootstrap.min.592b9fa...ab.js is aborted3request to https://screenshotone.com/js/highlight.min.e13cfba...5f.js is aborted4request to https://screenshotone.com/main.min.dabf7f45921a731...45.js is aborted

Puppetteer supports blocking the next resource types:

As you see, it is pretty straightforward.

Block images

------------

Disabling image loading dramatically improves the loading time of the page and speeds ups the rendering process.

You can block (disable) images in `Puppeteer` by blocking requests with resource type `image`.

It is no different from blocking any other resource type:

    1const puppeteer = require('puppeteer');2

    3(async () => {4    const browser = await puppeteer.launch({});5    try {6        const page = await browser.newPage();7        page.setRequestInterception(true);8

    9        page.on('request', (request) => {10            if (request.resourceType() == "image") {11                const u = request.url();12                console.log(`request to ${u.substring(0, 50)}...${u.substring(u.length - 5)} is aborted`);13

    14                request.abort();15

    16                return;17            }18

    19            request.continue();20        });21

    22        await page.goto('https://unsplash.com/');23    } catch (e) {24        console.log(e)25    } finally {26        await browser.close();27    }28})();

You can see from the logs that it works:

    1...2request to https://images.unsplash.com/photo-1657047211843-2d...h=594 is aborted3request to https://images.unsplash.com/photo-1657664072464-e5...&q=60 is aborted4...5request to https://secure.insightexpressai.com/adServer/adSer...l.gif is aborted6request to https://secure.insightexpressai.com/adServer/adSer...l.gif is aborted7request to https://secure.insightexpressai.com/adServer/adSer...l.gif is aborted8...

The result **without images**:

And compare it to the original rendering:

Also, I would consider blocking media, fonts, and stylesheets if your goal is not to take screenshots of the page but to crawl.

Have a nice day 👋

------------------

By the way, in our [screenshot API](/), you can easily block requests by specifying [the block requests parameter](/docs/options/#block_requests).

I hope I have helped you tackle request blocking in Puppeteer, and I honestly wish you a nice day!

Read more Puppeteer guides

--------------------------

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

[View all posts](/blog/tags/puppeteer-guides/)

#### [Taking screenshots with Puppeteer in GIF, JP2, TIFF, AVIF, HEIF, or SVG format](/blog/taking-screenshots-with-puppeteer-in-gif-jp2-tiff-avif-heif-or-svg-format/)

Puppeteer, by default, supports only four formats for taking screenshots or rendering HTML: PNG, JPEG, WebP, and PDF. But what if you want it to take it in a different format like GIF, JP2, TIFF, AVIF, HEIF, or SVG?

Read more

#### [page.waitForTimeout is not a function in Puppeteer](/blog/page-waitfortimeout-is-not-a-function-in-puppeteer/)

Puppeteer removed page.waitForTimeout(). Learn why the error happens and which modern alternatives to use instead.

Read more

#### [How to take bulk screenshots with Puppeteer](/blog/bulk-screenshots-with-puppeteer/)

Learn how to take screenshots of multiple URLs with Puppeteer, including concurrency management, error handling, retries, and proxy support.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/how-to-generate-pdf-with-puppeteer
----

How to generate PDFs with Puppeteer

===================================

A practical and working guide on how to generate PDFs with Puppeteer.

[Blog post](/blog/) 2 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

May 2, 2025

#### Tags

[PDF rendering](/blog/tags/pdf-rendering/) [Puppeteer guides](/blog/tags/puppeteer-guides/)

[Puppeteer](/blog/puppeteer/) is a Node library that interacts with browsers that support [Chrome DevTools Protocol (CDP)](https://chromedevtools.github.io/devtools-protocol/). It is not only Chrome and Chromium, but [Firefox also has partial support of CDP](https://firefox-source-docs.mozilla.org/remote/index.html#remote-protocol-cdp).

A working code example to generate PDFs with Puppeteer

------------------------------------------------------

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

    1npm i puppeteer

It is relatively easy to generate PDFs with Puppeteer:

    1"use strict";2

    3const puppeteer = require("puppeteer");4

    5(async () => {6    const browser = await puppeteer.launch({});7

    8    try {9        const page = await browser.newPage();10

    11        await page.goto("https://example.com/", {12            waitUntil: "networkidle0",13        });14

    15        const selector = "div";16        await page.waitForSelector(selector, {17            visible: true,18        });19

    20        await page.pdf({ path: "example.com.pdf", format: "a4" });21    } catch (e) {22        console.log(e);23    } finally {24        await browser.close();25    }26})();

Pros and cons of using Puppeteer for rendering PDFs

---------------------------------------------------

1.  I would love to repeat that, but the massive benefit of using Puppeteer is having fine-grained control over rendering results against rendering PDFs only in the browser.

2.  Managing headless browsers is a huge pain. The browsers might have memory leaks and suddenly restarts. You need to update them to the latest versions. And this is only a small list of problems that you will encounter.

3.  Puppeteer is imperfect, and the rendering PDF has different artifacts that must be addressed.

4.  It is a computation-heavy task for servers. And scaling it for running multiple browsers can be a problem in itself.

Look at [all possible Puppeteer PDF options](https://pptr.dev/#?product=Puppeteer&version=main&show=api-pagepdfoptions). It is an exciting and complex problem, which deserves a separate post.

It depends on your use case, but also consider using [PDFKit](https://www.npmjs.com/package/pdfkit) for programmatic PDF generation.

But there is a solution to address mentioned Puppeteer issues.

Using modern and scalable URL or HTML to PDF API

------------------------------------------------

If you don’t want to deal with all the burdens of managing headless browsers, you can use [ScreenshotOne PDF generation API](/pdf-generation-api/) to render PDFs from HTML or any URL. It is a free PDF to HTML API for up to 100 requests. The PDF generation API from ScreenshotOne is easy to use. It is scalable, covers a variety of use cases, and solves all the issues related to rendering PDFs in headless browsers.

Let’s take a look at how easy it is to render a PDF with a straightforward call:

    1https://api.screenshotone.com/take?url=https://example.com&format=pdf&access_key=<your access key>

And the result is [a PDF document](/pdfs/example.com.pdf).

Read more PDF rendering

-----------------------

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

[View all posts](/blog/tags/pdf-rendering/)

#### [What is Puppeteer](/blog/puppeteer/)

What is Puppeteer and what you can use it for.

Read more

#### [Take a screenshot "from the surface" in Puppeteer and Chrome DevTools Protocol](/blog/take-a-screenshot-from-the-surface-in-puppeteer-and-chrome-devtools-protocol/)

Let's talk about the fromSurface parameter introduced in Chrome DevTools Protocol which will soon be supported by Puppeteer or even supported now at the time when you are reading the post.

Read more

#### [How to add custom styles to a page in Puppeteer](/blog/how-to-add-custom-styles-to-a-page-in-puppeteer/)

To add custom styles to any page use Puppeteer's page method \`page.addStyleTag(options)\`. Let's discover how it works quickly.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/i-migrated-to-google-cloud
----

I migrated to Google Cloud

==========================

Google Cloud gives $300 in credits for 3 months for experimenting. And I decided to give it a try, but not because of the free credits.

[Changelog](/changelog/) 4 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Sep 14, 2022

I migrated my [screenshot API](https://screenshotone.com) project to Google Cloud.

My main reason is that I want peace of mind with my infrastructure for an extended period of time. And I want to concentrate solely on customer support, marketing, and selling, not on scaling issues and other technical matters.

If you are curious about the details, I am sharing a short story about my infrastructure journey and plans for the future.

MVP on DigitalOcean with 2 droplets

-----------------------------------

Truthfully, I started from MVP on DigitalOcean with 2 droplets (VPS), one for the dashboard and one for rendering screenshots.

It was enough to test the product and launch, but after users started to sign up and use the API, scaling issues arose, and I needed to act quickly. I had many options to choose from:

*   Scale the droplet vertically (increase CPU and RAM).

*   Add one more droplet and load balancer.

*   Set up Kubernetes cluster with autoscaling.

*   Move to Render or other services that can quickly spin up Docker containers and support autoscaling.

*   Buy powerful cheap servers or VPS to handle all the load I have in one or two instances.

*   Using AWS Lambda functions or Google Cloud Run or functions.

*   And many other options.

But I didn’t have time even to think. I needed a solution quickly. Kubernetes looked like the best choice then, but I didn’t have experience setting it up. I worked only as a developer with Kubernetes.

I had an experience with AWS, but not with AWS Lambda.

So, I decided to move to Render.

Moving to Render as a quick solution

------------------------------------

Moving to Render was easy. I needed to link my GitHub repository and choose the plan (means resources). Then in 2 clicks, I set up autoscaling. And it helped me to survive for a long time. At least 2-3 months.

But then, new requirements and use cases arose, which Render couldn’t handle for me. I needed to spin up a new service instance immediately upon request, not on an average load of the instances I had.

Some customers can send 6-20 requests in a batch simultaneously. Render’s load balancer distributes the load among instances evenly. But if I have 2 instances and 20 requests received simultaneously, it will split the batch by 10 requests each and send them to instances. And then spin up new instances which won’t process these requests and will just idle.

The easy solution is to have more instances in the pool available. And it won’t be a problem for me. But to process requests, I needed at least 8 GB of RAM. And that’s when it becomes too costly with Render.

I loved Render’s UI and support. Would it be cheaper? I won’t move away.

So, I started looking for other solutions. My limitations were time to migrate, obviously money, and to support new requirements to handle immediate bursts of load.

Trying Google Cloud Run

-----------------------

I started exploring AWS Lambda functions, Google Cloud Functions, and Google Cloud Run. Since I haven’t used Google Cloud before, I was eligible to use $300 in credits for 3 months. I decided it was a reasonable time period to test the cloud and estimate my costs and overall experience.

It took me 4 hours to deploy the service to Google Cloud Run with a straightforward command—`gcloud deploy`. For another 2 days, I spent on a solution to move my custom domain from Render to GCP without downtime. But it was costly in terms of time and nearly impossible, so I found the time slot when my servers were idle, and nobody used them and migrated my domain.

Why Run and not Functions?

I haven’t tried GCP functions, but GCP Run looked like a good fit. It can immediately spin up new containers to handle requests and reuse containers. And I pay only when my containers are running.

With such a configuration, I felt I could have a piece of mind for long periods.

Once the trial approaches the end, I will evaluate the costs and usability of the cloud and decide what to do next.

Why I share my infrastructure journey

-------------------------------------

Frankly, from the inside, it is hard to understand what I am doing wrong or if I do effectively what I do. But many brilliant minds can look at what you do and share many ideas on what can be done better, cheaper, more effective, and so on.

I would love to hear your thoughts, and thanks for reading.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Add ScreenshotOne to n8n workflows](/changelog/n8n-integration/)

You can now use ScreenshotOne in n8n workflows to render website screenshots, PDFs, scrolling screenshots and videos.

Read more →

1 min read

#### [Added a URL to Markdown Tool](/changelog/url-to-markdown-tool/)

A new free ScreenshotOne tool to convert any public webpage URL into Markdown.

Read more →

1 min read

#### [Get favicon used by a website with ScreenshotOne API](/changelog/metadata-icon/)

Now you can get favicon used by a website with ScreenshotOne API in just one simple API call.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/screenshot-api/go
----

[What's new API error insights API error insights in the dashboard](/changelog/error-metrics/)

Go Screenshot API

=================

Capture pixel-perfect website screenshots in Go with a simple API call. No browser management, no Chromium setup—just clean, reliable screenshots.

----------------------

----------------------------

------------------------------------

Take screenshots with Go

------------------------

Use our official Go SDK or send simple HTTP requests to capture screenshots.

    1// go get github.com/screenshotone/gosdk2

    3import screenshots "github.com/screenshotone/gosdk"4

    5client, err := screenshots.NewClient("<access key>", "<secret key>")6// check err7

    8options := screenshots.NewTakeOptions("https://example.com").9    Format("png").10    FullPage(true).11    DeviceScaleFactor(2).12    BlockAds(true).13    BlockTrackers(true)14

    15u, err := client.GenerateTakeURL(options)16// check err17

    18fmt.Println(u.String())19// Output: https://api.screenshotone.com/take?url=...20

    21// or download the screenshot22image, err := client.Take(context.TODO(), options)23// check err24

    25defer image.Close()26out, err := os.Create("example.png")27// check err28

    29defer out.Close()30io.Copy(out, image)31// the screenshot is stored in the example.png file

Mike Roberts

Founder, [SpyFu](https://www.spyfu.com/)

> ScreenshotOne is the best product on the market - and that's before you take into account how responsive and easy Dmytro is to work with.

> 

> Any time we've found a rare edge case, it's been resolved in hours.

> 

> Great company, great founder - can't say enough!

Without writing a line of code

No-code integrations

--------------------

Quickly render website screenshots with Zapier, Airtable, Make and other popular no-code platforms of your choice.

[](/integrations/zapier/)[](/integrations/airtable/)[](/integrations/make/)[](/integrations/bubble/)[](/integrations/n8n/)

Read

Lessons from running screenshot rendering infrastructure

--------------------------------------------------------

Practical guides and real updates based on our experience operating rendering infrastructure at production scale.

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots with Go](/blog/how-to-take-website-screenshots-with-go/)

The article examines how you can take screenshots of any URL with Go (a.k.a. Golang) by using Selenium, Puppeteer alternatives, Playwright, or screenshot API as a service.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jun 10, 2022

•

4 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Taking care of WordPress Sites with ScreenshotOne](/blog/kinsta/)

How Kinsta uses ScreenshotOne to deliver reliable automatic updates.

Written by

[Roger Williams](/contributors/roger-williams/), [Barnabás Ürmössy](/contributors/barnabs-rmssy/)

Published on

Apr 29, 2025

•

2 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Typeshare uses ScreenshotOne for image generation](/blog/how-typeshare-uses-screenshotone/)

Typeshare is a digital writing platform designed to enhance the writing experience by offering a suite of tools aimed at reducing common barriers writers face.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Apr 14, 2024

•

2 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/google-docs-and-slides
----

Rendering Google Documents and Slides is now available

======================================================

You can now easily render Google Documents and Slides with ScreenshotOne.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

May 7, 2025

You can now easily render Google Documents and Slides with ScreenshotOne in any image format or, if needed, as a PDF document.

ScreenshotOne supports both screenshotting Google Documents and Google Slides and for all our rendering methods. For example, you can render Google Slides as [scrolling screenshots](/scrolling-screenshots/):

 Sorry, your browser doesn't support embedded videos.

Guides

------

We have two simple guides to share with you on how to do that:

1.  [How to render Google Documents as screenshots](/docs/guides/screenshot-google-docs/).

2.  [How to render Google Slides as scrolling screenshots](/docs/guides/google-slides-as-scrolling-screenshots/).

Use cases

---------

There are many use cases for rendering Google Documents and Slides with ScreenshotOne. A few cases that stand out are:

1.  [Generate course handouts and certification PDFs from HTML templates based on Google Documents](/use-cases/courses-hand-outs-and-certification-documents/).

2.  [Legal evidence and discovery snapshots](/use-cases/legal-evidence-discovery-snapshots/).

3.  [Investor and board reporting decks](/use-cases/investor-and-board-reporting-decks/).

Support

-------

If you have any questions or need any assistance, please, reach out at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [ScreenshotOne CLI is available](/changelog/cli-integration/)

Use command line interface to automate screenshots in your workflows with ScreenshotOne.

Read more →

1 min read

#### [ScreenshotOne Dashboard performance has been improved](/changelog/upgraded-dashboard-underlying-framework/)

ScreenshotOne Dashboard has been upgraded to Next.js 16

Read more →

1 min read

#### [ScreenshotOne is available on Pipedream](/changelog/pipedream-integration/)

Automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos in Pipedream.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/contributors/bjarn-bronsveld
----

Bjarn Bronsveld

---------------

View all Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [How Spectate uses ScreenshotOne to improve incident observability](/blog/how-spectate-uses-screenshotone/)

If you are interested in diving deeper into the Spectate use case and discover if ScreenshotOne might be useful for you, too, keep reading.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Bjarn Bronsveld](/contributors/bjarn-bronsveld/)

Published on

Jul 21, 2024

•

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/2
----

Automate Website Screenshots

----------------------------

Guides, Product Updates, and Helpful Resources from ScreenshotOne.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [Why Promptwatch wins in the AI search space](/blog/promptwatch/)

About how Promptwatch uses ScreenshotOne to automate website screenshots and why that matters.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Klaas Foppen](/contributors/klaas-foppen/)

Updated on

Feb 11, 2026

•

3 min read

[Desktop screen capture](/blog/tags/desktop-screen-capture/)

#### [How to Capture Desktop Screenshots in Python](/blog/python-screen-capture/)

Complete guide to desktop screen capture in Python. Compare Python MSS, DXcam, PyAutoGUI for capturing monitors, windows, and screen regions.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 19, 2026

•

3 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/) [Playwright guides](/blog/tags/playwright-guides/)

#### [How to Take Full Page Screenshots with Playwright in Python](/blog/playwright-python-full-page-website-screenshots/)

Learn how to capture full page screenshots with Playwright in Python. Master the full\_page parameter, handle infinite scroll pages, lazy-loaded images, and maximum size limits.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 17, 2026

•

4 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/) [Playwright guides](/blog/tags/playwright-guides/)

#### [How to Take Website Screenshots with Playwright in Python](/blog/playwright-python-screenshots/)

A complete guide to taking website screenshots with Playwright in Python. Learn page.screenshot() parameters, async patterns, element screenshots, dark mode, and device emulation.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 16, 2026

•

5 min read

[Desktop screen capture](/blog/tags/desktop-screen-capture/)

#### [How to Take Screenshots with Python MSS](/blog/mss-python-screen-capture/)

Complete guide to the MSS Python screen capture library. Learn installation, capturing monitors, regions, performance optimization, and common errors like xgetimage() failed.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 15, 2026

•

4 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to Take Bulk Screenshots in Python with a Screenshot API](/blog/bulk-screenshots-python/)

Learn how to automate bulk website screenshots in Python using ScreenshotOne API. Process thousands of URLs efficiently with async requests, rate limiting, and error handling.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 14, 2026

•

3 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/) [Playwright guides](/blog/tags/playwright-guides/)

#### [How to Take Bulk Screenshots with Playwright in Python](/blog/bulk-screenshots-playwright-python/)

Learn how to automate bulk website screenshots with Playwright in Python. Master async batch processing, concurrent screenshots, rate limiting, and error handling for large-scale screenshot automation.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 14, 2026

•

7 min read

[Desktop screen capture](/blog/tags/desktop-screen-capture/)

#### [How to Capture Desktop Screen with DXcam in Python](/blog/dxcam-python-screenshots/)

Complete guide to DXcam, the fastest Python screen capture library. Learn high-FPS capture, video mode, region capture, and DXcam vs Python MSS performance comparison.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 14, 2026

•

4 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/13
----

Automate Website Screenshots

----------------------------

Guides, Product Updates, and Helpful Resources from ScreenshotOne.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

#### [How to take a screenshot of a webpage in Haskell](/blog/how-to-take-a-screenshot-of-a-webpage-in-haskell/)

It's very a common need to take a screenshot of a live website. On a project I worked on recently, we had a legal requirement to take screenshots of forms which our users filled, as at the time they filled the forms, for consent documentation purposes.

Written by

[Anthony Alaribe](/contributors/anthony-alaribe/)

Updated on

Oct 23, 2022

•

3 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to hide chat widgets when taking a screenshot with Puppeteer](/blog/how-to-hide-chat-widgets-when-taking-a-screenshot-with-puppeteer/)

When you want to take chat widgets, there are annoying chat widgets that you would love to hide. It is easy to do.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jul 28, 2022

•

1 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [How to hide cookie banners when taking a screenshot with Puppeteer](/blog/how-to-hide-cookie-banners-when-taking-a-screenshot-with-puppeteer/)

When taking a screenshot, you want to ensure that you take a clean screenshot without cookie banners or cookie consent forms. And in this article, I will share with you how you can do it when using Puppeteer.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Nov 12, 2024

•

11 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [How to fix the "Execution context was destroyed" error when using Puppeteer](/blog/puppeteer-execution-context-was-destroyed-most-likely-because-of-a-navigation/)

Fix the Puppeteer "Execution context was destroyed, most likely because of a navigation" error after click, form submit, redirect, reload, or page.evaluate.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Mar 13, 2026

•

5 min read

#### [A complete guide on how to take full page screenshots with Puppeteer, Playwright or Selenium](/blog/a-complete-guide-on-how-to-take-full-page-screenshots-with-puppeteer-playwright-or-selenium/)

You can take a full page screenshot with Pupeeter by specifying the \`fullPage\` parameter as true when taking a screenshot. But there is a caveat. If a site has lazy-loaded images, they won't be rendered. Let's examine how to fix the issue and trigger lazy image loading with Puppeteer.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Oct 19, 2022

•

7 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to create a site thumbnail with Puppeteer](/blog/how-to-create-a-site-thumbnail-with-puppeteer/)

We can consider the screenshot of URL or HTML as a thumbnail, but I write about the thumbnail of a screenshot. How do you take a screenshot within the defined viewport but with different image width and height? Resize!

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jul 17, 2022

•

3 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Taking screenshots with Puppeteer in GIF, JP2, TIFF, AVIF, HEIF, or SVG format](/blog/taking-screenshots-with-puppeteer-in-gif-jp2-tiff-avif-heif-or-svg-format/)

Puppeteer, by default, supports only four formats for taking screenshots or rendering HTML: PNG, JPEG, WebP, and PDF. But what if you want it to take it in a different format like GIF, JP2, TIFF, AVIF, HEIF, or SVG?

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jul 17, 2022

•

6 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Puppeteer waitUntil: how to wait for page load](/blog/puppeteer-wait-until-the-page-is-ready/)

Join me in exploring how to find the ideal wait time or event of when to take the page screenshot with Puppeteer.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Mar 13, 2026

•

8 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/archive-news-web-pages
----

Automate Website Screenshots

1 min read

Periodic News Webpage Documentation

===================================

Automate the periodic capture of news web pages for archival and legal reference.

Maintaining records of news publications is vital for archival or judicial purposes. ScreenshotOne API enables the automated capture of news web pages on an hourly basis.

Enhancement Through ScreenshotOne API

-------------------------------------

Utilizing the website screenshot API, entities can automate the documentation process, securing a detailed and timestamped archive of news dissemination. This resource is invaluable for legal professionals, researchers, and historians needing precise historical records.

Resource and Time Conservation

------------------------------

The automated documentation of news pages via ScreenshotOne markedly reduces the manual burden on teams, permitting them to dedicate more time to analysis and interpretation rather than data gathering. It offers a dependable, scalable method for recording and preserving essential information over time.

After searching far and wide for a solution, only ScreenshotOne was straightforward enough to quickly validate & implement easily. Now it's an integral part of the bookmarking experience for my app.

Sebastian Graz

Maker, [Herding.app](https://herding.app/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/guides/bulk-screenshots
----

[Skip to content](#_top)

How to take screenshots of multiple URLs

========================================

Copy page

ScreenshotOne API supports taking screenshots of multiple URLs in one request—[bulk screenshots](/docs/bulk-screenshots/). But since it is a simple wrapper around the regular screenshot API, you might find it much better to implement your own bulk screenshot solution.

A few tips:

1.  Use proxies if needed.

2.  Retry failed requests.

3.  Use a queue to process the URLs in batches, even internal onces.

4.  Respect the concurrency limit. Build your solution based on dynamically calculated quota from [the “get usage” API endpoint](/docs/get-usage/).

Check out working example in the [ScreenshotOne examples](https://github.com/screenshotone/examples) repository—[bulk screenshots example](https://github.com/screenshotone/examples/tree/main/nodejs/bulk-screenshots).

In case you need help, feel free to reach out to support at [support@screenshotone.com](mailto:support@screenshotone.com).

----
url: https://screenshotone.com/use-cases
----

The Screenshot API

Automate Website Screenshots

----------------------------

ScreenshotOne is developed to support a huge variety of use cases and to be the best assistant for developers in website screenshot automation.

### AI Agents With Browser Observation

Give AI agents reliable screenshots of web pages so they can inspect, compare, and act with visual context.

[Read more →](/use-cases/ai-agents/)

### Landing Page Evaluation with AI

Automate landing page roasting for your customers or yourself with modern technologies like OpenAI Vision.

[Read more →](/use-cases/ai-landing-page-roasting/)

### AI Vision For Analyzing Web Pages

Use AI to extract insights from web page visuals for enhanced content strategy and market analysis.

[Read more →](/use-cases/ai-vision-web-page-analysis/)

### Automate Personalized Videos at Scale

Using email marketing with dynamic, scrolling, or animated screenshots for personalized videos.

[Read more →](/use-cases/automate-personalized-videos/)

### Periodic News Webpage Documentation

Automate the periodic capture of news web pages for archival and legal reference.

[Read more →](/use-cases/archive-news-web-pages/)

### Brand Intellectual Property Surveillance

Track and store web content for unauthorized brand IP usage.

[Read more →](/use-cases/brand-ip-monitoring/)

Mike Roberts

Founder, [SpyFu](https://www.spyfu.com/)

> ScreenshotOne is the best product on the market - and that's before you take into account how responsive and easy Dmytro is to work with.

> 

> Any time we've found a rare edge case, it's been resolved in hours.

> 

> Great company, great founder - can't say enough!

### Browser Extension Font Detection

Build browser extensions to allow users to identify and learn about fonts on any website with a single click.

[Read more →](/use-cases/browser-extension-font-detection/)

### Automated Web Audits with Font Analysis

With our font detection API generate comprehensive typography reports to optimize websites for aesthetics and performance.

[Read more →](/use-cases/automated-web-audits-fonts/)

### Landing Page Design Inspiration Collection

Streamline the aggregation of web design inspirations.

[Read more →](/use-cases/collect-design-inspirations/)

### Brand Consistency Font Checks

Use ScreenshotOne font detection API to automatically verify font consistency across web pages to maintain brand integrity.

[Read more →](/use-cases/brand-consistency-font-checks/)

### Competitive Product Analysis

Automate the capture of competitor product listings for market analysis and strategy planning.

[Read more →](/use-cases/competitive-product-analysis/)

### Competitor Price Tracking

Automate the capture of competitor pricing data for analysis.

[Read more →](/use-cases/competitor-price-tracking/)

Barnabás Ürmössy

Development Manager, [Kinsta](https://screenshotone.com/blog/kinsta/)

> Working with Dmytro from ScreenshotOne has been an overwhelmingly positive and refreshing experience. He’s incredibly responsive, quick to act, and genuinely committed to making his service work for our needs.

### Course handouts and certification PDFs

Generate course handouts and certification PDFs from HTML templates.

[Read more →](/use-cases/courses-hand-outs-and-certification-documents/)

### Customer Support Enhancement

Use screenshots to quickly resolve customer queries about website navigation or features.

[Read more →](/use-cases/customer-support-enhancement/)

### Design Tools Font Detection

Use our font detection API to help designers identify and analyze typography on any website.

[Read more →](/use-cases/design-apps-font-detection/)

### Dynamic invoices and receipts

Generate pixel-perfect invoices and receipts from HTML templates.

[Read more →](/use-cases/dymaic-invoice-receipt-pdfs/)

### Educational Font Detection Tool

Use our font detection API to enable students to explore and learn from typography used in real-world web applications.

[Read more →](/use-cases/educational-font-detection/)

### Dynamic Email Campaign Previews

Automatically generate and embed website screenshots in email marketing campaigns.

[Read more →](/use-cases/email-marketing/)

Sam Shore

Founder, [Typeshare](https://screenshotone.com/blog/how-typeshare-uses-screenshotone/)

> We have lots of SaaS subscriptions with Typeshare but by far the best value is ScreenshotOne.

> 

> For a small monthly fee, we basically get a full-time developer who handles all our image generation.

> 

> We've spent thousands on building this in-house and it was nowhere near as good as what Dmytro Krasun has built.

> 

> Can't recommend ScreenshotOne enough!

### Enrich Blog Posts for SEO

Automatically capture and embed screenshots of websites mentioned in SEO content to enhance engagement and credibility.

[Read more →](/use-cases/enrich-content-with-screenshots/)

### Website Feature Enhancement

Incorporate 'export to PNG' and 'export to PDF' options on your blog or website.

[Read more →](/use-cases/export-to-image/)

### Landing Page Design Inspiration Collection

Financial applications need immutable copies of trade confirmations, order books, swap quotes, or K‑line charts for regulators and SOC 2 audits.

[Read more →](/use-cases/financial-audit-trail-capture/)

### Font Accessibility Checks

Use our font detection API to check fonts and and research whether websites use readable fonts for people with visual impairments or reading disabilities.

[Read more →](/use-cases/font-accessibility-checks/)

### Font Legal Compliance Check

Ensure fonts used on websites are legally compliant to avoid copyright issues.

[Read more →](/use-cases/font-legal-compliance/)

### Better Font Marketplaces

Show how fonts look on live websites to improve conversion rates.

[Read more →](/use-cases/font-marketplace-enhancement/)

Alex Rainey

Founder, [My AskAI](https://myaskai.com/)

> We needed to build a side product, fast, we signed up and within minutes we were set up and had pulled over 400 picture-perfect screenshots for use in a new directory tool we were launching.

### Font Trends Analysis

Use our font detection API to provide insights into typography trends of top-ranking websites across various industries.

[Read more →](/use-cases/font-trends/)

### Advertising Material Creation and Management

Facilitate the creation and storage of advertising content in various sizes.

[Read more →](/use-cases/generate-advertising-content/)

### Generate Site Thumbnails

Create small-sized previews of websites for cataloguing or summary purposes.

[Read more →](/use-cases/generate-site-thumbnails/)

### Investor and board reporting decks

Automatically reporting for investors and board members.

[Read more →](/use-cases/investor-and-board-reporting-decks/)

### Legal evidence and discovery snapshots

Preserve any web page exactly as it appeared, in a court‑ready bundle.

[Read more →](/use-cases/legal-evidence-discovery-snapshots/)

### Live dashboard report emails

Take a screenshot of a Grafana / BI dashboard and embed it in a daily PDF mailed to stakeholders who dislike logging in.

[Read more →](/use-cases/live-dashboad-emails/)

Eugene Zolotarenko

Co-Founder, [Outrank](https://screenshotone.com/blog/outrank/)

> Using the API was very simple, I just gave the docs to Cursor. Any issues I encountered were resolved quickly by the support team.

### Marketing Content Creation

Capture dynamic web content for marketing materials.

[Read more →](/use-cases/marketing-content-creation/)

### Screenshots for NemoClaw Agents

Use ScreenshotOne with NemoClaw to capture website screenshots for enterprise AI agents, browser verification, secure reporting, and visual audit trails.

[Read more →](/use-cases/nemoclaw-agents/)

### Automate Open Graph image generation

You can use our screenshot API to effortlessly generate images when sharing links on social media or messengers.

[Read more →](/use-cases/open-graph-images/)

### Personalized Onboarding

Personalize onboarding by analyzing a customer's website visually and using screenshots throughout the setup flow.

[Read more →](/use-cases/personalized-onboarding/)

### Screenshots for OpenClaw Workflows

Use ScreenshotOne to automate website screenshots inside OpenClaw workflows for visual checks, proactive monitoring, and image-based reporting.

[Read more →](/use-cases/openclaw-workflows/)

### Rendering Search Results Preview in Site Search

Using a screenshot API to generate visual previews of web pages for search results within a website.

[Read more →](/use-cases/preview-search-results/)

Bjarn Bronsveld

Founder, [Spectate](https://spectate.net/)

> That was a lot of work to get rendering screenshots work right (there's a lot of edge cases in my case) and I just opted for ScreenshotOne because of the pricing and great API.

### Real‑estate listing sheets

Automatically generate and embed website screenshots in investor and board reporting decks.

[Read more →](/use-cases/real-estate-listing-sheets/)

### Seize Live User-Contributed Content

Streamline the capture of lively user interactions and modifications.

[Read more →](/use-cases/screenshot-user-generated-content/)

### SEO Performance Tracking

Monitor SEO rankings and visibility for strategic insights.

[Read more →](/use-cases/seo-performance-tracking/)

### Social Media Content Compliance

Ensure compliance with regulations and brand standards on social media.

[Read more →](/use-cases/social-media-content-compliance/)

### User Experience Documentation

Document and improve website user experience.

[Read more →](/use-cases/user-experience-documentation/)

### Visual Regression Testing

Automate visual regression testing for your website with ScreenshotOne.

[Read more →](/use-cases/visual-regression-testing/)

Andy Hooke

Founder, [Saaspo](https://screenshotone.com/blog/saaspo/)

> I’ve been using ScreenshotOne for 3 years and couldn’t run Saaspo without it.

> 

> You can tell Dmytro really cares about the product as it keeps getting better.

> 

> Highly recommend to anyone looking for a screenshot tool!

### UX Font Analysis

Examine the impact of different fonts on user engagement and website usability.

[Read more →](/use-cases/ux-font-analysis/)

### Website Archiving for Compliance

Ensure regulatory compliance through periodic website archiving.

[Read more →](/use-cases/website-archiving-for-compliance/)

### Website Archivation for Historical Reference

Automate the archival of website versions for historical reference and data retrieval.

[Read more →](/use-cases/website-archivation/)

### Streamline Web Directory Submissions

Simplify the process of adding new sites to web directories.

[Read more →](/use-cases/website-directories/)

### Website Monitoring

Monitor website changes, or even errors. And notify your customers if needed.

[Read more →](/use-cases/website-monitoring/)

Chris Muktar

Co-Founder, [Glass Analytics](https://gl8ss.com/)

> We're using ScreenshotOne to build user behavior click heatmaps for Glass Analytics, a comprehensive and powerful Google Analytics alternative.

> 

> ScreenshotOne elegantly solves this problem, allowing our developers to focus on core functionality for our customers, while providing a reliable service we can count on.

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/contributors/nicolas-jeannen
----

Nicolas Jeannen

---------------

View all Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [How AdKit automated onboarding](/blog/adkit/)

A short story by the founder of AdKit about how they use ScreenshotOne for onboarding automation.

Written by

[Nicolas Jeannen](/contributors/nicolas-jeannen/)

Published on

Mar 12, 2026

•

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/organization-transfer-ownership
----

Transfer organization ownership

===============================

From today, you can transfer organization ownership to another user.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Feb 24, 2025

In ScreenshotOne, currently organization can have only one owner, and other roles are developers.

Owner can invite members and manage billing, while developer can only manage API keys, check out logs and other resources that allows to integrate and develop with ScreenshotOne API.

But due to many requests, we added a new feature that allows to transfer organization ownership to another user.

To transfer ownership, you need to go to [the organization settings in the ScreenshotOne Dashboard](https://dash.screenshotone.com/organization) and click on the “Transfer ownership” button:

That action is irreversible and will transfer ownership to the selected user.

If you have any questions or suggestions, please, contact us at [support@screenshotone.com](mailto:support@screenshotone.com).

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Trigger screenshot download](/changelog/attachment-name/)

Now you can set attachment filename to trigger screenshot download in the browser.

Read more →

1 min read

#### [Improved blocking of banners for specific websites](/changelog/improved-banner-blocking-for-specific-websites/)

We just released an updated version of our algorithm to block banners for specific websites by heuristics.

Read more →

1 min read

#### [Added an Above-the-Fold Checker Tool](/changelog/above-the-fold-checker/)

A new ScreenshotOne tool to capture what users see before the first scroll.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/featured-on-microlaunch
----

ScreenshotOne is featured on MicroLaunch

========================================

ScreenshotOne is featured on MicroLaunch

[Blog post](/blog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Apr 7, 2024

[MicroLaunch](https://microlaunch.net/) is a new alternative for Product Hunt that allows you to drive more traffic for your product and get feedback. They added more features than just upvote and it is a good platform to discover new products.

[](https://microlaunch.net/p/screenshotone)

On [MicroLaunch](https://microlaunch.net/) you can share feedback, roast the product, evaluate the idea, and get feedback about the product.

It is also a good place to discover new products.

[](https://microlaunch.net/)

Give feedback on ScreenshotOne and [support us](https://microlaunch.net/p/screenshotone) today!

Read more posts

---------------

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

[View all posts](/blog/)

#### [How to build a Programmatic SEO site with automated website screenshots using ScreenshotOne, Airtable, and Launchman](/blog/how-to-build-a-programmatic-seo-site-with-automated-website-screenshots-using-screenshotone-airtable-and-launchman/)

Programmatic SEO is a great growth hacking strategy where you create a large number of content pages that rank for long-tailed keywords on Google.

Read more

#### [Blast Banners with ScreenshotOne](/blog/blast-banners/)

A funny game built on top of ScreenshotOne API.

Read more

#### [Lessons learned from the AWS disruption](/blog/lessons-from-the-aws-us-east-1-disruption/)

Sharing thoughts and lessons learned from the AWS (us-east-1) disruption, including impact on ScreenshotOne.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/llms.txt
----

\# ScreenshotOne.com Documentation

\- \[Animated Screenshots\](https://screenshotone.com/docs/animated-screenshots/)
\- \[Async and Webhooks\](https://screenshotone.com/docs/async-and-webhooks/)
\- \[Bulk Screenshots\](https://screenshotone.com/docs/bulk-screenshots/)
\- \[Errors\](https://screenshotone.com/docs/errors/)
\- \[How credits work in ScreenshotOne\](https://screenshotone.com/docs/credits/)
\- \[ScreenshotOne IP Ranges\](https://screenshotone.com/docs/ip-ranges/)
\- \[Organizations and Roles\](https://screenshotone.com/docs/organizations/)
\- \[Signed Links\](https://screenshotone.com/docs/signed-requests/)
\- \[Charging Extra\](https://screenshotone.com/docs/charging-extra/)
\- \[Devices\](https://screenshotone.com/docs/viewport-devices/)
\- \[Screenshot URL\](https://screenshotone.com/docs/screenshot-url/)
\- \[Get Usage\](https://screenshotone.com/docs/get-usage/)
\- \[Access Key Invalid\](https://screenshotone.com/docs/errors/access-key-invalid/)
\- \[Access Key Required\](https://screenshotone.com/docs/errors/access-key-required/)
\- \[Concurrency Limit Reached\](https://screenshotone.com/docs/errors/concurrency-limit-reached/)
\- \[Content Contains Specified String\](https://screenshotone.com/docs/errors/content-contains-specified-string/)
\- \[Content Missing Specified String\](https://screenshotone.com/docs/errors/content-missing-specified-string/)
\- \[Internal Application Error\](https://screenshotone.com/docs/errors/internal-application-error/)
\- \[Caching\](https://screenshotone.com/docs/caching/)
\- \[Host Returned Error\](https://screenshotone.com/docs/errors/host-returned-error/)
\- \[Invalid Storage Configuration\](https://screenshotone.com/docs/errors/invalid-storage-configuration/)
\- \[Name Not Resolved\](https://screenshotone.com/docs/errors/name-not-resolved/)
\- \[Request Aborted\](https://screenshotone.com/docs/errors/request-aborted/)
\- \[Network Error\](https://screenshotone.com/docs/errors/network-error/)
\- \[Request Body Too Large\](https://screenshotone.com/docs/errors/request-body-too-large/)
\- \[Resulting Image Too Large\](https://screenshotone.com/docs/errors/resulting-image-too-large/)
\- \[Request Invalid\](https://screenshotone.com/docs/errors/request-invalid/)
\- \[Invalid Cookie Parameter\](https://screenshotone.com/docs/errors/invalid-cookie-parameter/)
\- \[Matched Failed Request\](https://screenshotone.com/docs/errors/matched-failed-request/)
\- \[Invalid Header Parameter\](https://screenshotone.com/docs/errors/invalid-header-parameter/)
\- \[Script Trigger Redirect\](https://screenshotone.com/docs/errors/script-triggers-redirect/)
\- \[Signature Invalid\](https://screenshotone.com/docs/errors/signature-is-invalid/)
\- \[Signature Required\](https://screenshotone.com/docs/errors/signature-is-required/)
\- \[Storage Returned Transient Error\](https://screenshotone.com/docs/errors/storage-returned-transient-error/)
\- \[Selector Not Found\](https://screenshotone.com/docs/errors/selector-not-found/)
\- \[Temporary Unavailable\](https://screenshotone.com/docs/errors/temporary-unavailable/)
\- \[Timeout Error\](https://screenshotone.com/docs/errors/timeout/)
\- \[Usage Quota Exceeded\](https://screenshotone.com/docs/errors/usage-quota-exceeded/)
\- \[Getting Started\](https://screenshotone.com/docs/getting-started/)
\- \[No-code Integrations\](https://screenshotone.com/docs/no-code/)
\- \[Guides\](https://screenshotone.com/docs/guides/)
\- \[Screenshot Options\](https://screenshotone.com/docs/options/)
\- \[C# (.NET) SDK and Code Examples\](https://screenshotone.com/docs/code-examples/c-net/)
\- \[Go SDK and Code Examples\](https://screenshotone.com/docs/code-examples/go/)
\- \[SDK and Code Examples\](https://screenshotone.com/docs/code-examples/)
\- \[Java SDK and Code Examples\](https://screenshotone.com/docs/code-examples/java/)
\- \[PHP SDK and Code Examples\](https://screenshotone.com/docs/code-examples/php/)
\- \[Python SDK and Code Examples\](https://screenshotone.com/docs/code-examples/python/)
\- \[Ruby SDK and Code Examples\](https://screenshotone.com/docs/code-examples/ruby/)
\- \[How to render website screenshots with Bubble\](https://screenshotone.com/docs/no-code/bubble/)
\- \[How to render website screenshots with Make\](https://screenshotone.com/docs/no-code/make/)
\- \[How to automate website screenshots with n8n\](https://screenshotone.com/docs/no-code/n8n/)
\- \[How to automate website screenshots with Zapier\](https://screenshotone.com/docs/no-code/zapier/)
\- \[How to automate website screenshots in Clay with ScreenshotOne\](https://screenshotone.com/docs/no-code/clay/)
\- \[Notifications\](https://screenshotone.com/docs/notifications/)
\- \[Storage Access Denied\](https://screenshotone.com/docs/errors/storage-access-denied/)
\- \[How to render Google Slides as scrolling screenshots with ScreenshotOne\](https://screenshotone.com/docs/guides/google-slides-as-scrolling-screenshots/)
\- \[How to take screenshots of multiple URLs\](https://screenshotone.com/docs/guides/bulk-screenshots/)
\- \[JavaScript and TypeScript (Node.js) SDK and Code Examples\](https://screenshotone.com/docs/code-examples/javascript-and-typescript-nodejs/)
\- \[How to use proxies\](https://screenshotone.com/docs/guides/how-to-use-proxies/)
\- \[Detect website fonts\](https://screenshotone.com/docs/guides/how-to-detect-website-fonts/)
\- \[How to render Google Documents as JPEG, PNG or WebP screenshots\](https://screenshotone.com/docs/guides/screenshot-google-docs/)
\- \[How to screenshot an area of a site\](https://screenshotone.com/docs/guides/how-to-screenshot-an-area-of-a-site/)
\- \[How to render screenshots with different emoji styles\](https://screenshotone.com/docs/guides/emojis/)
\- \[How to handle API errors\](https://screenshotone.com/docs/guides/how-to-handle-api-errors/)
\- \[Fail rendering if the content contains a string\](https://screenshotone.com/docs/guides/fail-if-content-contains/)
\- \[How to bypass CAPTCHAs\](https://screenshotone.com/docs/guides/how-to-bypass-captchas/)
\- \[Screenshot authenticated pages\](https://screenshotone.com/docs/guides/authenticated-pages/)
\- \[Customize websites before screenshotting\](https://screenshotone.com/docs/guides/how-to-customize-any-website-before-screenshotting/)
\- \[Full-page screenshots\](https://screenshotone.com/docs/guides/full-page-screenshots/)
\- \[How to Unblock ScreenshotOne in Cloudflare \](https://screenshotone.com/docs/guides/unblock-cloudflare-challenges/)
\- \[Rendering performance\](https://screenshotone.com/docs/guides/performance/)
\- \[How to translate and render a website as a screenshot\](https://screenshotone.com/docs/guides/how-to-translate-and-render-a-website-as-a-screenshot/)
\- \[Upload to S3\](https://screenshotone.com/docs/guides/upload-to-s3/)

----
url: https://screenshotone.com/changelog/2
----

Changes and updates

-------------------

Stay updated with the latest information about new features, bug fixes, and optimizations at ScreenshotOne

### Product updates in the last 12 months

Jan 7, 2026

#### [Add ScreenshotOne to Clay](/changelog/clay-integration/)

Generate website screenshots inside Clay to qualify leads, assess content, and enrich rows with visual context automatically.

Read more →

1 min read

Dec 10, 2025

#### [ScreenshotOne integration with Dirstarter](/changelog/dirstarter-integration/)

Build a directory with Dirstarter and add website screenshots automatically with ScreenshotOne.

Read more →

1 min read

Dec 8, 2025

#### [ScreenshotOne CLI is available](/changelog/cli-integration/)

Use command line interface to automate screenshots in your workflows with ScreenshotOne.

Read more →

1 min read

Dec 8, 2025

#### [ScreenshotOne is available on Pipedream](/changelog/pipedream-integration/)

Automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos in Pipedream.

Read more →

1 min read

Dec 6, 2025

#### [Added a "copy page" button in documentation](/changelog/copy-page-button-in-docs/)

You can now copy the page content as Markdown for LLMs and more.

Read more →

1 min read

Nov 28, 2025

#### [Error metrics in the dashboard](/changelog/error-metrics/)

You can now see error metrics in the dashboard to quickly understand what errors are happening and how often.

Read more →

1 min read

Nov 18, 2025

#### [ScreenshotOne on the Postman Public API Network](/changelog/postman-public-collections/)

You can now play with the ScreenshotOne API in Postman using many examples as starting points for integrations.

Read more →

1 min read

Oct 30, 2025

#### [Choose the format of the page content returned by the ScreenshotOne API](/changelog/metadata-content-format/)

Now you can choose the format of the page content returned by ScreenshotOne API with the metadata\_content\_format option.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/ai-screenshot-analysis-for-finding-customers
----

Using AI screenshot analysis to identify leads for a design agency

==================================================================

Elias shares his process for discovering high-quality leads for a design agency by using AI screenshot analysis within the Clay platform.

[Customer story](/blog/tags/customer-stories/) 4 min read

#### Written by

[Elias Stravik](/contributors/elias-stravik/)

#### Published on

Dec 23, 2024

Hi, I am Elias Stravik. I am the founder of [Prospecterra](https://prospecterra.com/) and I specialize in creating lead lists, and automation and scaling personalized emails.

Have you ever wanted to automate your lead generation process, especially if you’re targeting a specific niche like Web3 companies in need of design help?

In this blog post, I’ll walk you through the exact process I used to find potential clients for my friend’s Web3-focused design agency.

By combining a dedicated job board, a screenshot API, and the power of AI, I was able to efficiently sort through opportunities and identify which prospects might benefit most from professional design services.

If you prefer to watch instead of read, you can watch the video below:

[Play](https://youtube.com/watch?v=Q7IYa6q4aa8)

Step 1: Identifying Your Niche

------------------------------

My friend runs a design agency tailored for Web3 companies. Their unique value proposition is to provide a world-class designer embedded right within the client’s team to handle all design needs. With so many startups and organizations emerging in the Web3 space, I needed a way to filter potential leads quickly.

I started by focusing on Web3-specific sources of leads. One such platform is [web3.career](https://web3.career/), a job board dedicated to Web3 jobs. Since companies listing design roles here are already looking for talent, it’s a perfect place to start prospecting.

Step 2: Scanning a Web3 Job Board for Potential Leads

-----------------------------------------------------

On the job board website, I can see a variety of design-related job listings. Each company posting a job is either already aware of their design needs or actively searching for ways to improve their visual brand.

By browsing the listings, I compiled a list of company names and their corresponding domains.

For this example, I limited it to about 30 entries to keep things manageable.

Step 3: Capturing Website Screenshots with an API

-------------------------------------------------

Now that I had a list of companies, the next challenge was evaluating their current design quality at a glance. Sure, I could manually visit each website, but that’s time-consuming and subjective.

Instead, I used a product called [ScreenshotOne](https://screenshotone.com/), an API that allows developers to easily capture a screenshot of any given URL.

By integrating with this API, I could automatically fetch images of each company’s homepage. No manual clicking, no endless open tabs—just quick and efficient visual data.

Step 4: Using AI to Evaluate Website Design

-------------------------------------------

Here’s where it gets really interesting: AI doesn’t just read text; it can “see” images and provide analysis if prompted correctly.

I used an AI model (via a ChatGPT-like integration) and instructed it to:

*   Act like a world-class Web3 designer.

*   Evaluate the website screenshot.

*   Provide feedback on what’s good and what’s bad about the design.

*   Offer a summary of the site’s design quality.

*   Assign a score from 1 to 100 based on overall design quality.

With these instructions, the AI took each screenshot and returned a structured analysis and a quality score. This gave me a clear, standardized way to rank potential leads by their design needs.

Step 5: Sorting Leads by Design Quality

---------------------------------------

Now that I had a score for each company’s website, I could sort them by their design quality—either from highest to lowest or vice versa. The idea here is simple:

*   **High-Scoring Sites (e.g., 85/100):** These companies might already have solid design resources in place. While they’re still hiring, they may need more specialized or niche design work.

*   **Low-Scoring Sites (e.g., 62/100 or lower):** These are prime opportunities. A company with a lower score likely has gaps in their design execution. This is where my friend’s agency can add significant value, swooping in to offer a redesign or a more integrated design service.

Step 6: Prioritizing Outreach

-----------------------------

With the ranking in hand, it’s easy to prioritize outreach efforts. Rather than blindly emailing all 30 companies, I focus on those with the greatest potential upside—websites that scored lower on the design scale. In doing so, I increase the chances that my outreach is well-received, because I’m addressing a clear, identified need.

Step 7: Expanding the Use Cases

-------------------------------

This approach doesn’t have to stop at websites. Imagine applying the same logic to other assets:

*   **Logos:** Evaluate brand cohesion or logo quality.

*   **Product Screenshots:** Assess UI design or user experience flow.

*   **E-commerce Platforms:** Look at product imagery, layout, and conversion optimization potential.

Your creativity is the limit. The combination of scraping leads, capturing screenshots, and feeding those images into AI for evaluation can be adapted to many industries and use cases.

Step 8: Putting It All Together

-------------------------------

In summary, here’s the streamlined workflow:

1.  **Find a Dedicated Job Board (web3.career):** Gather a list of companies posting design jobs.

2.  **Compile a Domain List:** Extract company names and website domains.

3.  **Use a Screenshot API (ScreenshotOne):** Automatically capture website images.

4.  **AI Evaluation:** Have an AI model act as a design expert, analyze each screenshot, and provide feedback plus a score.

5.  **Filter & Prioritize:** Sort companies by their design score and focus your outreach on the ones that need help the most.

Final Thoughts

--------------

This entire system took shape thanks to a combination of clever integrations—[Clay (for data handling)](https://www.clay.com/), the ScreenshotOne API (for visual capture), and AI (for analysis and scoring).

It’s a powerful demonstration of how automation and machine learning can come together to streamline lead generation and qualification in a specialized field like Web3 design.

I hope this step-by-step walkthrough inspires you to think creatively about your own lead generation and qualification processes.

Read more customer stories

--------------------------

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

[View all posts](/blog/tags/customer-stories/)

#### [How Branding 5 uses ScreenshotOne for competitor analysis](/blog/how-branding5-uses-screenshotone/)

If you are interested in diving deeper into the Branding 5 use case and discover if ScreenshotOne might be useful for you, too, keep reading.

Read more

#### [Integrating ScreenshotOne into the directory management platform](/blog/makeadir-feedback/)

How and why "Make a Directory" used ScreenshotOne to automate screenshots for directory websites.

Read more

#### [How FounderPal uses ScreenshotOne for landing page analysis](/blog/how-founderpal-uses-screenshotone/)

If you are interested in diving deeper into the FounderPal use case and discover if ScreenshotOne might be useful for you, too, keep reading.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/lessons-from-the-aws-us-east-1-disruption
----

Lessons learned from the AWS disruption

=======================================

Sharing thoughts and lessons learned from the AWS (us-east-1) disruption, including impact on ScreenshotOne.

[Blog post](/blog/) 3 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Oct 30, 2025

On October 19 and 20, 2025 the AWS service disruption occurred in the N. Virginia (us-east-1) Region. It felt like almost half of the Internet was affected.

What happened?

--------------

[The AWS team already has shared in many details their official version on what happened](https://aws.amazon.com/message/101925/):

One of the AWS key services, Amazon DynamoDB, had a DNS failure due to a software “race condition”—a bug in their DNS automation system caused the main endpoint’s DNS record to be blank, so clients couldn’t connect.

And because many other AWS services (like EC2, Lambda, etc.) depend on DynamoDB and DNS, the failure cascaded: new EC2 instance launches failed, network load balancers misbehaved, and multiple services suffered elevated errors until manual fixes and throttling were applied.

In response AWS has disabled the faulty automation and is adding extra safeguards to prevent similar issues in future.

No impact on the ScreenshotOne API

----------------------------------

On that day, we were carefully observing all our services and error logs. And luckily, but the ScreenshotOne API was not affected, at all:

Impact on the ScreenshotOne dashboard authentication

----------------------------------------------------

The most major impact was on the ScreenshotOne dashboard authentication process. Users who were using magic links with emails, could not sign in/up because our downstream email provider [Resend](https://resend.com) relied on AWS:

Deploying to production failed

------------------------------

Since deploying to production relied on pulling images from Docker Registry, it was failing.

To our luck, there were no critical issues with the production environment that we needed to fix. But deploying a few features our for customers was postponed.

Lessons learned

---------------

### It happens

Since ScreenshotOne is hosted on DigitalOcean, Google Cloud and partially on Hetzner, we were not affected by the AWS disruption.

But it doesn’t mean that it won’t happen with our providers. Fails happen and it is a huge part of the software engineering.

We were lucky and that’s it. The question is how to avoid that in the future in case we are not lucky.

### Self-host your Docker registries and CI/CD infrastructure

ScreenshotOne relies on GitHub Actions for CI/CD. And it worked great, however, they might fail, too.

But what really failed was the Docker Registry since it relied on AWS.

Self-hosting our Docker registries and CI/CD infrastructure would prevent that.

### Backup email providers

ScreenshotOne uses Resend for email sending. And it didn’t work as expected. It can be prevented by setting up a few regions in Resend. And by adding a backup email provider.

There is one more argument in favor of the backup email provider. Sometimes they block you because if you are hacked, hackers might send a lot of spam through your account, in that case, you can switch quickly to the backup provider without any impact on your customers and focus your energy and time on fixing the security issue if happened.

Summary

-------

The AWS us-east-1 disruption showed that even large providers can go down, and critical dependencies can break unexpectedly. ScreenshotOne’s core API stayed unaffected thanks to multi-cloud infrastructure, but third-party services relying on AWS, like email authentication and Docker Registry, became unavailable.

A few key lessons is to host essential build and deploy infrastructure yourself, to set up backup providers for critical features like email, and always expect that outages will happen—resilience requires preparation.

Read more posts

---------------

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

[View all posts](/blog/)

#### [ScreenshotOne made it to the official Make conference](/blog/make-conference/)

One of our friends noticed ScreenshotOne at the official Make conference

Read more

#### [ScreenshotOne is featured in the Cloudflare "Built With" series](/blog/screenshotone-and-cloudflare/)

The Cloudflare platform is at the core of ScreenshotOne—it is used for caching, API gateway, storage for screenshots, and many other functions. It was an opportunity to learn about the company from a closer distance.

Read more

#### [Open Graph images](/blog/open-graph-images/)

You can control the preview image rendered when your site is shared on social media, messengers, or apps that support the Open Graph protocol.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/scrolling-screenshots-navigation
----

Navigate Pages when recording Scrolling Screenshots

===================================================

You can record a page navigation when recording scrolling screenshot video. It allows render less boring and more engaging videos.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

May 16, 2024

Let’s check an example, of how it looks like:

 Sorry, your browser doesn't support embedded videos.

It is rendered with a simple request like:

    1https://api.screenshotone.com/animate?url=https://screenshotone.com/&scenario=scroll&duration=10&scroll_try_navigate=true&scroll_navigate_link_hints=pricing&access_key=<YOUR KEY>

There is [a full documentation available with all options](https://screenshotone.com/docs/animated-screenshots/#scrollable-scrolling-screenshot).

The feature is still in its early stages of testing, but it is ready for production. You can already try it and see how it works for you.

It might not be perfect yet, but it will be improved with time. Any feedback is much appreciated. Feel free to reach out at `support@screenshotone.com` if you have any questions.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Use cases in the ScreenshotOne playground](/changelog/improved-playground/)

Having documentation and code examples is great, but not enough to allow developers to quickly integrate the API and assess all available features of the ScreenshotOne API.

Read more →

1 min read

#### [Better error coverage and documentation](/changelog/all-errors-are-covered/)

Since a few months ago, it has been possible to check errors in the dashboard request log and get explanations and more details in the documentation. But!

Read more →

1 min read

#### [Async, Webhooks, and Extra Limits](/changelog/async-webhooks-and-extra-limits/)

May was a great month and full of new and exciting updates. Let's check them out quickly.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/integrations/directify
----

Integrations

1 min read

Directify

=========

Build a website directory and add website screenshots with ScreenshotOne.

No-Code Automation CMS

[Directify](https://directify.app/) is a directory-as-a-service platform that allows anyone to create, customize, and launch a directory website quickly and easily. No technical skills required.

[](https://directify.app/)

They have launched [thousands of directories](https://directify.app/made-with-directify/) already and the product is in [active development](https://directify.app/changelog/).

Integration with [ScreenshotOne](/) in Directify allows you to automate the screenshot generation for your directory websites.

Resources

---------

*   [Integration Documentation](https://docs.directify.app/integrations/screenshotone)

*   [Automate Directory Screenshots](https://directify.app/blog/how-to-automate-website-screenshots-in-your-directory-with-screenshotone-and-directify/)

“It is super simple, works very well and fast.

Klaas Foppen

Founder, [Promptwatch](https://screenshotone.com/blog/promptwatch/)

Check more Integrations

-----------------------

No-code tools, AI, code libraries, and more.

[Check more Integrations](/integrations/)

No-Code Automation

### Zapier

Automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos in Zapier.

[Read more →](/integrations/zapier/)

No-Code Automation

### n8n

Use ScreenshotOne in n8n workflows to render website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

[Read more →](/integrations/n8n/)

No-Code Automation

### Clay

Generate website screenshots inside Clay to qualify leads, assess content, and enrich rows with visual context automatically.

[Read more →](/integrations/clay/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/itslaunchday
----

ScreenshotOne on LaunchDay!

===========================

ScreenshotOne participated in the first launch batch of the LaunchDay platform

[Blog post](/blog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jun 20, 2025

ScreenshotOne participated in the first batch of the [LaunchDay](https://launchday.com/) platform.

[](https://www.itslaunchday.com/products/screenshotone)

What is LaunchDay?

------------------

It is a new platform by [Dagobert Renouf](https://x.com/dagorenouf) that helps you to get more attention and sales for your product.

It is a competitor to Product Hunt, AppSumo and Indie Hackers in one package:

1.  It is a launch platform with upvotes and comments like Product Hunt.

2.  It drives sales like AppSumo by sharing your product with a discount for the community of makers, entrepreneurs, founders and indies.

3.  And in a way Dagobert surrounds himself and builds a community of indie makers which makes it a competitor to Indie Hackers in a sense.

If you are a product owner, consider [submitting your product to LaunchDay](https://www.itslaunchday.com/submit-product).

Results

-------

Since it was the first batch, the results are not that impressive. But it is a good start and I am sure that LaunchDay will grow and become a great platform for product marketing.

We didn’t have sales and a ton of traffic.

**Update!** But next batches already started to get sales:

[](https://x.com/sergeynazarovx/status/1947733135052923251)

Claim discount till the end of August 2025

------------------------------------------

We are happy to announce that the special discount is still available.

Every annual plan already has a two month discount! But till the end of August 2025, you can claim a 25% discount on any annual plan by using the code `LAUNCHDAYFRIENDS`, in addition to the two month discount.

Conclusion

----------

I believe in the platform and with time it will grow more and more. We need more alternatives to Product Hunt, AppSumo, Indie Hackers and other platforms.

Read more posts

---------------

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

[View all posts](/blog/)

#### [ScreenshotOne is featured in the Cloudflare "Built With" series](/blog/screenshotone-and-cloudflare/)

The Cloudflare platform is at the core of ScreenshotOne—it is used for caching, API gateway, storage for screenshots, and many other functions. It was an opportunity to learn about the company from a closer distance.

Read more

#### [ScreenshotOne October 2025 updates](/blog/screenshotone-october-2025-updates/)

Metadata content format, upgraded dashboard, improved webhooks, updated Go SDK, Make conference, and AWS disruption lessons.

Read more

#### [Alexander Schnebel about how he uses ScreenshotOne in Productglowup](/blog/alexander-schnebel-about-how-he-uses-screenshotone-in-productglowup/)

I had a great chat with Alexander Schnebel, the fullstack software engineer behind Productglowup.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/errors/request-invalid
----

[Skip to content](#_top)

Request Invalid

===============

Copy page

It is an API error returned when the API fails to serve the request due to internal reasons:

    1{2    "is_successful": false,3    "error_message": "The request parameters are not valid. You can look at the `error_details` response field to get more details.",4    "error_details": {5        // ... validation errors ...6    },7    "error_code": "request_invalid",8    "documentation_url": "https://screenshotone.com/docs/errors/request-invalid/"9}

Reasons and how to fix

----------------------

### Invalid Request Parameters

The most common reason for the “request\_not\_valid” error is that one or more of the request parameters are invalid or missing.

To fix this, you can:

1.  **Check `error_details` property**: Review the `error_details` field in the response to get specific information about which parameters are invalid.

2.  **Correct request parameters**: Ensure that all required parameters are included in the request and that they are correctly formatted and valid.

### Missing Required Parameters

If required parameters are missing from the request, this will trigger the “request\_not\_valid” error.

To fix this, ensure that all mandatory parameters are provided in the request. Refer to the API documentation for a list of required parameters.

### Incorrect Data Types

Providing parameters with incorrect data types (e.g., a string instead of an integer) can lead to this error.

To fix this, verify that the data types of all parameters match the expected types as specified in the API documentation.

### Parameter Value Constraints

Some parameters may have constraints on their values (e.g., minimum or maximum length, specific formats). Violating these constraints will result in this error.

To fix this, check the constraints for each parameter in the API documentation and ensure that the provided values comply with these constraints.

### Syntax Errors

Syntax errors in the request, such as missing commas or brackets in JSON, can make the request invalid.

To fix this, carefully review the syntax of your request and correct any errors. Using a JSON validator can help identify syntax issues.

Reach out to support

--------------------

If you continue to face issues or need further assistance, please reach out to `support@screenshotone.com`, and we will assist you as soon as possible.

----
url: https://screenshotone.com/changelog/guards-for-full-page-screenshots-by-sections
----

Improved guards for full-page screenshots by sections

=====================================================

Improved guards for full-page screenshots by sections.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Sep 23, 2025

When you use the `full_page_algorithm=by_sections` option, the API scrolls the page and captures each section.

In some cases, the API did not stop scrolling and could get stuck in an infinite loop.

We added additional guards to the scrolling algorithm to prevent this.

If you have any questions or suggestions, please let us know at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Improved favicon detection for metadata\_icon](/changelog/improved-metadata-icon-detection/)

Improved \`metadata\_icon\` to check common favicon link variants more reliably.

Read more →

1 min read

#### [Better and more extensible PDF rendering](/changelog/better-and-more-extensible-pdf-rendering/)

ScreenshotOne supports PDF rendering for a long time but it was used till recently by a small group of customers. Growing demand in PDF rendering required updating the API. And today, we introduce new options for PDF customization.

Read more →

1 min read

#### [Get the HTTP response status code and headers with screenshots](/changelog/http-response-metadata/)

On rare occasions, you might need to get the HTTP status code and headers of the target host. It is pretty easy to do now.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/attachment-name
----

Trigger screenshot download

===========================

Now you can set attachment filename to trigger screenshot download in the browser.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Mar 16, 2025

Use `attachment_name` option to set attachment filename to trigger screenshot download in the browser:

    1https://api.screenshotone.com/take?attachment_name=screenshot&url=https://example.com/&access_key=<access key>&format=jpg

It will trigger download of the screenshot with the filename `screenshot.jpg`.

You don’t need to set the file extension, it will be detected automatically by the format option.

As always, if you have any questions, please, reach out at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Added a "copy page" button in documentation](/changelog/copy-page-button-in-docs/)

You can now copy the page content as Markdown for LLMs and more.

Read more →

1 min read

#### [Add ScreenshotOne to n8n workflows](/changelog/n8n-integration/)

You can now use ScreenshotOne in n8n workflows to render website screenshots, PDFs, scrolling screenshots and videos.

Read more →

1 min read

#### [Set locale and language of the browser](/changelog/language-and-locale/)

A new version of the ScreenshotOne API has been just deployed. It allows you to set both locale and language of the browser when rendering screenshots with one simple option.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/pdf-margin
----

Set PDF margins

===============

Now you can set PDF margins for the resulting PDF file.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jul 4, 2025

Since today, you can set PDF margins for the resulting PDF file.

    1https://api.screenshotone.com/take?pdf_margin=20px&access_key=<access key>&url=https://example.com&format=pdf

You can also set the margin for each side separately:

    1https://api.screenshotone.com/take?pdf_margin=20px&pdf_margin_top=0px&access_key=<access key>&url=https://example.com&format=pdf

In this example, the margin for all sides will be `20px` except the top, which will be `0px`.

The result will be returned as a PDF file with the specified margins.

Check out the [documentation](/docs/options/#pdf-rendering) for more details. And in case of any questions, feel free to contact us at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [ScreenshotOne API supports GPU Rendering](/changelog/screenshotone-api-supports-gpu-rendering/)

From today ScreenshotOne supports GPU rendering for both regular and animated website screenshots. The API now leverages the latest in graphics processing technology to bring your screenshot needs to a whole new level.

Read more →

2 min read

#### [Remove organization members](/changelog/remove-organization-member/)

Improvements to the organization management.

Read more →

1 min read

#### [Fail ScreenshotOne API requests on purpose](/changelog/fail-if-request-failed/)

Use a new option to fail ScreenshotOne API requests on purpose.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/braidsmade-for-hire-case-study
----

Boosting email CTR for "Bridesmaid For Hire" with ScreenshotOne

===============================================================

How and why "Bridesmaid for Hire" used ScreenshotOne to boost their email campaign CTR.

[Customer story](/blog/tags/customer-stories/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

May 21, 2024

[Bridesmaid For Hire](https://bridesmaidforhire.com/ai-wedding-speech-and-vow-generators) specializes in writing wedding speeches for maids of honor, best men, and couples. To improve their user engagement and ensure that clients finalize their speeches, they rely on personalized emails.

Their goal was to increase the Click-Through Rate (CTR) of their emails, which previously stood at 0%, despite sending approximately thousands emails.

Challenge

---------

The product sends users a personalized link to their chat with the AI bot in order to retarget users a few days before the wedding, encouraging them to take a final look at their speech.

The goal was to achieving higher engagement and CTR through email communications.

ScreenshotOne as a Solution and Results

---------------------------------------

[Bridesmaid For Hire](https://bridesmaidforhire.com/ai-wedding-speech-and-vow-generators) Integrated the ScreenshotOne screenshot API to generate previews of the speeches:

As a result, the use of ScreenshotOne effectively increased the engagement levels, although specific metrics were not provided.

A few words by Stefan Wirth, a maker behind [Bridesmaid For Hire](https://bridesmaidforhire.com/ai-wedding-speech-and-vow-generators):

> I found ScreenshotOne very easy to get started with. The intuitive playground feature allowed me to seamlessly integrate and test our campaigns.

> 

> I love the playground, and it just works.

Conclusion

----------

By utilizing ScreenshotOne, Bridesmaid For Hire successfully enhanced their email strategy, leading to better engagement with their users and ensuring that clients were well-prepared for their special moments. This case study highlights the importance of leveraging the right tools to achieve business goals.

More Examples and Use Cases

---------------------------

You might be also interested in how [SpyFu uses ScreenshotOne for RivalFlowAI for competitive content analysis with AI](/blog/rivalflowai-by-spyfu/).

ScreenshotOne supports a huge variety of uses including but not only:

*   [Automating Open Graph image generation](/use-cases/open-graph-images/).

*   [Generating personalized videos](/use-cases/automate-personalized-videos/).

*   [Rendering site thumbnails for search previews](/use-cases/preview-search-results/)

And [many more](/use-cases/).

Read more customer stories

--------------------------

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

[View all posts](/blog/tags/customer-stories/)

#### [ScreenshotOne took away one major complexity off the Supawrite plate](/blog/supawrite/)

A short story about how ScreenshotOne helps a content marketing platform automate their screenshot workflow.

Read more

#### [Using AI screenshot analysis to identify leads for a design agency](/blog/ai-screenshot-analysis-for-finding-customers/)

Elias shares his process for discovering high-quality leads for a design agency by using AI screenshot analysis within the Clay platform.

Read more

#### [How Outrank enriches content generation with ScreenshotOne](/blog/outrank/)

A short story about how and why Outrank uses ScreenshotOne for screenshot generation to enrich SEO content.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/errors/signature-is-required
----

[Skip to content](#_top)

Signature Required

==================

Copy page

It is an API error returned when the signature parameter is missing in the request.

    1{2    "is_successful": false,3    "error_code": "signature_is_required",4    "error_message": "The `signature` parameter is required. Because signing requests is required in the access page—https://dash.screenshotone.com/access. Make sure you use the correct signing algorithm—https://screenshotone.com/docs/signed-requests/.",5    "documentation_url": "https://screenshotone.com/docs/errors/signature-is-required/"6}

Reasons and how to fix

----------------------

### Missing Signature Parameter

The most common reason for the “signature\_is\_required” error is that the `signature` parameter is not included in the request. This parameter is mandatory for authenticating and authorizing the API request if on the [access dashboard page](https://dash.screenshotone.com/access) forcing signing requests is activated.

To fix this, ensure that you include the `signature` parameter in your API request.

### Programmatic Issues

If you are dynamically generating requests (e.g., through a script or application), there might be a bug causing the `signature` to be omitted.

To fix this, debug your script or application to ensure the `signature` is being properly set and included in every API request.

### Request Validation

To ensure your request is valid, double-check all parameters and the generated signature before sending the request to the API.

Reach out to support

--------------------

If you continue to face issues or need further assistance, please reach out to `support@screenshotone.com`, and we will assist you as soon as possible.

----
url: https://screenshotone.com/changelog/improved-storage-upload
----

Improved uploading and error handling to S3-compatible storage

==============================================================

Today, the new version of ScreenshotOne API was deployed to production that enables a retries mechanism when uploading to an S3 storage and more granular error handling.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Feb 28, 2024

ScreenshotOne supports direct file upload of screenshots to [any S3-compatible storage](/docs/upload-to-s3/).

But often what happens is that storage can return a 500 error when you upload screenshots to them and then the overall request fails. You need to retry and render a screenshot again. By the way, failed requests are not counted. And check out our [simple guide on handling ScreenshotOne API errors](/docs/guides/how-to-handle-api-errors/).

Since today, the overflow flow has been improved thanks to one of our customers who requested that.

ScreenshotOne will retry at least 5 times to re-upload the file to your storage and if it doesn’t happen, you will get a better error than the generic one—“storage\_returned\_transient\_error”.

In that release, there is also a new error added like “storage\_access\_denied” to see if your credentials are expired or you misconfigured them.

That’s all for today. I wish you to enjoy your day and as always, feel free to reach out to `hey@screenshotone.com` if you have any questions.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Set locale and language of the browser](/changelog/language-and-locale/)

A new version of the ScreenshotOne API has been just deployed. It allows you to set both locale and language of the browser when rendering screenshots with one simple option.

Read more →

1 min read

#### [Improved error handling when networking fails](/changelog/improved-error-handling-when-networking-fails/)

We have improved error handling for network failures. Now, we ensure screenshot rendering fails instead of returning an error image.

Read more →

1 min read

#### [Rendering errors in webhooks](/changelog/screenshotone-webhook-errors/)

Check out how to get notified about rendering errors when using webhooks.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/security-compliance
----

Security Compliance

===================

ScreenshotOne maintains high standards of data privacy and security by implementing the following measures:

Monitoring

----------

[We monitor all the services](https://status.screenshotone.com/) and systems continuously to detect any anomalies or potential disruptions.

Password encryption

-------------------

All user passwords are encrypted (one-way hash) using the best industry-standard algorithms.

And all ScreenshotOne team members use password managers to store and manage their passwords.

Logging

-------

When storing logs, the cookies and proxy parameters are removed from the logs.

Development process

-------------------

Before deploying any changes to the production environment, we test all the changes thoroughly, and parts of these tests are automated.

Secret management

-----------------

Runtime secrets are injected from an encrypted vault.

Backups

-------

Database is backed up daily and encrypted at rest.

Rendering cache

---------------

Screenshots, videos and other rendered content is [cached for up to 30 days](/docs/caching/). But only if requested by the user.

Contacts and reporting

----------------------

Questions or vulnerability reports? Email **[support@screenshotone.com](mailto:support@screenshotone.com)** and we will respond as soon as possible.

_The document has been last updated on 2 May 2025_

----
url: https://screenshotone.com/docs/guides/full-page-screenshots
----

[Skip to content](#_top)

Full-page screenshots

=====================

Copy page

By default, the only thing you need to do is to set the `full_page` parameter to `true`:

    1https://api.screenshotone.com/take?url=https://example.com&full_page=true&access_key=...

The API tuned to balance performance and quality for the full-page screenshots. However, if you need to improve the quality of rendering, for the full-page screenshots, there is a few things you can do:

1.  [Understand how viewport dimensions affect full-page screenshots.](#viewport-dimensions)

2.  [Try different rendering algorithms.](#different-rendering-algorithms)

3.  [Tune scrolling of the page.](#tune-scrolling)

4.  [Reduce animations.](#reduce-animations)

5.  [Wait more.](#wait-more)

However, improving the quality of rendering might lead to a performance degradation.

Viewport dimensions

-------------------

The `viewport_width` and `viewport_height` options play an important role in full-page screenshots:

### Viewport width and height

The `viewport_width` option directly determines the **width of your final full-page screenshot** because:

*   **Responsive design**: Different viewport widths trigger different layouts and CSS breakpoints. A mobile viewport (e.g., 375px) will render a mobile layout, while a desktop viewport (e.g., 1920px) will render a desktop layout.

*   **Content visibility**: Wider viewports may show navigation menus, sidebars, or multi-column layouts that are hidden or stacked differently on narrower viewports.

By default, the viewport width is `1280` pixels.

The `viewport_height` option affects full-page screenshots differently depending on the algorithm used:

**For the default algorithm:**

*   The viewport height is temporarily stretched to match the full page height during rendering.

*   Your specified `viewport_height` is less relevant as it gets overridden.

**For the “by\_sections” algorithm:**

*   The `viewport_height` determines the **size of each section** that is captured.

*   The API scrolls by the viewport height, captures a screenshot, then scrolls again.

*   This affects lazy-loaded content: elements that load when they enter the viewport are triggered as the page scrolls through each section.

*   Smaller viewport heights mean more sections and more scroll events, which can trigger more lazy-loaded content but takes longer.

By default, the viewport height is `1024` pixels.

### Capturing beyond viewport

The `capture_beyond_viewport` option works together with viewport dimensions to control how content is captured:

**Default behavior (`capture_beyond_viewport=true`):**

*   The browser can capture content that extends beyond your `viewport_width` and `viewport_height`.

*   This is the default for full-page screenshots and is essential for capturing the entire page height.

*   The viewport dimensions still control the initial page layout and width of the screenshot.

**When set to `false`:**

    1capture_beyond_viewport=false

*   Content is clipped to the exact viewport dimensions.

*   For full-page screenshots, this usually produces undesired results as it clips the page.

*   Only useful in specific cases where you want to limit the capture area strictly to the viewport.

**Important note for “by\_sections” algorithm:**

*   When using `full_page_algorithm=by_sections`, the `capture_beyond_viewport` option is automatically set to `false` internally.

*   This is because the algorithm captures each section within the viewport and stitches them together.

*   You don’t need to worry about this option when using the “by\_sections” algorithm.

Different rendering algorithms

------------------------------

By default, the API uses the `full_page` uses a simple algorithm to screenshot the full page—it asks the browser to render it and usually that means that the browser just stretches the viewport to render the full-page screenshot. It rarely but leads to rendering issues.

You can try to use a different algorithm instead—by\_sections:

    1full_page_algorithm=by_sections

It might be better in most cases. Since it will try to scroll the page and render it section by section, and then stitch all the sections into one image.

But while scrolling the page, not every element might triggered due the speed of the scrolling and the delay between the scrolls. Try to tune scrolling.

Tune scrolling

--------------

Try to decrease or increase the size of the scroll step:

    1full_page_scroll_by=500

And increase the delay between the scrolls, it might help to render the page correctly

    1full_page_scroll_delay=1500

It might help to render the page better and trigger more lazy-loaded elements.

Reduce animations

-----------------

Request websites to reduce the number of animations by adding the `reduced_motion` parameter:

    1reduced_motion=true

Wait more

---------

Add from 5 to 10 seconds to wait for the page to load:

    1delay=5

Block ads, trackers, banners and other elements

-----------------------------------------------

Request the API to block ads, trackers, banners and other elements by use the following parameters:

    1block_ads=true&block_trackers=true&block_cookie_banners=true&block_chats=true&block_banners_by_heuristics=true

Summary

-------

Combining all the tips above, you might try to get the best results with something like that:

    1https://api.screenshotone.com/take?access_key=...&url=https://example.com&full_page=true&full_page_algorithm=by_sections&full_page_scroll_by=500&full_page_scroll_delay=1500&reduced_motion=true&delay=5&block_ads=true&block_trackers=true&block_cookie_banners=true&block_chats=true&block_banners_by_heuristics=true

Support

-------

Rendering full-page screenshots reliably is a real challenge. And even after a lot of tuning, it might not work for all the pages.

If you have any questions or suggestions, please contact us at [support@screenshotone.com](mailto:support@screenshotone.com).

----
url: https://screenshotone.com/use-cases/preview-search-results
----

Automate Website Screenshots

1 min read

Rendering Search Results Preview in Site Search

===============================================

Using a screenshot API to generate visual previews of web pages for search results within a website.

When users perform searches on a website, providing them with more than just text links can significantly enhance their experience. One innovative approach is to render visual previews of the search results. This is where the **website screenshot API**, like ScreenshotOne, becomes invaluable. By leveraging such a **screenshot API**, developers from small companies, especially those in industries where visual context is key, can greatly improve user engagement and satisfaction.

Implementing ScreenshotOne API allows for the automatic generation of screenshots for each search result link. This visual representation can help users make more informed decisions about which link to click, based on the content’s appearance and relevance to their search query. The primary value here is twofold: enhancing user experience by providing a visual snippet of what to expect before clicking a link, and potentially increasing the click-through rate for search results.

Developing a similar solution in-house would require significant resources, including time for development, testing, and maintenance. Moreover, handling scalability, responsiveness, and cross-platform compatibility issues adds additional layers of complexity. By using ScreenshotOne API, companies save on these costs and efforts, allowing them to focus on core product development and improvements. The efficiency, speed, and reliability of a dedicated **screenshot API** far outweigh the initial investment, making it a smart choice for businesses looking to add innovative features to their products without the overhead of in-house development.

I appreciate the fast customer support. Building the product, doing marketing is hard enough. But Dmytro still manages to solve my problems fast. Thank you!

Dan Kulkov

Co-Founder, [FounderPal](https://founderpal.ai/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/how-to-take-website-screenshots-with-javascript-or-typescript-nodejs
----

How to take website screenshots with JavaScript or TypeScript (Node.js)

=======================================================================

The article examines how you can take screenshots of any URL with Javascript and TypeScript (Node.js) by using Selenium, Puppeteer alternatives, Playwright, or screenshot API as a service.

[Blog post](/blog/) 4 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Jun 14, 2022

#### Tags

[Screenshot rendering](/blog/tags/screenshot-rendering/)

Today, there are many options to make screenshots of any URL with JavaScript or TypeScript (Node.js):

1.  [Selenium for JavaScript](#selenium).

2.  You can use [Puppeteer](#puppeteer).

3.  [Playwright library](#playwright).

4.  Or [Screenshot API as a service](#screenshot-api-as-a-service).

They might overlap, but there is no best solution. Each depends on your use case and requirements.

Selenium

--------

Selenium is a well-known kid in the QA automation area, so it is easy to start taking screenshots if you plan to write automation tests or already do it.

Install:

Terminal window

    1npm install selenium-webdriver --save

And then:

    1import * as fs from 'fs';2import { Builder } from 'selenium-webdriver';3

    4(async function example() {5    let driver = await new Builder().forBrowser('chrome').build();6    try {7        await driver.get('http://www.example.com');8        const screenshot = await driver.takeScreenshot();9        fs.writeFileSync("example.png", screenshot, "base64");10    } finally {11        await driver.quit();12    }13})();

If you just want to take one or two screenshots locally, Selenium is not the best fit. As I wrote earlier, it better serves you already write automation tests with Selenium or plan to write them.

Puppeteer

---------

It is a Node library that interacts with browsers that support [Chrome DevTools Protocol (CDP)](https://chromedevtools.github.io/devtools-protocol/). It is not only Chrome and Chromium, but [Firefox also has partial support of CDP](https://firefox-source-docs.mozilla.org/remote/index.html#remote-protocol-cdp).

The Chrome DevTools Protocol was developed to manage, debug and inspect Chromium and Chrome at the low level.

So, think of Puppeteer high-level API over Chrome DevTools Protocol which allows you to do everything in the browser that you can do manually:

1.  Extract data from a SPA, submit a form, type text, perform end-to-end UI testing and other automation-related tasks.

2.  [Debug performance issues](https://developer.chrome.com/docs/devtools/evaluate-performance/reference/).

3.  Run, debug and test Chrome Extensions.

4.  Pre-render SPA to make a static site. But for Google SEO, it does not matter since [Google renders JavaScript for every page](https://developers.google.com/search/docs/advanced/javascript/javascript-seo-basics) nowadays.

5.  And guess what? Make screenshots and PDFs of pages.

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

Terminal window

    1$ npm i puppeteer

And then just:

    1'use strict';2

    3const puppeteer = require('puppeteer');4(async () => {5       const browser = await puppeteer.launch();6       try {7           const page = await browser.newPage();8           await page.goto('https://example.com');9           await page.screenshot({ path: 'example.png' });10       } catch (e) {11           console.log(e)12       } finally {13           await browser.close();14       }15})();

It is very lightweight compared to Selenium and allows a broad spectrum for automation of the browser. You can use it for crawling, scrapping, taking screenshots, etc. If you need the simplest way to take screenshots, you do not expect to take millions of them, and I would go with `Puppeteer`. But if you want to take screenshots from different browsers or think about managing instances of browsers, there are more straightforward ways to go.

If you wish, dive deeper into the different use cases on [how to take screenshots with Puppeteer](/blog/how-take-a-screenshot-with-puppeteer).

Playwright

----------

[Playwright](https://playwright.dev) is the best Java library to automate [Chromium](https://www.chromium.org/Home), [Firefox](https://www.mozilla.org/en-US/firefox/new/), and [WebKit](https://webkit.org/) with a unified API. It is built to enable cross-browser web automation.

If you want to take screenshots in different browsers, Playwright is the best choice.

Install the library:

Terminal window

    1$ npm install playwright@latest --save

And then take a screenshot:

    1const { chromium } = require('playwright');2

    3(async () => {4    const browser = await chromium.launch();5

    6    try {7        const page = await browser.newPage();8        await page.goto('https://example.com');9        await page.screenshot({ path: 'example.png' });10    } catch (e) {11        console.log(e)12    } finally {13        await browser.close();14    }15})();

`Playwright` is the best choice. It is as powerful and allows you to run different browser instances if needed.

If you plan to take millions of screenshots and manage browser instances, you can do it yourself, but it is better to outsource to well-established services.

Screenshot API as a service

---------------------------

We specialize in taking screenshots and managing browser instances at scale. We provide [a high-quality Java client to take screenshots](https://www.npmjs.com/package/screenshotone-api-sdk) and cover a variety of use cases.

Easy to install:

Terminal window

    1npm install screenshotone-api-sdk --save

And easy to use:

    1import * as fs from 'fs';2import * as screenshotone from 'screenshotone-api-sdk';3

    4// create API client5const client = new screenshotone.Client("<access key>", "<secret key>");6

    7// set up options8const options = screenshotone.TakeOptions9    .url("https://example.com")10    .delay(3)11    .blockAds(true);12

    13// generate URL14const url = client.generateTakeURL(options);15console.log(url);16// expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com&delay=3&block_ads=true&access_key=%3Caccess+key%3E&signature=7f3419ece2c53ed2c7923c7d5deef290d662c3643822bf69ec8259ce10b3ea6117

    18// or download the screenshot19const imageBlob = await client.take(options);20const buffer = Buffer.from(await imageBlob.arrayBuffer());21fs.writeFileSync("example.png", buffer)22// the screenshot is store in the example.png file

If you feel that it is the best fit for you, feel free [to sign up for our screenshot API](https://screenshotone.com/) and get the access key.

Summary

-------

Pick the solution which suits your needs best. If you decide to go with our API, please ask any questions and mail us at [support@screenshotone.com](mailto:support@screenshotone.com). And have a nice day 👋

By the way, you might also find interesting how to:

*   [take web screenshots in Go](/blog/how-to-take-website-screenshots-with-go/)

*   [take web screenshots with Java](/blog/how-to-take-website-screenshots-with-java/)

*   [take web screenshots with PHP](/blog/how-to-take-website-screenshots-with-php/)

Read more Screenshot rendering

------------------------------

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

[View all posts](/blog/tags/screenshot-rendering/)

#### [How to Take Full Page Screenshots with Playwright in Python](/blog/playwright-python-full-page-website-screenshots/)

Learn how to capture full page screenshots with Playwright in Python. Master the full\_page parameter, handle infinite scroll pages, lazy-loaded images, and maximum size limits.

Read more

#### [Take a screenshot "from the surface" in Puppeteer and Chrome DevTools Protocol](/blog/take-a-screenshot-from-the-surface-in-puppeteer-and-chrome-devtools-protocol/)

Let's talk about the fromSurface parameter introduced in Chrome DevTools Protocol which will soon be supported by Puppeteer or even supported now at the time when you are reading the post.

Read more

#### [Let's build a screenshot API](/blog/building-screenshot-api/)

Two years have passed since the launch of ScreenshotOne, and I want to do a fun coding exercise and build a tiny subset of what the API is today, but from scratch.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/how-to-take-website-screenshots-with-csharp-dotnet
----

How to take website screenshots with C# (.NET)

==============================================

The article examines how you can take screenshots of any URL with C# (.NET) by using PuppeteerSharp, or screenshot API as a service.

[Blog post](/blog/) 3 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Mar 24, 2023

#### Tags

[Screenshot rendering](/blog/tags/screenshot-rendering/)

Let’s check out:

1.  [Puppeteer Sharp client for C# (.NET)](#puppeteer-sharp-client-for-c-net).

2.  Or [Screenshot API as a service](#screenshot-api-as-a-service).

They might overlap, but there is no best solution. Each depends on your use case and requirements.

Puppeteer Sharp client for C# (.NET)

------------------------------------

To take screenshots of any URL in the modern version of C#, you can use a headless browser library like [PuppeteerSharp](https://www.puppeteersharp.com/). Puppeteer Sharp is a .NET port of the popular JavaScript library Puppeteer, which controls headless Chromium or Chrome browsers.

In your .NET project, add the Puppeteer Sharp package using the NuGet Package Manager, or run the following command in the Package Manager Console:

Terminal window

    1Install-Package PuppeteerSharp

Create a new C# file and add the following code, replacing `https://example.com` with the URL you want to take a screenshot of, and “screenshot.png” with the desired output file name.

    1using System;2using System.Threading.Tasks;3using PuppeteerSharp;4

    5namespace ScreenshotExample6{7    class Program8    {9        static async Task Main(string[] args)10        {11            // Download the Chromium browser if needed12            await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);13

    14            // Launch the browser15            using var browser = await Puppeteer.LaunchAsync(new LaunchOptions16            {17                Headless = true18            });19

    20            // Create a new page21            using var page = await browser.NewPageAsync();22

    23            // Navigate to the URL24            await page.GoToAsync("https://example.com");25

    26            // Set the viewport size if needed (optional)27            await page.SetViewportAsync(new ViewPortOptions28            {29                Width = 1920,30                Height = 108031            });32

    33            // Take the screenshot34            await page.ScreenshotAsync("screenshot.png");35

    36            // Close the browser37            await browser.CloseAsync();38

    39            Console.WriteLine("Screenshot saved!");40        }41    }42}

Execute the program, and it will take a screenshot of the specified URL and save it as an image file in the project’s output directory. Remember to replace the URL and output file name with the desired values.

If you just want to take one or two screenshots locally, the PuppeteerSharp client is not the best fit. But if you plan to take millions of screenshots and manage browser instances, you can do it yourself, but it is better to outsource to well-established services.

Screenshot API as a service

---------------------------

ScreenshotOne specializes in taking screenshots and managing browser instances at scale. The service provides [a high-quality C# (.NET) client to take screenshots](https://github.com/screenshotone/dotnetsdk) and cover a variety of use cases.

Massive thanks and rays of goodness to Andy Robinson ([Indie Hackers](https://www.indiehackers.com/TheOrigin), [GitHub](https://github.com/theorigin)) for providing the fully-featured high-quality C# (.NET) SDK.

It is easy to install. You can add the library via nuget using the package manager console:

Terminal window

    1PM> Install-Package ScreenshotOne.dotnetsdk

Or from the .NET CLI as:

Terminal window

    1dotnet add package ScreenshotOne.dotnetsdk

Don’t forget to [sign up](https://dash.screenshotone.com/sign-up) to get access and secret keys.

Generate a screenshot URL without executing request:

    1var client = new Client("&lt;access key&gt;', '&lt;secret key&gt;");2var options = TakeOptions.Url("https://www.amazon.com")3  .FullPage(true)4  .Format(./Format.PNG)5  .BlockCookieBanners(true);6

    7var url = client.GenerateTakeUrl(options);8

    9// url = https://api.screenshotone.com/take?url=https%3A%2F%2Fwww.amazon.com&full_page=true&format=png&block_cookie_banners=true&access_key=_OzqMIjpCw-ARQ&signature=8a08e62d13a5c3490fda0734b6707791d3decc9ab9ba41e8cc045288a39db502

Take a screenshot and save the image in the file:

    1var client = new Client("&lt;access key&gt;', '&lt;secret key&gt;");2var options = TakeOptions.Url("https://www.google.com")3  .FullPage(true)4  .Format(./Format.PNG)5  .BlockCookieBanners(true);6

    7var bytes = await client.Take(options);8

    9File.WriteAllBytes(@"c:\temp\example.png", bytes);

If you feel that it is the best fit for you, feel free [to sign up for our screenshot API](https://screenshotone.com/) and get the access key.

Summary

-------

Pick the solution which suits your needs best. If you decide to go with our API, please ask any questions and mail us at [support@screenshotone.com](mailto:support@screenshotone.com). And have a nice day 👋

By the way, you might also find interesting how to:

*   [take web screenshots with Java](/blog/how-to-take-website-screenshots-with-java/)

*   [take web screenshots with JavaScript or TypeScript (Node.js)](/blog/how-to-take-website-screenshots-with-javascript-and-typescript-nodejs)

*   [take web screenshots with PHP](/blog/how-to-take-website-screenshots-with-php/)

Read more Screenshot rendering

------------------------------

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

[View all posts](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots with Go](/blog/how-to-take-website-screenshots-with-go/)

The article examines how you can take screenshots of any URL with Go (a.k.a. Golang) by using Selenium, Puppeteer alternatives, Playwright, or screenshot API as a service.

Read more

#### [How to take website screenshots with Java](/blog/how-to-take-website-screenshots-with-java/)

The article examines how you can take screenshots of any URL with Java by using Selenium, Puppeteer alternatives, Playwright, or screenshot API as a service.

Read more

#### [What is a screenshot or HTML rendering API?](/blog/what-is-a-screenshot-or-html-rendering-api/)

A screenshot API or a screenshot as a service is usually a cloud or a remote server service that provides the ability to render any website, HTML, Markdown, or even PDF by making a request to the service, be it over HTTP, TCP, or any other protocol.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/comparisons/playwright-alternative-for-screenshots
----

[What's new API error insights API error insights in the dashboard](/changelog/error-metrics/)

The Playwright alternative for rendering screenshots

====================================================

ScreenshotOne is one of the best Playwright alternatives that can render screenshots for you in one simple API call.

The best alternative to Playwright

Everything you need to render screenshots

-----------------------------------------

ScreenshotOne takes care of all the headaches related to maintaining Playwright and managing headless browsers, while you can focus on other features and code more relevant to your core business.

### Ease of Use and Integration

The ScreenshotOne API offers a simple integration for applications to capture screenshots with a single API call, eliminating the need for understanding browser automation or setup complexities.

### Scalability

ScreenshotOne is a cloud platform that offers scalable and reliable screenshot capture, handling many requests at once without user-managed servers or performance concerns, unlike Playwright, which requires complex and time-consuming setup for scaling.

### Reduced Maintenance Overhead

ScreenshotOne often outperforms self-managed Playwright setups by using optimized servers and caching for faster screenshot generation, whereas Playwright's efficiency varies with server setup, system load, and webpage complexity.

### Performance and Speed

Using our screenshot API offloads maintenance, updates, and compatibility issues to the provider, reducing user workload compared to Playwright, where users must manage servers, updates, and system health themselves.

ScreenshotOne takes care of scaling

Use the language you love

-------------------------

No need to worry about scaling headless browsers and handling all the corner cases. Choose your language and library and let's start rendering screenshots.

Java Go Node.js PHP Python Ruby C# (.NET)

    1// add com.screenshotone.jsdk:screenshotone-api-jsdk:[1.0.0,2.0.0)2// to your `pom.xml` or `build.gradle`3

    4import com.screenshotone.jsdk.Client;5import com.screenshotone.jsdk.TakeOptions;6

    7import java.io.File;8import java.nio.file.Files;9

    10public class App {11    public static void main(String[] args) throws Exception {12        final Client client = Client.withKeys("<access key>", "<secret key>");13        TakeOptions takeOptions = TakeOptions.url("https://example.com")14                .fullPage(true)15                .deviceScaleFactor(1)16                .viewportHeight(1200)17                .viewportWidth(1200)18                .format("png")19                .omitBackground(true);20        final String url = client.generateTakeUrl(takeOptions);21

    22        System.out.println(url);23        // Output: https://api.screenshotone.com/take?url=...24

    25        // or download the screenshot26        final byte[] image = client.take(takeOptions);27

    28        Files.write(new File("./example.png").toPath(), image);29        // the screenshot is stored in the example.png file30    }31}

    1// go get github.com/screenshotone/gosdk2

    3import screenshots "github.com/screenshotone/gosdk"4

    5client, err := screenshots.NewClient("<access key>", "<secret key>")6// check err7

    8options := screenshots.NewTakeOptions("https://example.com").9    Format("png").10    FullPage(true).11    DeviceScaleFactor(2).12    BlockAds(true).13    BlockTrackers(true)14

    15u, err := client.GenerateTakeURL(options)16// check err17

    18fmt.Println(u.String())19// Output: https://api.screenshotone.com/take?url=...20

    21// or download the screenshot22image, err := client.Take(context.TODO(), options)23// check err24

    25defer image.Close()26out, err := os.Create("example.png")27// check err28

    29defer out.Close()30io.Copy(out, image)31// the screenshot is stored in the example.png file

    1// $ npm install screenshotone-api-sdk --save2

    3import * as fs from 'fs';4import * as screenshotone from 'screenshotone-api-sdk';5

    6// create API client7const client = new screenshotone.Client("<access key>", "<secret key>");8

    9// set up options10const options = screenshotone.TakeOptions11    .url("https://example.com")12    .delay(3)13    .blockAds(true);14

    15// generate URL16const url = client.generateTakeURL(options);17console.log(url);18// expected output: https://api.screenshotone.com/take?url=...19

    20// or download the screenshot21const imageBlob = await client.take(options);22const buffer = Buffer.from(await imageBlob.arrayBuffer());23fs.writeFileSync("example.png", buffer)24// the screenshot is stored in the example.png file

    1<?php2

    3// composer require screenshotone/sdk:^1.04

    5use ScreenshotOneSdkClient;6use ScreenshotOneSdkTakeOptions;7

    8$client = new Client("<access key>", "<secret key>");9

    10$options = TakeOptions::url("https://example.com")11    ->fullPage(true)12    ->delay(2)13    ->geolocationLatitude(48.857648)14    ->geolocationLongitude(2.294677)15    ->geolocationAccuracy(50);16

    17$url = $client->generateTakeUrl($options);18echo $url.PHP_EOL;19// expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com...20

    21$image = $client->take($options);22file_put_contents('example.png', $image);23// the screenshot is stored in the example.png file

    1# pip install screenshotone2

    3import shutil4from screenshotone import Client, TakeOptions5

    6# create API client7client = Client('<access key>', '<secret key>')8

    9# set up options10options = (TakeOptions.url('https://screenshotone.com')11    .format("png")12    .viewport_width(1024)13    .viewport_height(768)14    .block_cookie_banners(True)15    .block_chats(True))16

    17# generate the screenshot URL and share it with a user18url = client.generate_take_url(options)19# expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fscreenshotone.com&viewport_width=1024&viewport_height=768&block_cookie_banners=True&block_chats=True&access_key=&signature=6afc9417a523788580fa01a9f668ea82c78a9d2b41441d2a696010bf2743170f20

    21# or render a screenshot and download the image as stream22image = client.take(options)23

    24# store the screenshot the example.png file25with open('example.png', 'wb') as result_file:26    shutil.copyfileobj(image, result_file)

    1# Add this gem to your Gemfile:2# gem 'screenshotone'3

    4# If you don't need to add a signature5client = ScreenshotOne::Client.new('<access key>')6

    7# Or ff you do need to add a signature8client = ScreenshotOne::Client.new('<access key>', '<secret key>')9

    10# You can set any available option, in a camel_case format, for example:11options = ScreenshotOne::TakeOptions.new(url: 'https://example.com').12            full_page(true).13            delay(2).14            geolocation_latitude(48.857648).15            geolocation_longitude(2.294677).16            geolocation_accuracy(50)17

    18# Verify all the parameters are valid (we will validate the parameters that should be19# numeric, booleans or that accept only certain values)20options.valid?21=> true22

    23# To simply get the final url:24client.generate_take_url(options)25=> "https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com..."26

    27# To actually get the image (the response body of a request to the previous url)28client.take(options)29=> "\xFF\xD8\xFF\xE0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xFF\..."

    1// Add the library via nuget using the package manager console: PM> Install-Package ScreenshotOne.dotnetsdk2// Or from the .NET CLI as: dotnet add package ScreenshotOne.dotnetsdk3

    4// And generate a screenshot URL without executing request:5var client = new Client("<access key>", "<secret key>");6var options = TakeOptions.Url("https://www.amazon.com")7  .FullPage(true)8  .Format(Format.PNG)9  .BlockCookieBanners(true);10

    11var url = client.GenerateTakeUrl(options);12// url = https://api.screenshotone.com/take?url=https%3A%2F%2Fwww.amazon.com&full_page=true&format=png&block_cookie_banners=true&access_key=_OzqMIjpCw-ARQ&signature=8a08e62d13a5c3490fda0734b6707791d3decc9ab9ba41e8cc045288a39db50213

    14// Or take a screenshot and save the image in the file:15var client = new Client("<access key>", "<secret key>");16var options = TakeOptions.Url("https://www.google.com")17  .FullPage(true)18  .Format(Format.PNG)19  .BlockCookieBanners(true);20

    21var bytes = await client.Take(options);22

    23File.WriteAllBytes(@"c:\temp\example.png", bytes);

Mike Roberts

Founder, [SpyFu](https://www.spyfu.com/)

> ScreenshotOne is the best product on the market - and that's before you take into account how responsive and easy Dmytro is to work with.

> 

> Any time we've found a rare edge case, it's been resolved in hours.

> 

> Great company, great founder - can't say enough!

Without writing a line of code

No-code Playwright is now possible

----------------------------------

As a Playwright alternative for screenshots, ScreenshotOne supports all its features and even more. But now you can integrate it with the most popular no-code platforms like Zapier, Airtable, Make and similar.

[](/integrations/zapier/)[](/integrations/airtable/)[](/integrations/make/)[](/integrations/bubble/)[](/integrations/n8n/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/font-detection-api
----

[What's new API error insights API error insights in the dashboard](/changelog/error-metrics/)

The font detection API for developers

=====================================

Detect fonts used by any website with ScreenshotOne in just one simple API call.

[Start rendering for free →](https://dash.screenshotone.com/sign-up)

No credit card required.

    1https://api.screenshotone.com/take2    ?metatada_fonts=true3    &url=https://screenshotone.com4    &...5

    6{7  "fonts": [8    {9      "first": "Jost",10      "fallback": [11        "-apple-system",12      ],13      "elements": [ "div", "span"]14    },15    {16      "first": "sfmono-regular",17      "fallback": [ "menlo" ],18      "elements": [ "pre" ]19    }20  ]21}

"Great support."

**Guillaume Barillot,** CTO at Deepidoo

"Great company, great founder!"

**Mike Roberts,** Founder at SpyFu

"ScreenshotOne is the way to go."

**Lukas Hermann,** Co-Founder of Stagetimer

Used by

3,700+

Active developers

[Proudly serving](/testimonials) companies from small to large every day.

No less than

99.624%

Uptime

[Reliability](https://status.screenshotone.com/) you can count on is one of our core priorities.

last 30 days

6.9M+

Screenshots rendered

Renders the growing screenshot number every day. The API is performant and proven to handle scale.

Integrate today

Use the language you love

-------------------------

Send simple HTTP requests or use native libraries for your language of choice.

Java Go Node.js PHP Python Ruby C# (.NET)

    1// add com.screenshotone.jsdk:screenshotone-api-jsdk:[1.0.0,2.0.0)2// to your `pom.xml` or `build.gradle`3

    4import com.screenshotone.jsdk.Client;5import com.screenshotone.jsdk.TakeOptions;6

    7import java.io.File;8import java.nio.file.Files;9

    10public class App {11    public static void main(String[] args) throws Exception {12        final Client client = Client.withKeys("<access key>", "<secret key>");13        TakeOptions takeOptions = TakeOptions.url("https://example.com")14                .fullPage(true)15                .deviceScaleFactor(1)16                .viewportHeight(1200)17                .viewportWidth(1200)18                .format("png")19                .omitBackground(true);20        final String url = client.generateTakeUrl(takeOptions);21

    22        System.out.println(url);23        // Output: https://api.screenshotone.com/take?url=...24

    25        // or download the screenshot26        final byte[] image = client.take(takeOptions);27

    28        Files.write(new File("./example.png").toPath(), image);29        // the screenshot is stored in the example.png file30    }31}

    1// go get github.com/screenshotone/gosdk2

    3import screenshots "github.com/screenshotone/gosdk"4

    5client, err := screenshots.NewClient("<access key>", "<secret key>")6// check err7

    8options := screenshots.NewTakeOptions("https://example.com").9    Format("png").10    FullPage(true).11    DeviceScaleFactor(2).12    BlockAds(true).13    BlockTrackers(true)14

    15u, err := client.GenerateTakeURL(options)16// check err17

    18fmt.Println(u.String())19// Output: https://api.screenshotone.com/take?url=...20

    21// or download the screenshot22image, err := client.Take(context.TODO(), options)23// check err24

    25defer image.Close()26out, err := os.Create("example.png")27// check err28

    29defer out.Close()30io.Copy(out, image)31// the screenshot is stored in the example.png file

    1// $ npm install screenshotone-api-sdk --save2

    3import * as fs from 'fs';4import * as screenshotone from 'screenshotone-api-sdk';5

    6// create API client7const client = new screenshotone.Client("<access key>", "<secret key>");8

    9// set up options10const options = screenshotone.TakeOptions11    .url("https://example.com")12    .delay(3)13    .blockAds(true);14

    15// generate URL16const url = client.generateTakeURL(options);17console.log(url);18// expected output: https://api.screenshotone.com/take?url=...19

    20// or download the screenshot21const imageBlob = await client.take(options);22const buffer = Buffer.from(await imageBlob.arrayBuffer());23fs.writeFileSync("example.png", buffer)24// the screenshot is stored in the example.png file

    1<?php2

    3// composer require screenshotone/sdk:^1.04

    5use ScreenshotOneSdkClient;6use ScreenshotOneSdkTakeOptions;7

    8$client = new Client("<access key>", "<secret key>");9

    10$options = TakeOptions::url("https://example.com")11    ->fullPage(true)12    ->delay(2)13    ->geolocationLatitude(48.857648)14    ->geolocationLongitude(2.294677)15    ->geolocationAccuracy(50);16

    17$url = $client->generateTakeUrl($options);18echo $url.PHP_EOL;19// expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com...20

    21$image = $client->take($options);22file_put_contents('example.png', $image);23// the screenshot is stored in the example.png file

    1# pip install screenshotone2

    3import shutil4from screenshotone import Client, TakeOptions5

    6# create API client7client = Client('<access key>', '<secret key>')8

    9# set up options10options = (TakeOptions.url('https://screenshotone.com')11    .format("png")12    .viewport_width(1024)13    .viewport_height(768)14    .block_cookie_banners(True)15    .block_chats(True))16

    17# generate the screenshot URL and share it with a user18url = client.generate_take_url(options)19# expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fscreenshotone.com&viewport_width=1024&viewport_height=768&block_cookie_banners=True&block_chats=True&access_key=&signature=6afc9417a523788580fa01a9f668ea82c78a9d2b41441d2a696010bf2743170f20

    21# or render a screenshot and download the image as stream22image = client.take(options)23

    24# store the screenshot the example.png file25with open('example.png', 'wb') as result_file:26    shutil.copyfileobj(image, result_file)

    1# Add this gem to your Gemfile:2# gem 'screenshotone'3

    4# If you don't need to add a signature5client = ScreenshotOne::Client.new('<access key>')6

    7# Or ff you do need to add a signature8client = ScreenshotOne::Client.new('<access key>', '<secret key>')9

    10# You can set any available option, in a camel_case format, for example:11options = ScreenshotOne::TakeOptions.new(url: 'https://example.com').12            full_page(true).13            delay(2).14            geolocation_latitude(48.857648).15            geolocation_longitude(2.294677).16            geolocation_accuracy(50)17

    18# Verify all the parameters are valid (we will validate the parameters that should be19# numeric, booleans or that accept only certain values)20options.valid?21=> true22

    23# To simply get the final url:24client.generate_take_url(options)25=> "https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com..."26

    27# To actually get the image (the response body of a request to the previous url)28client.take(options)29=> "\xFF\xD8\xFF\xE0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xFF\..."

    1// Add the library via nuget using the package manager console: PM> Install-Package ScreenshotOne.dotnetsdk2// Or from the .NET CLI as: dotnet add package ScreenshotOne.dotnetsdk3

    4// And generate a screenshot URL without executing request:5var client = new Client("<access key>", "<secret key>");6var options = TakeOptions.Url("https://www.amazon.com")7  .FullPage(true)8  .Format(Format.PNG)9  .BlockCookieBanners(true);10

    11var url = client.GenerateTakeUrl(options);12// url = https://api.screenshotone.com/take?url=https%3A%2F%2Fwww.amazon.com&full_page=true&format=png&block_cookie_banners=true&access_key=_OzqMIjpCw-ARQ&signature=8a08e62d13a5c3490fda0734b6707791d3decc9ab9ba41e8cc045288a39db50213

    14// Or take a screenshot and save the image in the file:15var client = new Client("<access key>", "<secret key>");16var options = TakeOptions.Url("https://www.google.com")17  .FullPage(true)18  .Format(Format.PNG)19  .BlockCookieBanners(true);20

    21var bytes = await client.Take(options);22

    23File.WriteAllBytes(@"c:\temp\example.png", bytes);

Mike Roberts

Founder, [SpyFu](https://www.spyfu.com/)

> ScreenshotOne is the best product on the market - and that's before you take into account how responsive and easy Dmytro is to work with.

> 

> Any time we've found a rare edge case, it's been resolved in hours.

> 

> Great company, great founder - can't say enough!

Without writing a line of code

Detect fonts on your favorite platforms

---------------------------------------

Quickly detect fonts used by any website with Zapier, Airtable, Make and other popular no-code platforms of your choice as part of your favorite no-code platform.

[](/integrations/zapier/)[](/integrations/airtable/)[](/integrations/make/)[](/integrations/bubble/)[](/integrations/n8n/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/magic-pages
----

Magic Pages: Showcasing Product Adoption with Screenshots

=========================================================

How and why "Magic Pages" used ScreenshotOne to showcase how their customers use their product.

[Customer story](/blog/tags/customer-stories/) 1 min read

#### Written by

[Jannis Fedoruk-Betschki](/contributors/jannis-fedorukbetschki/), [Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Mar 28, 2025

[Magic Pages](https://www.magicpages.co/) provides precisely what Ghost CMS users have always wanted—managed hosting, simple newsletter integration, reliable backups, and decent customization tools, all wrapped up with personal, dedicated support from founder Jannis, who shares the passion for Ghost CMS himself.

Jannis is a special customer of ScreenshotOne. He was one of the first customers of ScreenshotOne and has been using the service for years.

Why use screenshots?

--------------------

Jannis, the creator behind [Magic Pages](https://www.magicpages.co/), sought to showcase the diverse and creative websites built by Magic Pages customers, and built-in templates.

Using screenshots of templates and customers websites might be a good solution to showcase the platform and build trust.

> “ScreenshotOne has been my go-to tool for programmatic screenshot generation for several years now.”

Showcasing customer websites and templates

------------------------------------------

By using [ScreenshotOne](https://screenshotone.com/), Jannis dynamically generates and embeds screenshots of customer websites directly into blog posts and promotional content. This not only makes the storytelling better but also demonstrates the wide range of Magic Pages users—from personal newsletters and author communities to unique projects like scientific beekeeping archives.

Read more customer stories

--------------------------

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

[View all posts](/blog/tags/customer-stories/)

#### [How RivalFlowAI uses ScreenshotOne to help its customers improve existing content](/blog/rivalflowai-by-spyfu/)

RivalFlowAI is a new product by SpyFu, launched in 2023. The product helps to improve existing content with AI by finding the missing pieces your page needs to rank.

Read more

#### [Why Promptwatch wins in the AI search space](/blog/promptwatch/)

About how Promptwatch uses ScreenshotOne to automate website screenshots and why that matters.

Read more

#### [How BugSmash automates website screenshot rendering](/blog/bugsmash-story/)

How and why BugSmash uses ScreenshotOne for critical screenshot rendering tasks.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/contributors/chris-jayden
----

Chris Jayden

------------

View all Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [How Landing Gallery uses ScreenshotOne to automate screenshot generation](/blog/landing-gallery/)

How and why "Landing Gallery" uses ScreenshotOne to automate screenshot generation for their landing page inspiration platform.

Written by

[Chris Jayden](/contributors/chris-jayden/)

Published on

Nov 30, 2025

•

3 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/visual-regression-testing
----

Automate Website Screenshots

1 min read

Visual Regression Testing

=========================

Automate visual regression testing for your website with ScreenshotOne.

Keeping dozens—or even thousands—of websites up-to-date is risky, because a tiny change in a theme, plugin, or CSS file can shift a button, hide a banner, or break a checkout form.

Manually checking every page after each release is slow and people miss things. Teams needed a quick way to “see” whether an update harmed the page before it reached real visitors.

[Check out how Kinsta does that with the help of ScreenshotOne](/blog/kinsta/).

ScreenshotOne in the testing pipeline

-------------------------------------

That is why ops and QA engineers integrate [ScreenshotOne](/) into their testing pipeline.

The flow is easy: call our API to grab a “before” screenshot, run the update, call the API again for an “after” shot, then compare the two images (pixel diff, AI vision, or even a quick human glance). If the pages match, the deploy goes forward; if they differ, the script rolls back or flags the release for review. Because the API is stateless and fast, you can run this test on every site, every branch, or every pull-request without slowing the build.

The payoff is clear

-------------------

Automatic visual checks catch layout bugs early, so support tickets drop and releases move faster. Designers sleep better knowing tomorrow’s homepage will look like today’s, and product owners ship features without fearing hidden breakage. With ScreenshotOne doing the picture work, your team can focus on the code that matters—not on scrolling through pages by hand.

Working with Dmytro from ScreenshotOne has been an overwhelmingly positive and refreshing experience. He’s incredibly responsive, quick to act, and genuinely committed to making his service work for our needs.

Barnabás Ürmössy

Development Manager, [Kinsta](https://screenshotone.com/blog/kinsta/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/contributors/dmytro-krasun/3
----

Dmytro Krasun

-------------

With more than a decade of experience in software engineering, I share the best practices and solutions you can apply to your problems in the space of headless browsers. You can also find me on [Twitter](https://twitter.com/DmytroKrasun) and [LinkedIn](https://www.linkedin.com/in/dmytrokrasun)

View all Changelog

#### [ScreenshotOne August 2025 updates](/blog/screenshotone-august-2025-updates/)

Playground presets, screenshot URL in webhooks, improved full‑page rendering, and ownership change for subscribed orgs.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Sep 1, 2025

•

1 min read

#### [ScreenshotOne is available on Ravenala](/blog/ravenala/)

ScreenshotOne is available on Ravenala, a new AI-powered platform for creating and managing content.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Aug 3, 2025

•

1 min read

#### [Is it legal to screenshot websites?](/blog/screenshots-and-law/)

A few thoughts on the topic of screenshots and law.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jul 22, 2025

•

3 min read

[Engineering](/blog/tags/engineering/)

#### [A four day hiking trip into ScreenshotOne infrastructure to solve an issue](/blog/debugging-and-fixing-a-tricky-issue/)

A short story about how I debugged and fixed an uptime issue.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jul 21, 2025

•

3 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Outrank enriches content generation with ScreenshotOne](/blog/outrank/)

A short story about how and why Outrank uses ScreenshotOne for screenshot generation to enrich SEO content.

Written by

[Eugene Zolotarenko](/contributors/eugene-zolotarenko/), [Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jun 29, 2025

•

1 min read

#### [n8n integration for ScreenshotOne](/blog/n8n-integration/)

You can now use ScreenshotOne in n8n workflows to render website screenshots, PDFs, scrolling screenshots and videos.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jun 26, 2025

•

1 min read

#### [ScreenshotOne on LaunchDay!](/blog/itslaunchday/)

ScreenshotOne participated in the first launch batch of the LaunchDay platform

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jun 20, 2025

•

1 min read

[Playwright guides](/blog/tags/playwright-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to render screenshots with Playwright](/blog/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](/contributors/dmytro-krasun/)

Published on

Apr 29, 2025

•

10 min read

[Crawling and scraping](/blog/tags/crawling-and-scraping/)

#### [3 best scraping APIs in 2026](/blog/best-scraping-apis/)

ScreenshotOne is not a scraping API, but what if you could achieve your goals with it and get perfect screenshots as an additional benefit?

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jan 6, 2026

•

2 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How BugSmash automates website screenshot rendering](/blog/bugsmash-story/)

How and why BugSmash uses ScreenshotOne for critical screenshot rendering tasks.

Written by

[Nabil Kazi](/contributors/nabil-kazi/), [Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Apr 27, 2025

•

2 min read

#### [ScreenshotOne reached $200K ARR with 400+ paying customers](/blog/200000-arr-and-400-paying-customers/)

It is a good milestone to make a compact snapshot of the insights that (maybe?) led to it.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Apr 10, 2025

•

7 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [How to render screenshots with different emoji styles in Puppeteer](/blog/emojis/)

Learn how to render screenshots with different emoji styles in Puppeteer using emoji-js in a few lines of code.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Apr 4, 2025

•

2 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/best-scraping-apis
----

3 best scraping APIs in 2026

============================

ScreenshotOne is not a scraping API, but what if you could achieve your goals with it and get perfect screenshots as an additional benefit?

[Blog post](/blog/) 2 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Jan 6, 2026

#### Tags

[Crawling and scraping](/blog/tags/crawling-and-scraping/)

There hundreds of scraping APIs out there. Some are good, some are bad.

But there is no need to spend a ton of time searching and evaluating all these options. Check out the best scraping APIs in 2025:

1.  [ScreenshotOne](#1-screenshotone)

2.  [Web Unlocker by BrightData](#2-web-unlocker-by-brightdata)

3.  [ScrapingDog](#3-scrapingdog)

Try a few options and if one of the options has suitable pricing and quality that fits you, go with it.

3 best scraping APIs

--------------------

### 1\. ScreenshotOne

[](https://screenshotone.com)

[ScreenshotOne](https://screenshotone.com) is not a scraping API and not intended to be used for scraping. But surprisingly, there is a set of options that can make the ScreenshotOne API a decent scrapping solution. Just specify `format=html` and you get the HTML of the page:

    1https://api.screenshotone.com/take?access_key=<your access key>&url=https://example.com&format=html

But since the API optimized for rendering perfect screenshots and if you need screenshots, you can get both perfect screenshots and rendered HTML after JavaScript, just specify `metadata_content=true`:

    1https://api.screenshotone.com/take?access_key=<your access key>&url=https://example.com&metadata_content=true

And you will get as a header or in the response body when the JSON response is requested.

ScreenshotOne has basic stealth abilities included in every plan. But as mentioned before, it is not optimized for scrapping, rather for screenshots.

### 2\. Web Unlocker by BrightData

[](https://brightdata.com/products/web-unlocker)

[BrigthData Web Unlocker](https://brightdata.com/products/web-unlocker) is a simple API endpoint that returns you rendered HTML after JavaScript including by-passing protections.

It has an affordable pay-as-you-go pricing and you only pay for successful requests. It is a no-brainer deal.

It is a simple to use as:

    1curl -H "Content-Type: application/json" -H "Authorization: Bearer [INSERT_YOUR_API_TOKEN]" -d '{"zone": "[INSERT_YOUR_WEB_UNLOCKER_ZONE_NAME]","url": "[INSERT_YOUR_TARGET_URL]", "format": "raw"}' https://api.brightdata.com/request

Check out more details in [the Web Unlocker documentation](https://docs.brightdata.com/scraping-automation/web-unlocker/send-your-first-request).

### 3\. ScrapingDog

[](https://www.scrapingdog.com)

[ScrapingDog](https://www.scrapingdog.com) is a scraping API that can be used for scraping websites.

You can check out [reviews about ScrapingDog in Trustpilot](https://www.trustpilot.com/review/scrapingdog.com). Majority of them are positive.

They also support AI-based parsing. With a simple `ai_query` query parameter, you can get the specific data from the page without specifying any concrete selectors.

The benefit of using specialized scraping API over more generic solutions is that they cover special use cases and have custom scrappers. You can check out that in [their documentation](https://docs.scrapingdog.com/).

Summary

-------

If you have basic needs for scraping and will perform ethical and legal scraping, you can just use [ScreenshotOne](https://screenshotone.com) if it works for your cases. In addition, you will get perfect screenshots.

However, if you have more sophisticated scrapping needs, you can check out the other options that might fit better.

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/10
----

Automate Website Screenshots

----------------------------

Guides, Product Updates, and Helpful Resources from ScreenshotOne.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [SEOBot uses ScreenshotOne API to generate screenshots for articles](/blog/seobot-automates-screenshot-generation-for-articles/)

Customers can your product in unpredictable and surprising ways. SEOBot now uses ScreenshotOne API to enhance its articles with screenshots, making content more engaging and visually appealing.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [John Rush](/contributors/john-rush/)

Published on

Feb 27, 2024

•

1 min read

#### [ScreenshotOne is featured in the Cloudflare "Built With" series](/blog/screenshotone-and-cloudflare/)

The Cloudflare platform is at the core of ScreenshotOne—it is used for caching, API gateway, storage for screenshots, and many other functions. It was an opportunity to learn about the company from a closer distance.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Aug 3, 2024

•

1 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Rendering screenshots of social media pages](/blog/how-to-take-screenshots-of-social-media-pages/)

Social media platforms often restrict automation, but with the right tools and care for compliance, capturing screenshots is possible.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jul 4, 2025

•

2 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Ilias Ism, a founder of the MagicSpace SEO agency, uses ScreenshotOne daily](/blog/how-ilias-ism-a-founder-of-the-magicspace-seo-agency-uses-screenshotone-daily/)

We would love to share a quick review of ScreenshotOne by Ilias Ism, a founder of MagicSpace SEO agency and OG Image Generator on how he uses the API daily to generate screenshots and automate regular tasks associated with screenshots.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Dec 5, 2023

•

1 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [Comparing Puppeteer versus Selenium for rendering website screenshots](/blog/comparing-puppeteer-versus-selenium-for-rendering-website-screenshots/)

When comparing Puppeteer, Selenium, and ScreenshotOne for rendering screenshots, it's crucial to understand the distinct capabilities and use cases of each tool.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Oct 5, 2023

•

2 min read

#### [Using Clobbr to quickly load test the ScreenshotOne API](/blog/using-clobbr-to-quickly-load-test-the-screenshotone-api/)

Google Cloud gives $300 in credits for 3 months for experimenting. And I decided to give it a try, but not because of the free credits.

Written by

[Dan Mindru](/contributors/dan-mindru/), [Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Sep 23, 2023

•

3 min read

#### [Alexander Schnebel about how he uses ScreenshotOne in Productglowup](/blog/alexander-schnebel-about-how-he-uses-screenshotone-in-productglowup/)

I had a great chat with Alexander Schnebel, the fullstack software engineer behind Productglowup.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jul 23, 2023

•

1 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [Puppeteer Performance Monitoring with Inspector](/blog/puppeteer-performance-monitoring-with-inspector/)

In this article I'll show you how to monitor performance and errors of a browser automation script written with Puppeteer.

Written by

[Valerio Barbera](/contributors/valerio-barbera/)

Published on

Jun 13, 2023

•

5 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/improved-scroll-into-view
----

Improved the behavior and stability of the "scroll\_into\_view" option

======================================================================

Before the change, there was a subset of cases when the rendering requests were failing when using the scroll\_into\_view option. Now, it is improved and will make rendering more stable.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Aug 27, 2024

To be precise, for example, you were specifying a selector of some elements that is not loaded till you see it in the viewport. That behavior triggered timeout errors in the old implementation.

Now, the algorithm is improved to scroll and to try to trigger a lazy load of the specified element.

That way it is more stable and the request has a higher chance for success.

Enjoy! And if you have any questions, please don’t hesitate to reach out at [support@screenshotone.com](mailto:support@screenshotone.com).

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Download request content in the dashboard](/changelog/download-request-content/)

You can now download request content in the dashboard.

Read more →

1 min read

#### [Added support of external identifiers](/changelog/screenshotone-external-identifier/)

Check out how to use the external identifier to improve tracking of webhook executions.

Read more →

1 min read

#### [New organization role](/changelog/new-organization-role/)

Allow other members to manage your organization without transferring ownership.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/guides/fail-if-content-contains
----

[Skip to content](#_top)

Fail rendering if the content contains a string

===============================================

Copy page

There is a set of use cases when you want to fail screenshot rendering and retry it if the content of the page contains a string.

For example, if you use residential rotating proxies and a site blocks you with some specific test, you might want to retry the request instead of getting the successful screenshot of the page with the CAPTCHA or an error.

Did you know?

You don’t pay for failed and cached screenshots with ScreenshotOne.

That’s exactly what you need the option `fail_if_content_contains` for.

Let’s quickly see how it works and how you can use it. Let’s first render the example.com page:

    1https://api.screenshotone.com/take?access_key=<your access key>&url=https://example.com

The result is:

Now, let’s try to fail it:

    1https://api.screenshotone.com/take?fail_if_content_contains=Illustrative+Examples+In+Documents&access_key=<your access key>&url=https://example.com

The result is:

    1{2    "is_successful": false,3    "error_message": "The page content contains the specified string by the `fail_if_content_contains` option. If it seems to be a mistake or not what you expected, please, reach out to `support@screenshotone.com` as quickly as possible, and will assist and try to resolve your problem.",4    "error_code": "content_contains_specified_string",5    "documentation_url": "https://screenshotone.com/docs/errors/content-contains-specified-string/"6}

As you might notice, the match is case insensitive, it is done for simplicity.

You can also specify multiple strings to fail if any of them is matched on the page content:

    1https://api.screenshotone.com/take?fail_if_content_contains=Prior&fail_if_content_contains=Example&access_key=<your access key>&url=https://example.com

A few more similar options

--------------------------

Check out the other similar options:

*   [Fail rendering if the content is missing a string](/docs/options/#fail_if_content_missing)

*   [Fail rendering if the request fails](/docs/options/#fail_if_request_failed)

Support

-------

If you have any questions or need help, please, reach out to `support@screenshotone.com` as quickly as possible, and we will assist and try to resolve your problem.

----
url: https://screenshotone.com/blog/bulk-screenshots-python
----

How to Take Bulk Screenshots in Python with a Screenshot API

============================================================

Learn how to automate bulk website screenshots in Python using ScreenshotOne API. Process thousands of URLs efficiently with async requests, rate limiting, and error handling.

[Blog post](/blog/) 3 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jan 14, 2026

#### Tags

[Screenshot rendering](/blog/tags/screenshot-rendering/)

I’ve built screenshot systems with both approaches—managing browsers myself and using APIs. For production workloads with thousands of URLs, an API almost always makes more sense. Let me show you why and how.

When to Use an API vs Playwright

--------------------------------

Factor

DIY (Playwright)

Screenshot API

Volume

< 1000/month

1000+/month

Infrastructure

You manage

They manage

Anti-bot handling

Manual

Built-in

Cookie banners

Manual coding

One parameter

Cost

Server costs

Per-screenshot

Maintenance

Ongoing

None

Getting Started with ScreenshotOne

----------------------------------

Install the SDK:

Terminal window

    1pip install screenshotone

Basic usage:

    1from screenshotone import Client, TakeOptions2import shutil3

    4client = Client('your-access-key', 'your-secret-key')5

    6options = (TakeOptions.url('https://example.com')7    .format('png')8    .viewport_width(1920)9    .viewport_height(1080)10    .full_page(True))11

    12image = client.take(options)13

    14with open('screenshot.png', 'wb') as f:15    shutil.copyfileobj(image, f)

Bulk Processing with the API

----------------------------

Here’s how to process multiple URLs efficiently:

    1from screenshotone import Client, TakeOptions2import asyncio3import aiohttp4from pathlib import Path5

    6class BulkScreenshotter:7    def __init__(self, access_key, secret_key, output_dir='screenshots'):8        self.client = Client(access_key, secret_key)9        self.output_dir = Path(output_dir)10        self.output_dir.mkdir(exist_ok=True)11

    12    def _get_signed_url(self, url):13        """Generate a signed URL for the screenshot."""14        options = (TakeOptions.url(url)15            .format('png')16            .viewport_width(1920)17            .viewport_height(1080)18            .full_page(True)19            .block_cookie_banners(True)20            .block_chats(True))21        return self.client.generate_take_url(options)22

    23    async def _fetch_screenshot(self, session, url, output_path):24        """Fetch a single screenshot."""25        signed_url = self._get_signed_url(url)26        try:27            async with session.get(signed_url) as response:28                if response.status == 200:29                    content = await response.read()30                    with open(output_path, 'wb') as f:31                        f.write(content)32                    return {'url': url, 'status': 'success', 'path': str(output_path)}33                else:34                    return {'url': url, 'status': 'failed', 'error': f'HTTP {response.status}'}35        except Exception as e:36            return {'url': url, 'status': 'failed', 'error': str(e)}37

    38    async def process(self, urls, concurrency=5):39        """Process URLs with controlled concurrency."""40        semaphore = asyncio.Semaphore(concurrency)41        results = []42

    43        async def bounded_fetch(session, url, index):44            async with semaphore:45                output_path = self.output_dir / f'{index:05d}.png'46                return await self._fetch_screenshot(session, url, output_path)47

    48        async with aiohttp.ClientSession() as session:49            tasks = [50                bounded_fetch(session, url, i)51                for i, url in enumerate(urls)52            ]53            results = await asyncio.gather(*tasks)54

    55        return results56

    57# Usage58async def main():59    urls = [60        'https://example.com',61        'https://github.com',62        'https://stackoverflow.com',63    ]64

    65    screenshotter = BulkScreenshotter('your-access-key', 'your-secret-key')66    results = await screenshotter.process(urls, concurrency=5)67

    68    success = sum(1 for r in results if r['status'] == 'success')69    print(f"Completed: {success}/{len(results)} successful")70

    71asyncio.run(main())

Built-in Features That Save Time

--------------------------------

### Block Cookie Banners

    1options = (TakeOptions.url('https://example.com')2    .block_cookie_banners(True))

No more writing CSS selectors to hide consent dialogs.

### Block Chat Widgets

    1options = (TakeOptions.url('https://example.com')2    .block_chats(True))

Removes Intercom, Drift, and other chat widgets automatically.

### Dark Mode

    1options = (TakeOptions.url('https://example.com')2    .dark_mode(True))

### Delay for Dynamic Content

    1options = (TakeOptions.url('https://example.com')2    .delay(3000))  # Wait 3 seconds before capture

### Wait for Selector

    1options = (TakeOptions.url('https://example.com')2    .selector('.main-content'))  # Wait for element

Reading URLs from CSV

---------------------

    1import csv2import asyncio3from pathlib import Path4

    5async def process_csv(csv_path, access_key, secret_key):6    urls = []7    with open(csv_path, 'r') as f:8        reader = csv.DictReader(f)9        urls = [row['url'] for row in reader]10

    11    screenshotter = BulkScreenshotter(access_key, secret_key)12    results = await screenshotter.process(urls, concurrency=10)13

    14    # Save results15    with open('results.csv', 'w', newline='') as f:16        writer = csv.DictWriter(f, fieldnames=['url', 'status', 'path', 'error'])17        writer.writeheader()18        writer.writerows(results)19

    20    return results21

    22asyncio.run(process_csv('urls.csv', 'your-access-key', 'your-secret-key'))

Error Handling and Retries

--------------------------

    1import asyncio2import aiohttp3from tenacity import retry, stop_after_attempt, wait_exponential4

    5class RobustScreenshotter:6    def __init__(self, access_key, secret_key):7        self.client = Client(access_key, secret_key)8

    9    @retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=10))10    async def _fetch_with_retry(self, session, url, output_path):11        """Fetch with automatic retry on failure."""12        options = (TakeOptions.url(url)13            .format('png')14            .full_page(True))15

    16        signed_url = self.client.generate_take_url(options)17

    18        async with session.get(signed_url) as response:19            response.raise_for_status()20            content = await response.read()21            with open(output_path, 'wb') as f:22                f.write(content)23            return {'url': url, 'status': 'success'}24

    25    async def process(self, urls):26        results = []27        async with aiohttp.ClientSession() as session:28            for i, url in enumerate(urls):29                try:30                    result = await self._fetch_with_retry(session, url, f'screenshots/{i}.png')31                    results.append(result)32                except Exception as e:33                    results.append({'url': url, 'status': 'failed', 'error': str(e)})34        return results

Cost Comparison: API vs DIY

---------------------------

Let’s compare costs for 10,000 screenshots/month:

### DIY with Playwright

*   Server: $50-100/month (cloud VM)

*   Maintenance: 4+ hours/month

*   Risk: Browser crashes, memory leaks

### Screenshot API

*   ~$50-100/month for 10K screenshots

*   Zero maintenance

*   Built-in reliability

For most teams, the API is cheaper when you factor in engineering time.

When to Use Playwright Instead

------------------------------

Use [Playwright directly](/blog/bulk-screenshots-playwright-python/) when:

*   You need offline processing

*   Volume is very low (< 100/month)

*   You need custom browser interactions

*   Data must stay on your servers

Integration with Workflows

--------------------------

### Zapier Integration

ScreenshotOne integrates with Zapier for no-code workflows. Trigger screenshots from forms, spreadsheets, or other apps.

### Webhook Delivery

For async processing, use webhooks:

    1options = (TakeOptions.url('https://example.com')2    .webhook_url('https://your-server.com/webhook'))

Summary

-------

For bulk screenshots in Python:

1.  Use an API for high volume (1000+/month)

2.  Use async requests with controlled concurrency

3.  Leverage built-in features (cookie blocking, dark mode)

4.  Implement retry logic for reliability

5.  Consider total cost including engineering time

Frequently Asked Questions

--------------------------

If you read the article, but still have questions. Please, check the most frequently asked. And if you still have questions, feel free reach out at [support@screenshotone.com](mailto:support@screenshotone.com).

### When should I use a screenshot API instead of Playwright?

Use an API when you need high volume (1000+ screenshots), don't want to manage browser infrastructure, need features like ad blocking or cookie banner removal, or want to avoid anti-bot detection issues.

### How to automate taking screenshots of websites?

For small volumes, use Playwright with Python. For large volumes or production systems, use a screenshot API like ScreenshotOne that handles browser management, scaling, and edge cases automatically.

### What is the best website screenshot API?

It depends on your needs. ScreenshotOne offers a good balance of features, reliability, and pricing. Consider factors like rate limits, supported features (full page, PDF, etc.), and pricing model.

Read more Screenshot rendering

------------------------------

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

[View all posts](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots with C# (.NET)](/blog/how-to-take-website-screenshots-with-csharp-dotnet/)

The article examines how you can take screenshots of any URL with C# (.NET) by using PuppeteerSharp, or screenshot API as a service.

Read more

#### [How to take website screenshots with Java](/blog/how-to-take-website-screenshots-with-java/)

The article examines how you can take screenshots of any URL with Java by using Selenium, Puppeteer alternatives, Playwright, or screenshot API as a service.

Read more

#### [Let's build a screenshot API](/blog/building-screenshot-api/)

Two years have passed since the launch of ScreenshotOne, and I want to do a fun coding exercise and build a tiny subset of what the API is today, but from scratch.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/collect-design-inspirations
----

Automate Website Screenshots

1 min read

Landing Page Design Inspiration Collection

==========================================

Streamline the aggregation of web design inspirations.

Assembling a collection of webpage designs for inspiration is invaluable for designers and developers. ScreenshotOne API streamlines this process by automating the capture of webpage screenshots, creating a rich gallery of inspirations.

How ScreenshotOne API Contributes

---------------------------------

Through the screenshot API, developers can seamlessly gather and compile designs from a variety of websites. This automated approach aids in assembling a varied collection of webpage aesthetics, color palettes, and user interaction designs for inspiration.

Efficiency and Time Management

------------------------------

Utilizing ScreenshotOne to automate the compilation of a web design inspiration gallery conserves hours that would be otherwise dedicated to manually collecting and categorizing screenshots. It offers an effective, streamlined method for accumulating design inspirations, fostering creativity and efficiency.

ScreenshotOne is a terrific Screenshot API. We're taking screenshots at scale at landing.gallery and ScreenshotOne is handling it like an absolute champ.

The founder is incredibly responsive and the docs are outstanding and get you going within minutes.

Chris Jayden

Maker, [Landing Gallery](https://screenshotone.com/blog/landing-gallery/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/ai-landing-page-roasting
----

Automate Website Screenshots

1 min read

Landing Page Evaluation with AI

===============================

Automate landing page roasting for your customers or yourself with modern technologies like OpenAI Vision.

ScreenshotOne API has [a native seamless integration with OpenAI Vision](/blog/support-of-the-openai-gpt-vision-api-in-screenshotone/), where in one simple API call, you can both render a screenshot and evaluate a prompt over it.

This integration allows developers to automatically assess the visual appeal, layout, and content effectiveness of landing pages, providing actionable insights for optimization.

There are already companies providing that landing page evaluation as a product, if you are curious, read more about [how GetWebsite.Report uses ScreenshotOne for automated landing page evaluation with AI](/blog/how-website-report-uses-screenshotone/).

Integrated ScreenshotOne in my production app within minutes. Flexible API that has fit every use case I've thrown at it.

Tim Wheeler

Maker, [BotRoast.io](https://www.botroast.io/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

### AI Agents With Browser Observation

Give AI agents reliable screenshots of web pages so they can inspect, compare, and act with visual context.

[Read more →](/use-cases/ai-agents/)

### AI Vision For Analyzing Web Pages

Use AI to extract insights from web page visuals for enhanced content strategy and market analysis.

[Read more →](/use-cases/ai-vision-web-page-analysis/)

### Screenshots for OpenClaw Workflows

Use ScreenshotOne to automate website screenshots inside OpenClaw workflows for visual checks, proactive monitoring, and image-based reporting.

[Read more →](/use-cases/openclaw-workflows/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/errors/concurrency-limit-reached
----

[Skip to content](#_top)

Concurrency Limit Reached

=========================

Copy page

It is an API error returned when the request concurrency limit has been reached.

    1{2    "is_successful": false,3    "error_code": "concurrency_limit_reached",4    "error_message": "You reached the request concurrency limit, retry after a while. Or feel free to upgrade your current plan—https://dash.screenshotone.com/subscription.",5    "documentation_url": "https://screenshotone.com/docs/errors/concurrency-limit-reached/"6}

Reasons and how to fix

----------------------

### Exceeded Concurrency Limit

The most common reason for the “concurrency\_limit\_reached” error is that you have reached the maximum number of concurrent requests allowed by your current subscription plan.

To fix this, you can:

1.  **Wait and retry**: Wait for some of the current requests to complete and then retry your request.

2.  **Upgrade your plan**: Visit the [subscription page](https://dash.screenshotone.com/subscription) to upgrade your plan, which will increase your concurrency limit.

### High Traffic Periods

During high traffic periods, you might hit the concurrency limit more frequently if multiple requests are being made simultaneously.

To fix this, consider:

1.  **Load balancing**: Implementing load balancing strategies to distribute requests more evenly over time.

2.  **Queueing requests**: Queueing requests and processing them in batches to avoid hitting the concurrency limit.

### Inefficient Request Handling

If your application is not handling requests efficiently, it might lead to a buildup of concurrent requests, hitting the limit.

To fix this, review your application’s request handling logic to ensure that requests are being processed and completed as efficiently as possible.

Reach out to support

--------------------

If you continue to face issues, please reach out to `support@screenshotone.com`, and we will assist you as soon as possible.

----
url: https://screenshotone.com/changelog/screenshotone-webhook-errors
----

Rendering errors in webhooks

============================

Check out how to get notified about rendering errors when using webhooks.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Apr 24, 2025

ScreenshotOne supports delivering rendering results via webhooks. However, there wasn’t a way to track errors.

Now, you can enable error notifications to your webhook URL by setting the `webhook_errors` option to `true`.

[Read more about how to use webhooks with ScreenshotOne](/docs/async-and-webhooks/).

If you have any ideas, suggestions or issues on using this feature, please let us know at [support@screenshotone.com](mailto:support@screenshotone.com).

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Trigger screenshot download](/changelog/attachment-name/)

Now you can set attachment filename to trigger screenshot download in the browser.

Read more →

1 min read

#### [Fixed a validation issue in the playground](/changelog/fixed-a-playground-issue/)

We fixed a validation issue in the ScreenshotOne playground caused by selector scroll into view.

Read more →

1 min read

#### [Update your company information in the dashboard](/changelog/company-information-management/)

Starting today, you can update your company information in the dashboard. It includes updating the address, tax number, company number, and company name.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog
----

Automate Website Screenshots

----------------------------

Guides, Product Updates, and Helpful Resources from ScreenshotOne.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

[Playwright guides](/blog/tags/playwright-guides/)

#### [Playwright "Execution context was destroyed": how to fix navigation and page.evaluate errors](/blog/playwright-execution-context-was-destroyed-most-likely-because-of-a-navigation/)

Fix the Playwright "Execution context was destroyed, most likely because of a navigation" error after click, form submit, redirect, reload, or page.evaluate.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 13, 2026

•

4 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [page.waitForTimeout is not a function in Puppeteer](/blog/page-waitfortimeout-is-not-a-function-in-puppeteer/)

Puppeteer removed page.waitForTimeout(). Learn why the error happens and which modern alternatives to use instead.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 13, 2026

•

2 min read

#### [OpenClaw with Playwright or Puppeteer: how to install browser support](/blog/openclaw-playwright-puppeteer/)

A practical guide to OpenClaw browser automation, why Playwright is the documented path, where Puppeteer fits, how to make screenshots, and when ScreenshotOne is the better choice for screenshot-only flows.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 12, 2026

•

6 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How AdKit automated onboarding](/blog/adkit/)

A short story by the founder of AdKit about how they use ScreenshotOne for onboarding automation.

Written by

[Nicolas Jeannen](/contributors/nicolas-jeannen/)

Published on

Mar 12, 2026

•

1 min read

#### [What is OpenClaw and how can it help?](/blog/openclaw/)

A short practical introduction to OpenClaw, what it is good at, and why it is useful if you want a proactive AI assistant that lives in your chat apps.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Mar 12, 2026

•

3 min read

#### [NemoClaw an enterprise alternative to OpenClaw by NVIDIA](/blog/openclaw-alternative-by-nvidia/)

A practical look at what NemoClaw appears to be, what OpenClaw already is, and the main differences between them as of March 11, 2026.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 11, 2026

•

5 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Why FrameKit chose ScreenshotOne for their business](/blog/framekit/)

A short story about how and why FrameKit chose ScreenshotOne for their use case.

Written by

[Anatoly Pashias](/contributors/anatoly-pashias/)

Published on

Mar 2, 2026

•

1 min read

#### [ScreenshotOne and viaSocket integration](/blog/screenshotone-and-viasocket-integration/)

Use viaSocket with ScreenshotOne to build workflows that include website screenshot automation.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Feb 25, 2026

•

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/ip-ranges
----

[Skip to content](#_top)

ScreenshotOne IP Ranges

=======================

Copy page

In case you need to allow access from the ScreenshotOne API to your servers or your proxy provider allow list, you can configure your firewall to allow the following IP addresses:

1.  IPs for the `east-4` region [from public Google Cloud IP ranges](https://www.gstatic.com/ipranges/cloud.json).

2.  Hetzner GPU rendering IP (if applicable for your use case)—`95.216.67.59`.

3.  IP range for New York from [DigitalOcean Public IPs](https://digitalocean.com/geo/google.csv).

If that doesn’t work for you, please, reach out at `support@screenshotone.com` with any questions you have and we will try to get back to you as soon as possible.

----
url: https://screenshotone.com/blog/python-screen-capture
----

How to Capture Desktop Screenshots in Python

============================================

Complete guide to desktop screen capture in Python. Compare Python MSS, DXcam, PyAutoGUI for capturing monitors, windows, and screen regions.

[Blog post](/blog/) 3 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jan 19, 2026

#### Tags

[Desktop screen capture](/blog/tags/desktop-screen-capture/)

If you’re looking to take screenshots of websites, you are in the wrong place—check our my [website screenshots guide](/blog/how-to-take-website-screenshots-in-python/) instead. This guide is about capturing your desktop: applications, games, or anything displayed on your screen.

Quick Comparison

----------------

Library

Speed

Cross-platform

Best For

[Python MSS](/blog/mss-python-screen-capture/)

Fast (30-60 FPS)

Yes

General purpose

[DXcam](/blog/dxcam-python-screenshots/)

Very fast (240+ FPS)

Windows only

Gaming/streaming

[PyAutoGUI](/blog/pyautogui-python-screenshots/)

Slow (1-5 FPS)

Yes

Automation scripts

Python MSS: The best general-purpose choice

-------------------------------------------

Python MSS is my recommendation for most use cases—it’s fast, cross-platform, and reliable.

    1import mss2

    3with mss.mss() as sct:4    # Capture the entire screen5    screenshot = sct.grab(sct.monitors[0])6

    7    # Save to file8    mss.tools.to_png(screenshot.rgb, screenshot.size, output='screenshot.png')

**Best for**: General desktop capture on any platform.

[Full mss guide →](/blog/mss-python-screen-capture/)

DXcam: Maximum Performance, Windows only

----------------------------------------

For gaming, streaming, or any high-FPS application, dxcam is unbeatable on Windows.

    1import dxcam2

    3camera = dxcam.create()4frame = camera.grab()  # Returns numpy array5

    6# Or continuous capture7camera.start(target_fps=60)8# ... frames available via camera.get_latest_frame()9camera.stop()

**Best for**: Game capture, screen recording, real-time processing.

[Full dxcam guide →](/blog/dxcam-python-screenshots/)

PyAutoGUI: Automation first, capture second

-------------------------------------------

PyAutoGUI is the easiest to use, though slower. Great for automation scripts.

    1import pyautogui2

    3# Full screen4screenshot = pyautogui.screenshot()5screenshot.save('screenshot.png')6

    7# Specific region8region_shot = pyautogui.screenshot(region=(0, 0, 500, 500))

**Best for**: Automation scripts, simple captures, beginners.

[Full PyAutoGUI guide →](/blog/pyautogui-python-screenshots/)

Capturing Specific Monitors

---------------------------

### With mss

    1import mss2

    3with mss.mss() as sct:4    # List all monitors5    for i, monitor in enumerate(sct.monitors):6        print(f"Monitor {i}: {monitor}")7

    8    # Capture specific monitor (1 = first monitor)9    monitor_1 = sct.grab(sct.monitors[1])10

    11    # Capture all monitors combined12    all_monitors = sct.grab(sct.monitors[0])

### With dxcam

    1import dxcam2

    3# List available outputs4outputs = dxcam.device_info()5

    6# Create camera for specific monitor7camera = dxcam.create(output_idx=0)  # First monitor

Capturing Specific Regions

--------------------------

### With mss

    1import mss2

    3with mss.mss() as sct:4    region = {5        'left': 100,6        'top': 100,7        'width': 500,8        'height': 5009    }10    screenshot = sct.grab(region)

### With DXcam

    1import dxcam2

    3camera = dxcam.create()4frame = camera.grab(region=(100, 100, 600, 600))  # left, top, right, bottom

### With pyautogui

    1import pyautogui2

    3# region = (left, top, width, height)4screenshot = pyautogui.screenshot(region=(100, 100, 500, 500))

Continuous Capture (Screen Recording)

-------------------------------------

### With DXcam (Fastest)

    1import dxcam2import time3

    4camera = dxcam.create(output_color="BGR")5camera.start(target_fps=60)6

    7frames = []8start = time.time()9

    10while time.time() - start < 5:  # Record for 5 seconds11    frame = camera.get_latest_frame()12    if frame is not None:13        frames.append(frame)14

    15camera.stop()16print(f"Captured {len(frames)} frames")

### With Python MSS

    1import mss2import time3

    4frames = []5start = time.time()6

    7with mss.mss() as sct:8    monitor = sct.monitors[1]9

    10    while time.time() - start < 5:11        frame = sct.grab(monitor)12        frames.append(frame)13

    14print(f"Captured {len(frames)} frames")

Converting to Other Formats

---------------------------

### Python MSS to PIL Image

    1import mss2from PIL import Image3

    4with mss.mss() as sct:5    screenshot = sct.grab(sct.monitors[1])6    img = Image.frombytes('RGB', screenshot.size, screenshot.bgra, 'raw', 'BGRX')7    img.save('screenshot.png')

### Python MSS to NumPy Array

    1import mss2import numpy as np3

    4with mss.mss() as sct:5    screenshot = sct.grab(sct.monitors[1])6    img_array = np.array(screenshot)  # BGRA format

### DXcam Output

DXcam returns NumPy arrays directly:

    1import dxcam2

    3camera = dxcam.create(output_color="RGB")  # or "BGR" for OpenCV4frame = camera.grab()  # Returns numpy array

Performance Benchmarks

----------------------

Tested on Windows 10, 1920x1080 monitor:

Library

FPS

Notes

dxcam

240+

DirectX-based

mss

30-60

Cross-platform

PIL ImageGrab

10-15

Built-in

pyautogui

1-5

Uses PIL internally

Choosing the Right Library

--------------------------

    1Need high FPS (gaming/streaming)?2├── Yes → Use dxcam (Windows only)3└── No4    ├── Cross-platform needed?5    │   ├── Yes → Use mss6    │   └── No7    │       ├── Already using PIL? → Use ImageGrab8    │       └── Want automation? → Use pyautogui

Website Screenshots versus Desktop Screen Capture

-------------------------------------------------

As a reminder on what to use and when:

Task

Use This

Screenshot a website

[Playwright](/blog/playwright-python-screenshots/)

Screenshot desktop apps

Python MSS or DXcam

Record gameplay

DXcam

Automate desktop tasks

PyAutoGUI

If you need to capture websites, don’t use desktop capture libraries—they’ll just capture your browser window. Use [proper website screenshot tools](/blog/how-to-take-website-screenshots-in-python/) instead.

Summary

-------

Desktop screen capture in Python:

1.  **Python MSS**: Best general-purpose choice (fast, cross-platform)

2.  **DXcam**: Best for gaming/high-FPS (Windows only)

3.  **PyAutoGUI**: Easiest to use (but slowest)

For website screenshots, just use [Playwright for Python](/blog/playwright-python-screenshots/) instead or check our [guide on website screenshots in Python](/blog/how-to-take-website-screenshots-in-python/).

Frequently Asked Questions

--------------------------

If you read the article, but still have questions. Please, check the most frequently asked. And if you still have questions, feel free reach out at [support@screenshotone.com](mailto:support@screenshotone.com).

### What is the difference between desktop screen capture and website screenshots?

Desktop screen capture captures what's displayed on your monitor (any application). Website screenshots render a web page in a browser. Use Playwright/Selenium for websites, use Python MSS/DXcam for desktop capture.

### What is the fastest Python screen capture library?

DXcam is fastest on Windows (240+ FPS), followed by Python MSS (30-60 FPS cross-platform). PyAutoGUI is slowest but easiest to use. Choose based on your speed requirements and platform.

### How to capture a specific monitor in Python?

Use mss with the monitor parameter. mss.monitors\[1\] is the first monitor, mss.monitors\[2\] is the second, etc. mss.monitors\[0\] captures all monitors combined.

Read more Desktop screen capture

--------------------------------

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

[View all posts](/blog/tags/desktop-screen-capture/)

#### [How to Take Screenshots with PyAutoGUI in Python](/blog/pyautogui-python-screenshots/)

Complete guide to taking screenshots with PyAutoGUI in Python. Learn screenshot(), region parameters, locateOnScreen(), and common errors with ImageNotFoundException.

Read more

#### [How to Capture Desktop Screen with DXcam in Python](/blog/dxcam-python-screenshots/)

Complete guide to DXcam, the fastest Python screen capture library. Learn high-FPS capture, video mode, region capture, and DXcam vs Python MSS performance comparison.

Read more

#### [How to Take Screenshots with Python MSS](/blog/mss-python-screen-capture/)

Complete guide to the MSS Python screen capture library. Learn installation, capturing monitors, regions, performance optimization, and common errors like xgetimage() failed.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/integrations/google-sheets
----

Integrations

1 min read

Google Sheets

=============

Render website screenshots in Google Sheets.

Low-Code Automation

Resources

---------

*   [Guide](https://screenshotone.com/blog/a-friendly-guide-on-how-to-render-html-or-site-screenshots-in-google-sheets-in-less-than-10-minutes/)

ScreenshotOne is the best product on the market - and that's before you take into account how responsive and easy Dmytro is to work with.

Any time we've found a rare edge case, it's been resolved in hours.

Great company, great founder - can't say enough!

Mike Roberts

Founder, [SpyFu](https://www.spyfu.com/)

Check more Integrations

-----------------------

No-code tools, AI, code libraries, and more.

[Check more Integrations](/integrations/)

No-Code Automation

### n8n

Use ScreenshotOne in n8n workflows to render website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

[Read more →](/integrations/n8n/)

No-Code Automation

### Zapier

Automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos in Zapier.

[Read more →](/integrations/zapier/)

No-Code Automation

### Clay

Generate website screenshots inside Clay to qualify leads, assess content, and enrich rows with visual context automatically.

[Read more →](/integrations/clay/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/personalized-onboarding
----

Automate Website Screenshots

1 min read

Personalized Onboarding

=======================

Personalize onboarding by analyzing a customer's website visually and using screenshots throughout the setup flow.

Many SaaS products can make onboarding much more relevant if they start by understanding what the customer’s website actually looks like. ScreenshotOne helps capture that visual context so products can analyze the site, tailor recommendations, and guide users through a setup flow that already feels connected to their brand.

Personalize the onboarding flow

-------------------------------

By rendering screenshots of the customer’s site, a SaaS product can inspect branding, layout structure, copy, calls to action, and other visible elements. That visual input can be used to prefill settings, suggest improvements, or adapt onboarding steps to the actual site instead of sending every user through the same generic process.

Make onboarding feel familiar

-----------------------------

Screenshots can also be shown directly inside the onboarding flow. When users see their own website reflected in setup screens, suggested changes, or previews, the product feels more concrete and easier to trust. That reduces confusion and helps users understand what the tool is doing for them.

Useful for AI-assisted setup and review

---------------------------------------

This is especially useful for AI-assisted onboarding. A product can capture the site, analyze it visually, generate tailored onboarding guidance, and then render screenshots again after changes to confirm that everything looks right.

Reliable when the first impression matters

------------------------------------------

Onboarding is a critical moment. ScreenshotOne gives SaaS teams a dependable way to capture and render websites without building their own browser automation stack, making it easier to deliver personalized onboarding at scale.

I use ScreenshotOne for Adkit, and it works perfectly! I have my own infrastructure, so I could do it myself, but I need the screenshot at a critical time (when onboarding new users), so it’s “too important to fail”. Screenshot One never failed me once! And it’s also much faster than my own system.

Nicolas Jeannen

Founder, [AdKit](https://screenshotone.com/blog/adkit/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

### Design Tools Font Detection

Use our font detection API to help designers identify and analyze typography on any website.

[Read more →](/use-cases/design-apps-font-detection/)

### Font Legal Compliance Check

Ensure fonts used on websites are legally compliant to avoid copyright issues.

[Read more →](/use-cases/font-legal-compliance/)

### UX Font Analysis

Examine the impact of different fonts on user engagement and website usability.

[Read more →](/use-cases/ux-font-analysis/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/live-dashboad-emails
----

Automate Website Screenshots

1 min read

Live dashboard report emails

============================

Take a screenshot of a Grafana / BI dashboard and embed it in a daily PDF mailed to stakeholders who dislike logging in.

Situation

---------

Your team keeps a live Grafana (or any BI) dashboard that shows key numbers—traffic, revenue, error rates. Some execs and investors need that data every morning, but they hate logging in or hunting for URLs. They want the highlights waiting in their inbox.

Goal

----

Send a clean, one‑page PDF each day that shows an up‑to‑the‑minute screenshot of the dashboard, so stakeholders can see trends at a glance without opening any tools.

How ScreenshotOne helps

-----------------------

[ScreenshotOne PDF generation API](/pdf-generation-api/) helps you with that:

1.  **Grab the view:** Call the ScreenshotOne PDF endpoint with the dashboard URL. It spins up a headless browser, waits for all the charts to render, then captures a full‑page image.

2.  **Wrap as PDF:** Add `format=pdf` in the same request. ScreenshotOne drops the screenshot into a PDF—no extra code needed.

3.  **Automate & email:** Schedule the call with a cron job (or GitHub Action, Zapier, etc.). Once the PDF is saved, trigger your usual email service (SendGrid, SES, Gmail API) to attach the file and send it to the mailing list.

Terminal window

    1curl "https://api.screenshotone.com/take?access_key=<your api key></your>&format=pdf&url=https://dashboard.example.com/"

Result

------

Every morning, stakeholders open their email, glance at a single‑page PDF, and know exactly how the business is doing—no logins, no forgotten passwords, no extra noise. You stay focused on building dashboards; ScreenshotOne handles the capture and formatting.

ScreenshotOne is a really helpful service provider. All that I need for my work is combined here.

Service is comfortable, fast, and consistent. It has a nice support service that always stays active to problems of users and has an immediate response time.

I really appreciate and recommend ScreenshotOne to everyone.

Alexandr Bezhan

Chief Product Officer, [AMS Pilot](https://www.amspilot.com/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/slack-notifications
----

Added support of Slack notifications

====================================

We added support of Slack notifications to ScreenshotOne. Now you can set up and get Slack notifications when you reach your quota limits.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Apr 20, 2025

Since today, you can set up Slack notifications for ScreenshotOne in the dashboard:

It will allow you to get notifications when you reach your quota limits.

[Read the complete guide on how to set up Slack notifications in the documentation](/docs/notifications/#slack).

Please, let us know if you have any feedback or suggestions at [support@screenshotone.com](mailto:support@screenshotone.com).

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Include shadow DOM when requesting the page content](/changelog/include-shadow-dom/)

A new version of the ScreenshotOne API has been just deployed. It allows you to include the shadow DOM contents when requesting the page content.

Read more →

1 min read

#### [Update your company information in the dashboard](/changelog/company-information-management/)

Starting today, you can update your company information in the dashboard. It includes updating the address, tax number, company number, and company name.

Read more →

1 min read

#### [Notifications when the usage reaches 50% of the limit](/changelog/half-quota-reached-notifications/)

You can now get notifications when the usage reaches 50% of the limit.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/contributors/dan-mindru
----

Dan Mindru

----------

Dan Mindru likes to design & develop UIs, but also likes pizza 🍕 He is building [Shipixen](https://shipixen.com/). You can also find him on [Twitter](https://twitter.com/d4m1n).

View all Changelog

#### [Using Clobbr to quickly load test the ScreenshotOne API](/blog/using-clobbr-to-quickly-load-test-the-screenshotone-api/)

Google Cloud gives $300 in credits for 3 months for experimenting. And I decided to give it a try, but not because of the free credits.

Written by

[Dan Mindru](/contributors/dan-mindru/), [Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Sep 23, 2023

•

3 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/8
----

Automate Website Screenshots

----------------------------

Guides, Product Updates, and Helpful Resources from ScreenshotOne.

View all Customer stories Playwright guides Puppeteer guides Desktop screen capture Screenshot rendering Engineering Crawling and scraping PDF rendering Changelog

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to screenshot websites in Next.js](/blog/nextjs-screenshots/)

There 3 simple ways to render website screenshots in Next.js—using Puppeteer, Cloudflare Browser Rendering, and a screenshot API like ScreenshotOne or similar.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

May 7, 2024

•

5 min read

#### [Cloudflare Browser Rendering](/blog/cloudflare-browser-rendering/)

Cloudflare recently launched a new Browser Rendering platform. I decided to dive into it and quickly check if I could use it in ScreenshotOne to provide a faster and better customer experience.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

May 7, 2024

•

5 min read

[Playwright guides](/blog/tags/playwright-guides/)

#### [What is Playwright](/blog/playwright/)

What is Playwright and what you can use it for.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

May 6, 2024

•

2 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Playwright guides](/blog/tags/playwright-guides/)

#### [Puppeteer versus Playwright](/blog/puppeteer-versus-playwright/)

When to use Playwright and when to use Puppeteer.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

May 6, 2024

•

2 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [What is Puppeteer](/blog/puppeteer/)

What is Puppeteer and what you can use it for.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

May 6, 2024

•

4 min read

[PDF rendering](/blog/tags/pdf-rendering/) [Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [How to generate PDFs with Puppeteer](/blog/how-to-generate-pdf-with-puppeteer/)

A practical and working guide on how to generate PDFs with Puppeteer.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

May 2, 2025

•

2 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Typeshare uses ScreenshotOne for image generation](/blog/how-typeshare-uses-screenshotone/)

Typeshare is a digital writing platform designed to enhance the writing experience by offering a suite of tools aimed at reducing common barriers writers face.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Apr 14, 2024

•

2 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How RivalFlowAI uses ScreenshotOne to help its customers improve existing content](/blog/rivalflowai-by-spyfu/)

RivalFlowAI is a new product by SpyFu, launched in 2023. The product helps to improve existing content with AI by finding the missing pieces your page needs to rank.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Apr 9, 2024

•

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/screenshot-api/csharp
----

[What's new API error insights API error insights in the dashboard](/changelog/error-metrics/)

C# (.NET) Screenshot API

========================

Capture pixel-perfect website screenshots in C# with a simple API call. No browser management, no Selenium setup—just clean, reliable screenshots.

----------------------

----------------------------

------------------------------------

Take screenshots with C# (.NET)

-------------------------------

Use our official C# (.NET) SDK or send simple HTTP requests to capture screenshots.

    1// Add the library via nuget using the package manager console: PM> Install-Package ScreenshotOne.dotnetsdk2// Or from the .NET CLI as: dotnet add package ScreenshotOne.dotnetsdk3

    4// And generate a screenshot URL without executing request:5var client = new Client("<access key>", "<secret key>");6var options = TakeOptions.Url("https://www.amazon.com")7  .FullPage(true)8  .Format(Format.PNG)9  .BlockCookieBanners(true);10

    11var url = client.GenerateTakeUrl(options);12// url = https://api.screenshotone.com/take?url=https%3A%2F%2Fwww.amazon.com&full_page=true&format=png&block_cookie_banners=true&access_key=_OzqMIjpCw-ARQ&signature=8a08e62d13a5c3490fda0734b6707791d3decc9ab9ba41e8cc045288a39db50213

    14// Or take a screenshot and save the image in the file:15var client = new Client("<access key>", "<secret key>");16var options = TakeOptions.Url("https://www.google.com")17  .FullPage(true)18  .Format(Format.PNG)19  .BlockCookieBanners(true);20

    21var bytes = await client.Take(options);22

    23File.WriteAllBytes(@"c:\temp\example.png", bytes);

Mike Roberts

Founder, [SpyFu](https://www.spyfu.com/)

> ScreenshotOne is the best product on the market - and that's before you take into account how responsive and easy Dmytro is to work with.

> 

> Any time we've found a rare edge case, it's been resolved in hours.

> 

> Great company, great founder - can't say enough!

Without writing a line of code

No-code integrations

--------------------

Quickly render website screenshots with Zapier, Airtable, Make and other popular no-code platforms of your choice.

[](/integrations/zapier/)[](/integrations/airtable/)[](/integrations/make/)[](/integrations/bubble/)[](/integrations/n8n/)

Read

Lessons from running screenshot rendering infrastructure

--------------------------------------------------------

Practical guides and real updates based on our experience operating rendering infrastructure at production scale.

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots with C# (.NET)](/blog/how-to-take-website-screenshots-with-csharp-dotnet/)

The article examines how you can take screenshots of any URL with C# (.NET) by using PuppeteerSharp, or screenshot API as a service.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 24, 2023

•

3 min read

[Customer stories](/blog/tags/customer-stories/)

#### [Taking care of WordPress Sites with ScreenshotOne](/blog/kinsta/)

How Kinsta uses ScreenshotOne to deliver reliable automatic updates.

Written by

[Roger Williams](/contributors/roger-williams/), [Barnabás Ürmössy](/contributors/barnabs-rmssy/)

Published on

Apr 29, 2025

•

2 min read

[Customer stories](/blog/tags/customer-stories/)

#### [How Typeshare uses ScreenshotOne for image generation](/blog/how-typeshare-uses-screenshotone/)

Typeshare is a digital writing platform designed to enhance the writing experience by offering a suite of tools aimed at reducing common barriers writers face.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Apr 14, 2024

•

2 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/metadata-icon
----

Get favicon used by a website with ScreenshotOne API

====================================================

Now you can get favicon used by a website with ScreenshotOne API in just one simple API call.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Nov 27, 2024

Yes, it is as simple as that.

Use `metadata_icon` option to get the favicon used by a website. The default value is `false`:

    1https://api.screenshotone.com/take?metadata_icon=true&url=https://screenshotone.com/&access_key=<access key>

The result will be returned as headers:

    1X-ScreenshotOne-Icon: {"url":"https://screenshotone.com/favicon-32x32.png","type":"image/png"}

Or as JSON:

    1{2    "metadata": {3        "icon": {4            "url": "https://screenshotone.com/favicon-32x32.png",5            "type": "image/png"6        }7    }8}

It is also available in the [playground](https://dash.screenshotone.com/playground).

As always, if you have any questions, please, reach out at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Better error coverage and documentation](/changelog/all-errors-are-covered/)

Since a few months ago, it has been possible to check errors in the dashboard request log and get explanations and more details in the documentation. But!

Read more →

1 min read

#### [Convert any website to Markdown format with ScreenshotOne API](/changelog/website-to-markdown-format/)

Now you can convert any website to Markdown format with ScreenshotOne API in just one simple API call.

Read more →

1 min read

#### [Improved blocking of banners for specific websites](/changelog/improved-banner-blocking-for-specific-websites/)

We just released an updated version of our algorithm to block banners for specific websites by heuristics.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/contributors/roger-williams
----

Roger Williams

--------------

View all Changelog

[Customer stories](/blog/tags/customer-stories/)

#### [Taking care of WordPress Sites with ScreenshotOne](/blog/kinsta/)

How Kinsta uses ScreenshotOne to deliver reliable automatic updates.

Written by

[Roger Williams](/contributors/roger-williams/), [Barnabás Ürmössy](/contributors/barnabs-rmssy/)

Published on

Apr 29, 2025

•

2 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/book-a-call
----

"Great support."

"It brings reliability to our business."

"It works like a charm."

Let's talk

Schedule a demo

---------------

It is not a sales call. The goal is to understand your needs and to check together on ScreenshotOne's abilities and see if it is a perfect fit for you.

Or just send an email with any questions to **support@screenshotone.com**  

and we will get back to you.

Guillaume Barillot

CTO, [Deepidoo](https://www.deepidoo.com/en/)

> Awesome product that-just-works™. Took me 10 minutes to add it to my (Rails) stack. Simple pricing. Great support. If you need something like a "Screenshot as a Service" API. Give it a try!

[Read more customer stories →](/blog/tags/customer-stories/)

Frequently Asked Questions

--------------------------

Discover quick and comprehensive answers to common questions about our platform, services, and features.

Is it a free service for taking screenshots?

Yes, ScreenshotOne is a free screenshot API. You can take up to 100 screenshots of any URL for free per month, including rendering HTML and PDF.

Do failed screenshots count against the limitation on the plan?

Only successfully rendered screenshots are counted.

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/tools/full-page-website-screenshot
----

Make full page screenshots

--------------------------

Render full page screenshots website online for free and without registration.

[Tools](/tools/) Free Full Page Website Screenshots

--------------------------

Discover quick and comprehensive answers to common questions about our platform, services, and features.

What is this full page screenshotter tool about?

The full page screenshot taker is a free tool by ScreenshotOne that captures full page screenshots online. You can get any full page screenshot without signing up and hassle.

Why is it free to render full page screenshots?

It is not free to run that tool. But the tool is built for demonstration purposes to see what's possible to do with ScreenshotOne. The main audience for ScreenshotOne is developers who seek a screenshot API that can automate website screenshotting.

What is ScreenshotOne?

ScreenshotOne is one of the best screenshot APIs in the market which allows you to automate website screenshots fast and renders them with good enough quality.

Integrate today

Automate screenshot rendering with the language you love

--------------------------------------------------------

Send simple HTTP requests or use native libraries for your language of choice.

Java Go Node.js PHP Python Ruby C# (.NET)

    1// add com.screenshotone.jsdk:screenshotone-api-jsdk:[1.0.0,2.0.0)2// to your `pom.xml` or `build.gradle`3

    4import com.screenshotone.jsdk.Client;5import com.screenshotone.jsdk.TakeOptions;6

    7import java.io.File;8import java.nio.file.Files;9

    10public class App {11    public static void main(String[] args) throws Exception {12        final Client client = Client.withKeys("<access key>", "<secret key>");13        TakeOptions takeOptions = TakeOptions.url("https://example.com")14                .fullPage(true)15                .deviceScaleFactor(1)16                .viewportHeight(1200)17                .viewportWidth(1200)18                .format("png")19                .omitBackground(true);20        final String url = client.generateTakeUrl(takeOptions);21

    22        System.out.println(url);23        // Output: https://api.screenshotone.com/take?url=...24

    25        // or download the screenshot26        final byte[] image = client.take(takeOptions);27

    28        Files.write(new File("./example.png").toPath(), image);29        // the screenshot is stored in the example.png file30    }31}

    1// go get github.com/screenshotone/gosdk2

    3import screenshots "github.com/screenshotone/gosdk"4

    5client, err := screenshots.NewClient("<access key>", "<secret key>")6// check err7

    8options := screenshots.NewTakeOptions("https://example.com").9    Format("png").10    FullPage(true).11    DeviceScaleFactor(2).12    BlockAds(true).13    BlockTrackers(true)14

    15u, err := client.GenerateTakeURL(options)16// check err17

    18fmt.Println(u.String())19// Output: https://api.screenshotone.com/take?url=...20

    21// or download the screenshot22image, err := client.Take(context.TODO(), options)23// check err24

    25defer image.Close()26out, err := os.Create("example.png")27// check err28

    29defer out.Close()30io.Copy(out, image)31// the screenshot is stored in the example.png file

    1// $ npm install screenshotone-api-sdk --save2

    3import * as fs from 'fs';4import * as screenshotone from 'screenshotone-api-sdk';5

    6// create API client7const client = new screenshotone.Client("<access key>", "<secret key>");8

    9// set up options10const options = screenshotone.TakeOptions11    .url("https://example.com")12    .delay(3)13    .blockAds(true);14

    15// generate URL16const url = client.generateTakeURL(options);17console.log(url);18// expected output: https://api.screenshotone.com/take?url=...19

    20// or download the screenshot21const imageBlob = await client.take(options);22const buffer = Buffer.from(await imageBlob.arrayBuffer());23fs.writeFileSync("example.png", buffer)24// the screenshot is stored in the example.png file

    1<?php2

    3// composer require screenshotone/sdk:^1.04

    5use ScreenshotOneSdkClient;6use ScreenshotOneSdkTakeOptions;7

    8$client = new Client("<access key>", "<secret key>");9

    10$options = TakeOptions::url("https://example.com")11    ->fullPage(true)12    ->delay(2)13    ->geolocationLatitude(48.857648)14    ->geolocationLongitude(2.294677)15    ->geolocationAccuracy(50);16

    17$url = $client->generateTakeUrl($options);18echo $url.PHP_EOL;19// expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com...20

    21$image = $client->take($options);22file_put_contents('example.png', $image);23// the screenshot is stored in the example.png file

    1# pip install screenshotone2

    3import shutil4from screenshotone import Client, TakeOptions5

    6# create API client7client = Client('<access key>', '<secret key>')8

    9# set up options10options = (TakeOptions.url('https://screenshotone.com')11    .format("png")12    .viewport_width(1024)13    .viewport_height(768)14    .block_cookie_banners(True)15    .block_chats(True))16

    17# generate the screenshot URL and share it with a user18url = client.generate_take_url(options)19# expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fscreenshotone.com&viewport_width=1024&viewport_height=768&block_cookie_banners=True&block_chats=True&access_key=&signature=6afc9417a523788580fa01a9f668ea82c78a9d2b41441d2a696010bf2743170f20

    21# or render a screenshot and download the image as stream22image = client.take(options)23

    24# store the screenshot the example.png file25with open('example.png', 'wb') as result_file:26    shutil.copyfileobj(image, result_file)

    1# Add this gem to your Gemfile:2# gem 'screenshotone'3

    4# If you don't need to add a signature5client = ScreenshotOne::Client.new('<access key>')6

    7# Or ff you do need to add a signature8client = ScreenshotOne::Client.new('<access key>', '<secret key>')9

    10# You can set any available option, in a camel_case format, for example:11options = ScreenshotOne::TakeOptions.new(url: 'https://example.com').12            full_page(true).13            delay(2).14            geolocation_latitude(48.857648).15            geolocation_longitude(2.294677).16            geolocation_accuracy(50)17

    18# Verify all the parameters are valid (we will validate the parameters that should be19# numeric, booleans or that accept only certain values)20options.valid?21=> true22

    23# To simply get the final url:24client.generate_take_url(options)25=> "https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com..."26

    27# To actually get the image (the response body of a request to the previous url)28client.take(options)29=> "\xFF\xD8\xFF\xE0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xFF\..."

    1// Add the library via nuget using the package manager console: PM> Install-Package ScreenshotOne.dotnetsdk2// Or from the .NET CLI as: dotnet add package ScreenshotOne.dotnetsdk3

    4// And generate a screenshot URL without executing request:5var client = new Client("<access key>", "<secret key>");6var options = TakeOptions.Url("https://www.amazon.com")7  .FullPage(true)8  .Format(Format.PNG)9  .BlockCookieBanners(true);10

    11var url = client.GenerateTakeUrl(options);12// url = https://api.screenshotone.com/take?url=https%3A%2F%2Fwww.amazon.com&full_page=true&format=png&block_cookie_banners=true&access_key=_OzqMIjpCw-ARQ&signature=8a08e62d13a5c3490fda0734b6707791d3decc9ab9ba41e8cc045288a39db50213

    14// Or take a screenshot and save the image in the file:15var client = new Client("<access key>", "<secret key>");16var options = TakeOptions.Url("https://www.google.com")17  .FullPage(true)18  .Format(Format.PNG)19  .BlockCookieBanners(true);20

    21var bytes = await client.Take(options);22

    23File.WriteAllBytes(@"c:\temp\example.png", bytes);

Mike Roberts

Founder, [SpyFu](https://www.spyfu.com/)

> ScreenshotOne is the best product on the market - and that's before you take into account how responsive and easy Dmytro is to work with.

> 

> Any time we've found a rare edge case, it's been resolved in hours.

> 

> Great company, great founder - can't say enough!

Without writing a line of code

No-code integrations

--------------------

Quickly render website screenshots with Zapier, Airtable, Make and other popular no-code platforms of your choice.

[](/integrations/zapier/)[](/integrations/airtable/)[](/integrations/make/)[](/integrations/bubble/)[](/integrations/n8n/)

Read

Lessons from running screenshot rendering infrastructure

--------------------------------------------------------

Practical guides and real updates based on our experience operating rendering infrastructure at production scale.

[Playwright guides](/blog/tags/playwright-guides/)

#### [Playwright "Execution context was destroyed": how to fix navigation and page.evaluate errors](/blog/playwright-execution-context-was-destroyed-most-likely-because-of-a-navigation/)

Fix the Playwright "Execution context was destroyed, most likely because of a navigation" error after click, form submit, redirect, reload, or page.evaluate.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 13, 2026

•

4 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [page.waitForTimeout is not a function in Puppeteer](/blog/page-waitfortimeout-is-not-a-function-in-puppeteer/)

Puppeteer removed page.waitForTimeout(). Learn why the error happens and which modern alternatives to use instead.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 13, 2026

•

2 min read

#### [OpenClaw with Playwright or Puppeteer: how to install browser support](/blog/openclaw-playwright-puppeteer/)

A practical guide to OpenClaw browser automation, why Playwright is the documented path, where Puppeteer fits, how to make screenshots, and when ScreenshotOne is the better choice for screenshot-only flows.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 12, 2026

•

6 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/ux-font-analysis
----

Automate Website Screenshots

1 min read

UX Font Analysis

================

Examine the impact of different fonts on user engagement and website usability.

Use [ScreenshotOne font detection API](/font-detection-api/) to develop features in UX analysis tools that examine the impact of different fonts on user engagement and website usability.

Typography’s Impact on User Experience

--------------------------------------

Typography significantly affects how users interact with websites, influencing readability, comprehension, and engagement. ScreenshotOne’s font detection API enables UX analysis tools to correlate typography choices with user behavior metrics.

Comprehensive UX Insights

-------------------------

UX professionals can use the API to analyze which fonts are used on high-performing pages and understand how typography choices relate to metrics like time on page, bounce rate, and conversion rates. This data-driven approach helps identify typography best practices.

Check out [our guide on how to detect website fonts](/docs/guides/how-to-detect-website-fonts/) for more details.

Efficient UX Research

---------------------

Rather than manually documenting fonts during UX research, teams can use ScreenshotOne API to automatically capture typography data as part of their analysis workflow. This automation saves significant time and ensures accurate font identification, allowing UX researchers to focus on analyzing patterns and drawing insights rather than collecting data.

I use ScreenshotOne for Adkit, and it works perfectly! I have my own infrastructure, so I could do it myself, but I need the screenshot at a critical time (when onboarding new users), so it’s “too important to fail”. Screenshot One never failed me once! And it’s also much faster than my own system.

Nicolas Jeannen

Founder, [AdKit](https://screenshotone.com/blog/adkit/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

### Font Accessibility Checks

Use our font detection API to check fonts and and research whether websites use readable fonts for people with visual impairments or reading disabilities.

[Read more →](/use-cases/font-accessibility-checks/)

### Font Trends Analysis

Use our font detection API to provide insights into typography trends of top-ranking websites across various industries.

[Read more →](/use-cases/font-trends/)

### Personalized Onboarding

Personalize onboarding by analyzing a customer's website visually and using screenshots throughout the setup flow.

[Read more →](/use-cases/personalized-onboarding/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/real-estate-listing-sheets
----

Automate Website Screenshots

1 min read

Real‑estate listing sheets

==========================

Automatically generate and embed website screenshots in investor and board reporting decks.

When buyers visit an open house, agents still hand out paper flyers. Each flyer needs clean photos, a small map, key amenities, and the agent’s contact info. Building those PDFs by hand—or exporting them from a bulky MLS tool—takes time and never looks quite the same from one property to the next.

With [ScreenshotOne’s PDF generation API](/pdf-generation-api/), a property portal can create those flyers automatically. Your app builds a simple, mobile‑friendly web page for every listing. One call to the API turns that page into a pixel‑perfect PDF, complete with high‑resolution images, map embeds, and brand colors. Agents get a “Download flyer” button that works 24/7, even when new photos, prices, or amenity lists change.

The same API call can power instant MLS previews. Brokers drop a link in chat, and ScreenshotOne returns a neatly cropped, one‑page PDF of the listing—ready to share with clients or save for compliance. No manual exports, no desktop software, just a reliable endpoint that keeps every sheet on‑brand and up to date.

I found ScreenshotOne very easy to get started with. The intuitive playground feature allowed me to seamlessly integrate and test our campaigns.

I love the playground, and it just works.

Stefan Wirth

Maker, [Bridesmaid For Hire](https://bridesmaidforhire.com/ai-wedding-speech-and-vow-generators)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/guides/emojis
----

[Skip to content](#_top)

How to render screenshots with different emoji styles

=====================================================

Copy page

It might happen that you need to render screenshots with different emoji styles rather than the default emoji style provided by the ScreenshotOne API.

There are many emoji libraries out there that can help. For example, [emoji-js](https://www.npmjs.com/package/emoji-js) is a popular library that can be used to render emojis in different styles.

Note

Whatever library you decided to use, or whatever emoji style you decided to use, make sure you do not violate any license of the emoji set you are using.

E.g. if you use [emojis provided by Twitter](https://github.com/twitter/twemoji), you must follow their license requirements.

You can use it to replace emojis in the page with the desired style. E.g. you can replace all emojis with the emojis that look like Twitter emojis:

    1const stylesheet = document.createElement("link");2stylesheet.href = "https://cdn.jsdelivr.net/npm/emoji-js@3.8.1/lib/emoji.min.css";3stylesheet.rel = "stylesheet";4document.head.appendChild(stylesheet);5

    6const script = document.createElement("script");7script.onload = () => {8    // change to one you are interested in,9    // check the library documentation for the list of available emoji sets10    const img_set = "apple";11

    12    const emoji = new window.EmojiConvertor();13

    14    emoji.img_sets[img_set].path =15        `https://cdn.jsdelivr.net/npm/emoji-datasource-${img_set}@15.1.2/img/${img_set}/64/`;16    emoji.img_sets[img_set].sheet =17        `https://cdn.jsdelivr.net/npm/emoji-datasource-${img_set}@15.1.2/img/${img_set}/sheets/64.png`;18    emoji.img_set = img_set;19

    20    emoji.replace_mode = "img";21

    22    function replaceEmojisInTextNodes(node) {23        if (node.nodeType === Node.TEXT_NODE) {24            if (node.textContent && node.textContent.trim()) {25                const span = document.createElement("span");26                const replaced = emoji.replace_unified(node.textContent);27                span.innerHTML = replaced;28

    29                if (replaced.trim() !== node.textContent.trim()) {30                    const parent = node.parentNode;31                    if (parent) {32                        while (span.firstChild) {33                            parent.insertBefore(span.firstChild, node);34                        }35                        parent.removeChild(node);36                    }37                }38            }39        } else if (node.nodeType === Node.ELEMENT_NODE) {40            if (node.tagName === "SCRIPT" || node.tagName === "STYLE") {41                return;42            }43

    44            const childNodes = Array.from(node.childNodes);45            childNodes.forEach((child) => replaceEmojisInTextNodes(child));46        }47    }48

    49    replaceEmojisInTextNodes(document.body);50};51

    52script.src = "https://cdn.jsdelivr.net/npm/emoji-js@3.8.1/lib/emoji.min.js";53script.crossOrigin = "anonymous";54

    55document.body.appendChild(script);

To use this script with the ScreenshotOne API, you can use `scripts` parameter to pass a script that will be executed on the page after it is loaded, and it will be rendered in the screenshot:

    1https://api.screenshotone.com/take?access_key=<your_access_key>&url=<your_url>&scripts=<your_script>

Where `<your_script>` is the URL-encoded script above.

E.g. like this:

    1https://api.screenshotone.com/take?access_key=<your_access_key>&url=https://example.com&scripts=const%20stylesheet%20%3D%20document.createElement%28%27link%27%29%3B%0Astylesheet.href%20%3D%20%27https%3A%2F%2Fcdn.jsdelivr.net%2Fnpm%2Femoji-js%403.8.1%2Flib%2Femoji.min.css%27%3B%0Astylesheet.rel%20%3D%20%27stylesheet%27%3B%0Adocument.head.appendChild%28stylesheet%29%3B%0A%0Aconst%20script%20%3D%20document.createElement%28%27script%27%29%3B%0Ascript.onload%20%3D%20%28%29%20%3D%3E%20%7B%0A%20%20%20%20%2F%2F%20change%20to%20one%20you%20are%20interested%20in%2C%20%0A%20%20%20%20%2F%2F%20check%20the%20library%20documentation%20for%20the%20list%20of%20available%20emoji%20sets%0A%20%20%20%20const%20img_set%20%3D%20%27apple%27%3B%0A%0A%20%20%20%20const%20emoji%20%3D%20new%20window.EmojiConvertor%28%29%3B%20%20%20%20%0A%20%20%20%20%0A%20%20%20%20emoji.img_sets%5Bimg_set%5D.path%20%3D%20%60https%3A%2F%2Fcdn.jsdelivr.net%2Fnpm%2Femoji-datasource-%24%7Bimg_set%7D%4015.1.2%2Fimg%2F%24%7Bimg_set%7D%2F64%2F%60%3B%0A%20%20%20%20emoji.img_sets%5Bimg_set%5D.sheet%20%3D%20%60https%3A%2F%2Fcdn.jsdelivr.net%2Fnpm%2Femoji-datasource-%24%7Bimg_set%7D%4015.1.2%2Fimg%2F%24%7Bimg_set%7D%2Fsheets%2F64.png%60%3B%0A%20%20%20%20emoji.img_set%20%3D%20img_set%3B%0A%0A%20%20%20%20emoji.replace_mode%20%3D%20%27img%27%3B%0A%0A%20%20%20%20function%20replaceEmojisInTextNodes%28node%29%20%7B%0A%20%20%20%20%20%20%20%20if%20%28node.nodeType%20%3D%3D%3D%20Node.TEXT_NODE%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20%28node.textContent%20%26%26%20node.textContent.trim%28%29%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20const%20span%20%3D%20document.createElement%28%27span%27%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20const%20replaced%20%3D%20emoji.replace_unified%28node.textContent%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20span.innerHTML%20%3D%20replaced%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20%28replaced.trim%28%29%20%21%3D%3D%20node.textContent.trim%28%29%29%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20const%20parent%20%3D%20node.parentNode%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20%28parent%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20while%20%28span.firstChild%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20parent.insertBefore%28span.firstChild%2C%20node%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20parent.removeChild%28node%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%20else%20if%20%28node.nodeType%20%3D%3D%3D%20Node.ELEMENT_NODE%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20%28node.tagName%20%3D%3D%3D%20%27SCRIPT%27%20%7C%7C%20node.tagName%20%3D%3D%3D%20%27STYLE%27%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20const%20childNodes%20%3D%20Array.from%28node.childNodes%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20childNodes.forEach%28child%20%3D%3E%20replaceEmojisInTextNodes%28child%29%29%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20replaceEmojisInTextNodes%28document.body%29%3B%0A%7D%3B%0A%0Ascript.src%20%3D%20%27https%3A%2F%2Fcdn.jsdelivr.net%2Fnpm%2Femoji-js%403.8.1%2Flib%2Femoji.min.js%27%3B%0Ascript.crossOrigin%20%3D%20%27anonymous%27%3B%0A%0Adocument.body.appendChild%28script%29%3B

In case you have any issues, do not hesitate to reach out to us at [support@screenshotone.com](mailto:support@screenshotone.com).

----
url: https://screenshotone.com/use-cases/investor-and-board-reporting-decks
----

Automate Website Screenshots

1 min read

Investor and board reporting decks

==================================

Automatically reporting for investors and board members.

Ops teams often need fresh screenshots of competitor homepages every quarter, then spend an afternoon copy‑pasting them into the slide deck’s appendix. ScreenshotOne turns that chore into a single API call: schedule the URLs, let the service grab crisp full‑page images, and receive a ready‑to‑share PDF bundle—no browsers, no manual work.

[By the way, in case you need to generate a PDF from a Google Document or Slide, ScreenshotOne has you covered](/blog/google-docs-and-slides/).

Why ScreenshotOne PDF generation API?

-------------------------------------

[ScreenshotOne’s PDF‑generation endpoint](/pdf-generation-api/) captures each homepage in the exact resolution you specify, stitches the images into one neat document, and stores it for direct download or S3 push. Version control is built in: add a date stamp to the file name and your archive is complete for any future audit.

Value & Time Savings

--------------------

Automating the screenshot‑to‑PDF flow frees up hours of Ops time every quarter, eliminates copy‑paste errors, and guarantees the deck always contains the latest visuals. Analysts stay focused on insights, not formatting; execs get a clean, consistent appendix they can trust.

Kudos to the team for building ScreenshotOne. It's been more than 4 months now, and there's hardly been an outage/downtime.

ScreenshotOne handled even the rarest of edge cases where websites were loading slowly, which I found other products in the market failed to do.

Lastly, the support has been extremely top-notch, which is like a cherry on top.

Sankeerth Julapally

Founder, [GetWebsite.Report](https://screenshotone.com/blog/how-website-report-uses-screenshotone/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/full-page-chrome-extension
----

A Chrome Extension by ScreenshotOne for rendering full-page screenshots

=======================================================================

We just launched a new full-page screenshot Chrome extension that allows you to take full page screenshots of any websites and annotate them in a few clicks.

[Blog post](/blog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Dec 28, 2024

You don’t need to use ScreenshotOne API to render full-page screenshots. Use our [a new full-page screenshot Chrome extension](/tools/full-page-screenshot-chrome-extension/) instead:

 Sorry, your browser doesn't support embedded videos.

The extension is free to use and does not require any API key or subscription.

Why?

----

Many people find ScreenshotOne and use it for their simple screenshot needs—render a few full-page screenshots once in a while.

It loads our support and doesn’t bring much revenue, but since we try to help as many people as possible with screenshot automation, the extension we built seems a balanced solution:

1.  It allows to take full-page screenshots in a few clicks and don’t load the ScreenshotOne API and support.

2.  But in case if somebody of the extension users needs automation and using our API for that, then the extension could be a great magnet lead for that.

It is a win-win solution.

A free tool for full-page screenshots

-------------------------------------

There is [a free tool that uses ScreenshotOne API to render full-page screenshots](/tools/full-page-website-screenshot/).

What is the difference between the tool and the extension?

1.  Use the tool if you need to render a few full-page screenshots once in a while or from your mobile.

2.  The tool always uses the latest version of [our screenshot API](https://screenshotone.com/) which has the best algorithms for full-page screenshots and the best possible quality. However, the downside is that sometimes the API might be blocked. The extension solves that—if you rendered a website, you can use the extension to screenshot it.

3.  The tool is free to use and does not require any API key or subscription. It doesn’t send your data anywhere and doesn’t store anything.

When to use the screenshot API?

-------------------------------

Use [the screenshot API](https://screenshotone.com/) if you need to render full-page screenshots at scale or in your application/SaaS.

If you have any issues, feedback or questions, please, let us know at [support@screenshotone.com](mailto:support@screenshotone.com).

Read more posts

---------------

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

[View all posts](/blog/)

#### [ScreenshotOne made it to the official Make conference](/blog/make-conference/)

One of our friends noticed ScreenshotOne at the official Make conference

Read more

#### [Lessons learned from the AWS disruption](/blog/lessons-from-the-aws-us-east-1-disruption/)

Sharing thoughts and lessons learned from the AWS (us-east-1) disruption, including impact on ScreenshotOne.

Read more

#### [ScreenshotOne October 2025 updates](/blog/screenshotone-october-2025-updates/)

Metadata content format, upgraded dashboard, improved webhooks, updated Go SDK, Make conference, and AWS disruption lessons.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/a-complete-guide-on-how-to-take-full-page-screenshots-with-puppeteer-playwright-or-selenium
----

A complete guide on how to take full page screenshots with Puppeteer, Playwright or Selenium

============================================================================================

You can take a full page screenshot with Pupeeter by specifying the \`fullPage\` parameter as true when taking a screenshot. But there is a caveat. If a site has lazy-loaded images, they won't be rendered. Let's examine how to fix the issue and trigger lazy image loading with Puppeteer.

[Blog post](/blog/) 7 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Oct 19, 2022

If you don’t have time to read, proceed to the [“fix most issues at once”](#fixing-the-most-issues-at-once) section.

The problem is so painful and common that one of the most common questions you see in Google search results is “Puppeteer full page screenshot not working”. While it is not grammatically correct, it is valid literally.

Let’s list some issues you may encounter when taking a full-page screenshot with Puppeteer, Playwright, or Selenium:

*   triggering and waiting for lazy load images and other lazy load resources;

*   animations that are appeared and are played only at the time you scroll a page;

*   impossible to take the entire page screenshot of very long sites.

Let’s address them one-by-one by building a sophisticated solution that solves them all at once.

The pitfalls of taking full-page screenshots in Playwright, Selenium, or Puppeteer are the same. But I will use Puppeteer as the most popular library to demonstrate how to solve them.

Wait for lazy load images

-------------------------

Let’s take a full-page screenshot of the Apple site:

    1const puppeteer = require("puppeteer");2

    3(async () => {4    const browser = await puppeteer.launch({ headless: true });5    try {6        const page = await browser.newPage();7

    8        await page.setViewport({ width: 1280, height: 1024 });9        await page.goto("https://apple.com/", {10            waitUntil: ["load", "domcontentloaded"],11        });12

    13        await page.screenshot({14            type: "jpeg",15            path: "screenshot.jpeg",16            fullPage: true,17        });18    } catch (e) {19        console.log(e);20    } finally {21        await browser.close();22    }23})();

The site has lazy load images. It means they are not loaded until they are shown in the viewport—you need to scroll and view them to trigger loading. And Puppeteer, Playwright, or Selenium, by design, don’t support triggering the image load when taking a full-page screenshot.

Look at the result of the default behavior:

But it is relatively easy to fix by scrolling the page to the bottom and then taking a screenshot. Let’s do it and see what happens:

    1const puppeteer = require("puppeteer");2

    3(async () => {4    const browser = await puppeteer.launch({ headless: true });5    try {6        const page = await browser.newPage();7

    8        await page.setViewport({ width: 1280, height: 1024 });9        await page.goto("https://railway.app/", {10            waitUntil: ["load", "domcontentloaded"],11        });12

    13        await scroll(page);14

    15        await page.screenshot({16            type: "png",17            path: "screenshot.png",18            fullPage: true,19        });20    } catch (e) {21        console.log(e);22    } finally {23        await browser.close();24    }25})();26

    27async function scroll(page) {28    return await page.evaluate(async () => {29        return await new Promise((resolve, reject) => {30            var i = setInterval(() => {31                window.scrollBy(0, window.innerHeight);32                if (33                    document.scrollingElement.scrollTop + window.innerHeight >=34                    document.scrollingElement.scrollHeight35                ) {36                    window.scrollTo(0, 0);37                    clearInterval(i);38                    resolve();39                }40            }, 100);41        });42    });43}

You can check out the result, and it looks promising:

It works. But it is not the only pitfall you will encounter while taking full-page screenshots.

For example, you might encounter an infinite scroll issue, and how to solve it depends on your needs. Limiting the number of “scrolls” you perform is the easiest way. Or you might use a bit tricky but straightforward logic to detect infinite scroll. If you reach the bottom of the site and the site height suddenly increases, there is probably an endless scroll.

Animations are played only on the page scroll

---------------------------------------------

The approach we applied for lazy load images won’t work for sites with complex animations:

But the expected result is:

How can we achieve it? One of the easiest ways is to take site screenshots by sections and then merge all sections. It is pretty easy to do.

We need to install libraries to help us merging images:

Terminal window

    1npm i jimp merge-img

And then, we are going to scroll the site until the bottom, take a screenshot of each section and then merge them:

    1const puppeteer = require("puppeteer");2const merge = require("merge-img");3const Jimp = require("jimp");4

    5async function scrollDown(page) {6    return await page.evaluate(() => {7        window.scrollBy(0, window.innerHeight);8

    9        return (10            window.scrollY >=11            document.documentElement.scrollHeight - window.innerHeight12        );13    });14}15

    16function wait(milliseconds) {17    return new Promise((resolve) => {18        setTimeout(resolve, milliseconds);19    });20}21

    22(async () => {23    const browser = await puppeteer.launch({ headless: true });24    try {25        const page = await browser.newPage();26

    27        await page.goto(`https://apitoolkit.io/`);28

    29        const path = "screenshot.png";30

    31        const { pages, extraHeight, viewport } = await page.evaluate(() => {32            window.scrollTo(0, 0);33            const pageHeight = document.documentElement.scrollHeight;34            return {35                pages: Math.ceil(pageHeight / window.innerHeight),36                extraHeight:37                    (pageHeight % window.innerHeight) * window.devicePixelRatio,38                viewport: {39                    height: window.innerHeight * window.devicePixelRatio,40                    width: window.innerWidth * window.devicePixelRatio,41                },42            };43        });44

    45        const sectionScreenshots = [];46        for (let index = 0; index < pages; index += 1) {47            // wait until animations are played48            await wait(400);49

    50            const screenshot = await page.screenshot({51                type: "png",52                captureBeyondViewport: false,53            });54            sectionScreenshots.push(screenshot);55

    56            await scrollDown(page);57        }58

    59        if (pages === 1) {60            const screenshot = await Jimp.read(sectionScreenshots[0]);61            screenshot.write(path);62

    63            return screenshot;64        }65

    66        if (extraHeight > 0) {67            const cropped = await Jimp.read(sectionScreenshots.pop())68                .then((image) =>69                    image.crop(70                        0,71                        viewport.height - extraHeight,72                        viewport.width,73                        extraHeight74                    )75                )76                .then((image) => image.getBufferAsync(Jimp.AUTO));77

    78            sectionScreenshots.push(cropped);79        }80        const result = await merge(sectionScreenshots, { direction: true });81

    82        await new Promise((resolve) => {83            result.write(path, () => {84                resolve();85            });86        });87    } catch (e) {88        console.log(e);89    } finally {90        await browser.close();91    }92})();

Let’s test it:

And it works fine.

I set `captureBeyondViewport` to `false` to ensure that only the elements shown in the viewport are rendered. Otherwise, some elements might be stretched beyond the viewport and break screenshotting.

Taking the entire page screenshot of very long sites

----------------------------------------------------

Puppeteer or Playwright might stop taking full-page screenshots when the site is very long. In that case, the same idea used for [the animation issue](#animations-are-played-only-on-the-page-scroll) of taking screenshots by sections and merging them can help to handle the problem.

Fixing the most issues at once

------------------------------

Taking screenshots by sections is the best solution we might have today for taking the complete page screenshots:

    1const puppeteer = require("puppeteer");2const merge = require("merge-img");3const Jimp = require("jimp");4

    5async function scrollDown(page) {6    return await page.evaluate(() => {7        window.scrollBy(0, window.innerHeight);8

    9        return (10            window.scrollY >=11            document.documentElement.scrollHeight - window.innerHeight12        );13    });14}15

    16function wait(milliseconds) {17    return new Promise((resolve) => {18        setTimeout(resolve, milliseconds);19    });20}21

    22(async () => {23    const browser = await puppeteer.launch({ headless: true });24    try {25        const page = await browser.newPage();26

    27        await page.goto(`https://apitoolkit.io/`);28

    29        const path = "screenshot.png";30

    31        const { pages, extraHeight, viewport } = await page.evaluate(() => {32            window.scrollTo(0, 0);33            const pageHeight = document.documentElement.scrollHeight;34            return {35                pages: Math.ceil(pageHeight / window.innerHeight),36                extraHeight:37                    (pageHeight % window.innerHeight) * window.devicePixelRatio,38                viewport: {39                    height: window.innerHeight * window.devicePixelRatio,40                    width: window.innerWidth * window.devicePixelRatio,41                },42            };43        });44

    45        const sectionScreenshots = [];46        for (let index = 0; index < pages; index += 1) {47            // wait until animations are played48            await wait(400);49

    50            const screenshot = await page.screenshot({51                type: "png",52                captureBeyondViewport: false,53            });54            sectionScreenshots.push(screenshot);55

    56            await scrollDown(page);57        }58

    59        if (pages === 1) {60            const screenshot = await Jimp.read(sectionScreenshots[0]);61            screenshot.write(path);62

    63            return screenshot;64        }65

    66        if (extraHeight > 0) {67            const cropped = await Jimp.read(sectionScreenshots.pop())68                .then((image) =>69                    image.crop(70                        0,71                        viewport.height - extraHeight,72                        viewport.width,73                        extraHeight74                    )75                )76                .then((image) => image.getBufferAsync(Jimp.AUTO));77

    78            sectionScreenshots.push(cropped);79        }80        const result = await merge(sectionScreenshots, { direction: true });81

    82        await new Promise((resolve) => {83            result.write(path, () => {84                resolve();85            });86        });87    } catch (e) {88        console.log(e);89    } finally {90        await browser.close();91    }92})();

Let’s test the code for a different site that we haven’t checked before and ensure it works. There is a screenshot for Stripe:

Yes, it works. But from time to time, you may still encounter different issues. Each site is different, and they might add custom code that might break scrolling or other tricks that will break your logic. So, you need to constantly update the code and ensure it works and supports more and more sites.

Home exercise

-------------

Want to improve the algorithm and practice full page screenshot taking? Try to take a screenshot of the [Tesla](https://www.tesla.com/) website:

 Sorry, your browser doesn't support embedded videos.

The problem is that you scroll the site’s background, and there is no full page. Try to do it by yourself.

Alternatives

------------

So, what alternative is to render full-page screenshots when Puppeteer, Playwright, or Selenium can’t render them suitable?

Easy peasy. You can use a screenshot API as a service. Many [good screenshot APIs](https://screenshotone.com/the-best-screenshot-api/) might already solve your problem. As a maker of the such [screenshot as a service API](https://screenshotone.com/), I will show you how easy it is to use and the benefits you will receive as a bonus.

[Sign up](https://dash.screenshotone.com/sign-up) to get an access key and then take a screenshot as easy as sending an HTTP request:

    1https://api.screenshotone.com/take?url=https://apple.com&full_page=true

As you see the lazy load images are handled correctly:

Let’s test the problem with rendering animations by scrolling in and out of them:

    1https://api.screenshotone.com/take?url=https://apitoolkit.io&full_page=true

It works:

So, why waste time fixing all the problems with Puppeteer and not just using a simple API, especially when you can [start for free](https://screenshotone.com/)?

Summary

-------

In case you have time and energy to invest and to build screenshotting or HTML rendering infrastructure. I would go with Puppeetter or Playwright for full-page screenshots. Otherwise, you can save time and money by starting free with [a screenshot API](https://screenshotone.com/).

Additional resources

--------------------

Have a nice day 👋 and you also might find helpful 👉 [the complete guide on how to take a screenshot with Puppeteer](https://screenshotone.com/blog/how-to-take-a-screenshot-with-puppeteer/)

Read more posts

---------------

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

[View all posts](/blog/)

#### [Rendering screenshot with Browserless](/blog/browserless/)

A few words about what is Browserless, when to use it, and if it is suitable for screenshots or not.

Read more

#### [How to take a screenshot of the element with Puppeteer](/blog/how-to-take-a-screenshot-of-the-element-with-puppeteer/)

Puppeteer allows you to automate everything you can do in the browser manually and even more. You can take screenshots of the entire page and the specific elements.

Read more

#### [OpenAI 4o image generation and marketing opportunities](/blog/openai-4o-marketing-opportunities/)

OpenAI 4o image generation is a really good model that can change the way you automate marketing

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/integrations/openclaw
----

Integrations

1 min read

OpenClaw

========

Use ScreenshotOne to automate website screenshots inside OpenClaw workflows for visual checks, proactive monitoring, and image-based reporting.

AI Automation

Resources

---------

*   [Screenshots for OpenClaw](https://screenshotone.com/openclaw/)

*   [More about the use case of website screenshots in OpenClaw](https://screenshotone.com/use-cases/openclaw-workflows/)

*   [OpenClaw: Getting Started](https://docs.openclaw.ai/start/getting-started)

The best thing about [ScreenshotOne](/) is it just works!

With all the useful documentation in place and library support,it's very easy to setup ScreenshotOne.

On top of that, Dmytro's commitment towards improving the appmakes it an easy choice.

Rishi Mohan

Maker, [Pika.style](https://pika.style/)

Check more Integrations

-----------------------

No-code tools, AI, code libraries, and more.

[Check more Integrations](/integrations/)

Code API

### SDK and Code Examples

Use the SDKs and code examples to take screenshots in your own code.

[Read more →](/integrations/code/)

No-Code Automation

### Make

Use ScreenshotOne with Make to automate website screenshots, HTML as images, Markdown as images, PDFs, scrolling screenshots and videos.

[Read more →](/integrations/make/)

No-Code Automation

### Clay

Generate website screenshots inside Clay to qualify leads, assess content, and enrich rows with visual context automatically.

[Read more →](/integrations/clay/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/how-to-record-videos-with-puppeteer
----

How to record videos with Puppeteer

===================================

Let's quickly record a video with Puppeteer and see what upsides and downsides the native Puppeteer method of screencasting has. And how they can be tackled.

[Blog post](/blog/) 6 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Apr 9, 2024

#### Tags

[Puppeteer guides](/blog/tags/puppeteer-guides/)

A quickstart

------------

To record videos with Puppeteer use the `screencast` method on the `page` object:

    1import puppeteer from 'puppeteer';2

    3const browser = await puppeteer.launch();4

    5const page = await browser.newPage();6await page.goto("https://screenshotone.com");7

    8

    9const recorder = await page.screencast({path: 'recording.webm'});10

    11await recorder.stop();12

    13browser.close();

It requires [ffmpeg](https://ffmpeg.org/) to be installed and the latest version of Puppeteer.

But currently, the method is quite limited:

*   It doesn’t allow to record in different formats. However, you can convert the resulting file.

*   It doesn’t allow recording the video a stream, it writes to the file system—which might degrade your performance. However, you can write files in memory.

*   The number of options and codecs is limited.

But it does the job, and has a valuable method `crop`, if you want to record only a part of the screen.

You can use an external library to do the same for you and it has more advanced options.

Using the Puppeteer screen recorder library

-------------------------------------------

To generate a video with Puppeteer for page, we are going to use the [puppeteer-screen-recorder](https://www.npmjs.com/package/puppeteer-screen-recorder) library:

Terminal window

    1npm i puppeteer-screen-recorder

Let’s start with a simple example by generating a video for loading the landing page of [Tailwind CSS](https://tailwindcss.com/) and opening their pricing page:

    1"use strict";2

    3const puppeteer = require("puppeteer");4const { PuppeteerScreenRecorder } = require("puppeteer-screen-recorder");5

    6(async () => {7    const browser = await puppeteer.launch();8    try {9        const page = await browser.newPage();10        await page.setViewport({11            width: 1920,12            height: 1080,13            deviceScaleFactor: 2,14        });15

    16        const recorder = new PuppeteerScreenRecorder(page);17

    18        await page.goto("https://tailwindcss.com/");19

    20        await recorder.start("video.mp4");21        await animate(page);22        await recorder.stop();23    } catch (e) {24        console.log(e);25    } finally {26        await browser.close();27    }28})();29

    30const animate = async (page) => {31    await wait(500);32    await page.evaluate(() => {33        window.scrollBy({ top: 500, left: 0, behavior: "smooth" });34    });35    await wait(500);36    await page.evaluate(() => {37        window.scrollBy({ top: 1000, left: 0, behavior: "smooth" });38    });39    await wait(1000);40};41

    42const wait = (ms) => new Promise((res) => setTimeout(res, ms));

I added a simple one-time scroll to make the video interactive. Look at the result, how beautiful it is:

 Sorry, your browser doesn't support embedded videos.

You can generate videos in AVI, MP4, MOV, or WebM formats. You can use [WebM format if you target the latest versions of modern browsers, but not everyone supports it](https://caniuse.com/webm).

If you need to generate GIF (an image format, not video) for animated screenshots, you can use the [FFmpeg](https://ffmpeg.org/) library to convert MP4 to GIF. Make sure it is installed locally. And then you can upgrade your script to generate GIFs on demand:

    1"use strict";2

    3const puppeteer = require("puppeteer");4const { PuppeteerScreenRecorder } = require("puppeteer-screen-recorder");5const util = require("util");6const exec = util.promisify(require("child_process").exec);7

    8(async () => {9    const browser = await puppeteer.launch();10    try {11        const page = await browser.newPage();12        await page.setViewport({13            width: 1920,14            height: 1080,15            deviceScaleFactor: 2,16        });17

    18        const recorder = new PuppeteerScreenRecorder(page);19

    20        await page.goto("https://tailwindcss.com/");21

    22        await recorder.start("video.mp4");23        await animate(page);24        await recorder.stop();25

    26        await exec("ffmpeg -i video.mp4 -qscale 0 animated.gif");27    } catch (e) {28        console.log(e);29    } finally {30        await browser.close();31    }32})();33

    34const animate = async (page) => {35    await wait(500);36    await page.evaluate(() => {37        window.scrollBy({ top: 500, left: 0, behavior: "smooth" });38    });39    await wait(500);40    await page.evaluate(() => {41        window.scrollBy({ top: 1000, left: 0, behavior: "smooth" });42    });43    await wait(1000);44};45

    46const wait = (ms) => new Promise((res) => setTimeout(res, ms));

The result is:

Imagine how far you can go with animating screenshots. You can record movies and generate interactive mockups. It opens a new level of marketing for you. It is also a new level of debugging and generating reports for developers and QA automation engineers.

Use cases

---------

### Marketing with animated screenshots

You can generate [scrollable screenshots](https://screenshotone.com/scrolling-screenshots/) of the sites and apply them in many areas of your marketing:

*   send personalized emails with animated screenshots of the lead site;

*   place screenshots of parts of your site on your landing page;

*   make your blog posts interactive with scrollable preview screenshots of the sites you share;

*   And many more.

### Debug

In complex cases, if you run Puppetteer at production, you might want to debug what happens and record a video.

Imagine you scrape a site with a complex scenario by navigating through many pages. Something happens, and the script fails to scrape one of the pages.

Of course, the best way to debug is to reproduce the error locally, but if your environments are different, you can record a video of what happens in the script and review them.

But please, always synchronize your environments and ensure they are identical.

### Automate testing reports

One of the most beautiful use cases, for me, is to generate a video on how automated tests are executed and then, if the test fails, attach videos to the report. It might shorten communication time between the QA team and developers and improve the overall R&D velocity.

### Interactive mockups and programmatic movies

You can write simple scripts to make your site interactive. Scroll through it. And record the footage with Puppeteer.

And even more. You can generate cartoons and movies by using JavaScript and CSS! Only your imagination is the limit.

Use API to save time and energy

-------------------------------

If you don’t have time to implement and generate animated screenshots and deal with video streaming infrastructure, you can rely on [ScreenshotOne API](https://screenshotone.com/).

It supports [animated (including scrollable) screenshots](/docs/animated-screenshots/) of different types, caching based on the world’s fastest and most potent CDN (Cloudflare) and blocking ads, cookie banners, and chats.

In just one API request, you can quickly generate animated screenshots. And if you need more, a variety of options and use cases are covered.

Grasp how simple it is:

    1https://api.screenshotone.com/animate?url=https://tailwindcss.com&access_key=<your access key>

The result might differ a bit in case default options are changed, but as for now, it is similar to what I have shown in the video.

And the result is the same:

 Sorry, your browser doesn't support embedded videos.

The ScreenshotOne API also support rendering GIFs which is not possible with both Puppeteer and the external library.

Frequently Asked Questions

--------------------------

A few questions and answers as a summary:

**What are the limitations of using Puppeteer’s native screencast method for recording videos?**

Puppeteer’s native screencast method comes with several limitations:

1.  First, it restricts the video recording to a single format, though the recorded file can be converted to other formats using additional tools.

2.  Second, it only allows recording to the file system, which could potentially degrade performance, but there’s a workaround to write files in memory.

3.  Lastly, the number of options and codecs available for customization is limited.

However, it offers a useful crop method for recording specific parts of the screen.

**How does the puppeteer-screen-recorder library enhance the video recording capabilities over Puppeteer’s native method?**

The puppeteer-screen-recorder library significantly enhances video recording capabilities by providing more advanced options. It supports multiple video formats, including AVI, MP4, MOV, and WebM, catering to a broader range of browser compatibility and user needs. This flexibility allows for more diverse applications, such as generating interactive mockups or marketing materials, and can accommodate different project requirements more effectively than the native screencast method.

**Can Puppeteer be used for generating GIFs from video recordings, and what are the potential applications?**

Yes, Puppeteer can be used to generate GIFs from video recordings by leveraging the FFmpeg library to convert MP4 videos to GIF format. This capability opens up numerous creative and practical applications, such as enhancing marketing materials with animated screenshots, improving debugging and reporting for developers and QA engineers by visualizing issues, and creating interactive blog posts or emails. Generating GIFs allows for a wider range of expression and communication options, providing an innovative tool for engaging audiences and streamlining development processes.

Summary

-------

Start with the native Puppeteer method and if it doesn’t fit you, try the external library—[puppeteer-screen-recorder](https://www.npmjs.com/package/puppeteer-screen-recorder).

In the worst case, outsource the solution to ScreenshotOne for recording videos.

Read more Puppeteer guides

--------------------------

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

[View all posts](/blog/tags/puppeteer-guides/)

#### [How to render HTML with Puppeteer](/blog/how-to-render-html-with-puppeteer/)

Use Puppeteer or screenshot API to generate the Open Graph protocol images, bills, receipts, or invoices PDF or PNG files from the HTML templates.

Read more

#### [Puppeteer Performance Monitoring with Inspector](/blog/puppeteer-performance-monitoring-with-inspector/)

In this article I'll show you how to monitor performance and errors of a browser automation script written with Puppeteer.

Read more

#### [How to generate PDFs with Puppeteer](/blog/how-to-generate-pdf-with-puppeteer/)

A practical and working guide on how to generate PDFs with Puppeteer.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/how-to-use-proxy-per-page-with-puppeteer
----

How to use proxy per page with Puppeteer

========================================

It is easy to use proxy globally for the puppeteer instance, but there is a trick to use proxy on a per-page basis.

[Blog post](/blog/) 2 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Apr 29, 2025

#### Tags

[Puppeteer guides](/blog/tags/puppeteer-guides/)

Puppeteer allows you to automate everything you can do in the browser manually and even more. There are cases when you need to use a proxy. It is easy to use proxy globally for the puppeteer instance, but there is a trick to use proxy on a per-page basis.

In our \[screenshot API\](/) you just need to specify \[proxy option to take screenshots through proxy\](/docs/options#proxy).

Puppeteer plugin for proxying requests per page

-----------------------------------------------

### Installation and usage

Make sure you installed [the puppeteer library](https://www.npmjs.com/package/puppeteer) first:

Terminal window

    1npm i puppeteer

We are going to use an excellent plugin [puppeteer-page-proxy](https://www.npmjs.com/package/puppeteer-page-proxy) to solve the problem with proxy per page.

The plugin supports:

*   proxy per page and proxy per request;

*   `http`, `https`, `socks4` and `socks5` proxies;

*   authentication;

*   and cookies.

Install:

Terminal window

    1npm i puppeteer-page-proxy

Then you can import the library and use proxy on per-page basis:

    1const puppeteer = require("puppeteer");2const useProxy = require("puppeteer-page-proxy");3

    4(async () => {5    const browser = await puppeteer.launch({});6

    7    try {8        const page = await browser.newPage();9

    10        useProxy(page, "socks5://127.0.0.1:9876");11

    12        await page.goto("https://example.com/", {13            waitUntil: "networkidle0",14        });15

    16        await page.screenshot({ path: "example.com.png" });17    } catch (e) {18        console.log(e);19    } finally {20        await browser.close();21    }22})();

In this example I take a screenshot through proxy.

### Authentication

To use authentication with proxying, you need to specify user and password in your proxy connection URL:

    1const puppeteer = require("puppeteer");2const useProxy = require("puppeteer-page-proxy");3

    4(async () => {5    const browser = await puppeteer.launch({});6

    7    try {8        const page = await browser.newPage();9

    10        useProxy(page, "https://user:password@host:port");11

    12        await page.goto("https://example.com/", {13            waitUntil: "networkidle0",14        });15

    16        await page.screenshot({ path: "example.com.png" });17    } catch (e) {18        console.log(e);19    } finally {20        await browser.close();21    }22})();

### Proxy per request

You can go further and proxy on per request basis:

    1const puppeteer = require("puppeteer");2const useProxy = require("puppeteer-page-proxy");3

    4(async () => {5    const browser = await puppeteer.launch({});6

    7    try {8        const page = await browser.newPage();9

    10        await page.setRequestInterception(true);11        page.on("request", async (request) => {12            await useProxy(request, "https://127.0.0.1:443");13        });14

    15        await page.goto("https://example.com/", {16            waitUntil: "networkidle0",17        });18

    19        await page.screenshot({ path: "example.com.png" });20    } catch (e) {21        console.log(e);22    } finally {23        await browser.close();24    }25})();

This example is not different from the regular usage because we proxy every page request. But! Imagine you don’t want to load your proxy bandwidth and skip proxying images. This way, it becomes more valuable:

    1const puppeteer = require("puppeteer");2const useProxy = require("puppeteer-page-proxy");3

    4(async () => {5    const browser = await puppeteer.launch({});6

    7    try {8        const page = await browser.newPage();9

    10        await page.setRequestInterception(true);11        page.on("request", async (request) => {12            if (request.resourceType() === "image") {13                request.abort();14            } else {15                await useProxy(request, "socks4://127.0.0.1:1080");16            }17        });18

    19        await page.goto("https://example.com/", {20            waitUntil: "networkidle0",21        });22

    23        await page.screenshot({ path: "example.com.png" });24    } catch (e) {25        console.log(e);26    } finally {27        await browser.close();28    }29})();

The plugin covers as many cases as you can image.

Proxy taking screenshots with API

---------------------------------

If, in your case, you want to take screenshots or render HTML and you are OK with saving time and money, you can use our [screenshot API with proxy](/docs/options/#proxy) to take screenshots.

That’s it. If you want to check out [the complete guide on how to take screenshots with Puppeteer](/blog/how-to-take-a-screenshot-with-puppeteer/), you are welcome, and have a nice day!

Read more Puppeteer guides

--------------------------

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

[View all posts](/blog/tags/puppeteer-guides/)

#### [Capture beyond viewport in Puppeteer and Chrome DevTools Protocol](/blog/capture-beyond-viewport-in-puppeteer-and-chrome-devtools-protocol/)

Let's talk about the captureBeyondViewport parameter introduced in Chrome DevTools Protocol which will soon be supported by Puppeteer or even supported now at the time when you are reading the post.

Read more

#### [Uploading website screenshots to any S3-compatible storage](/blog/uploading-website-screenshots-to-any-s3-compatible-storage/)

In this note, I share how I take website screenshots or render HTML and upload the resulted images or PDF to any S3-compatible storage like Amazon S3, Cloudflare R2, or Backblaze B2.

Read more

#### [How to block requests with Puppeteer](/blog/how-to-block-requests-with-puppeteer/)

Puppeteer allows blocking any outgoing requests while loading the page. Whether you want to block ads, tracking scripts, or different types of resources, it is relatively easy to do with Puppeteer.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/take-a-screenshot-from-the-surface-in-puppeteer-and-chrome-devtools-protocol
----

Take a screenshot "from the surface" in Puppeteer and Chrome DevTools Protocol

==============================================================================

Let's talk about the fromSurface parameter introduced in Chrome DevTools Protocol which will soon be supported by Puppeteer or even supported now at the time when you are reading the post.

[Blog post](/blog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jan 3, 2023

#### Tags

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

When `fromSurface` is set to `true`, captures screenshot from the surface rather than the view. When it is set to `false`, works only in headful mode and ignores page viewport (but not browser window’s bounds). Defaults to `true`.

The option doesn’t make much sense when using headless mode. But to understand how it works, let’s execute the next code in the headful mode:

    1'use strict';2

    3const puppeteer = require('puppeteer');4(async () => {5    const browser = await puppeteer.launch({headless: false});6    try {7        const page = await browser.newPage();8        await page.setViewport({width: 1920, height: 1280});9

    10        await page.goto('https://screenshotone.com');11

    12        await page.screenshot({ path: 'from_surface_false.png', fromSurface: false});13    } catch (e) {14        console.log(e)15    } finally {16        await browser.close();17    }18})();

The window is opened, and it is size is limited by the default window size, but the viewport size is different, so that’s what you would see if you run the code:

So, when `fromSurface` is set to `false`, that’s how the screenshot will look like:

By the way, there is a few related articles you might be interested in:

1.  [Capture beyond viewport in Puppeteer and Chrome DevTools Protocol](/blog/capture-beyond-viewport-in-puppeteer-and-chrome-devtools-protocol).

2.  [Optimize for speed when rendering screenshots in Puppeteer and Chrome DevTools Protocol](/blog/optimize-for-speed-when-rendering-screenshots-in-puppeteer-and-chrome-devtools-protocol).

3.  [A complete guide on how to take full page screenshots with Puppeteer, Playwright or Selenium](/blog/puppeteer-full-page-screenshot).

Read more Puppeteer guides

--------------------------

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

[View all posts](/blog/tags/puppeteer-guides/)

#### [How to add custom styles to a page in Puppeteer](/blog/how-to-add-custom-styles-to-a-page-in-puppeteer/)

To add custom styles to any page use Puppeteer's page method \`page.addStyleTag(options)\`. Let's discover how it works quickly.

Read more

#### [What is a screenshot or HTML rendering API?](/blog/what-is-a-screenshot-or-html-rendering-api/)

A screenshot API or a screenshot as a service is usually a cloud or a remote server service that provides the ability to render any website, HTML, Markdown, or even PDF by making a request to the service, be it over HTTP, TCP, or any other protocol.

Read more

#### [How to screenshot websites in Next.js](/blog/nextjs-screenshots/)

There 3 simple ways to render website screenshots in Next.js—using Puppeteer, Cloudflare Browser Rendering, and a screenshot API like ScreenshotOne or similar.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/alexander-schnebel-about-how-he-uses-screenshotone-in-productglowup
----

Alexander Schnebel about how he uses ScreenshotOne in Productglowup

===================================================================

I had a great chat with Alexander Schnebel, the fullstack software engineer behind Productglowup.

[Blog post](/blog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jul 23, 2023

[Productglowup](https://www.productglowup.com/) is a service that helps creatives to quickly turn their Gumroad products into a custom product portfolio. And guess what? ScreenshotOne plays the key role in their marketing efforts.

Here’s what Alex had to share about his experience:

Questions and Answers

---------------------

### Could you introduce yourself and tell us a bit about your product?

I’m Alex, a fullstack software Engineer. I’m currently working on Productglowup.

### What are your use cases and favorite features, if any, of ScreenshotOne?

I’m currently using ScreenshotOne for demo purposes. When I reach out to potential customers, I create a demo Landing Page of the specific Gumroad product and use the ScreenshotOne API to render a preview of the landing page in the open graph image.

### How was your experience with integrating ScreenshotOne? How would you rate our product quality and customer support?

The integration and customization is really simple. I use the native `img` tag and reference the previously created landing page URL to get a screenshot. It’s fast and efficient.

Afterthoughts

-------------

Stories like Alex’s remind me why I developed ScreenshotOne. It’s not just about creating a screenshot API that’s fast and efficient. It’s about making things simpler for hard-working professionals. It’s about helping them focus on what they do best while ScreenshotOne takes care of the rest.

Stay tuned for more such engaging customer experiences.

Read more posts

---------------

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

[View all posts](/blog/)

#### [ScreenshotOne is featured in the Cloudflare "Built With" series](/blog/screenshotone-and-cloudflare/)

The Cloudflare platform is at the core of ScreenshotOne—it is used for caching, API gateway, storage for screenshots, and many other functions. It was an opportunity to learn about the company from a closer distance.

Read more

#### [Unveil the Power of Automation with ScreenshotOne and Zapier](/blog/unveil-the-power-of-automation-with-screenshotone-and-zapier/)

I am thrilled to announce an exciting update for the ScreenshotOne users – the much-anticipated integration of ScreenshotOne with Zapier. This powerful combination is here to enhance your automation journey and expand your workflow capabilities to new heights.

Read more

#### [How to set a time zone in Puppeteer for page](/blog/how-to-set-a-time-zone-in-puppeteer-for-page/)

Puppeteer allows changing the time zone on a per-page basis. In automation testing, you can use it to test how the website behaves for different time zones. Or you can use it for scrapping to imitate the user from the expected time zone by the site.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/screenshotone-moves-to-a-different-affiliate-program-provider
----

ScreenshotOne moves to a different affiliate program provider

=============================================================

I am really sorry but we moved our affiliate program to Tolt because Reflio is not in active maintenance anymore—it is a forced move.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Feb 11, 2024

My apologies to all affiliates of ScreenshotOne.

I have sent an email twice with an invite link to a new affiliate program to make sure that everybody received it.

Once I get data from Reflio, I will recalculate payouts manually and if any send them to relevant affiliates.

I also made sure that the new affiliate program worked by testing it a few times with real payment cards and browsers with blockers to navigate to a website and make a purchase.

I am grateful to you for being a partner for ScreenshotOne, and I hope will continue our partnership further.

Check out our affiliate program terms and you can sign up for the new program at [affiliates.screenshotone.com](https://affiliates.screenshotone.com/).

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [New organization role](/changelog/new-organization-role/)

Allow other members to manage your organization without transferring ownership.

Read more →

1 min read

#### [Improved errors](/changelog/improved-errors/)

Now, errors will have relevant documentation links. It will be also possible to see why some requests failed in the dashboard and get recommendations on how to address the issue.

Read more →

1 min read

#### [Improved API request log](/changelog/introducing-request-log/)

A new and improved request log has been deployed. That is a good beginning of the week! Check out why.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/about
----

About

=====

Hi, I am Dmytro Krasun, and I am a regular human behind ScreenshotOne. I am a software engineer with over a decade of experience in server-side development, high-load, big data, and distributed systems.

I created ScreenshotOne to offload the tedious tasks from developers and empower them to focus on more creative work. Rather than having headaches from dealing with headless browsers.

I launched ScreenshotOne at the end of May 2022, and since then, more than hundreds of users have signed up and have taken hundreds of thousands of screenshots.

The project has many paying customers and is profitable and self-sustainable. It is technically stable without significant downtimes, and I am excited about the product’s future as never before.

I have a massive roadmap for the product dictated by customers. And improve ScreenshotOne every day. If you have any propositions, ideas, or questions or want to chat, feel free to email me at `hey@screenshotone.com`.

----
url: https://screenshotone.com/changelog/screenshot-url
----

Screenshot URLs are now available in the response

=================================================

You can now get a screenshot URL in the response of the API call.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Jul 14, 2025

We have added a new field to the response of the API call: `screenshot_url`.

This field contains a URL to the screenshot of the rendered page.

Before the change, you needed to use cache to get the screenshot URL via the `cache_url` field. Now, you can get it directly in the response every time you request a screenshot with `response_type=json`.

Read more in [our documentation on how it works](/docs/screenshot-url/).

If you have any questions or need any assistance, please, reach out at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Improving performance and stability by consolidating validation and access check logic in the API gateway](/changelog/improving-performance-and-stability-by-consolidating-validation-and-access-check-logic-in-the-api-gateway/)

For the past few days, I have been working on improving the stability and performance of the ScreenshotOne API. I started from low-hanging fruits—moving validations and access key management from rendering services to ScreenshotOne's API gateway. The API will be more stable and performant as a result. If you are curious why, please continue reading.

Read more →

2 min read

#### [Documentation for LLMs](/changelog/docs-for-llms/)

ScreenshotOne now supports documentation format specifically targeted for LLMs—llms.txt and llms-full.txt.

Read more →

1 min read

#### [I migrated to Google Cloud](/changelog/i-migrated-to-google-cloud/)

Google Cloud gives $300 in credits for 3 months for experimenting. And I decided to give it a try, but not because of the free credits.

Read more →

4 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/embracing-the-future-of-web-archiving-with-screenshotone-api
----

Embracing the Future of Web Archiving with ScreenshotOne API

============================================================

Enter the ScreenshotOne API – a revolutionary tool designed to change the face of web archiving.

[Blog post](/blog/) 2 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Apr 17, 2023

As the online world continuously evolves, maintaining a lasting record of this digital progression is paramount. Web archiving - the practice of gathering and preserving web pages for future reference - becomes an increasingly crucial part of preserving our digital heritage. The dynamic nature of web content, however, presents a significant challenge to traditional web archiving methods. Enter the ScreenshotOne API – a revolutionary tool designed to change the face of web archiving.

The Significance of Web Archiving

---------------------------------

Web archiving is not just about storing web pages; it’s about creating a snapshot of the digital landscape as it exists at a particular moment. These records are an indispensable resource for businesses, researchers, historians, and anyone needing access to historical web data.

Given the transient nature of online content, valuable information can vanish overnight due to website updates, accidents, or intentional changes. Traditional web archiving methods often fall short in capturing this digital fluidity, leading to gaps in the historical record. This is where ScreenshotOne API comes into play.

How ScreenshotOne API is Reshaping Web Archiving

------------------------------------------------

The ScreenshotOne API is designed to capture real-time screenshots of any web page, providing an accurate visual representation of a page as it appears at a specific moment. This includes elements often missed with HTML archiving, such as interactive content, dynamic scripts, and ads.

Through the automation of the screenshot process, ScreenshotOne API provides a reliable and efficient way to archive web content. It allows for frequent snapshots of selected web pages, ensuring a complete and up-to-date record of your digital presence.

Integrating ScreenshotOne API into Your Web Archiving Strategy

--------------------------------------------------------------

Incorporating [ScreenshotOne API](https://screenshotone.com) into your web archiving strategy is a straightforward process:

1.  **Define Your Archiving Targets:** Identify the web pages you wish to archive. This could include your own web pages, competitor sites, significant news sites, influential blogs, or any other web page of interest.

2.  **Schedule Routine Screenshots:** [ScreenshotOne API](https://screenshotone.com) allows you to schedule automated snapshots at regular intervals - whether hourly, daily, weekly, or custom frequencies - to best suit your archiving needs.

3.  **Organize and Store Your Screenshots:** Once captured, screenshots can be systematically organized for easy access. Store them in cloud storage or on local servers, depending on your preference and data security policies.

With ScreenshotOne API, the shifting digital landscape no longer poses a threat to the integrity of your historical web records. You can build a comprehensive library of the web, a visual archive that stands firm even when the original content has changed or disappeared.

In Conclusion

-------------

[ScreenshotOne API](https://screenshotone.com) heralds a new era in web archiving. Its ability to capture the web as seen by users offers a more authentic and comprehensive approach to preserving our digital past. Its user-friendly implementation and customizable features make ScreenshotOne API a reliable solution to the transitory nature of online content.

Join us as we journey into the future of web archiving. Embrace the power of ScreenshotOne API and create a robust, reliable digital archive that stands the test of time.

Read more posts

---------------

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

[View all posts](/blog/)

#### [ScreenshotOne and viaSocket integration](/blog/screenshotone-and-viasocket-integration/)

Use viaSocket with ScreenshotOne to build workflows that include website screenshot automation.

Read more

#### [ScreenshotOne August 2025 updates](/blog/screenshotone-august-2025-updates/)

Playground presets, screenshot URL in webhooks, improved full‑page rendering, and ownership change for subscribed orgs.

Read more

#### [How to build a Programmatic SEO site with automated website screenshots using ScreenshotOne, Airtable, and Launchman](/blog/how-to-build-a-programmatic-seo-site-with-automated-website-screenshots-using-screenshotone-airtable-and-launchman/)

Programmatic SEO is a great growth hacking strategy where you create a large number of content pages that rank for long-tailed keywords on Google.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/screenshotone-external-identifier
----

Added support of external identifiers

=====================================

Check out how to use the external identifier to improve tracking of webhook executions.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Apr 25, 2025

ScreenshotOne API now supports the `external_identifier` parameter. It allows you to track requests and errors ([in webhooks](/docs/async-and-webhooks/)) by setting any alphanumeric value.

You will get the result as `x-screenshotone-external-identifier` header in the webhook request headers.

It is helpful for tracking screenshots or videos errors or successful renders in your application.

If you have any ideas, suggestions or issues on using this feature, please let us know at [support@screenshotone.com](mailto:support@screenshotone.com).

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [An improved screenshot history page](/changelog/an-improved-screenshot-history-page/)

Daily, I work as hard as I can to ensure that ScreeenshotOne is the best screenshot API out there possible. But I rarely share updates but trust me, a ton of them might go unnoticed. Let's fix this situation.

Read more →

1 min read

#### [Choose the full page screenshot algorithm](/changelog/full-page-algorithm/)

Now, you can choose the full page screenshot algorithm.

Read more →

1 min read

#### [Better error coverage and documentation](/changelog/all-errors-are-covered/)

Since a few months ago, it has been possible to check errors in the dashboard request log and get explanations and more details in the documentation. But!

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/full-page-screenshot-chrome-extension
----

Full-page screen capture by ScreenshotOne

=========================================

Add to Chrome

[](https://support.google.com/chrome_webstore/?hl=en-US&p=cws_badges)

Created by the owner of the listed website. The publisher has a good record with no history of violations. [Learn more.](https://support.google.com/chrome_webstore/?hl=en-US&p=cws_badges)

[screenshotone.com](https://screenshotone.com)

5.0([5 ratings](./detail/full-page-screen-capture/pojlibebgkalnapokkpiddephnjijjea/reviews))

Ratings are updated daily and may not reflect the most recent reviews.

Share

[Extension](./category/extensions)[Tools](./category/extensions/productivity/tools)1,000 users

Overview

------------

Render full-page screenshots as a single image. No more scrolling and resizing. Just click and download.

Take full-page screenshots of any website. Just click on the extension icon and select the type of capture. After that, you can annotate the captured screenshot with text/arrows and download the image. The extension supports PNG/JPEG image formats and a few capture types: 1. A full-page capture of the current page. 2. A full-page capture from the current position. 3. Capture the screenshot of the visible area only. Privacy: No ads and no network requests are made to any third-party services.

5 out of 5

5 ratings

[Learn more about results and reviews.](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results)

--------------------------------------------------------------------------------------------------------------------------------------------------

See all reviews[](./detail/full-page-screen-capture/pojlibebgkalnapokkpiddephnjijjea/reviews)

Details

-------

*   Version

    0.2.1

*   Updated

    January 9, 2025

*   [Flag concern](./detail/pojlibebgkalnapokkpiddephnjijjea/report)

*   Size

    279KiB

*   Languages

    English

*   Developer

    [Website](https://screenshotone.com) Email

    support@screenshotone.com

*   Non-trader

    This developer has not identified itself as a trader. For consumers in the European Union, please note that consumer rights do not apply to contracts between you and this developer.

Privacy

-------

Manage extensions and learn how they're being used in your organization

Try Chrome Enterprise Core

The developer has disclosed that it will not collect or use your data.

This developer declares that your data is

-----------------------------------------

*   Not being sold to third parties, outside of the [approved use cases](https://developer.chrome.com/docs/webstore/program-policies/limited-use/)

*   Not being used or transferred for purposes that are unrelated to the item's core functionality

*   Not being used or transferred to determine creditworthiness or for lending purposes

Support

-------

For help with questions, suggestions, or problems, visit the developer's [support site](https://screenshotone.com/support/)

Related

-------

[](./detail/fullcapture/pefhdagggemohjknegodpkblfdamoohc)

FullCapture

5.0

[](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Average rating 5 out of 5 stars.

[Learn more about results and reviews.](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Capture full webpage screenshots with ease

[](./detail/full-page-screenshot-pdfp/ojdlmlnhachhldfncijckajopjjgnoia)

Full-Page Screenshot PDF&PNG

5.0

[](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Average rating 5 out of 5 stars.

[Learn more about results and reviews.](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Take full-page screenshots free and securely in PDF or PNG

[](./detail/shotmypage-full-page-scre/aogdlbdnkgbeekfcgdcdlkknomfammgf)

ShotMyPage - Full Page Screen Capture

5.0

[](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Average rating 5 out of 5 stars.

[Learn more about results and reviews.](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Chrome full page screenshot and screen capture extension with professional editing tools and project management

[](./detail/fullpagesnap-full-page-sc/lndijinckcedmojaddbioalhmkknogmc)

FullPageSnap - Full Page Screenshot Capture

5.0

[](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Average rating 5 out of 5 stars.

[Learn more about results and reviews.](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Capture entire webpage screenshots with one click. Take full page screenshots, long screenshots & scrolling captures. PNG/JPEG

[](./detail/instascroll-full-page-scr/ebdmmkibdejonmmcadggfnkpgcpkmddf)

InstaScroll: Full Page Screenshots for Chrome

5.0

[](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Average rating 5 out of 5 stars.

[Learn more about results and reviews.](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Capture full-page screenshots

[](./detail/full-page-screenshot-capt/fbnbbolkneooclodhplkkepodfceaocb)

Full Page Screenshot Capture

5.0

[](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Average rating 5 out of 5 stars.

[Learn more about results and reviews.](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Capture full webpage screenshots with a single click. Simple, focused, and privacy-friendly.

[](./detail/full-page-screenshot/pdijbblchoddckbjignafhoehoecnhnm)

Full Page Screenshot

5.0

[](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Average rating 5 out of 5 stars.

[Learn more about results and reviews.](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Capture full page screenshots of web pages

[](./detail/snapfullpage-full-page-ca/cjfnnnhijjohmcbkahgkegpgjclnfegf)

SnapFullPage - Full Page Capture & Edit

5.0

[](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Average rating 5 out of 5 stars.

[Learn more about results and reviews.](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Increase productivity by taking full page screenshots in just a few seconds with SnapFullPage.

[](./detail/full-page-screen-capture/pmabjgjpcbofkbbeiphkiaanogobokgg)

Full Page Screen Capture

4.1

[](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Average rating 4.1 out of 5 stars.

[Learn more about results and reviews.](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Enable this extension to capture screenshots whether it's a visible screen, crop capture andfull-page screen

[](./detail/full-page-screenshot/aecnmadngpjbokeakinhbgfanlnjdnom)

Full Page Screenshot

4.6

[](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Average rating 4.6 out of 5 stars.

[Learn more about results and reviews.](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Full page screen capture is a simple extension that lets you capture the entire screen in one click. Get an entire page screenshot.

[](./detail/screen-capture/ceafoeioefanmdknapelbdaokbhgcpff)

Screen Capture

5.0

[](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Average rating 5 out of 5 stars.

[Learn more about results and reviews.](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

To capture entire current web page..

[](./detail/fullpage-blitz-lightning/nnhplomobinijgpongnbofokpibpbioa)

Fullpage Blitz - Lightning-Fast Full Screen Captures

5.0

[](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Average rating 5.0 out of 5 stars.

[Learn more about results and reviews.](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Capture full-screen scrolls at lightning speed, completing 6-10 pages in just 1 second

[](./detail/fullcapture/pefhdagggemohjknegodpkblfdamoohc)

FullCapture

5.0

[](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Average rating 5 out of 5 stars.

[Learn more about results and reviews.](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Capture full webpage screenshots with ease

[](./detail/full-page-screenshot-pdfp/ojdlmlnhachhldfncijckajopjjgnoia)

Full-Page Screenshot PDF&PNG

5.0

[](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Average rating 5 out of 5 stars.

[Learn more about results and reviews.](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Take full-page screenshots free and securely in PDF or PNG

[](./detail/shotmypage-full-page-scre/aogdlbdnkgbeekfcgdcdlkknomfammgf)

ShotMyPage - Full Page Screen Capture

5.0

[](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Average rating 5 out of 5 stars.

[Learn more about results and reviews.](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Chrome full page screenshot and screen capture extension with professional editing tools and project management

[](./detail/fullpagesnap-full-page-sc/lndijinckcedmojaddbioalhmkknogmc)

FullPageSnap - Full Page Screenshot Capture

5.0

[](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Average rating 5 out of 5 stars.

[Learn more about results and reviews.](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Capture entire webpage screenshots with one click. Take full page screenshots, long screenshots & scrolling captures. PNG/JPEG

[](./detail/instascroll-full-page-scr/ebdmmkibdejonmmcadggfnkpgcpkmddf)

InstaScroll: Full Page Screenshots for Chrome

5.0

[](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Average rating 5 out of 5 stars.

[Learn more about results and reviews.](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Capture full-page screenshots

[](./detail/full-page-screenshot-capt/fbnbbolkneooclodhplkkepodfceaocb)

Full Page Screenshot Capture

5.0

[](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Average rating 5 out of 5 stars.

[Learn more about results and reviews.](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Capture full webpage screenshots with a single click. Simple, focused, and privacy-friendly.

[](./detail/full-page-screenshot/pdijbblchoddckbjignafhoehoecnhnm)

Full Page Screenshot

5.0

[](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Average rating 5 out of 5 stars.

[Learn more about results and reviews.](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Capture full page screenshots of web pages

[](./detail/snapfullpage-full-page-ca/cjfnnnhijjohmcbkahgkegpgjclnfegf)

SnapFullPage - Full Page Capture & Edit

5.0

[](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Average rating 5 out of 5 stars.

[Learn more about results and reviews.](https://support.google.com/chrome_webstore/answer/12225786?p=cws_reviews_results&hl=en-US)

Increase productivity by taking full page screenshots in just a few seconds with SnapFullPage.

Google apps

----
url: https://screenshotone.com/use-cases/website-directories
----

Automate Website Screenshots

1 min read

Streamline Web Directory Submissions

====================================

Simplify the process of adding new sites to web directories.

Compiling a directory of website designs for inspiration proves invaluable to web developers and designers. ScreenshotOne API automates the capture of web page screenshots, facilitating the creation of a comprehensive inspiration gallery.

Support from ScreenshotOne API

------------------------------

Leveraging the screenshot API, developers can effortlessly automate the collection and organization of designs from a myriad of websites. This enables the creation of a diverse repository of web layouts, color themes, and interactive features for inspiration.

Advantages and Efficiency Gains

-------------------------------

The automation provided by ScreenshotOne in building a web design inspiration gallery saves extensive hours that would be otherwise spent in manual screenshot capture and organization. It provides an efficient, streamlined method for compiling design inspirations, boosting creativity and productivity.

We needed to build a side product, fast, we signed up and within minutes we were set up and had pulled over 400 picture-perfect screenshots for use in a new directory tool we were launching.

Alex Rainey

Founder, [My AskAI](https://myaskai.com/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/generating-landing-page-feedback-with-vision
----

How Elias Stråvik uses GPT-4 Vision and Zapier for landing page feedback automation

===================================================================================

A quick review of ScreenshotOne by Elias Stråvik, a founder of Roast as A Service on how he uses the ScreenshotOne daily to automate regular tasks associated with screenshots.

[Customer story](/blog/tags/customer-stories/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/), [Elias Stravik](/contributors/elias-stravik/)

#### Updated on

Mar 4, 2024

OpenAI GPT-4 Vision introduced new opportunities

------------------------------------------------

Using screenshot APIs like ScreenshotOne and OpenAI’s GPT-4 vision, marketing agents and landing page page optimization experts can now give better advice on how to improve landing pages.

ScreenshotOne take pictures of web pages. GPT-4 looks at these pictures to understand and critique the page’s design and text. This helps find and fix issues faster and share them with customers.

Automating landing page analysis

--------------------------------

Here is what Elias Stråvik, a founder of [Roast as a Service](https://www.roastasaservice.com/), shared with us:

“When OpenAI launched GPT-4 Vision I immediately thought that this would be great to give instant feedback to founders on their landing pages.

I wanted to launch an MVP in just a day or two to try it out and immediately ran into the problem of getting great screenshots of landing pages from a URL. It turned out that cookie banners, animations, and more often got in the way.

Then I found ScreenshotOne which had a fantastic integration with Zapier. It just immediately worked out of the box. Four weeks later, and hundreds of founders have had thousands of tests run on their landing pages. I couldn’t be a happier user of ScreenshotOne!”

More Examples and Use Cases

---------------------------

You might be also interested in how [Stagetimer automates Open Graph image generation](/blog/how-stagetimer-automates-og-image-generation/).

ScreenshotOne supports a huge variety of uses including but not only:

*   [Automating Open Graph image generation](/use-cases/open-graph-images/).

*   [Generating personalized videos](/use-cases/automate-personalized-videos/).

*   [Rendering site thumbnails for search previews](/use-cases/preview-search-results/)

And [many more](/use-cases/).

Read more customer stories

--------------------------

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

[View all posts](/blog/tags/customer-stories/)

#### [Why FrameKit chose ScreenshotOne for their business](/blog/framekit/)

A short story about how and why FrameKit chose ScreenshotOne for their use case.

Read more

#### [How RankPill uses ScreenshotOne](/blog/rankpill/)

Sharing how RankPill uses ScreenshotOne to automate website screenshot generation for SEO and GEO automation.

Read more

#### [How AdKit automated onboarding](/blog/adkit/)

A short story by the founder of AdKit about how they use ScreenshotOne for onboarding automation.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/bulk-screenshots-with-puppeteer
----

How to take bulk screenshots with Puppeteer

===========================================

Learn how to take screenshots of multiple URLs with Puppeteer, including concurrency management, error handling, retries, and proxy support.

[Blog post](/blog/) 8 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Dec 16, 2025

#### Tags

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

Taking screenshots of multiple URLs is a common requirement for [building website directories](/use-cases/website-directories/), monitoring tools, SEO analyzers, and [archiving systems](/use-cases/website-archivation/). While taking a single screenshot with [Puppeteer](how-to-take-a-screenshot-with-puppeteer) is straightforward, processing hundreds or thousands of URLs requires careful consideration of concurrency, error handling, and resource management.

In this guide, I will walk you through building a robust bulk screenshot solution with Puppeteer, from a basic sequential approach to a production-ready implementation with retries and proxy support.

Setting up the project

----------------------

You can skip that section if you already have a project where you want to add Puppeteer or it is already installed.

First, create a new Node.js project and install the required dependencies:

Terminal window

    1mkdir bulk-screenshots2cd bulk-screenshots3npm init -y4npm install puppeteer typescript ts-node @types/node

Create a `tsconfig.json`:

    1{2    "compilerOptions": {3        "target": "ES2020",4        "module": "commonjs",5        "strict": true,6        "esModuleInterop": true,7        "outDir": "./dist"8    }9}

Sequential processing

---------------------

> Make it work first. Make it fast. And then make it simple.

The simplest way to take bulk screenshots is to process URLs one by one:

    1import puppeteer from "puppeteer";2

    3const urls = ["https://example.com", "https://screenshotone.com"];4

    5async function takeScreenshots() {6    const browser = await puppeteer.launch();7

    8    for (const url of urls) {9        const page = await browser.newPage();10        await page.setViewport({ width: 1280, height: 800 });11        await page.goto(url, { waitUntil: "networkidle0" });12

    13        const filename = url.replace(/[^a-z0-9]/gi, "_") + ".png";14        await page.screenshot({ path: filename });15        await page.close();16

    17        console.log(`Screenshot saved: ${filename}`);18    }19

    20    await browser.close();21}22

    23takeScreenshots();

This approach works but has significant limitations:

1.  **Slow execution** — URLs are processed one at a time, wasting resources while waiting for pages to load.

2.  **No error handling** — A single failed URL stops the entire process.

3.  **No retry mechanism** — Temporary network issues cause permanent failures.

Concurrent processing

---------------------

To speed up bulk screenshots, we can process multiple URLs in parallel using a worker pool pattern:

    1import puppeteer, { Browser } from "puppeteer";2

    3const urls = ["https://example.com", "https://screenshotone.com"];4

    5const CONCURRENCY = 3;6

    7async function takeScreenshot(browser: Browser, url: string): Promise<void> {8    const page = await browser.newPage();9

    10    try {11        await page.setViewport({ width: 1280, height: 800 });12        await page.goto(url, { waitUntil: "networkidle0", timeout: 30000 });13

    14        const filename = url.replace(/[^a-z0-9]/gi, "_") + ".png";15        await page.screenshot({ path: filename });16

    17        console.log(`Success: ${url}`);18    } finally {19        await page.close();20    }21}22

    23async function processWithConcurrency() {24    const browser = await puppeteer.launch();25    const queue = [...urls];26

    27    async function worker() {28        while (queue.length > 0) {29            const url = queue.shift();30            if (url) {31                try {32                    await takeScreenshot(browser, url);33                } catch (error) {34                    console.error(`Failed: ${url}`, error);35                }36            }37        }38    }39

    40    const workers = Array(CONCURRENCY)41        .fill(null)42        .map(() => worker());43    await Promise.all(workers);44

    45    await browser.close();46}47

    48processWithConcurrency();

This implementation creates a pool of workers that continuously pull URLs from a shared queue. The `CONCURRENCY` constant controls how many screenshots are taken simultaneously.

Be careful with concurrency limits. Too many concurrent pages can exhaust system memory and cause crashes. Start with 3-5 concurrent workers and adjust based on your system resources.

Error handling and retries

--------------------------

If you plan to deploy it to production, consider covering the following errors and issues:

*   Network timeouts;

*   Pages returning error status codes (403, 429, 503);

*   Memory issues;

Here is an implementation with retry logic:

    1import puppeteer, { Browser, Page } from "puppeteer";2

    3interface ScreenshotResult {4    url: string;5    success: boolean;6    filepath?: string;7    error?: string;8}9

    10const MAX_RETRIES = 3;11const RETRY_DELAY = 1000;12

    13async function delay(ms: number): Promise<void> {14    return new Promise((resolve) => setTimeout(resolve, ms));15}16

    17function isRetryableError(error: unknown): boolean {18    if (error instanceof Error) {19        const retryableMessages = [20            "net::ERR_CONNECTION_RESET",21            "net::ERR_CONNECTION_REFUSED",22            "net::ERR_TIMED_OUT",23            "Navigation timeout",24        ];25        return retryableMessages.some((msg) => error.message.includes(msg));26    }27    return false;28}29

    30async function takeScreenshotWithRetry(browser: Browser, url: string): Promise<ScreenshotResult> {31    let lastError: unknown;32

    33    for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {34        const page = await browser.newPage();35

    36        try {37            await page.setViewport({ width: 1280, height: 800 });38            await page.goto(url, {39                waitUntil: "networkidle0",40                timeout: 30000,41            });42

    43            const filename = `screenshots/${url.replace(/[^a-z0-9]/gi, "_")}.png`;44            await page.screenshot({ path: filename });45

    46            return {47                url,48                success: true,49                filepath: filename,50            };51        } catch (error) {52            lastError = error;53

    54            if (!isRetryableError(error) || attempt === MAX_RETRIES) {55                break;56            }57

    58            console.log(`Retry ${attempt + 1}/${MAX_RETRIES} for ${url}`);59            await delay(RETRY_DELAY * (attempt + 1));60        } finally {61            await page.close();62        }63    }64

    65    return {66        url,67        success: false,68        error: lastError instanceof Error ? lastError.message : String(lastError),69    };70}

The retry logic uses exponential backoff (increasing delay between retries) and only retries on specific error types that are likely to be transient.

Using proxies for failed requests

---------------------------------

Some websites block requests from datacenter IPs or rate-limit aggressive crawlers. Using proxies can help bypass these restrictions. Check out [how to use proxy per page with Puppeteer](/blog/how-to-use-proxy-per-page-with-puppeteer/) for detailed proxy configuration.

Here is how to integrate proxy rotation into the retry logic:

    1import puppeteer, { Browser } from "puppeteer";2

    3const proxies = [4    "http://user:pass@proxy1.example.com:8080",5    "http://user:pass@proxy2.example.com:8080",6];7

    8async function takeScreenshotWithProxy(9    browser: Browser,10    url: string,11    proxyIndex: number12): Promise<ScreenshotResult> {13    const proxy = proxies[proxyIndex % proxies.length];14    const page = await browser.newPage();15

    16    try {17        await page.setViewport({ width: 1280, height: 800 });18

    19        await page.setRequestInterception(true);20        page.on("request", (request) => {21            request.continue();22        });23

    24        await page.goto(url, {25            waitUntil: "networkidle0",26            timeout: 30000,27        });28

    29        const filename = `screenshots/${url.replace(/[^a-z0-9]/gi, "_")}.png`;30        await page.screenshot({ path: filename });31

    32        return { url, success: true, filepath: filename };33    } catch (error) {34        return {35            url,36            success: false,37            error: error instanceof Error ? error.message : String(error),38        };39    } finally {40        await page.close();41    }42}

For proper per-page proxy support, you will need the [puppeteer-page-proxy](https://www.npmjs.com/package/puppeteer-page-proxy) package as described in [the proxy guide](/blog/how-to-use-proxy-per-page-with-puppeteer/).

Complete working example

------------------------

Here is a production-ready implementation that combines all the concepts:

    1import puppeteer, { Browser } from "puppeteer";2import * as fs from "node:fs/promises";3import * as path from "node:path";4

    5interface Config {6    concurrency: number;7    maxRetries: number;8    outputDirectory: string;9    viewport: {10        width: number;11        height: number;12    };13    timeout: number;14}15

    16interface ScreenshotResult {17    url: string;18    success: boolean;19    filepath?: string;20    error?: string;21    attempts: number;22}23

    24const config: Config = {25    concurrency: 3,26    maxRetries: 3,27    outputDirectory: "./screenshots",28    viewport: {29        width: 1280,30        height: 800,31    },32    timeout: 30000,33};34

    35const urls = ["https://example.com", "https://screenshotone.com"];36

    37function getFilename(url: string): string {38    const urlObj = new URL(url);39    const hostname = urlObj.hostname.replace(/\./g, "_");40    const pathname = urlObj.pathname.replace(/\//g, "_").replace(/^_/, "");41    return pathname ? `${hostname}${pathname}.png` : `${hostname}.png`;42}43

    44function isRetryableError(error: unknown): boolean {45    if (!(error instanceof Error)) return false;46    const retryable = [47        "net::ERR_CONNECTION",48        "net::ERR_TIMED_OUT",49        "Navigation timeout",50        "Protocol error",51    ];52    return retryable.some((msg) => error.message.includes(msg));53}54

    55async function delay(ms: number): Promise<void> {56    return new Promise((resolve) => setTimeout(resolve, ms));57}58

    59async function takeScreenshot(browser: Browser, url: string): Promise<ScreenshotResult> {60    let lastError: unknown;61    let attempts = 0;62

    63    for (let attempt = 0; attempt <= config.maxRetries; attempt++) {64        attempts = attempt + 1;65        const page = await browser.newPage();66

    67        try {68            await page.setViewport(config.viewport);69            await page.goto(url, {70                waitUntil: "networkidle0",71                timeout: config.timeout,72            });73

    74            const filename = getFilename(url);75            const filepath = path.join(config.outputDirectory, filename);76            await page.screenshot({ path: filepath });77

    78            return {79                url,80                success: true,81                filepath,82                attempts,83            };84        } catch (error) {85            lastError = error;86

    87            if (!isRetryableError(error) || attempt === config.maxRetries) {88                break;89            }90

    91            await delay(1000 * (attempt + 1));92        } finally {93            await page.close();94        }95    }96

    97    return {98        url,99        success: false,100        error: lastError instanceof Error ? lastError.message : String(lastError),101        attempts,102    };103}104

    105async function processUrls(urls: string[]): Promise<ScreenshotResult[]> {106    const browser = await puppeteer.launch({107        args: ["--disable-setuid-sandbox", "--disable-dev-shm-usage", "--no-first-run"],108    });109

    110    await fs.mkdir(config.outputDirectory, { recursive: true });111

    112    const queue = [...urls];113    const results: ScreenshotResult[] = [];114

    115    async function worker(): Promise<void> {116        while (queue.length > 0) {117            const url = queue.shift();118            if (!url) continue;119

    120            console.log(`Processing: ${url}`);121            const result = await takeScreenshot(browser, url);122            results.push(result);123

    124            if (result.success) {125                console.log(`Success: ${url} -> ${result.filepath}`);126            } else {127                console.log(`Failed: ${url} - ${result.error}`);128            }129        }130    }131

    132    const workers = Array(config.concurrency)133        .fill(null)134        .map(() => worker());135

    136    await Promise.all(workers);137    await browser.close();138

    139    return results;140}141

    142async function main() {143    console.log(`Processing ${urls.length} URLs with concurrency ${config.concurrency}`);144

    145    const results = await processUrls(urls);146

    147    const successful = results.filter((r) => r.success).length;148    const failed = results.filter((r) => !r.success).length;149

    150    console.log(`\nCompleted: ${successful} successful, ${failed} failed`);151

    152    if (failed > 0) {153        console.log("\nFailed URLs:");154        results.filter((r) => !r.success).forEach((r) => console.log(`  ${r.url}: ${r.error}`));155    }156}157

    158main().catch(console.error);

Run this with `npx ts-node index.ts` and it will process all URLs concurrently with retry support.

In case, if you plan to render full-page screenshots, check out [the complete guide on how to take full page screenshots with Puppeteer, Playwright, or Selenium](/blog/a-complete-guide-on-how-to-take-full-page-screenshots-with-puppeteer-playwright-or-selenium/) for detailed instructions on handling lazy loading and other corner cases.

ScreenshotOne API as an alternative

-----------------------------------

Building and maintaining your own bulk screenshot infrastructure requires handling many edge cases: cookie banners, anti-bot protection, proxy management, browser crashes, memory leaks, and more. [ScreenshotOne](/) provides a managed API that handles all of this complexity.

You can use a [bulk screenshots endpoint](/docs/bulk-screenshots/) that can process multiple URLs in a single request or for more complex bulk processing with retries and concurrency management, check out our [bulk screenshots guide](/docs/guides/bulk-screenshots/).

A few nuances on why and when use ScreenshotOne:

*   **No infrastructure to manage**: No need to run and maintain headless browsers, handle crashes, or manage server resources.

*   **Built-in caching**. Screenshots [are cached if requested](/docs/caching/), reducing costs for repeated requests.

*   **Cookie banners and ads blocking** — Built-in features to hide cookie banners, ads and more block ads without additional configuration compared to [doing with Puppeteer](/blog/how-to-hide-cookie-banners-when-taking-a-screenshot-with-puppeteer/).

*   **S3 storage integration**. You can upload screenshots directly to [any S3-compatible storage](/docs/guides/upload-to-s3/).

*   **Concurrency management**. The API manages concurrency limits and queuing automatically.

*   **SDKs for multiple languages** and many more [integrations](/integrations/).

But:

*   **Monthly cost**. However, there is a cost compared to self-hosted solutions, though often cheaper than running your own infrastructure at scale.

*   **Third-party dependency**. Your application depends on an external service availability.

*   **Less browser control**. Some advanced browser configurations may not be available. But you can reach to our support at `support@screenshotone.com` and we will try to help you as fast as possible.

Summary

-------

Taking bulk screenshots with Puppeteer requires careful consideration of:

1.  **Concurrency**: process multiple URLs in parallel but respect system limits.

2.  **Error handling**: implement retry logic with exponential backoff.

3.  **Proxies**: use proxy rotation for blocked or rate-limited sites.

4.  **Resource management**: close pages properly and monitor memory usage.

For production workloads, consider using [ScreenshotOne API](/) which handles all these complexities out of the box, letting you focus on your application logic instead of infrastructure management.

Read more Puppeteer guides

--------------------------

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

[View all posts](/blog/tags/puppeteer-guides/)

#### [How to Take Screenshots with pyppeteer in Python](/blog/pyppeteer-python-screenshots/)

Guide to taking screenshots with pyppeteer in Python. Learn the basics, full page captures, and why you should migrate to Playwright.

Read more

#### [How to take website screenshots with Java](/blog/how-to-take-website-screenshots-with-java/)

The article examines how you can take screenshots of any URL with Java by using Selenium, Puppeteer alternatives, Playwright, or screenshot API as a service.

Read more

#### [3 best screenshot APIs in 2026](/blog/best-screenshot-apis/)

The truth is, that there is no single best screenshot API that fits everyone. But some APIs stand out and shine when compared to others. Also, it depends on your use case and needs which must be included in considering what API to use.

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/better-numbers-formatting-in-the-dashboard
----

Better numbers formatting in the dashboard

==========================================

We improve UI/UX of rendering numbers in the dashboard for better readability.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Apr 19, 2025

It is a minor improvement, but it is a step towards the better UI/UX and more pleasant experience for you with the ScreenshotOne dashboard:

In every possible place where numbers are rendered, we now show them in a more readable format.

If you have any feedback or suggestions, please let us know at [support@screenshotone.com](mailto:support@screenshotone.com).

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Added support of Slack notifications](/changelog/slack-notifications/)

We added support of Slack notifications to ScreenshotOne. Now you can set up and get Slack notifications when you reach your quota limits.

Read more →

1 min read

#### [Improved error handling when networking fails](/changelog/improved-error-handling-when-networking-fails/)

We have improved error handling for network failures. Now, we ensure screenshot rendering fails instead of returning an error image.

Read more →

1 min read

#### [Improved webhooks documentation and playground](/changelog/improved-webhooks-documentation-and-playground/)

We improved the webhooks documentation and playground.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/errors/request-body-too-large
----

[Skip to content](#_top)

Request Body Too Large

======================

Copy page

It is an API error returned when the API fails to serve the request due to internal reasons:

    1{2    "is_successful": false,3    "error_message": "The request body is too large. Please, reduce the size of the request body or reach out to `support@screenshotone.com` for assistance.",4    "error_code": "request_body_too_large",5    "documentation_url": "https://screenshotone.com/docs/errors/request-body-too-large/"6}

How to fix

----------

Reduce the size of the request body. It should be no more than 50MB.

Reach out to support

--------------------

If nothing helps you, please, reach out to `support@screenshotone.com` and we will try to help you as fast as possible.

----
url: https://screenshotone.com/changelog/cli-integration
----

ScreenshotOne CLI is available

==============================

Use command line interface to automate screenshots in your workflows with ScreenshotOne.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Dec 8, 2025

We have released a new [ScreenshotOne CLI](/integrations/cli/).

With ScreenshotOne CLI, you can:

*   render website screenshots from the command line;

*   generate PDFs from HTML or URLs;

*   create scrolling screenshots and videos;

*   run it anywhere with Docker;

*   and more…

The CLI is available on [GitHub](https://github.com/screenshotone/cli) and [Docker Hub](https://hub.docker.com/r/screenshotone/cli), as of now.

If you have any questions or need any assistance, please, reach out at `support@screenshotone.com`.

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Fail ScreenshotOne API requests on purpose](/changelog/fail-if-request-failed/)

Use a new option to fail ScreenshotOne API requests on purpose.

Read more →

1 min read

#### [Rendering website screenshots in LLMs](/changelog/mcp-server/)

Integrate ScreenshotOne to render website screenshots with any LLM that supports MCP.

Read more →

3 min read

#### [Add ScreenshotOne to n8n workflows](/changelog/n8n-integration/)

You can now use ScreenshotOne in n8n workflows to render website screenshots, PDFs, scrolling screenshots and videos.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog/full-page-algorithm
----

Choose the full page screenshot algorithm

=========================================

Now, you can choose the full page screenshot algorithm.

[Changelog](/changelog/) 1 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Published on

Oct 29, 2024

ScreenshotOne API now allows you to choose the full page screenshot algorithm. It wasn’t available before, and most of the time the API was guessing the best algorithm automatically.

Use [the `full_page_algorithm` option](/docs/options#full_page_algorithm) to choose the algorithm. The default value is `default`.

The `default` algorithm is the same as the one used in the Chrome DevTools Protocol, with some tuning and for some websites with different optimizations.

But if you set `full_page_algorithm=by_sections`, the API will take a screenshot section by section and then combine them into one image.

It allows more complex pages with animations to be rendered correctly.

The `by_sections` will scroll the website automatically regardless of the [full\_page\_scroll](#full_page_scroll) option value.

If you have any questions or suggestions, feel free to contact us at [support@screenshotone.com](mailto:support@screenshotone.com).

Read more product updates

-------------------------

New features, bug fixes, and optimizations...

[View all product updates](/changelog/)

#### [Documentation for LLMs](/changelog/docs-for-llms/)

ScreenshotOne now supports documentation format specifically targeted for LLMs—llms.txt and llms-full.txt.

Read more →

1 min read

#### [Detect any website fonts with a ScreenshotOne API](/changelog/detect-any-website-fonts-with-a-screenshotone-api/)

Now you can detect fonts used by any website with ScreenshotOne API in just one simple API call.

Read more →

1 min read

#### [Better error coverage and documentation](/changelog/all-errors-are-covered/)

Since a few months ago, it has been possible to check errors in the dashboard request log and get explanations and more details in the documentation. But!

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/pricing
----

"Great support."

"It brings reliability to our business."

"It works like a charm."

Pricing

Start rendering  

for free

--------------------------

Cancel anytime, without any questions.  

Try **all the features** with 100 free screenshots.

Payment frequency

Monthly

Annually (2 months free)

### Basic

$17per month

The essentials to start rendering screenshots today.

*   2,000 screenshots

*   40 requests per minute

*   $0.009 per extra[](/docs/charging-extra)

*   Pay only for successful requests

*   Block ads and cookie banners

*   Render PDFs[](/pdf-generation-api/)

*   PNG, WebP, JPEG, and more

*   HTML rendering

*   Full page screenshots

*   Caching[](/docs/caching/)

*   Upload to S3[](/docs/upload-to-s3/)

*   Zapier, Make, and similar[](/integrations/)

*   Webhooks[](/docs/async-and-webhooks/)

*   Signed links[](/docs/signed-requests/)

*   Stealth mode

[Try for free →](https://dash.screenshotone.com/sign-up)

### Growth

Recommended

$79per month

A plan that scales with your rapidly growing business.

*   10,000 screenshots

*   80 requests per minute

*   $0.006 per extra[](/docs/charging-extra)

*   Pay only for successful requests

*   Block ads and cookie banners

*   Render PDFs[](/pdf-generation-api/)

*   PNG, WebP, JPEG, and more

*   HTML rendering

*   Full page screenshots

*   Caching[](/docs/caching/)

*   Upload to S3[](/docs/upload-to-s3/)

*   Zapier, Make, and similar[](/integrations/)

*   Webhooks[](/docs/async-and-webhooks/)

*   Signed links[](/docs/signed-requests/)

*   Stealth mode

*   Choose IP location

*   Scrolling screenshots[](/scrolling-screenshots/)

*   Generate videos[](/docs/animated-screenshots/)

[Try for free →](https://dash.screenshotone.com/sign-up)

### Scale

$259per month

Prioritized support and infrastructure for your company.

*   50,000 screenshots

*   150 requests per minute

*   $0.004 per extra[](/docs/charging-extra)

*   Pay only for successful requests

*   Block ads and cookie banners

*   Render PDFs[](/pdf-generation-api/)

*   PNG, WebP, JPEG, and more

*   HTML rendering

*   Full page screenshots

*   Caching[](/docs/caching/)

*   Upload to S3[](/docs/upload-to-s3/)

*   Zapier, Make, and similar[](/integrations/)

*   Webhooks[](/docs/async-and-webhooks/)

*   Signed links[](/docs/signed-requests/)

*   Stealth mode

*   Choose IP location

*   Scrolling screenshots[](/scrolling-screenshots/)

*   Generate videos[](/docs/animated-screenshots/)

*   GPU rendering

*   Priority Support

[Try for free →](https://dash.screenshotone.com/sign-up)

**No credit card required.** Prices don't include VAT.  

Need more screenshots? Request →

Guillaume Barillot

CTO, [Deepidoo](https://www.deepidoo.com/en/)

> Awesome product that-just-works™. Took me 10 minutes to add it to my (Rails) stack. Simple pricing. Great support. If you need something like a "Screenshot as a Service" API. Give it a try!

[Read more customer stories →](/blog/tags/customer-stories/)

Frequently Asked Questions

--------------------------

Discover quick and comprehensive answers to common questions about our platform, services, and features.

Do failed screenshots count against the limitation on the plan?

No. Only screenshots that are successfully rendered (without HTTP, browser, or network errors) and not served from cache count toward your quota. Screenshots with visual issues still count toward your quota, but if you report a defect caused by our algorithms rather than the source, we will review it for a refund.

Is it a free service for taking screenshots?

Yes, ScreenshotOne is a free screenshot API. You can take up to 100 screenshots of any URL for free per month, including rendering HTML and PDF.

Is ScreenshotOne the best screenshot API?

Yes, it is certainly one of [the best screenshot APIs](/blog/best-screenshot-apis/). And we are working hard to keep it so.

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/use-cases/educational-font-detection
----

Automate Website Screenshots

1 min read

Educational Font Detection Tool

===============================

Use our font detection API to enable students to explore and learn from typography used in real-world web applications.

Use [ScreenshotOne font detection API](/font-detection-api/) to build educational features in web design learning platforms or tutorials, enabling students to explore and learn from the typography used in real-world web applications.

Learning from Real Examples

---------------------------

Web design students benefit greatly from analyzing how professional websites use typography. ScreenshotOne’s font detection API allows educational platforms to create interactive learning experiences where students can examine the typography choices of successful websites.

Hands-On Typography Education

-----------------------------

By integrating the API, educational tools can offer students the ability to inspect any website’s fonts with a single click. This hands-on approach helps students understand how typography principles are applied in practice, bridging the gap between theory and real-world application.

Check out [our guide on how to detect website fonts](/docs/guides/how-to-detect-website-fonts/) for more details.

Enhanced Learning Experience

----------------------------

Rather than building complex font detection systems from scratch, educational platform developers can integrate ScreenshotOne API to provide instant typography analysis. This allows them to focus on creating engaging educational content while offering students powerful analysis tools that would otherwise require significant development resources.

I found ScreenshotOne through an AI agent (great GEO btw 😁), you had good docs and looked solid, had it up and running and working in 10 minutes, with Cursor.

Modern premium site screenshots on publish with extensive easy configuration like browser with + height, hiding certain elements very easy (like our branding) by targeting et

Anatoly Pashias

Co-Founder, [Framekit](https://screenshotone.com/blog/framekit/)

Check more Use Cases

--------------------

Analyzing screenshots with AI, using screenshots for marketing purposes and more.

[Check more Use Cases](/use-cases/)

### Font Accessibility Checks

Use our font detection API to check fonts and and research whether websites use readable fonts for people with visual impairments or reading disabilities.

[Read more →](/use-cases/font-accessibility-checks/)

### Font Legal Compliance Check

Ensure fonts used on websites are legally compliant to avoid copyright issues.

[Read more →](/use-cases/font-legal-compliance/)

### Personalized Onboarding

Personalize onboarding by analyzing a customer's website visually and using screenshots throughout the setup flow.

[Read more →](/use-cases/personalized-onboarding/)

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/errors/invalid-header-parameter
----

[Skip to content](#_top)

Invalid Header Parameter

========================

Copy page

It is an API error returned when the `headers` parameter is invalid.

    1{2    "is_successful": false,3    "error_message": "The `headers` parameters you provided are invalid. Please, consider providing different values and adhere to the format specified in the ScreenshotOne documentation.",4    "error_code": "invalid_header_parameter",5    "documentation_url": "https://screenshotone.com/docs/errors/invalid-header-parameter/"6}

Reasons and how to fix

----------------------

### The format of the parameter is invalid

Make sure you adhere to the format specified in the [ScreenshotOne options documentation](https://screenshotone.com/docs/options/#headers). If you sent a GET request, your headers must be in the query string as:

    1headers=name1:val1&headers=name2:val2

If you sent a POST request, your headers must be in the request body as:

    1{2    // ...3    "headers": ["name1:val1", "name2:val2"]4    // ...5}

Reach out to support

--------------------

If you continue to face issues, please reach out to `support@screenshotone.com`, and we will assist you as soon as possible.

----
url: https://screenshotone.com/contributors/dmytro-krasun/7
----

Dmytro Krasun

-------------

With more than a decade of experience in software engineering, I share the best practices and solutions you can apply to your problems in the space of headless browsers. You can also find me on [Twitter](https://twitter.com/DmytroKrasun) and [LinkedIn](https://www.linkedin.com/in/dmytrokrasun)

View all Changelog

#### [Unveil the Power of Automation with ScreenshotOne and Zapier](/blog/unveil-the-power-of-automation-with-screenshotone-and-zapier/)

I am thrilled to announce an exciting update for the ScreenshotOne users – the much-anticipated integration of ScreenshotOne with Zapier. This powerful combination is here to enhance your automation journey and expand your workflow capabilities to new heights.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jun 1, 2023

•

2 min read

#### [Embracing the Future of Web Archiving with ScreenshotOne API](/blog/embracing-the-future-of-web-archiving-with-screenshotone-api/)

Enter the ScreenshotOne API – a revolutionary tool designed to change the face of web archiving.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Apr 17, 2023

•

2 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots with C# (.NET)](/blog/how-to-take-website-screenshots-with-csharp-dotnet/)

The article examines how you can take screenshots of any URL with C# (.NET) by using PuppeteerSharp, or screenshot API as a service.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 24, 2023

•

3 min read

#### [A friendly guide on how to render HTML or site screenshots in Google Sheets in less than 10 minutes](/blog/a-friendly-guide-on-how-to-render-html-or-site-screenshots-in-google-sheets-in-less-than-10-minutes/)

It is not the first time that one of the ScreenshotOne users asked how to render screenshots in Google Sheets. I wrote a simple but complete tutorial once and for all.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 5, 2023

•

3 min read

#### [Optimize for speed when rendering screenshots in Puppeteer and Chrome DevTools Protocol](/blog/optimize-for-speed-when-rendering-screenshots-in-puppeteer-and-chrome-devtools-protocol/)

Let's talk about the optimizeForSpeed parameter introduced in Chrome DevTools Protocol which will soon be supported by Puppeteer or even supported now at the time when you are reading the post.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 4, 2023

•

1 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [Take a screenshot "from the surface" in Puppeteer and Chrome DevTools Protocol](/blog/take-a-screenshot-from-the-surface-in-puppeteer-and-chrome-devtools-protocol/)

Let's talk about the fromSurface parameter introduced in Chrome DevTools Protocol which will soon be supported by Puppeteer or even supported now at the time when you are reading the post.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 3, 2023

•

1 min read

[PDF rendering](/blog/tags/pdf-rendering/)

#### [How to convert HTML to PDF in JavaScript](/blog/how-to-convert-html-to-pdf-in-javascript/)

Nowadays, you have various options to generate PDFs from HTML or any given URL: generating PDF in the browser, on the server-side (Node.js), or even using a modern and friendly API to generate PDF.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

May 2, 2025

•

3 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [Capture beyond viewport in Puppeteer and Chrome DevTools Protocol](/blog/capture-beyond-viewport-in-puppeteer-and-chrome-devtools-protocol/)

Let's talk about the captureBeyondViewport parameter introduced in Chrome DevTools Protocol which will soon be supported by Puppeteer or even supported now at the time when you are reading the post.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Jan 1, 2023

•

3 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots in Python](/blog/how-to-take-website-screenshots-in-python/)

With Python, you can take website screenshots in multiple ways. But the best way to do it depends solely on your needs and your use case. Let's quickly examine all the options.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Mar 18, 2024

•

8 min read

[Screenshot rendering](/blog/tags/screenshot-rendering/)

#### [How to take website screenshots in Ruby](/blog/how-to-take-website-screenshots-in-ruby/)

Let's examine what Ruby proposes for us to render HTML or URL as a screenshot dynamically.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Dec 15, 2022

•

5 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [How to record videos with Puppeteer](/blog/how-to-record-videos-with-puppeteer/)

Let's quickly record a video with Puppeteer and see what upsides and downsides the native Puppeteer method of screencasting has. And how they can be tackled.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Apr 9, 2024

•

6 min read

#### [Open Graph images](/blog/open-graph-images/)

You can control the preview image rendered when your site is shared on social media, messengers, or apps that support the Open Graph protocol.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Updated on

Jan 21, 2026

•

12 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/tools/website-screenshot
----

Make website screenshot

-----------------------

Render screenshots website online for free and without registration.

[Tools](/tools/) Free Website Screenshots

--------------------------

Discover quick and comprehensive answers to common questions about our platform, services, and features.

What is this website screenshotter tool about?

The website screenshot taker is a free tool by ScreenshotOne that captures website screenshots online. You can get any website screenshot without registration and hassle.

Why is it free to render website screenshots?

It is not free to run that tool. But the tool is built for demonstration purposes to see what's possible to do with ScreenshotOne. The main audience for ScreenshotOne is developers who seek a screenshot API that can automate website screenshotting.

What is ScreenshotOne?

ScreenshotOne is one of the best screenshot APIs in the market which allows you to automate website screenshots fast and renders them with good enough quality.

Integrate today

Automate screenshot rendering with the language you love

--------------------------------------------------------

Send simple HTTP requests or use native libraries for your language of choice.

Java Go Node.js PHP Python Ruby C# (.NET)

    1// add com.screenshotone.jsdk:screenshotone-api-jsdk:[1.0.0,2.0.0)2// to your `pom.xml` or `build.gradle`3

    4import com.screenshotone.jsdk.Client;5import com.screenshotone.jsdk.TakeOptions;6

    7import java.io.File;8import java.nio.file.Files;9

    10public class App {11    public static void main(String[] args) throws Exception {12        final Client client = Client.withKeys("<access key>", "<secret key>");13        TakeOptions takeOptions = TakeOptions.url("https://example.com")14                .fullPage(true)15                .deviceScaleFactor(1)16                .viewportHeight(1200)17                .viewportWidth(1200)18                .format("png")19                .omitBackground(true);20        final String url = client.generateTakeUrl(takeOptions);21

    22        System.out.println(url);23        // Output: https://api.screenshotone.com/take?url=...24

    25        // or download the screenshot26        final byte[] image = client.take(takeOptions);27

    28        Files.write(new File("./example.png").toPath(), image);29        // the screenshot is stored in the example.png file30    }31}

    1// go get github.com/screenshotone/gosdk2

    3import screenshots "github.com/screenshotone/gosdk"4

    5client, err := screenshots.NewClient("<access key>", "<secret key>")6// check err7

    8options := screenshots.NewTakeOptions("https://example.com").9    Format("png").10    FullPage(true).11    DeviceScaleFactor(2).12    BlockAds(true).13    BlockTrackers(true)14

    15u, err := client.GenerateTakeURL(options)16// check err17

    18fmt.Println(u.String())19// Output: https://api.screenshotone.com/take?url=...20

    21// or download the screenshot22image, err := client.Take(context.TODO(), options)23// check err24

    25defer image.Close()26out, err := os.Create("example.png")27// check err28

    29defer out.Close()30io.Copy(out, image)31// the screenshot is stored in the example.png file

    1// $ npm install screenshotone-api-sdk --save2

    3import * as fs from 'fs';4import * as screenshotone from 'screenshotone-api-sdk';5

    6// create API client7const client = new screenshotone.Client("<access key>", "<secret key>");8

    9// set up options10const options = screenshotone.TakeOptions11    .url("https://example.com")12    .delay(3)13    .blockAds(true);14

    15// generate URL16const url = client.generateTakeURL(options);17console.log(url);18// expected output: https://api.screenshotone.com/take?url=...19

    20// or download the screenshot21const imageBlob = await client.take(options);22const buffer = Buffer.from(await imageBlob.arrayBuffer());23fs.writeFileSync("example.png", buffer)24// the screenshot is stored in the example.png file

    1<?php2

    3// composer require screenshotone/sdk:^1.04

    5use ScreenshotOneSdkClient;6use ScreenshotOneSdkTakeOptions;7

    8$client = new Client("<access key>", "<secret key>");9

    10$options = TakeOptions::url("https://example.com")11    ->fullPage(true)12    ->delay(2)13    ->geolocationLatitude(48.857648)14    ->geolocationLongitude(2.294677)15    ->geolocationAccuracy(50);16

    17$url = $client->generateTakeUrl($options);18echo $url.PHP_EOL;19// expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com...20

    21$image = $client->take($options);22file_put_contents('example.png', $image);23// the screenshot is stored in the example.png file

    1# pip install screenshotone2

    3import shutil4from screenshotone import Client, TakeOptions5

    6# create API client7client = Client('<access key>', '<secret key>')8

    9# set up options10options = (TakeOptions.url('https://screenshotone.com')11    .format("png")12    .viewport_width(1024)13    .viewport_height(768)14    .block_cookie_banners(True)15    .block_chats(True))16

    17# generate the screenshot URL and share it with a user18url = client.generate_take_url(options)19# expected output: https://api.screenshotone.com/take?url=https%3A%2F%2Fscreenshotone.com&viewport_width=1024&viewport_height=768&block_cookie_banners=True&block_chats=True&access_key=&signature=6afc9417a523788580fa01a9f668ea82c78a9d2b41441d2a696010bf2743170f20

    21# or render a screenshot and download the image as stream22image = client.take(options)23

    24# store the screenshot the example.png file25with open('example.png', 'wb') as result_file:26    shutil.copyfileobj(image, result_file)

    1# Add this gem to your Gemfile:2# gem 'screenshotone'3

    4# If you don't need to add a signature5client = ScreenshotOne::Client.new('<access key>')6

    7# Or ff you do need to add a signature8client = ScreenshotOne::Client.new('<access key>', '<secret key>')9

    10# You can set any available option, in a camel_case format, for example:11options = ScreenshotOne::TakeOptions.new(url: 'https://example.com').12            full_page(true).13            delay(2).14            geolocation_latitude(48.857648).15            geolocation_longitude(2.294677).16            geolocation_accuracy(50)17

    18# Verify all the parameters are valid (we will validate the parameters that should be19# numeric, booleans or that accept only certain values)20options.valid?21=> true22

    23# To simply get the final url:24client.generate_take_url(options)25=> "https://api.screenshotone.com/take?url=https%3A%2F%2Fexample.com..."26

    27# To actually get the image (the response body of a request to the previous url)28client.take(options)29=> "\xFF\xD8\xFF\xE0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xFF\..."

    1// Add the library via nuget using the package manager console: PM> Install-Package ScreenshotOne.dotnetsdk2// Or from the .NET CLI as: dotnet add package ScreenshotOne.dotnetsdk3

    4// And generate a screenshot URL without executing request:5var client = new Client("<access key>", "<secret key>");6var options = TakeOptions.Url("https://www.amazon.com")7  .FullPage(true)8  .Format(Format.PNG)9  .BlockCookieBanners(true);10

    11var url = client.GenerateTakeUrl(options);12// url = https://api.screenshotone.com/take?url=https%3A%2F%2Fwww.amazon.com&full_page=true&format=png&block_cookie_banners=true&access_key=_OzqMIjpCw-ARQ&signature=8a08e62d13a5c3490fda0734b6707791d3decc9ab9ba41e8cc045288a39db50213

    14// Or take a screenshot and save the image in the file:15var client = new Client("<access key>", "<secret key>");16var options = TakeOptions.Url("https://www.google.com")17  .FullPage(true)18  .Format(Format.PNG)19  .BlockCookieBanners(true);20

    21var bytes = await client.Take(options);22

    23File.WriteAllBytes(@"c:\temp\example.png", bytes);

Mike Roberts

Founder, [SpyFu](https://www.spyfu.com/)

> ScreenshotOne is the best product on the market - and that's before you take into account how responsive and easy Dmytro is to work with.

> 

> Any time we've found a rare edge case, it's been resolved in hours.

> 

> Great company, great founder - can't say enough!

Without writing a line of code

No-code integrations

--------------------

Quickly render website screenshots with Zapier, Airtable, Make and other popular no-code platforms of your choice.

[](/integrations/zapier/)[](/integrations/airtable/)[](/integrations/make/)[](/integrations/bubble/)[](/integrations/n8n/)

Read

Lessons from running screenshot rendering infrastructure

--------------------------------------------------------

Practical guides and real updates based on our experience operating rendering infrastructure at production scale.

[Playwright guides](/blog/tags/playwright-guides/)

#### [Playwright "Execution context was destroyed": how to fix navigation and page.evaluate errors](/blog/playwright-execution-context-was-destroyed-most-likely-because-of-a-navigation/)

Fix the Playwright "Execution context was destroyed, most likely because of a navigation" error after click, form submit, redirect, reload, or page.evaluate.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 13, 2026

•

4 min read

[Puppeteer guides](/blog/tags/puppeteer-guides/)

#### [page.waitForTimeout is not a function in Puppeteer](/blog/page-waitfortimeout-is-not-a-function-in-puppeteer/)

Puppeteer removed page.waitForTimeout(). Learn why the error happens and which modern alternatives to use instead.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 13, 2026

•

2 min read

#### [OpenClaw with Playwright or Puppeteer: how to install browser support](/blog/openclaw-playwright-puppeteer/)

A practical guide to OpenClaw browser automation, why Playwright is the documented path, where Puppeteer fits, how to make screenshots, and when ScreenshotOne is the better choice for screenshot-only flows.

Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

Published on

Mar 12, 2026

•

6 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/openclaw
----

What is OpenClaw and how can it help?

=====================================

A short practical introduction to OpenClaw, what it is good at, and why it is useful if you want a proactive AI assistant that lives in your chat apps.

[Blog post](/blog/) 3 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Mar 12, 2026

[OpenClaw](https://openclaw.ai/) is an AI assistant platform built around a simple idea: your assistant should live where you already work and message, not inside one more isolated dashboard.

Instead of opening a separate app every time, you can interact with OpenClaw through channels like WhatsApp, Telegram, Discord, and iMessage. It is also self-hosted, which makes it especially appealing if you want more control over data, tools, and workflows.

If you are comparing it with NemoClaw, read [NemoClaw an enterprise alternative to OpenClaw by NVIDIA](/blog/openclaw-alternative-by-nvidia/). That post focuses more on the enterprise-oriented positioning around NemoClaw and how it differs from OpenClaw.

What OpenClaw actually is

-------------------------

OpenClaw is not just a chat wrapper around an LLM. It is better understood as a gateway for an always-on assistant that can:

*   stay connected to messaging apps;

*   keep context and memory across conversations;

*   run tools and workflows;

*   browse the web;

*   trigger actions in the background;

*   route tasks across different agents or skills.

That combination is what makes it interesting. The value is not only that it can answer questions, but that it can actually do work and report back inside channels you already check all day.

Why OpenClaw is useful

----------------------

The biggest appeal of OpenClaw is convenience plus control.

On the convenience side, it makes AI feel more like a persistent operator than a tab you open occasionally. You can message it quickly, ask it to check something later, let it watch for updates, or have it summarize and follow up.

On the control side, OpenClaw is attractive because it is self-hosted and local-first in spirit. For many developers, operators, founders, and technical teams, that matters a lot more than flashy demos. It means:

*   your setup can be tailored to your own tools and workflows;

*   your assistant can stay closer to your own infrastructure;

*   you are not limited to whatever one hosted AI product decides to support.

Where OpenClaw can help in practice

-----------------------------------

OpenClaw is especially useful when you want an assistant that is both conversational and operational.

Examples:

*   monitoring websites, products, or competitor pages and sending updates;

*   preparing daily or weekly summaries;

*   running browser tasks and confirming results;

*   coordinating recurring research workflows;

*   acting as a personal or team operations assistant inside chat.

That makes it more practical than many AI tools that are good at answering prompts but weak at staying present in day-to-day work.

Why people like the chat-first model

------------------------------------

There is a real difference between “an AI app” and “an AI you can message.”

When the assistant lives inside channels like Telegram or WhatsApp, the friction drops a lot. You do not have to switch context as much, and it becomes easier to treat the assistant as something persistent rather than something occasional.

That is one of OpenClaw’s strongest ideas. It makes AI feel less like a separate destination and more like infrastructure for your day-to-day work.

Where ScreenshotOne fits

------------------------

If your OpenClaw workflows touch the web, screenshots are often part of the output. Instead of building browser rendering yourself, keep that part separate and use [ScreenshotOne](/openclaw/) for visual capture.

Check out our guide on [how to use OpenClaw with Playwright or Puppeteer](/blog/openclaw-playwright-puppeteer/), in case you are interested in adding browser capabilities to OpenClaw.

The short version is here: [Screenshots for OpenClaw Workflows](/use-cases/openclaw-workflows/).

Final thoughts

--------------

OpenClaw is helpful because it combines three things that are usually split apart: chat-native access, operational workflows, and self-hosted control.

If that is the shape of assistant you want, OpenClaw is worth a serious look.

Frequently Asked Questions

--------------------------

If you read the article, but still have questions. Please, check the most frequently asked. And if you still have questions, feel free reach out at [support@screenshotone.com](mailto:support@screenshotone.com).

### What is OpenClaw?

OpenClaw is a self-hosted AI assistant that connects to chat apps like WhatsApp, Telegram, Discord, and iMessage and can run tools, workflows, and browser tasks.

### Who is OpenClaw for?

OpenClaw is useful for people and teams who want a proactive assistant they control themselves instead of a closed hosted product.

Read more posts

---------------

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

[View all posts](/blog/)

#### [Using Clobbr to quickly load test the ScreenshotOne API](/blog/using-clobbr-to-quickly-load-test-the-screenshotone-api/)

Google Cloud gives $300 in credits for 3 months for experimenting. And I decided to give it a try, but not because of the free credits.

Read more

#### [Building a website directory with Next.js, Tailwind CSS, and Prisma](/blog/building-a-website-directory-with-nextjs-tailwind-css-and-prisma/)

See how easy it is to build a website directory with screenshots with Next.js, Tailwind CSS, and Prisma.

Read more

#### [OpenAI 4o image generation and marketing opportunities](/blog/openai-4o-marketing-opportunities/)

OpenAI 4o image generation is a really good model that can change the way you automate marketing

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/blog/puppeteer-wait-until-the-page-is-ready
----

Puppeteer waitUntil: how to wait for page load

==============================================

Join me in exploring how to find the ideal wait time or event of when to take the page screenshot with Puppeteer.

[Blog post](/blog/) 8 min read

#### Written by

[Dmytro Krasun](/contributors/dmytro-krasun/)

#### Updated on

Mar 13, 2026

#### Tags

[Puppeteer guides](/blog/tags/puppeteer-guides/) [Screenshot rendering](/blog/tags/screenshot-rendering/)

A short and quick answer

------------------------

While waiting a fixed period of time is a bad practice, in the real world, it is hard to find a solution that works well in all cases.

In order to take a screenshot when the page is fully loaded and rendered, one of the most working combination is to set `waitUntil` for the `page.goto()` function to `domcontentloaded` and wait a bit before taking a screenshot:

    1const puppeteer = require("puppeteer");2

    3(async () => {4    const browser = await puppeteer.launch({});5    try {6        const page = await browser.newPage();7

    8        // viewport and device scale factor of my laptop9        await page.setViewport({10            width: 2880,11            height: 1800,12            deviceScaleFactor: 2,13        });14

    15        await page.goto("https://finance.yahoo.com/", {16            timeout: 15 * 1000,17            waitUntil: ["domcontentloaded"],18        });19

    20        await page.screenshot({ path: "finance.yahoo.com.png" });21    } catch (e) {22        console.error(e);23    } finally {24        await browser.close();25    }26})();

[Avoid using `page.waitForTimeout()`, it is not a good practice and the method is removed](/blog/page-waitfortimeout-is-not-a-function-in-puppeteer/).

While `waitUntil` with `domcontentloaded` might work for most scenarios with `networkidle0` or `networkidle2`, there are [caveats](#caveats).

Without waiting

---------------

If you are interested, there is [a deep dive guide on how to take screenshots with Puppeteer](/blog/how-to-take-a-screenshot-with-puppeteer/).

Let’s take a simple screenshot without waiting for any event and see what happens.

Install `Puppeteer`:

    1npm i puppeteer

And as an example, I will take a screenshot of the [Yahoo Finance](https://finance.yahoo.com) site. It has a lot of widgets, and they are loaded asynchronously, so it will be indicative that we can’t take the screenshot right away.

Let’s take a screenshot without any waiting options:

    1const puppeteer = require("puppeteer");2

    3(async () => {4    const browser = await puppeteer.launch({});5    try {6        const page = await browser.newPage();7        // viewport and device scale factor of my laptop8        await page.setViewport({9            width: 2880,10            height: 1800,11            deviceScaleFactor: 2,12        });13

    14        let response = await page.goto("https://finance.yahoo.com/");15        if (!response) {16            response = await page.waitForResponse(() => true, {17                timeout: 15 * 1000,18            });19        }20

    21        const status = response.status();22        if (status !== 200) {23            throw new Error(`Unexpected status code: ${status}`);24        }25

    26        await page.screenshot({ path: "finance.yahoo.com.png" });27    } catch (e) {28        console.error(e);29    } finally {30        await browser.close();31    }32})();

And the result is:

You can see that the widgets on the right are not loaded, but we take a screenshot anyway. It is half-backed — it is not good. Let’s improve it.

Delay

-----

The simplest, but not the best solution is to wait for some amount of time before taking a screenshot:

    1const puppeteer = require("puppeteer");2

    3(async () => {4    const browser = await puppeteer.launch({});5    try {6        const page = await browser.newPage();7

    8        // viewport and device scale factor of my laptop9        await page.setViewport({10            width: 2880,11            height: 1800,12            deviceScaleFactor: 2,13        });14

    15        await page.goto("https://finance.yahoo.com/");16

    17        // wait for 15 seconds before taking the screenshot18        await new Promise((resolve) => setTimeout(resolve, 15000));19

    20        await page.screenshot({ path: "finance.yahoo.com.png" });21    } catch (e) {22        console.error(e);23    } finally {24        await browser.close();25    }26})();

And the result is OKish:

Now, we see the widgets on the right.

By the way, the ads are probably not loaded because headless browsers might block them, and the video is not loaded because Puppeteer uses Chromium which does not support the rendering of `MP4` videos.

Why is it not good to use delay before taking a screenshot? It does not scale:

*   time varies on your Internet connection;

*   different sites have different loading times;

*   rendering time also varies on the machine load.

You can safely use this simple approach if you need to take one or two screenshots occasionally for well-known sites and with big enough delays.

Puppeteer page.goto() waitUntil options

---------------------------------------

With some exceptions, the most optimal and bullet-proof approach is to specify the `waitUntil` parameter when calling `page.goto()`.

The `page.goto()` function accepts an instance of the `WaitForOptions` type, which is defined as:

    1export declare interface WaitForOptions {2    /**3     * Maximum wait time in milliseconds, defaults to 30 seconds, pass `0` to4     * disable the timeout.5     *6     * @remarks7     * The default value can be changed by using the8     * {@link Page.setDefaultTimeout} or {@link Page.setDefaultNavigationTimeout}9     * methods.10     */11    timeout?: number;12    waitUntil?: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[];13}14

    15export declare type PuppeteerLifeCycleEvent = 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2';

Let’s consider the definition of which accepted value in the `waitUntil` property of the `WaitForOptions` type:

*   `load` : the navigation is successful when the load even is fired;

*   `domcontentloaded`: the navigation is finished when the `DOMContentLoaded` even is fired;

*   `networkidle0`: the navigation is finished when there are no more than 0 network connections for at least `500` ms;

*   `networkidle2`: consider navigation to be finished when there are no more than 2 network connections for at least `500` ms.

You might specify an array of expected events. This way `page.goto()` will resolve after all events are fired.

Specifying the `timeout` option is supercritical. By default, it is 30000 milliseconds — 30 seconds. If events are not resolved within this time, `page.goto()` will throw an error.

### Difference between networkidle0 and networkidle2

With these options, `Puppeteer` waits for the network idle.

Use `networkidle0` for sites that loaded once and then don’t send requests. An example is a SPA without any background activities.

While `networkidle2` is suitable for applications with open connections and sends requests after the page is loaded. Imagine observing a trading graph in real time on an exchange site.

There is a also separate method in `Puppeteer` to wait for the network idle:

    1class Page {2    waitForNetworkIdle(options?: {3        idleTime?: number;4        timeout?: number;5    }): Promise<void>;6}

Wait until DOMContentLoaded

---------------------------

Let’s try to use wait for page until the `DOMContentLoaded` event occurs and see if it helps, to render the [Finance Yahoo](https://finance.yahoo.com) page correctly:

    1const puppeteer = require("puppeteer");2

    3(async () => {4    const browser = await puppeteer.launch({});5    try {6        const page = await browser.newPage();7        // viewport and device scale factor of my laptop8        await page.setViewport({9            width: 2880,10            height: 1800,11            deviceScaleFactor: 2,12        });13

    14        await page.goto("https://finance.yahoo.com/", {15            timeout: 15 * 1000,16            waitUntil: ["domcontentloaded"],17        });18

    19        await page.screenshot({ path: "finance.yahoo.com.png" });20    } catch (e) {21        console.error(e);22    } finally {23        await browser.close();24    }25})();

It does not help a lot:

Probably, because after the DOMContentLoaded event occurred, they sent another request for widgets. Let’s try with both events and `networkidle2`:

    1const puppeteer = require("puppeteer");2

    3(async () => {4    const browser = await puppeteer.launch({});5    try {6        const page = await browser.newPage();7

    8        // viewport and device scale factor of my laptop9        await page.setViewport({10            width: 2880,11            height: 1800,12            deviceScaleFactor: 2,13        });14

    15        await page.goto("https://finance.yahoo.com/", {16            timeout: 15 * 1000,17            waitUntil: ["domcontentloaded", "networkidle2"],18        });19

    20        await page.screenshot({ path: "finance.yahoo.com.png" });21    } catch (e) {22        console.error(e);23    } finally {24        await browser.close();25    }26})();

And here we go:

It works fast and as we need. I chose `networkidle2` instead of `networkidle0`, because they constantly send requests, and `page.goto()` will throw an error on timeout.

Always wait and check for response

----------------------------------

Many guides miss that, but always check and wait for response with `page.waitForResponse()`.

It is especially important to handle scenarios where network errors, timeouts, or unexpected HTTP status codes occur. This helps ensure your script completes only when the page is really available, and provides a chance to act on HTTP failures or unusual responses.

    1let response = await page.goto(...);2if (!response) {3    response = await page.waitForResponse(() => true, {4        timeout: 15 * 1000,5    });6}7

    8const status = response.status();9if (status !== 200) {10    throw new Error(`Unexpected status code: ${status}`);11}

Why does this matter? Some sites may return redirects or error pages without obvious visual cues. Checking the response and HTTP status code allows you to reliably catch those cases early, and build more robust automations or screenshot tools.

Caveats

-------

The combination of options like `domcontentloaded` and `networkidle2`, might work well in many cases, but not in all cases.

You still might have pages with lazy loading images, so you need to scroll to the bottom of the page and then wait until the images are loaded. And sometimes, you trap in infinite scrolling. Some pages can stop sending networking requests, and some not.

You can write standard code to handle these issues if you are working with a known set of sites. But you might trap in new problems, so test your code repeatedly and on many sites.

Wait for page load after click

------------------------------

In case, if you need to wait for page to be ready a button click or a form submit, use `page.waitForNavigation()`

    1const [response] = await Promise.all([2    page.waitForNavigation(),3    page.click("a.my-link"),4]);

The `Puppeteer` API suggests using a `Promise.All()` to prevent a race condition.

Wait for selector

-----------------

If you know what element you are waiting for, you can use `page.waitForSelector()` to wait for it to be visible:

    1await page.waitForSelector(".chart-container", {2    visible: true,3    timeout: 10_000,4});

It is a super effective solution when you screenshotting your websites or the websites you know visible elements selectors of.

Wait for function

-----------------

Or for more complex scenarios, you can use `page.waitForFunction()` to wait for a function to be executed:

    1await page.waitForFunction(() => {2    // check some state of the page or some process is completed3    return true;4});

A perfect solution

------------------

In case you need a perfect screenshot with everything rendered, a perfect solution would be:

1.  To implement all of the above, but wait until the DOM changes are completed or at least it changes slowly.

2.  Check the render screenshot with AI vision to any inconsistencies or missing elements. And re-render the screenshot if needed.

But that might be too costly and slow. Depends on your use case and budget. It is always a trade-off.

A third-party API to take screenshots

-------------------------------------

If your use case to take screenshots, consider using an enterprise-grade production ready screenshot API to take screenshots, like [ScreenshotOne](/). [It is proved to be a reliable, scalable and one of the best solutions for screenshot automation](/blog/best-screenshot-apis/).

You don’t want to waste on handling all Puppeeter issues and scaling, it is already solved by ScreenshotOne.

But if you need to, [all described options are supported](/docs/options/#wait)! And you can [start for free](https://dash.screenshotone.com/sign-up).

Afterwords and recommendations

------------------------------

I hope I helped you today to solve your problem and have a nice day 👋

Read more Puppeteer guides

--------------------------

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

[View all posts](/blog/tags/puppeteer-guides/)

#### [What is a screenshot or HTML rendering API?](/blog/what-is-a-screenshot-or-html-rendering-api/)

A screenshot API or a screenshot as a service is usually a cloud or a remote server service that provides the ability to render any website, HTML, Markdown, or even PDF by making a request to the service, be it over HTTP, TCP, or any other protocol.

Read more

#### [How to use proxy per page with Puppeteer](/blog/how-to-use-proxy-per-page-with-puppeteer/)

It is easy to use proxy globally for the puppeteer instance, but there is a trick to use proxy on a per-page basis.

Read more

#### [Taking screenshots with Puppeteer in GIF, JP2, TIFF, AVIF, HEIF, or SVG format](/blog/taking-screenshots-with-puppeteer-in-gif-jp2-tiff-avif-heif-or-svg-format/)

Puppeteer, by default, supports only four formats for taking screenshots or rendering HTML: PNG, JPEG, WebP, and PDF. But what if you want it to take it in a different format like GIF, JP2, TIFF, AVIF, HEIF, or SVG?

Read more

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/contributors/anthony-alaribe
----

Anthony Alaribe

---------------

View all Changelog

#### [How to take a screenshot of a webpage in Haskell](/blog/how-to-take-a-screenshot-of-a-webpage-in-haskell/)

It's very a common need to take a screenshot of a live website. On a project I worked on recently, we had a legal requirement to take screenshots of forms which our users filled, as at the time they filled the forms, for consent documentation purposes.

Written by

[Anthony Alaribe](/contributors/anthony-alaribe/)

Updated on

Oct 23, 2022

•

3 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/changelog
----

Changes and updates

-------------------

Stay updated with the latest information about new features, bug fixes, and optimizations at ScreenshotOne

### Product updates in the last 12 months

Mar 10, 2026

#### [Added a URL to Markdown Tool](/changelog/url-to-markdown-tool/)

A new free ScreenshotOne tool to convert any public webpage URL into Markdown.

Read more →

1 min read

Mar 10, 2026

#### [Added an Above-the-Fold Checker Tool](/changelog/above-the-fold-checker/)

A new ScreenshotOne tool to capture what users see before the first scroll.

Read more →

1 min read

Feb 28, 2026

#### [Improved favicon detection for metadata\_icon](/changelog/improved-metadata-icon-detection/)

Improved \`metadata\_icon\` to check common favicon link variants more reliably.

Read more →

1 min read

Feb 28, 2026

#### [Better Markdown output](/changelog/better-markdown-output/)

Markdown output is now cleaner by removing non-content HTML blocks during conversion.

Read more →

1 min read

Feb 7, 2026

#### [New hover option](/changelog/hover-option/)

Use the new hover option to interact with elements before rendering, and choose whether to fail if the hover selector is not found.

Read more →

1 min read

Jan 28, 2026

#### [New organization role](/changelog/new-organization-role/)

Allow other members to manage your organization without transferring ownership.

Read more →

1 min read

Jan 26, 2026

#### [ScreenshotOne is available on viaSocket](/changelog/viasocket-integration/)

Automate website screenshots, animated scrolling captures, and visual documentation workflows with ScreenshotOne and viaSocket.

Read more →

1 min read

Jan 12, 2026

#### [Notifications when the usage reaches 50% of the limit](/changelog/half-quota-reached-notifications/)

You can now get notifications when the usage reaches 50% of the limit.

Read more →

1 min read

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.

[Start rendering →](https://dash.screenshotone.com/sign-up) [Book a demo](/book-a-call)

----
url: https://screenshotone.com/docs/caching
----

[Skip to content](#_top)

Caching

=======

Copy page

Note

When you don’t use caching (`cache=true`), storage (`store=true`) or similar options, screenshots are rendered on-demand and returned directly to you without being stored anywhere on ScreenshotOne infrastructure. This ensures maximum privacy for your rendered content. Except if you use `response_type=json`, in which case the screenshot is temporarily stored on ScreenshotOne servers to serve the screenshot URL for you.

**During processing**, rendered content may be temporarily stored to pass through internal system components (such as queues, message brokers, or temporary buffers).

Caching is free and available for all plans. However, it is not intended to be used in CDN-like scenarios. It is for you to save costs on rendering.

To use cache, the only option you need to set is `cache=true`:

    1https://api.screenshotone.com/screenshot?url=https://example.com&cache=true

[Check out more cache options](/docs/options/#caching).

And the screenshot will be cached for 4 hours by default or if you specify the `cache_ttl` option in seconds, you can prolong the cache time up to one month.

Caching is available for all rendering methods.

When to use cache

-----------------

The best usage of cache is to make rendering less expensive and faster, in case if you plan to render a lot of similar websites.

Cache key

---------

Screenshots are cached by the combination of all specified request options. And the [cache\_key](/docs/options/#cache_key) option allows having different cached versions of the same screenshot.

Impact on rendering quota

-------------------------

Cached screenshots are not counted by quota and are not logged anywhere. They are served directly from the cache. Screenshots are cached in a combination of Cloudflare CDN and R2 storage (like Amazon S3).

However, rarely but cache misses might happen and screenshots might be rendered again and counted towards your quota.

Cache URL

---------

Note

Fetching the cache URL doesn’t trigger the rendering process. It is a direct link to the cached screenshot.

If you want to regenerate the cache, you need to make a new API request with the same parameters and if the cache is expired, it will be rendered again.

There is a header `x-screenshotone-cache-url` that provides a direct link to the cached image, PDF or video. The file exist as long as it was defined in the [cache\_ttl](/docs/options/#cache_key) parameter when API request was performed with `cache=true`.

And if the `response_type` option is specified as `json`, you can find a cache URL in the JSON response too:

    1{2    "cache_url": "https://cache.screenshotone.com/..."3}

What is the benefits of using the cache URL?

1.  You don’t share API keys and don’t complicate your code with [signed links](/docs/signed-requests/).

2.  You have full control over when the cache is refreshed—only you can trigger cache regeneration by making a new API request with the same parameters. If you share just the cache URL, others can only access the cached screenshot and cannot cause it to be regenerated after it expires. In contrast, sharing an API request link would allow anyone to trigger a new rendering once the cache expires. **Important!** The link will be unavailable after the cache is expired.

[The screenshot URL](/docs/screenshot-url/) might be different from the cache URL, but it will be likely the same as the cache URL.

Cache TTL

---------

Note

For long-term screenshot or video archival, consider [uploading them to any compatible S3-storage](/docs/guides/upload-to-s3/).

The cache TTL is 4 hours by default. You can change it by specifying the `cache_ttl` option in seconds up to one month.

Once the cache TTL is reached, the cached screenshot is deleted and the next request will be rendered again and counted towards your quota.

Cache URL will not be accessible after the cache TTL is reached. It is recommended to avoid using it and always render screenshots and videos with the rendering API request. It will rely on the cache anyway (if specified).

Support

-------

In case if you have any issues with caching or any ideas on how to improve it and make it better, please contact us at [support@screenshotone.com](mailto:support@screenshotone.com).