Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Direct answer: package a Lambda-compatible headless Chromium (or Chrome) and its matching driver with your Java function, launch Selenium with ChromeOptions, navigate to the page, cast the driver to TakesScreenshot, and write the result to /tmp. Upload that file to Amazon S3 or another durable destination before the invocation ends; Lambda’s local storage is temporary.
The Java screenshot call itself is small. The difficult, deployment-specific work is supplying mutually compatible browser binaries, native libraries, and launch flags in the exact Lambda runtime and CPU architecture you deploy. The pattern below is deliberately explicit about those boundaries so you can test a real browser build instead of treating an unverified path as a drop-in recipe.
What you need before writing code
- A Java Lambda function deployed as a ZIP/JAR archive or a container image. AWS documents both formats and Java layers for dependencies: ZIP/JAR packaging and Java container images.
- A headless Chromium/Chrome binary and a ChromeDriver build that is compatible with that browser, compiled for the function’s architecture (for example, arm64 or x86_64).
- Selenium Java libraries and every native shared library required by the selected browser distribution.
- An IAM role that can write to your chosen durable destination if screenshots must survive the invocation.
AWS’s Java pages do not distribute Chromium or prescribe Selenium paths. Select a maintained Lambda-compatible browser package, then verify its version pair and libraries in the deployed image. The historical AWS Selenium example (published June 1, 2020) used Python, a Lambda layer, and older Chromium tooling; it is useful architecture context, not proof of current Java compatibility: AWS case study.
Choose ZIP/JAR plus layers or a container image
| Concern | ZIP/JAR and layers | Container image |
|---|---|---|
| Browser dependency fit | Put Selenium in the archive and large browser/native dependencies in one or more layers. | Install the Java runtime, browser, driver, libraries, and application in one image. |
| Build and updates | Publish new function and layer versions; keep the combined unzipped package within Lambda limits. | Build, scan, push, and deploy an image; browser updates are image rebuilds. |
| Local parity | Local execution must reproduce Lambda’s filesystem and libraries. | The same image can be run locally with the Lambda Runtime Interface Emulator. |
| Limits | Lambda currently documents a 250 MB unzipped ZIP package including layers and a maximum of five layers; direct-upload limits vary by upload path. | Lambda documents a maximum 10 GB uncompressed container-image package. |
These are service ceilings, not recommended Selenium settings. Check the live Lambda quotas page when you build. AWS-provided Java base images include the runtime interface client and emulator. Java 21 and later images use Amazon Linux 2023, where package installation uses microdnf/dnf rather than yum; do not copy Amazon Linux 2 commands unchanged.
Implement the Java capture path
The following handler is a pattern to adapt and test against your exact browser distribution. It assumes you provide paths through environment variables and that the browser can run without a display server.
package example;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.time.Duration;
import java.util.Map;
public class ScreenshotHandler implements RequestHandler<Map<String, String>, String> {
@Override
public String handleRequest(Map<String, String> event, Context context) {
String url = event.getOrDefault("url", "https://example.com");
String browser = System.getenv().getOrDefault("CHROME_BINARY", "/opt/chrome/chrome");
String driver = System.getenv().getOrDefault("CHROMEDRIVER", "/opt/chromedriver");
File output = new File("/tmp/shot.png");
WebDriver webDriver = null;
try {
System.setProperty("webdriver.chrome.driver", driver);
ChromeOptions options = new ChromeOptions();
options.setBinary(browser);
options.addArguments(
"--headless=new",
"--no-sandbox",
"--disable-dev-shm-usage",
"--disable-gpu",
"--window-size=1365,900",
"--user-data-dir=/tmp/chrome-profile");
webDriver = new ChromeDriver(options);
webDriver.manage().timeouts().pageLoadTimeout(Duration.ofSeconds(60));
webDriver.get(url);
// Replace this with an explicit wait for your page's ready element when needed.
File captured = ((TakesScreenshot) webDriver)
.getScreenshotAs(OutputType.FILE);
Files.copy(captured.toPath(), output.toPath(),
StandardCopyOption.REPLACE_EXISTING);
return output.getAbsolutePath();
} catch (IOException e) {
throw new RuntimeException("Could not write screenshot", e);
} finally {
if (webDriver != null) {
webDriver.quit();
}
}
}
}
TakesScreenshot#getScreenshotAs(OutputType) can return a temporary FILE, bytes, or a Base64 representation. The API also permits taking a screenshot from an element. Scope is driver-dependent: for non-W3C-conformant drivers, Selenium describes a browser-dependent best effort that may prefer the full page, current window, visible frame, or display. Confirm what your browser/driver pair actually returns in tests: Selenium TakesScreenshot API.
Wait for the content you intend to capture
A navigation returning does not guarantee that a single-page application has rendered. Add an explicit wait for a semantic element rather than an arbitrary long sleep:
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problemsWebDriverWait wait = new WebDriverWait(webDriver, Duration.ofSeconds(30));
wait.until(ExpectedConditions.visibilityOfElementLocated(
By.cssSelector("main[data-ready='true']")));
File captured = ((TakesScreenshot) webDriver)
.getScreenshotAs(OutputType.FILE);
Use a CSS selector that your application controls, and set a timeout consistent with your Lambda function timeout. If you need one component rather than the viewport, locate it and call element.getScreenshotAs(OutputType.FILE) where supported by the driver.
Rank #2
Persist the image outside Lambda
/tmp is encrypted at rest with an AWS-managed key and is unique to a Lambda execution environment, but it is temporary. Configure between 512 MB and 10,240 MB in 1 MB increments through the function’s Ephemeral storage setting or infrastructure configuration. Reused environments can retain old files, so generate unique names and overwrite deliberately.
For durable storage, upload the file to S3 after capture. Give the execution role only the required s3:PutObject permission, set an appropriate content type such as image/png, and return the object key (or a presigned URL generated by a trusted service) rather than assuming the local path is downloadable. The S3 destination and workflow are an architectural choice; AWS’s historical Selenium post used S3 for failed-test screenshots.
Packaging details that commonly decide success
Maven dependencies
Use the Selenium Java artifact and Lambda Java interfaces in your build, then create a deployable artifact with Maven Shade or the Gradle equivalent as described in AWS’s Java package guide. Keep browser binaries outside the shaded JAR when they are better delivered as a layer or image filesystem.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Executable paths and permissions
At startup, log the resolved browser and driver paths, their executable permissions, and their reported versions. In a layer they commonly appear under /opt; in an image they may be under /usr/bin or another path chosen by the image. Do not hard-code a path from a different distribution.
Architecture and native libraries
Build the browser, driver, and libraries for the same architecture selected in Lambda. A missing ELF loader or shared library often appears as “cannot open shared object file” or an immediate process exit. Reproduce the Lambda base image locally and run the browser’s version command before invoking Selenium.
Configure memory, timeout, and temporary storage deliberately
Lambda currently allows 128 MB–10,240 MB of memory, a standard timeout up to 900 seconds, and 512 MB–10,240 MB of /tmp. These are quotas, not a universal Selenium minimum. Browser startup, page complexity, screenshot dimensions, and concurrency determine the values you need. Start with a measured workload, watch duration and out-of-memory errors, and increase memory or timeout only when observations justify it. Keep enough /tmp for the browser profile, downloads, temporary screenshot files, and concurrent work in one invocation.
Cold starts and reuse
Creating a browser is expensive. A simple handler can create and quit per request for isolation. If you reuse a driver across invocations, reset cookies, storage, window state, and navigation explicitly, and still quit it when the environment is finally retired. Never assume a warm environment exists or that its files are safe to expose to another request.
Free tools Windows power users keep installed
One-click scans. No signup required.
Troubleshooting checklist
| Symptom | Likely cause | Fix |
|---|---|---|
SessionNotCreatedException |
Browser and ChromeDriver versions or architectures do not match. | Inspect both versions in the deployed environment and install a compatible pair built for the selected architecture. |
| “DevToolsActivePort file doesn’t exist” | Browser cannot start with the current profile, sandbox, shared-memory, or flags. | Use a writable unique profile under /tmp, verify required headless flags for your build, and inspect stderr. |
| “cannot open shared object file” | A native library or loader is absent. | Install the libraries required by that exact browser build in the image/layer; test inside the Lambda base image. |
| Timeout while loading | Slow network, blocked outbound access, or a page waiting on third-party resources. | Check VPC egress and DNS, set page-load and script timeouts, and wait for a known application element instead of network-idle assumptions. |
| Blank or incomplete screenshot | Capture occurred before client-side rendering or lazy content finished. | Wait for a readiness selector, scroll if lazy loading requires it, and capture after the state is observable. |
| Works locally, fails in Lambda | Different OS libraries, architecture, filesystem paths, or environment variables. | Run the same image/base image locally, print versions and paths, and compare launch stderr. |
| File disappears after return | /tmp is not durable. |
Upload to S3 or another persistent service before returning. |
Or skip the browser setup
If you only need a reliable website image rather than Selenium-specific interaction, ScreenshotNeo provides a website screenshot API and MCP server. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Only clean shots are billed: bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status.
One GET request returns PNG, JPEG, WebP, or PDF. The API supports full-page lazy-image loading, CSS-selector element capture, dark mode, device presets or custom viewports, retina scale, PDF paper and page controls, custom CSS/JavaScript, clicks, hidden selectors, selector/delay/network-idle waits, request and resource blocking, headers/cookies/user agents/Authorization, timezone and geolocation, transparency, resizing, TTL caching, signed image links, asynchronous signed webhooks, bulk capture of up to 100 URLs per call, usage reporting, and an OpenAPI specification. Its parameter names are compatible with those used by other screenshot APIs, easing migration.
Rank #4
cURL (see the ScreenshotNeo documentation):
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python:
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
require('fs').writeFileSync('shot.webp', Buffer.from(await res.arrayBuffer()));
An MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients, so an AI agent can request captures without you maintaining a browser layer. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots, and every feature is on every plan. Create a free ScreenshotNeo account.
FAQ
Can Selenium guarantee a full-page image?
No. The result depends on the browser and driver implementation. Test full-page behavior with your selected pair; otherwise use viewport capture or a service that explicitly offers full-page rendering.
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallCrashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteShould I use a Lambda layer or an image?
Either is supported. Choose the format your team can build, patch, test, and reproduce while staying within the relevant package limits.
Is the AWS 2020 Selenium post a Java recipe?
No. It is a June 1, 2020 Python example and should not be used as evidence of current Java browser compatibility.
Best Value
Frequently Asked Questions
Can Selenium guarantee a full-page image?
No. The result depends on the browser and driver implementation. Test full-page behavior with your selected pair; otherwise use viewport capture or a service that explicitly offers full-page rendering.
Should I use a Lambda layer or an image?
Either is supported. Choose the format your team can build, patch, test, and reproduce while staying within the relevant package limits.
Is the AWS 2020 Selenium post a Java recipe?
No. It is a June 1, 2020 Python example and should not be used as evidence of current Java browser compatibility.
The Bottom Line
Use TakesScreenshot for the capture, /tmp only as temporary workspace, and a tested browser/driver package built for your Lambda runtime and architecture. Persist the resulting file before the invocation ends.
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.

