ScreenshotRender
← Back to blog
Tutorials

How to Screenshot a Webpage in Python: 3 Ways

Robert Belt·9 min read
Updated On :
Orange minimalist illustration of a Python script turning a URL into a full page screenshot

Search how to take a screenshot in Python and half the answers show you how to grab your desktop, not a web page. By the end of this you'll have three working ways to capture a full web page in Python, and a rule for which one to reach for.

The three are PIL or pyautogui (the wrong tool, but worth knowing why), Selenium or Playwright (a real browser you drive yourself), and a single HTTP call (no browser at all). They are ordered from worst to best fit for the specific job of capturing a URL.

What's the fastest way to screenshot a webpage in Python?

The fastest way to screenshot a webpage in Python is one HTTP request to a screenshot API, with no browser to install. With ScreenshotRender the entire capture is a single requests call: res = requests.get("https://screenshotrender.com/api/v1/screenshot?apiKey=YOUR_API_KEY&url=https://en.wikipedia.org/wiki/HTTP&fullPage=true"). The JSON response carries a hosted image URL at res.json()["data"]["screenshot"].

If you'd rather own the whole pipeline, drive a real browser with Selenium or Playwright instead. Both render the page locally and write a PNG to disk, at the cost of a Chromium binary you install and keep current. The rest of this post shows all three, so you can pick by how much infrastructure you want to own.

Why don't PIL and pyautogui work for web pages?

PIL and pyautogui screenshot your screen, not a web page, so they only work if a browser is already open and visible on a desktop. ImageGrab.grab() from Pillow and pyautogui.screenshot() both capture the operating system's display buffer. There is no URL involved and no rendering happening; they photograph whatever pixels are on the monitor right now.

That rules them out for the thing you actually want. They cannot run on a headless server with no display, they capture your taskbar and other windows along with the page, and they have no idea when a page has finished loading. If your goal is a clean image of a URL, you need something that loads the URL itself. That means a browser engine.

How do you screenshot a webpage in Python with Selenium?

Selenium drives a real browser, so it can load a URL and call driver.save_screenshot('page.png') to write a PNG, with no display required once you run Chrome headless. After pip install selenium, the flow is four lines: create a driver, point it at the URL, capture, quit. Launch headless by passing --headless=new to Chrome so it runs on a server with no screen attached.

The capture step itself is one call. The Selenium docs cover driver.save_screenshot() and get_screenshot_as_file(), which do the same thing. The catch arrives the moment you want the whole page rather than the slice currently in view.

How do you take a full page screenshot in Selenium with Python?

Selenium's save_screenshot only captures the viewport, so a true full page screenshot needs the Chrome DevTools Protocol or a window resized to the full scroll height. The clean way is to call the DevTools command Page.captureScreenshot with captureBeyondViewport set to true, which renders the entire document in one image. The hacky way is to read document.body.scrollHeight, resize the window to it, and then capture. Both work; neither is one line, which is why Playwright is the nicer DIY option for full page shots.

How do you take a screenshot in Python with Playwright?

Playwright captures a full page screenshot in one line: page.screenshot(path='page.png', full_page=True), which is why it's the better browser-driven choice for web pages. After pip install playwright and playwright install to fetch the browser binaries, you open a browser with sync_playwright(), call page.goto(url), then take the shot. The full_page=True flag handles the scrolling that costs you extra code in Selenium.

Playwright is the strongest of the do-it-yourself options: modern API, full page in one call, and a built-in command to install the browsers. It is still a browser you run, which means a Chromium binary in your environment, memory headroom for each concurrent capture, and the version drift that turns a green CI run red after an unrelated upgrade. For a handful of local screenshots that is fine. At any real volume, those costs are the reason the HTTP option exists.

Skip the Selenium install, the chromedriver chase, and the headless flags.

If you only need the screenshot, one GET request to ScreenshotRender returns a hosted PNG with cookie banners and ads already stripped. A real Chromium renders the JavaScript on our infrastructure, so there is nothing to install or keep current. 100 free screenshots per month, no credit card.

Get an API key

How do you screenshot a webpage in Python without running a browser?

You skip the browser entirely by calling a screenshot API: send the URL to an HTTP endpoint and get a hosted image back, which in Python is a single requests.get call. The full request is one copy-pasteable line: requests.get("https://screenshotrender.com/api/v1/screenshot?apiKey=YOUR_API_KEY&url=https://en.wikipedia.org/wiki/HTTP&fullPage=true"). Read the image URL from res.json()["data"]["screenshot"] and either store it or download the bytes.

The parameters are the whole API surface. url is the page to capture, fullPage=true captures the entire scrollable document instead of the default 1280 by 720 viewport, and wait takes a millisecond delay for pages that finish rendering after the initial load, like a React single page app. There is no SDK to install; the landing page shows the same call in Python, Node.js, and cURL because any language that speaks HTTP works identically.

The other thing you stop doing yourself is cleanup. Cookie consent banners, ad overlays, and chat widgets are removed automatically before every capture, on every plan including the free one, so the PNG is the page rather than the page plus three popups. With Selenium or Playwright you would write that dismissal logic by hand for each site. The free plan covers 100 screenshots a month with no credit card, which is enough to wire this into a script before you decide on volume.

When does each Python screenshot method fail?

Every method here fails on the same short list of pages: bot-protected sites, login walls, lazy-loaded content, and fragile CI environments. Knowing which case you are in saves you a day of debugging the wrong layer.

  • Cloudflare and bot protection. A vanilla headless Selenium or Playwright gets served a challenge page, so your screenshot is the challenge, not the site. You need a stealth setup and usually a residential proxy, or an API that bakes it in. ScreenshotRender ships Stealth Mode on the Hobby plan and above; see our guide to screenshotting Cloudflare-protected sites for what changes.
  • Login walls. A URL-only API takes a URL, not a session cookie, so it cannot reach a page behind a login. This is the one case where driving Selenium yourself wins: you can script the sign-in and capture the authenticated page. For public pages, the URL-only call is the simpler trade.
  • Lazy-loaded images and SPAs. Content that loads on scroll or after the network goes idle will be missing if you capture too early. In Selenium or Playwright you scroll and wait for a selector; with the API you pass the wait parameter in milliseconds.
  • CI fragility. A different Chromium version or a missing font on the runner shifts pixels and breaks brittle tests. Driving a browser in CI means owning that drift; an HTTP call renders on fixed infrastructure, so the output for the same URL stays stable across runs. This is the same reason a full page capture is more reliable through an API than a hand-rolled scroll loop.

None of this means browsers are bad. It means a local browser carries costs (install, memory, version drift) that you only want to pay when you genuinely need to drive the page, not when you just need an image of it.

Common questions about taking a screenshot of a webpage in Python

How do I take a full page screenshot in Python?

Playwright is the simplest: page.screenshot(path='page.png', full_page=True) captures the entire scrollable page in one call. Selenium's save_screenshot only grabs the viewport, so a true full page shot there needs the Chrome DevTools Protocol or resizing the window to the document height. A screenshot API does it with fullPage=true in the query string and no browser at all.

Can I screenshot a website in Python without Chrome installed?

Yes, by calling a screenshot API instead of driving a local browser. The rendering happens on the provider's infrastructure, so your machine only needs the requests library. Selenium and Playwright both require a Chromium binary installed locally, which is the part that drifts and breaks in CI; an HTTP call has nothing to install.

How do I screenshot a JavaScript-heavy or React page in Python?

Use a real browser engine, not PIL or pyautogui. Selenium and Playwright run Chromium and execute the page's JavaScript; add a wait for a specific selector or a short fixed delay so the content renders before you capture. ScreenshotRender runs a real Chromium too, so pass the wait parameter in milliseconds to let a single page app finish loading.

Is there a free Python screenshot API?

Yes. ScreenshotRender's free plan includes 100 screenshots per month with no credit card required, full page capture, and cookie banner and ad removal enabled by default. That is enough to wire screenshot capture into a Python script end to end before deciding whether you need more volume.

How do I screenshot a Cloudflare-protected site in Python?

Vanilla Selenium or Playwright gets served a Cloudflare challenge page instead of the real content, so your capture is the challenge, not the site. You need a stealth setup plus a residential proxy, or an API that handles bot detection for you. ScreenshotRender's Stealth Mode, bundled on the Hobby plan and above, returns the real page from the same one line call.

The honest takeaway: pick by how much you want to own. If you only need an image of a public URL, the one line requests call is the least to maintain. If you need to drive the page, sign in, or fill a form, run Playwright and accept the browser that comes with it. And leave PIL for screenshotting your actual screen, which is the one job it was built for.

Keep reading