Skip to content

AWS Lambda Selenium ChromeDriver: Run Headless Automation | ShillehTek

July 13, 2024

Video Tutorial (Optional)

Watch first if you want to see the full AWS Lambda + Selenium + ChromeDriver container workflow end to end.

Project Overview

AWS Lambda + Selenium + ChromeDriver: In this tutorial, you run Selenium with ChromeDriver inside an AWS Lambda function (Python) by packaging everything into a Docker container, enabling scalable serverless browser automation.

This setup is useful for web scraping, web app testing, or other headless browser automation tasks in the cloud. The example Lambda searches for “OpenAI” on Google and returns the titles of the search results.

  • Time: 45 to 90 minutes
  • Skill level: Intermediate
  • What you will build: A containerized AWS Lambda function that runs headless Chrome via Selenium and ChromeDriver

Support and links: Subscribe on YouTube: YouTube - Shilleh. Support: Buy Me A Coffee. Hire services: UpWork. ShillehTek store: https://shillehtek.com/collections/all. Amazon stores: ShillehTek Amazon Store - US, ShillehTek Amazon Store - Canada, ShillehTek Amazon Store - Japan.

Parts List

From ShillehTek

External

  • AWS account
  • GitHub account
  • Docker Desktop
  • AWS CLI (configured)
  • Python AWS Lambda base image: amazon/aws-lambda-python:3.12
  • Selenium (Python package)
  • Headless Chrome and ChromeDriver (installed into the container by script)
  • Linux dependencies and tools used in the image build: dnf, curl, jq, unzip

Note: This project installs Chrome and ChromeDriver into /opt inside the container and configures Selenium to use those paths at runtime.

Step-by-Step Guide

Step 1 - Create the Lambda handler (main.py)

Goal: Create a Python Lambda function that launches headless Chrome with Selenium, performs a Google search for “OpenAI”, and returns the titles of results.

What to do: Create a file named main.py and paste in the code below.

Code:

import os
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options as ChromeOptions
from tempfile import mkdtemp


def lambda_handler(event, context):
    chrome_options = ChromeOptions()
    chrome_options.add_argument("--headless=new")
    chrome_options.add_argument("--no-sandbox")
    chrome_options.add_argument("--disable-dev-shm-usage")
    chrome_options.add_argument("--disable-gpu")
    chrome_options.add_argument("--disable-dev-tools")
    chrome_options.add_argument("--no-zygote")
    chrome_options.add_argument("--single-process")
    chrome_options.add_argument(f"--user-data-dir={mkdtemp()}")
    chrome_options.add_argument(f"--data-path={mkdtemp()}")
    chrome_options.add_argument(f"--disk-cache-dir={mkdtemp()}")
    chrome_options.add_argument("--remote-debugging-pipe")
    chrome_options.add_argument("--verbose")
    chrome_options.add_argument("--log-path=/tmp")
    chrome_options.binary_location = "/opt/chrome/chrome-linux64/chrome"

    service = Service(
        executable_path="/opt/chrome-driver/chromedriver-linux64/chromedriver",
        service_log_path="/tmp/chromedriver.log",
    )

    driver = webdriver.Chrome(
        service=service,
        options=chrome_options,
    )

    # Open a webpage
    driver.get("https://www.google.com")

    # Find the search box
    search_box = driver.find_element(By.NAME, "q")

    # Enter a search query
    search_box.send_keys("OpenAI")

    # Submit the search query
    search_box.send_keys(Keys.RETURN)

    # Wait for the results to load
    time.sleep(2)

    # Get the results
    results = driver.find_elements(By.CSS_SELECTOR, "div.g")

    # Print the titles of the results
    titles = [result.find_element(By.TAG_NAME, "h3").text for result in results]

    # Close the WebDriver
    driver.quit()

    return {
        "statusCode": 200,
        "body": titles,
    }

Expected result: Your handler is ready and references Chrome at /opt/chrome/chrome-linux64/chrome and ChromeDriver at /opt/chrome-driver/chromedriver-linux64/chromedriver.

Step 2 - Create the Dockerfile for AWS Lambda

Goal: Build a Lambda-compatible container image that includes Chrome dependencies, installs Chrome and ChromeDriver, installs Selenium, and sets the Lambda entrypoint.

What to do: Create a file named Dockerfile and paste in the following.

Code:

FROM amazon/aws-lambda-python:3.12

# Install chrome dependencies
RUN dnf install -y atk cups-libs gtk3 libXcomposite alsa-lib \
    libXcursor libXdamage libXext libXi libXrandr libXScrnSaver \
    libXtst pango at-spi2-atk libXt xorg-x11-server-Xvfb \
    xorg-x11-xauth dbus-glib dbus-glib-devel nss mesa-libgbm jq unzip

# Copy and run the chrome installer script
COPY ./chrome-installer.sh ./chrome-installer.sh
RUN chmod +x ./chrome-installer.sh
RUN ./chrome-installer.sh
RUN rm ./chrome-installer.sh

# Install selenium
RUN pip install selenium

# Copy the main application code
COPY main.py ./

# Command to run the Lambda function
CMD [ "main.lambda_handler" ]

Expected result: The image will be able to run Selenium with headless Chrome in the Lambda runtime environment.

Step 3 - Add the Chrome and ChromeDriver installer script

Goal: Download and install the latest stable “Chrome for Testing” binaries (Chrome and ChromeDriver) into the container’s /opt directory.

What to do: Create a file named chrome-installer.sh and paste in the following.

Code:

#!/bin/bash
set -e

latest_stable_json="https://googlechromelabs.github.io/chrome-for-testing/last-known-good-versions-with-downloads.json"

# Retrieve the JSON data using curl
json_data=$(curl -s "$latest_stable_json")

latest_chrome_linux_download_url="$(echo "$json_data" | jq -r ".channels.Stable.downloads.chrome[0].url")"
latest_chrome_driver_linux_download_url="$(echo "$json_data" | jq -r ".channels.Stable.downloads.chromedriver[0].url")"

download_path_chrome_linux="/opt/chrome-headless-shell-linux.zip"
download_path_chrome_driver_linux="/opt/chrome-driver-linux.zip"

mkdir -p "/opt/chrome"

curl -Lo $download_path_chrome_linux $latest_chrome_linux_download_url
unzip -q $download_path_chrome_linux -d "/opt/chrome"
rm -rf $download_path_chrome_linux

mkdir -p "/opt/chrome-driver"

curl -Lo $download_path_chrome_driver_linux $latest_chrome_driver_linux_download_url
unzip -q $download_path_chrome_driver_linux -d "/opt/chrome-driver"
rm -rf $download_path_chrome_driver_linux

Expected result: The container image will include Chrome under /opt/chrome and ChromeDriver under /opt/chrome-driver.

Step 4 - Build the Docker image locally

Goal: Build the container that AWS Lambda will run.

What to do: From the folder containing main.py, Dockerfile, and chrome-installer.sh, run:

Code:

docker build -t selenium-chrome-driver .

Expected result: A local image named selenium-chrome-driver is created successfully.

Step 5 - Tag and push the image to AWS ECR

Goal: Upload your built image to Amazon ECR so Lambda can pull it.

What to do: Tag your image, authenticate Docker to ECR, then push.

Code:

docker tag selenium-chrome-driver <your amazon account id>.dkr.ecr.us-east-1.amazonaws.com/docker-images:v1.0.0

aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin <your amazon account id>.dkr.ecr.us-east-1.amazonaws.com/docker-images

docker push <your amazon account id>.dkr.ecr.us-east-1.amazonaws.com/docker-images:v1.0.0

Expected result: Your image version v1.0.0 is available in your ECR repository.

Step 6 - Deploy the container image as an AWS Lambda function

Goal: Create or update a Lambda function that uses your ECR image.

What to do: In AWS Lambda, choose the container image from ECR and deploy. Make sure to increase the configuration resources for the container so it does not time out or run out of memory.

AWS Lambda console showing container image deployment settings for a Selenium and ChromeDriver Docker image

Expected result: The Lambda function is created (or updated) and configured to run your container image.

Step 7 - Run a test event and confirm output

Goal: Verify the function runs Selenium in headless Chrome and returns titles from Google results.

What to do: Run a test event in the Lambda console and confirm you get a successful response with a list of titles.

AWS Lambda test execution output showing a successful response with titles returned by Selenium ChromeDriver

Expected result: You see a successful output returned from the Lambda invocation.

Conclusion

You just set up Selenium with ChromeDriver inside an AWS Lambda function by containerizing the runtime, browser, and dependencies into a Docker image. This approach brings serverless scalability to headless browser automation while keeping environment setup repeatable.

Want to support future tutorials and grab project resources? Visit ShillehTek.com. If you want help adapting this pattern for your own automation, scraping, or product workflow, check out our consulting: https://shillehtek.com/pages/iot-consulting.