Optimizely will be sunsetting Full Stack Experimentation on July 29, 2024. See the recommended Feature Experimentation migration timeline and documentation.

Dev GuideAPI Reference
Dev GuideAPI ReferenceUser GuideGitHubNuGetDev CommunitySumbit a ticketLog In
GitHubNuGetDev CommunitySumbit a ticket

AWS Lambda@Edge

Starter Kit hosted on GitHub for running Optimizely Full Stack feature flags and experiments on the AWS Lambda@Edge functions using AWS Lambda and AWS CloudFront.

AWS Lambda@Edge

Lambda@Edge is an extension of AWS Lambda, a compute service that lets you execute functions that customizes the content that CloudFront delivers.

Advantages of Lambda@Edge

  • Speed – Extend your compute location closer to our users with CloudFront's reduction in latency.

  • Cost – Consolidate requests and remove transfer out fees from AWS origins.

  • Security – Improved security from DDOS attacks through AWS Standard Shield.

AWS Lambda@Edge use cases

You can build a variety of solutions, such as:

  • Inspect cookies to rewrite URLs to different versions of a site for experimentation.

  • Send different objects to your users based on the User-Agent header, which contains information about the device that submitted the request. For example, you can send images in different resolutions to users based on their devices.

  • Inspect headers or authorized tokens, inserting a corresponding header and allowing access control before forwarding a request to the origin.

  • Add, delete and modify headers and rewrite the URL path to direct users to different objects in the cache.

  • Generate new HTTP responses to do things like redirect unauthenticated users to login pages or create and deliver static webpages right from the edge. For more information, see Using Lambda functions to generate HTTP responses to viewer and origin requests in the Amazon CloudFront Developer Guide.

In this starter kit, we utilize Lambda@Edge to call to your Optimizely datafile and make decisions on whether feature flags are enabled or disabled based on an incoming user ID by checking the value of OPTIMIZELY_USER_ID from the cookies.

AWS Lambda@Edge Restrictions & Limitations

  • There are some restrictions to using Lambda@Edge. Please read the official documentation for the most up-to-date details.

  • As of July 2022, the maximum compressed size of a Lambda@Edge package can't exceed 50MB for origin events and 1MB for viewer events.

Further Considerations

Optimizely + AWS Lambda@Edge Starter Kit

The Optimizely starter kit for AWS's Lambda@Edge embeds and extends our Javascript SDK to provide a starting point for you to implement experimentation and feature flagging for your experiences at the edge. For a guide to getting started with our platform more generally, this can be combined with the steps outlined in our Javascript Quickstart.

📘

Note

This starter kit makes use of the "Lite" version of our Javascript SDK for Node.js.

External Data Fetching & Caching

This starter kit uses standard ES7 async/await fetch methods to handle external data fetching. After fetching the Optimizely datafile, the datafile itself is cached as a JSON object in-memory. Large datafiles may cause this method presented in the starter kit to break. If you experience issues with large datafiles breaking in-memory Lambda caching, you can consider one of the alternative methods of caching with Lambda@Edge outlined in this article.

Alternative methods to in-memory data caching include using a persistent connection to your datafile JSON or caching via CloudFront.

For even faster data fetching, you can store your datafile in an S3 bucket that you own and refactor the datafile fetching mechanism to use Lambda's built-in AWS SDK library and fetch from your S3 bucket instead.

📘

Note

Additional caching mechanisms may be available through your CloudFront distribution's configuration.

Identity Management

Out of the box, Optimizely's Full Stack SDKs require a user-provided identifier to be passed in at runtime to drive experiment and feature flag decisions. In case a user ID is not provided directly from the client, this starter kit generates a unique ID as a fallback, stores it into the cookie and re-uses it to ensure decisions are sticky per user session. Alternatively, you can use an existing unique identifier available within your application and pass it in as the value for the OPTIMIZELY_USER_ID cookie.

Bucketing

For more information on how Optimizely Full Stack SDKs assign users to feature flags and experiments, see the documentation on how bucketing works.

How to use

Prerequisites

You will need to complete the following prerequisites to use this template:

  • Set up and configure AWS Lambda@Edge. For a tutorial on how to setup a basic AWS Lambda@Edge environment, click here.
  • Have an Optimizely account. If you do not have an account, you can register for a free account.

Get started

  1. After your Lambda@Edge environment is prepared, clone the starter kit from GitHub to your local development environment and run:
 npm install
  1. Navigate to src/index.js and update the <YOUR_SDK_KEY_HERE> and <YOUR_FLAG_HERE> values to the respective values from your Optimizely dashboard. To access your SDK key from the Optimizely app, navigate to the Settings tab.

📘

Note

You can not store environment variables with Lambda@Edge. Read more about the limitation here. If you'd like to inject the SDK Key into your Lambda, an alternative method is outlined in this StackOverflow post detailing how to use CloudFront Origin Custom Headers as a workaround.

  1. Hook into different lifecycle events by inserting logic to change headers, cookies, and more in the switch-case statement in src/index.js.
  2. Utilize Optimizely's JavaScript Lite bundle to get decisions and log events to influence the behavior of that logic.
  3. Use Rollup to bundle the source code into a neat .zip file to be imported into Lambda:
npm run build

📘

Note

Notice that a /dist folder is generated with the new dist.zip file. It should be roughly ~22kb in size assuming you have not made any additional changes.

  1. Upload your function to AWS Lambda via GUI or CLI.
    1. Navigate to your AWS Lambda console, select the function associated your Lambda@Edge environment and import the dist.zip file. After you upload it, there should now be a minified index.js file located inside of your Lambda function's "Code Source" section.
    2. AWS CLI: You can use the AWS CLI to update your AWS Lambda function programmatically. Example command: aws lambda update-function-code --function-name my-aws-lambda-at-edge-function --zip-file fileb://dist.zip
    3. Lambda Layers: If you need additional libraries, custom runtimes or configuration files to use alongside your Lambda function, consider looking into utilizing Lambda Layers.
  2. After your Lambda Function is set up, ensure that you have provisioned it with Lambda@Edge permissions and associate it with your CloudFront distribution. Set the CloudFront trigger for this function to be "Viewer Request".

📘

Note

CloudFront triggers are associated with only one specific version of your Lambda function. Remember to update the CloudFront trigger assignment as needed when pushing new versions of your Lambda function. You may, for example, need to have one function that handles receiving viewer requests (viewer request trigger) and one function that handles returning a response to the viewer (viewer response trigger).

  1. Test your Lambda@Edge function - you should see that it returns a simple home page with the results of your feature flag test. Hooray!

To see what the starter kit is accomplishing, you can go to your CloudWatch console. Under Logs > Log groups > /aws/lambda/<YOUR_LAMBDA_NAME>, click into your Lambda's log group and view the test. You'll find the entire process of reading the headers, assigning the User ID, fetching the datafile and making the decision all there.

📘

Note

Also provided are:

  • A slightly altered version of index.js - viewer_request.js, which is a file that outlines how to return a request object instead of a response object. You can refer to this file when designing functions that only adjust the request to your origin rather than return a response.
  • viewer_response.js, which is a file that reads the cookie from the request headers and includes them in the return response. You can refer to this file when accommodating for retrieving a user ID generated from the viewer request hook and re-using it in the viewer response hook.
  1. Adjust your Lambda's configuration as needed. For example, you may need to increase your function's memory, storage and timeout threshold to accommodate your function's needs.
  2. From here, you can use Optimizely's experimentation features as desired. You can modify the cookies and headers based on experimentation results, add hooks to the "Origin Request" and "Origin Response" CloudFront triggers to do things like origin redirects or dynamic asset manipulation or add more services to the pipeline including your own logging systems, databases, CDN origins and more. Keep in mind that Lambda@Edge has some limitations - you can familiarize yourself with those by referencing this article - Edge Functions Restrictions.

Additional resources