ScreenshotNeo

BlogScreenshots on your device

How to Display Selenium Screenshots in a Tkinter GUI

Capture a Selenium browser image, load it into Tkinter, keep it visible, and handle sizing, errors, threading, and in-memory workflows.

By the ScreenshotNeo team30 September 20268 min read

How to Display Selenium Screenshots in a Tkinter GUI

Direct answer: save the Selenium screenshot as a PNG, create a tkinter.PhotoImage from that file, and pass it to a label or another image-capable widget. Keep a Python reference to the PhotoImage for as long as it is displayed.

This approach uses Selenium’s documented save_screenshot() method and Tk 8.6 or newer PNG support. Selenium also exposes screenshot bytes and base64 data when you need an in-memory workflow.

1. Complete working example

Install Selenium first:

The basic workflow is browser capture, PNG handoff, and a retained Tkinter image object.
The basic workflow is browser capture, PNG handoff, and a retained Tkinter image object.
python -m pip install selenium

Save this as selenium_tkinter.py:

import tkinter as tk
from pathlib import Path
from selenium import webdriver

SCREENSHOT_PATH = Path("capture.png")
TARGET_URL = "https://example.com"


def main():
    # The browser must be installed and configured for your Selenium driver.
    with webdriver.Chrome() as driver:
        driver.get(TARGET_URL)
        saved = driver.save_screenshot(str(SCREENSHOT_PATH))
        if not saved:
            raise OSError(f"Could not save screenshot to {SCREENSHOT_PATH}")

    root = tk.Tk()
    root.title("Selenium screenshot")

    # PNG loading requires Tk 8.6 or later.
    photo = tk.PhotoImage(file=str(SCREENSHOT_PATH))
    label = tk.Label(root, image=photo)

    # Keep the image alive while the label displays it.
    label.image = photo
    label.pack()

    root.mainloop()


if __name__ == "__main__":
    main()

save_screenshot(filename) returns a Boolean. A false result indicates that Selenium could not write the file, so the example raises an error instead of attempting to display a missing image. Selenium documents this API along with get_screenshot_as_file(), get_screenshot_as_png(), and get_screenshot_as_base64() in its WebDriver documentation.

2. How the handoff works

  1. Selenium navigates the browser with driver.get().
  2. save_screenshot() writes the current browser view as a PNG.
  3. tk.PhotoImage(file=...) decodes that PNG.
  4. A Label, Canvas, or other image-capable widget receives the image.
  5. A reference such as label.image = photo prevents Python from deleting the underlying Tk image.

The Python documentation explains that deleting all references to an image object deletes the underlying Tk image. The same documentation specifies PNG support in Tk 8.6 and later: tkinter documentation.

3. Showing the image in a different Tkinter widget

Canvas

canvas = tk.Canvas(root, width=photo.width(), height=photo.height())
canvas.pack()
canvas.create_image(0, 0, image=photo, anchor="nw")
canvas.image = photo

Replacing an existing preview

def replace_preview(label, filename):
    photo = tk.PhotoImage(file=filename)
    label.configure(image=photo)
    label.image = photo

# Later:
replace_preview(label, "another-capture.png")

Store the new image on the widget or application object. A local variable that goes out of scope can leave the widget blank.

4. File-based versus in-memory screenshots

Approach Advantages Trade-offs
File-based Smallest dependency path; easy to inspect and troubleshoot; native PhotoImage loading Creates a temporary PNG and needs write permissions
In-memory Avoids an intermediate file; useful for repeated previews or temporary captures PNG bytes must be decoded into an image object Tk can display

Getting PNG bytes from Selenium

with webdriver.Chrome() as driver:
    driver.get("https://example.com")
    png_bytes = driver.get_screenshot_as_png()

get_screenshot_as_png() returns binary PNG data. A common bridge is an image-processing library that decodes those bytes before creating a Tk-compatible image object. Keep that decoder as a separate layer so the browser capture and GUI code remain easy to diagnose. If you choose Pillow’s ImageTk path, check the current Pillow documentation for the exact API and supported Tk setup before shipping it.

get_screenshot_as_base64() is also available when another part of your application already transports base64 data, but it adds an encode/decode step compared with PNG bytes.

5. Waiting for the page before capture

A screenshot captures the browser state at the moment Selenium takes it. Navigate to the page, then use Selenium’s normal waiting tools when a specific element must exist before capture. Avoid arbitrary delays unless the page has a known animation or asynchronous transition that cannot be represented by an element condition.

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

with webdriver.Chrome() as driver:
    driver.get("https://example.com")
    WebDriverWait(driver, 20).until(
        EC.visibility_of_element_located((By.TAG_NAME, "body"))
    )
    if not driver.save_screenshot("capture.png"):
        raise OSError("Screenshot write failed")

6. Window size, full-page output, and large images

Standard WebDriver screenshots normally represent the current browser viewport. Set the window size before navigation when a predictable viewport matters:

with webdriver.Chrome() as driver:
    driver.set_window_size(1440, 900)
    driver.get("https://example.com")
    driver.save_screenshot("viewport.png")

A large screenshot can be wider or taller than the Tk window. The label will still contain the image, but parts may be outside the visible area. For a scrollable preview, place the image on a Canvas and connect scrollbars. For resizing, decode the PNG through an image-processing layer and retain the resulting Tk image reference.

7. Keeping the GUI responsive

Browser startup, navigation, waits, and screenshot writes can take long enough to make a desktop window stop repainting if they run inside a button callback. Keep slow browser work away from the GUI event loop, then schedule the UI update through Tk’s event mechanism. The exact thread-safety rules depend on your Python and Tk build, so verify them against the current Tk and Python documentation for production use.

Run slow browser navigation outside Tkinter's event loop, then schedule the preview update.
Run slow browser navigation outside Tkinter's event loop, then schedule the preview update.

A simple structure is:

import threading
import tkinter as tk
from selenium import webdriver


def capture_in_background(on_done):
    def worker():
        result = None
        error = None
        try:
            with webdriver.Chrome() as driver:
                driver.get("https://example.com")
                if not driver.save_screenshot("capture.png"):
                    raise OSError("Screenshot write failed")
            result = "capture.png"
        except Exception as exc:
            error = exc
        on_done(result, error)

    threading.Thread(target=worker, daemon=True).start()


root = tk.Tk()
status = tk.Label(root, text="Ready")
status.pack()


def finished(path, error):
    # Schedule widget work on Tk's event loop.
    root.after(0, lambda: status.config(
        text=f"Saved {path}" if error is None else f"Error: {error}"
    ))


tk.Button(root, text="Capture", command=lambda: capture_in_background(finished)).pack()
root.mainloop()

Do not update Tk widgets directly from the worker. Pass results back to the GUI event loop and decide how to handle errors there.

8. Troubleshooting

Symptom Likely cause Fix
save_screenshot() returns False The destination cannot be written, the directory is missing, or the process lacks permission Use an absolute path, create the directory first, check permissions, and handle the Boolean result
PNG format error from PhotoImage The runtime is using Tk older than 8.6 or a different unsupported format Check the Tk version and use Tk 8.6+ for native PNG loading
The label is blank The PhotoImage object was garbage-collected Assign it to label.image or an application-level attribute
Browser starts but navigation fails Browser, driver, URL, network, or page readiness problem Check the WebDriver setup, log the target URL, add an explicit wait, and capture the exception
The preview is cut off The image is larger than the available window Use a scrollable Canvas or resize the image before display
The window freezes Navigation or capture is running in the Tk event callback Move browser work to a worker and schedule the result with root.after()
Only part of a dynamic page appears Capture happened before the required content loaded Wait for a meaningful element or state instead of relying only on a fixed sleep

9. Reliability and performance checklist

  • Use an explicit output path and check the Boolean result from save_screenshot().
  • Close each WebDriver with a context manager or an explicit quit().
  • Set a known browser window size when previews must be comparable.
  • Wait for the page state your screenshot actually requires.
  • Keep browser work out of the GUI event loop.
  • Retain every displayed PhotoImage.
  • Use unique filenames if multiple captures can overlap.
  • Clean up temporary files after the preview closes if they are not needed later.
  • For large images, consider a resize or scrollable preview to reduce memory and repaint work.

Capture time is affected by browser startup, page loading, waits, rendering, and filesystem writes. Reusing a browser session can avoid repeated startup cost, while isolating each capture in its own driver can simplify failure recovery. The appropriate choice depends on whether your application values throughput or strict separation between captures.

10. Or skip the browser setup

If you only need a screenshot delivered to your Python or desktop application, ScreenshotNeo provides a single HTTP request instead of requiring local browser and driver configuration. Its API can return PNG, JPEG, WebP, or PDF, and its cleanup steps accept consent banners before capture and remove more than 60 known consent platforms, newsletter popups, and chat widgets. Each cleanup step can be turned off.

Use the API from Python:

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)

cURL:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp

Node.js:

import { writeFile } from "node:fs/promises";

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await writeFile("shot.webp", Buffer.from(await res.arrayBuffer()));

See the ScreenshotNeo API documentation for request options. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers. ScreenshotNeo also provides an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. One thousand screenshots per month are free with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

11. FAQ

Can Tkinter display a Selenium screenshot without saving a file?

Yes. Selenium’s get_screenshot_as_png() returns PNG bytes. Decode those bytes with a compatible image layer, then create the Tk image object and retain a reference to it.

Why does PhotoImage lose the image?

Tk removes the underlying image when all Python references to the image object are gone. Store the object on the widget or application instance.

Does PhotoImage support PNG?

Python’s Tkinter documentation specifies PNG loading in Tk 8.6 and later.

Should I use a fixed sleep before taking the screenshot?

Use an explicit wait for the element or page state that must be visible. A fixed delay is useful only when you understand the page’s timing and no better condition is available.

Can I show a JPEG or WebP directly with native Tkinter?

The documented native path in this guide is PNG. Convert other formats through an image-processing layer before creating the Tk image, or request PNG from the capture service you use.