AWS Lambda@Edge Integration
May 13, 2026 · View on GitHub
AWS Lambda@Edge can add ostr.io pre-rendering in front of any public site already served through Amazon CloudFront. Use it when CloudFront is the CDN layer you control and Cloudflare Workers, Vercel middleware, or a reverse proxy are not the right fit.
- Pre-rendering overview
- Rendering endpoints
- Complete AWS examples
- Canonical regex sources - Crawler User-Agent, Static-asset extensions
Contents
- How it works
- When to use
- Quick start
- Operational notes
- Cache behavior
- Validation
- Common issues
- Related
How it works
AWS splits the Cloudflare Worker-style middleware into two edge pieces:
- CloudFront Function, viewer-request - runs before cache lookup, detects crawler traffic with the canonical regex, and adds
X-Ostr-Prerender: 1or0. - Lambda@Edge, origin-request - runs on cache misses, reads
X-Ostr-Prerender, and rewrites matching HTML requests tohttps://render.ostr.io/?url=...&bot=....
This shape avoids caching on raw User-Agent, avoids Lambda-generated response body limits, and keeps visitor traffic on the original CloudFront origin.
When to use
- The website is already behind Amazon CloudFront.
- You can edit the distribution behavior, cache policy, origin request policy, and origin custom headers.
- You want CDN-level pre-rendering without changing the origin app.
- You need one integration that works across S3, ALB, API Gateway, EC2, ECS, or any custom HTTPS origin behind CloudFront.
Do not use this integration when you can deploy a simpler platform-native middleware at the HTML layer. Prefer Cloudflare Worker, Vercel, Nginx, Apache, Caddy, Next.js, or Node.js when those layers are already controlled by the project.
Quick start
-
Add and verify the production domain in the ostr.io pre-rendering panel; copy the
Basic ...token. -
Copy
examples/aws-lambda/cloudfront-viewer-request.jsinto a CloudFront Function, publish it, and associate it with the cache behavior as Viewer request. -
Configure the cache behavior policies:
- Cache policy — include header
X-Ostr-Prerenderin the cache key. Include all query strings (or at least every public query parameter plus_escaped_fragment_). - Origin request policy — forward both
X-Ostr-PrerenderandX-Ostr-User-Agentto origin, and forward query strings consistent with the cache policy. - Do not put raw
User-Agentin the cache key. AWS recommends against it because UA values fragment the cache; this integration uses a low-cardinalityX-Ostr-Prerender: 0|1instead.
- Cache policy — include header
-
Add origin custom header
X-Ostr-Auth: Basic <token>to the CloudFront origin. Lambda@Edge does not support custom environment variables, so this is the recommended secret path. -
Create the Lambda execution role with a trust policy for both Lambda and Lambda@Edge:
{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": { "Service": ["lambda.amazonaws.com", "edgelambda.amazonaws.com"] }, "Action": "sts:AssumeRole" }] }Attach
AWSLambdaBasicExecutionRolefor CloudWatch Logs. No additional permissions are required. -
Copy
examples/aws-lambda/lambda-edge-origin-request.jsinto a Node.js Lambda function inus-east-1using the role above. -
Publish a numbered Lambda version and associate that version with the cache behavior as Origin request.
-
Deploy the distribution and run Validation.
See examples/aws-lambda/ for file-level setup and behavior details.
Operational notes
- Logs spread across regions — Lambda@Edge writes to CloudWatch Logs in the region nearest each viewer, not
us-east-1. Default retention is "Never expire". Set retention (e.g. 7 days) on the/aws/lambda/us-east-1.<function-name>log group in every region the distribution serves, or apply it programmatically. - Tests — the example Lambda exports private helpers for unit testing. Run
node --test examples/aws-lambda/from the docs tree.
Cache behavior
CloudFront origin-request Lambda@Edge runs only when CloudFront sends a request to origin. If a page is already in edge cache, the origin-request Lambda does not execute. The viewer-request CloudFront Function solves this by adding a low-cardinality X-Ostr-Prerender cache-key header before cache lookup:
| Header | Cache variant |
|---|---|
X-Ostr-Prerender: 0 | Human / normal HTML |
X-Ostr-Prerender: 1 | Crawler / rendered HTML |
Do not put raw User-Agent in the cache key. AWS documents that User-Agent has many possible values and can fragment the cache. The example copies the original viewer UA into X-Ostr-User-Agent only for Lambda routing and renderer analytics.
Validation
After deploying, invalidate the CloudFront cache so the first test request does not hit a pre-integration cached response:
aws cloudfront create-invalidation --distribution-id <id> --paths '/*'
Bot request should return a pre-rendered snapshot with X-Prerender-Id:
curl -sI -A 'Googlebot/2.1' https://example.com/
Regular browser request should not include X-Prerender-Id:
curl -sI -A 'Mozilla/5.0' https://example.com/
Legacy fragment request should hit the renderer:
curl -sI 'https://example.com/?_escaped_fragment_='
Direct renderer smoke test:
curl -v -H "Authorization: Basic dGVzdDp0ZXN0" "https://render-bypass.ostr.io/?url=https://example.com"
Common issues
- Bot gets human HTML -
X-Ostr-Prerenderis not in the cache key, the CloudFront Function is not associated with viewer-request, or CloudFront cache was not invalidated after deployment. - Lambda never runs - origin-request Lambda@Edge only runs on cache misses. Invalidate the URL or wait for TTL expiry.
- Renderer returns
401/403-X-Ostr-Authis missing from origin custom headers or the copied token is not theBasic ...value from ostr.io. - Lambda deploy fails - Lambda@Edge functions must be created in
us-east-1, published as numbered versions, and associated by version ARN rather than$LATESTor alias. - Query parameters disappear - cache and origin request policies are not forwarding query strings. Include all query strings unless the site has a tighter documented list.
- Origin receives
X-Ostr-Auth- keep the cleanup block inlambda-edge-origin-request.js; it removes the origin custom header before visitor pass-through. - Every crawler request misses cache - raw
User-Agentis in the cache key. UseX-Ostr-Prerenderinstead.
Related
- AWS Lambda@Edge examples
- Cloudflare Worker integration
- Vercel integration
- Nginx integration
- Rendering endpoints
- AWS Lambda@Edge restrictions
- AWS Lambda@Edge event associations
- AWS CloudFront Functions restrictions
- AWS Lambda@Edge generated response limits
- AWS origin request policies
- AWS origin custom headers