docker-selenium-lambda packs headless Chrome into a Lambda container
The simplest demo of chrome automation by python and selenium in AWS Lambda
At a glance
- What is it?
- umihico's docker-selenium-lambda is a minimal container image that runs headless Chromium and Selenium inside AWS Lambda, built on the Amazon Linux Python base image with the Chrome and chromedriver binaries fetched at build time. It suits teams that want a small serverless scraping function, and it is a demo first and a product second.
- Who is it for?
- Adopt docker-selenium-lambda if you want a small, current Chrome and Selenium environment for a single serverless scraping function and you are comfortable maintaining a container image, because the upstream project publishes a public image and the demo gives you a working Dockerfile to copy. Do not adopt it if you need browser concurrency beyond what Lambda gives you, or if you need a hosted browser grid with session management, since this is one function in one container.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly Dockerfile, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A container image, not a Selenium service
docker-selenium-lambda is described as the minimum demo of headless chrome and selenium on a container image on AWS Lambda, and the primary language of the repository is Dockerfile, which is a hint about what the artefact actually is. The whole repository is five things at the top level: the Dockerfile, main.py, a serverless.yml, a LICENSE and the README. There is no library here and no client. The deliverable is a container image that can drive a headless browser, plus a function definition that deploys it. The mechanism is AWS Lambda's container image support, so the image is pushed to a registry and the function runs it as a Lambda runtime rather than as a zip of source. The practical consequence is that everything the browser needs has to be inside the image, which is why the Dockerfile is where the engineering is. For a team that wants to scrape a handful of pages from a scheduled function, this is the smallest possible arrangement: no browser VM, no Selenium Grid, no session to keep alive between calls.
Version pinning, and the daily rebuild behind it
The README states the versions the image goes with, and adds that these are automatically updated and tested every day. The current set is Python 3.14.8, chromium 155.0.8059.84, chromedriver 155.0.8059.84 and selenium 4.51.0. Two details in that list matter more than the others. First, Chromium and chromedriver carry the identical build number, 155.0.8059.84, and they have to. Chrome and its driver are released together and a driver built for a different Chrome build will fail in confusing ways, so a matching pair is the baseline of a working image rather than a detail. Second, the project uses the Chrome for Testing downloads hosted on Google Cloud Storage rather than the older standalone Chrome download paths, which is why the Dockerfile fetches two separate archives with a pinned version in the URL. Selenium is pinned separately with pip install selenium==4.51.0. The daily update workflow is what keeps this pairing intact, and it is why the README says the image goes with these versions rather than that it works with a range.
The Dockerfile, in two stages
The image is built in two stages from the same Amazon Linux Lambda Python base image, pinned by digest. The first stage is a builder that installs unzip and downloads both archives, then unzips them into /opt/.
FROM public.ecr.aws/lambda/python@sha256:27483b5d8a13e85d0f8207706759a30d6a7c89e60aa9d48ec926b445bdc518d2 as build
RUN dnf install -y unzip && \
curl -Lo "/tmp/chromedriver-linux64.zip" "https://storage.googleapis.com/chrome-for-testing-public/155.0.8059.84/linux64/chromedriver-linux64.zip" && \
curl -Lo "/tmp/chrome-linux64.zip" "https://storage.googleapis.com/chrome-for-testing-public/155.0.8059.84/linux64/chrome-linux64.zip" && \
unzip /tmp/chromedriver-linux64.zip -d /opt/ && \
unzip /tmp/chrome-linux64.zip -d /opt/The second stage installs the runtime libraries a headless browser needs rather than the ones a desktop browser wants, which is the part that makes this work in Lambda. The list includes atk, cups-libs, gtk3, alsa-lib, several X11 libraries, pango, at-spi2-atk, xorg-x11-server-Xvfb, xorg-x11-xauth, dbus-glib, nss and mesa-libgbm. Xvfb is there because Chrome still wants a display even in headless mode on some paths, and the set of X libraries is what it dynamically links against. The final instructions copy the browser and the driver out of the build stage into /opt/ in the runtime image, copy main.py, and set the command.
Deploying the demo with the Serverless Framework
The running demo is four commands once the Serverless Framework is installed, and the README gives them with explanatory comments inline.
$ npm install -g serverless@^3 # skip this line if you have already installed Serverless Framework
$ export AWS_REGION=ap-northeast-1 # You can specify region or skip this line. us-east-1 will be used by default.
$ sls create --template-url "https://github.com/umihico/docker-selenium-lambda/tree/main" --path docker-selenium-lambda && cd $_
$ sls deploy
$ sls invoke --function demo # Yay! You will get texts of example.comThe structure of that is worth reading. The region is set through the standard AWS environment variable, and the comment says us-east-1 will be used by default if you skip it. The project is created from a template URL that points at this repository's main branch, into a directory called docker-selenium-lambda, and then the shell changes into it. The deploy step pushes the container image and creates the Lambda function, and the invoke step calls the demo function, which returns the text of example.com. That last output is the acceptance test in one line, and it is a good one, because it exercises the whole chain: the image is built and pushed, the function starts, Chrome launches, Selenium drives it, the page is fetched and the result comes back through the Lambda response. The README also says a demo test workflow runs in CI, which is how the daily version bumps get checked.
The public image as the shortcut
If you do not want to build the image yourself, there is a published one, and the README tells you exactly how to use it. The instruction is to rewrite the Dockerfile with the following commands, which points at the maintained base image and keeps your own function file.
FROM umihico/aws-lambda-selenium-python:latest
COPY main.py ./
CMD [ "main.handler" ]The available tags are listed on Docker Hub, under the umihico/aws-lambda-selenium-python repository. This is the difference between a demo and a reusable base, and it is the reason the project is worth a look even if you never run the demo as it ships. Your own image becomes three lines that inherit a Chrome, chromedriver, Selenium and library stack that is rebuilt and tested every day. The trade is that you are now depending on a third party image that changes underneath you, so a build that worked yesterday may pick up a new Chrome build today. For a team that pins and tests its own image, the safest pattern is to pin a tag of the public image rather than tracking latest, and to keep the version numbers in your own build visible.
Where this approach stops working
A single container running one headless browser inside one Lambda invocation has hard edges, and they are structural rather than configuration problems. The first is duration. A Lambda function has a maximum execution time, and a browser that is slow to start, slow to load a heavy page and then has to shut down cleanly will spend a meaningful share of that budget on overhead rather than on work. The second is concurrency. One function invocation is one browser, so throughput scales with the number of invocations and with the memory and CPU you allocate, and the images are large because a browser is large, so cold starts are not cheap either. The third is the browser itself, since a headless Chromium in a Linux container is a moving target: every Chrome release changes something, and a scraper that breaks on a Chrome update is a scraper that breaks on a schedule you did not choose. The fourth is scope. This repository is explicitly a minimum demo, so there is no session pool, no proxy rotation, no CAPTCHA handling and no scheduling layer. If you need those, you need a different tool, and the README points at the alternatives rather than pretending to be one.
The sibling projects, and the maintenance model
The README names two related projects, and they tell you where this one sits. If you are interested in Node.js or Playwright, it points at docker-playwright-lambda. If you do not want to create functions each time for each purpose, it points at pythonista-chromeless. Both are the same idea moved along one axis: the first swaps the automation stack from Selenium to Playwright while keeping the Lambda container approach, and the second addresses the function-per-purpose awkwardness by giving you a long lived service instead. That comparison is worth making on its own, because the operational difference between one function per job and one service handling many jobs is where the real complexity of scraping infrastructure lives. On maintenance, the project publishes no GitHub releases in the usual sense; what it does publish is dated version artefacts such as 2026-10-16-040658 and 2026-10-14-042839, and the last push to the repository was on 2026-10-16. Those dated tags and the daily version update workflow are the release model, which suits a repository whose main output is an image rather than a library. The licence is MIT, so the Dockerfile and main.py are yours to fork and adapt without the copyleft obligations that would apply to a more restrictive scheme.
Editorial conclusion
Adopt docker-selenium-lambda if you want a small, current Chrome and Selenium environment for a single serverless scraping function and you are comfortable maintaining a container image, because the upstream project publishes a public image and the demo gives you a working Dockerfile to copy. Do not adopt it if you need browser concurrency beyond what Lambda gives you, or if you need a hosted browser grid with session management, since this is one function in one container. Verify two things before you build on it: that the pinned Chrome, chromedriver and selenium versions still match, since the image is rebuilt daily and a version drift between Chrome and chromedriver is the classic failure, and that your function's memory and timeout settings fit a headless browser, which is the resource profile that decides whether this is viable for you. The practical first step is to install the Serverless Framework, create the project from the template URL, and run sls invoke --function demo to confirm you get the text of example.com back before you change anything.
Frequently asked questions
What does docker-selenium-lambda contain?
It is a minimal AWS Lambda container image demo for headless Chrome and Selenium. The repository holds a Dockerfile, main.py, a serverless.yml and the README, and the Dockerfile installs Chromium, chromedriver, selenium and the X11 and graphics libraries a headless browser needs.
How do I run the docker-selenium-lambda demo?
Install the Serverless Framework, set AWS_REGION, then run sls create with the template URL pointing at the repository main branch, sls deploy, and sls invoke --function demo. The last command returns the text of example.com.
Which versions of Chrome, chromedriver and selenium does the image use?
The README lists Python 3.14.8, chromium 155.0.8059.84, chromedriver 155.0.8059.84 and selenium 4.51.0, and states that these are automatically updated and tested every day.
Is there a prebuilt image I can use instead of building my own?
Yes. The public image umihico/aws-lambda-selenium-python is published on Docker Hub with a list of available tags, and the README shows rewriting your Dockerfile to start FROM that image, copy main.py and set the command to main.handler.
What happens when Chrome and chromedriver versions disagree?
The image pins chromium and chromedriver to the same build number, 155.0.8059.84, because a driver built for a different Chrome build will not drive it correctly. The daily version update workflow exists to keep that pairing intact.
Are there alternatives to docker-selenium-lambda?
The README points at docker-playwright-lambda if you want Node.js or Playwright instead of Selenium, and at pythonista-chromeless if you would rather run a long lived service than create a function for each purpose.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/umihico-docker-selenium-lambda)Was this useful?