An AWS Lambda Layer containing Playwright and Chromium, optimized for AWS Lambda with Node.js 22.x runtime, and deployed using the Serverless Framework v4.
- Node.js 20.x or later
- NPM or Yarn
- AWS CLI installed and configured with credentials
- A centralised Serverless Framework deployment S3 bucket using the format {aws-account-id}--serverless-deploys
Replace {aws-account-id} with your AWS account ID. Create the bucket with default settings.
Install NPM dependencies:
npm installThis will install the Serverless Framework used for deploying the layer to AWS.
Build the layer with all required dependencies:
npm run buildThis will install the Playwright (playwright-core) library and an file size optimised version of Chromium (@sparticuz/chromium) which fits within the AWS Lambda layer size limit of 250MB.
Deploy the layer to AWS:
npx serverless deployOnce deployed, the console will output a layer ARN like below:
layers:
playwright: arn:aws:lambda:us-east-1:272354801446:layer:playwright-chromium-layer-dev:1Deploy infrastructure with a specific stage name appended to the layer name. In the example below the layer will have -production appended to the name.
npx serverless deploy --stage productionReference the layer in your Lambda functions in the serverless.yml file, like this:
functions:
myFunction:
handler: handler.handler
layers:
- arn:aws:lambda:${aws:region}:${aws:accountId}:layer:playwright-chromium-layer-${self:provider.stage}:1
runtime: nodejs22.xOnce the Layer is attached to your Lambda, Playwright and Chromium can be imported (required) and used in your Lambda function. You do not need to install them via NPM or Yarn as part of you application and they can be excluded from any deployments.
Here's how to use Playwright with Chromium in your Lambda function:
const playwright = require('playwright-core');
const chromium = require('@sparticuz/chromium');
exports.handler = async (event) => {
let browser = null;
try {
browser = await playwright.chromium.launch({
args: chromium.args,
executablePath: await chromium.executablePath(),
headless: chromium.headless,
});
const page = await browser.newPage();
await page.goto(event.url || 'https://example.com');
const screenshot = await page.screenshot({ type: 'png' });
return {
statusCode: 200,
headers: { 'Content-Type': 'image/png' },
body: screenshot.toString('base64'),
isBase64Encoded: true
};
} catch (error) {
console.error('Error:', error);
return {
statusCode: 500,
body: JSON.stringify({ error: error.message })
};
} finally {
if (browser) await browser.close();
}
};The example above will take a screenshot of the URL provided in the event object and return it as a base64 encoded image.
Note: The layer is currently only compatible with Node.js 20.x and 22.x due to dependency issues with Node.js 24.x. Make sure your Lambda is running on the Node.js 20.x or 22.x runtime.