Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Capture the browser window with Selenium, then use Pillow to draw a text or image watermark onto a transparent layer and composite it over the screenshot. This post-processing approach keeps the watermark out of the page being tested, gives you control over placement and opacity, and produces a separate PNG artifact.
What this method captures—and what it does not
Selenium Python’s save_screenshot() captures the current browser window as a PNG file; it is not a general full-page capture method. Use a filename ending in .png, and check the method’s Boolean return value: it returns False when an I/O error occurs. See the Selenium Python WebDriver source for the current implementation; trunk source can change.
The example below uses Pillow after capture. It does not alter the live page, so the watermark cannot cover a button or change page layout while Selenium is taking the screenshot. The mark is baked into the saved output, however, so do not use the watermarked artifact for pixel-exact visual assertions unless that is intentional.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Install the image library and prepare a font
Install Pillow in the same Python environment as the script:
#1 Best Overall
python -m pip install Pillow
Selenium must also be installed and configured for your browser and driver. This workflow assumes you already have a working Selenium WebDriver instance. The watermark example uses a TrueType font file: the illustrative filename DejaVuSans.ttf must exist in the runtime or be replaced with a valid font path. If a font cannot be loaded, Pillow raises an error rather than silently guaranteeing a substitute.
Capture a screenshot and add a translucent text watermark
Use a transparent RGBA image the same size as the screenshot as a drawing layer. Draw the watermark on that layer, then use Image.alpha_composite() to combine it with the original image. Pillow documents this drawing and compositing pattern in its ImageDraw documentation and its Image documentation.
from pathlib import Path
from PIL import Image, ImageDraw, ImageFont
from selenium import webdriver
input_path = Path("screenshot.png")
output_path = Path("screenshot_watermarked.png")
watermark = "Example.com"
font_path = "DejaVuSans.ttf" # Replace with a font file available in this runtime.
# Configure the driver for your browser and environment before running this script.
driver = webdriver.Chrome()
try:
driver.get("https://example.com")
# Selenium saves PNG and returns False if it encounters an I/O error.
if not driver.save_screenshot(str(input_path)):
raise OSError(f"Could not save screenshot to {input_path}")
finally:
driver.quit()
with Image.open(input_path) as opened:
base = opened.convert("RGBA")
overlay = Image.new("RGBA", base.size, (0, 0, 0, 0))
draw = ImageDraw.Draw(overlay)
font = ImageFont.truetype(font_path, 24)
# RGBA alpha controls the watermark layer's opacity; tune it for your image.
draw.text((20, 20), watermark, font=font, fill=(255, 255, 255, 150))
result = Image.alpha_composite(base, overlay)
result.save(output_path)
print(f"Saved watermarked screenshot to {output_path}")
The browser setup is deliberately explicit: driver installation and browser selection vary by environment. Replace the example URL and configure webdriver.Chrome() for the browser you use. The image-processing portion starts from the PNG Selenium wrote and can be reused independently.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Rank #2
Why use RGBA and a separate layer?
RGBA images carry red, green, blue, and alpha channels. In Pillow’s RGBA color tuple, alpha controls transparency: lower values are more transparent and higher values are more opaque. Pillow’s documentation uses 128 as an example of half opacity; it is not a universal watermark recommendation. A separate transparent layer makes the watermark translucent without painting opaque replacement pixels directly into an RGB screenshot.
Place the watermark where it fits the actual image
The example places text at the top-left coordinate (20, 20). The right coordinates depend on screenshot dimensions and page content. To place text in a bottom corner, measure the rendered text and subtract its width and height plus a margin from the screenshot dimensions. Inspect the image at its final size: a mark that is legible on a light area may disappear against a pale page, while a mark that is too opaque can obscure details.
Use bytes instead of an intermediate screenshot file
If you prefer to keep the capture in memory, Selenium’s get_screenshot_as_png() returns PNG bytes. Pillow can open those bytes through a stream, which avoids writing and rereading the original screenshot file. Keeping capture and processing as separate stages can still make failures easier to diagnose.
from io import BytesIO
from PIL import Image, ImageDraw, ImageFont
from selenium import webdriver
# Configure this driver for your browser and environment.
driver = webdriver.Chrome()
try:
driver.get("https://example.com")
png_bytes = driver.get_screenshot_as_png()
finally:
driver.quit()
with Image.open(BytesIO(png_bytes)) as opened:
base = opened.convert("RGBA")
overlay = Image.new("RGBA", base.size, (0, 0, 0, 0))
draw = ImageDraw.Draw(overlay)
font = ImageFont.truetype("DejaVuSans.ttf", 24)
draw.text((20, 20), "Example.com", font=font, fill=(255, 255, 255, 150))
Image.alpha_composite(base, overlay).save("screenshot_watermarked.png")
Use a logo image instead of text
For a logo watermark, open the logo as an image, convert it to RGBA, and paste it onto the same transparent overlay before compositing. Resize the logo deliberately for the screenshot dimensions; a logo that is larger than the overlay or has no transparency may cover important content. This is Pillow image handling rather than a Selenium watermark feature.
Free tools Windows power users keep installed
One-click scans. No signup required.
from PIL import Image
logo = Image.open("logo.png").convert("RGBA")
# Choose a size that fits the screenshot; this example keeps the logo's aspect ratio.
logo.thumbnail((240, 100))
margin = 20
position = (base.width - logo.width - margin, base.height - logo.height - margin)
overlay.alpha_composite(logo, dest=position)
result = Image.alpha_composite(base, overlay)
result.save("screenshot_with_logo.png")
This snippet uses base and overlay from the text example. If the logo itself should be translucent, adjust its alpha channel before pasting; otherwise, a fully opaque logo covers the screenshot pixels beneath it.
Choose between post-processing and a page overlay
| Approach | When it fits | Trade-off |
|---|---|---|
| Post-process with Pillow | The mark is for the saved artifact, report, or evidence image. | It is outside the page under test; placement and opacity are controlled in image code. |
| Inject a DOM overlay before capture | The mark must appear as rendered page content at capture time. | It becomes page state and can affect visual tests. This is a general JavaScript technique, not a watermark recipe documented by Selenium’s cited API. |
For ordinary screenshot labeling, post-processing is usually simpler: it separates test-page behavior from artifact decoration. Add a DOM overlay only when rendering the mark in the browser is itself required.
Save the final image in the intended format
Use a .png output filename for the examples above. Pillow infers the image format from the filename extension when save() is called without an explicit format. PNG is a sensible choice when you want lossless output or transparency. If you choose JPEG, convert the final image to RGB before saving; JPEG is lossy and can change pixel values. That can matter for visual comparisons or other downstream image assertions.
Troubleshoot common failures
- The input screenshot is missing or unreadable: confirm the target directory exists and is writable, use a
.pngfilename, and check thatsave_screenshot()returnedTrue. An I/O error can make it returnFalse. - Pillow cannot find the font: replace
DejaVuSans.ttfwith the path to a font file installed in your runtime. A font path that works on one operating system or container may not exist in another. - The mark is invisible: inspect its fill color against the pixels underneath it, increase opacity if appropriate, and move it to a contrasting area. Alpha controls transparency, not whether the chosen color contrasts with the page.
- The mark hides useful content: change its coordinates, size, or opacity after inspecting the actual screenshot. There is no universally safe corner or opacity for every page.
- The output does not preserve transparency or has unexpected colors: check the mode and format. The examples convert the screenshot to RGBA for compositing and save PNG. For JPEG, convert to RGB and account for lossy changes.
- A screenshot comparison now fails: compare the original screenshot for visual assertions, or make watermarking optional and apply it only when producing human-facing artifacts.
Performance, reliability, and artifact cost
Post-processing adds image work after Selenium has captured the page, and a full-size transparent overlay occupies memory proportional to the screenshot dimensions. If you process many large screenshots, account for that extra image allocation and close opened files promptly. Save the raw capture separately when you need an unmodified test artifact; the composited result is a new image, not a reversible annotation.
Recommended Free Tools
For reproducible output, keep the watermark text or logo, font file, size, color, alpha, and placement under configuration rather than relying on a machine-specific default. Choose the font explicitly in the runtime, and preserve the original screenshot when later audits or pixel comparisons may depend on it.
Best Value
Or skip the browser setup
If you need a screenshot endpoint rather than a Selenium workflow, ScreenshotNeo accepts a URL in one GET request and returns an image or PDF. It can remove cookie banners, newsletter popups, and chat widgets before capture; each cleanup step can be turned off. Bot checks, blank pages, and failed loads are not billed, and response headers identify the page verdict and billing status. Its MCP server gives AI agents screenshot tools, and every plan includes its features. You would still add a custom watermark to the returned image yourself.
For example, this cURL request saves a WebP screenshot:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
See the ScreenshotNeo documentation for API details. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. Sign up for ScreenshotNeo’s free plan to try it.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Frequently Asked Questions
Can I use this method for a full-page screenshot?
The general Selenium method shown captures the current window. Selenium has Firefox-specific full-page screenshot methods, but they are separate from this cross-browser example.
Can I use the watermarked screenshot for visual regression tests?
You can, but the watermark changes pixels. Keep watermarking optional or compare the unmodified capture when tests expect the original page image.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

