Skip to main content
menu-icon.png

 

x
Optimizely Knowledge Base

Optimizely self-hosting for Amazon Cloudfront users

 
relevant products:
  • Optimizely X Web Experimentation
  • Optimizely X Web Personalization

THIS ARTICLE WILL HELP YOU:
  • Set up CDN self-hosting using Amazon Cloudfront

If you need to download and self-host the Optimizely snippet on your own site, Amazon Cloudfront offers an easy way to do it, via multiple AWS services working together. And because this approach involves setting up a webhook in Optimizely, there will be no need for you to poll for any revisions in your snippet.

Self-hosting is ideal for customers who are using HTTP/2 to serve their website and Amazon Cloudfront as their CDN.  By self-hosting, you can eliminate a SSL connection to Optimizely while using multiplexing to request the snippet faster.

While self-hosting with an HTTP/1 connection may eliminate an additional DNS lookup and the SSL handshake, there is no guarantee the script will begin it's download earlier than if it was being downloaded directly from Optimizely.

This article will describe how to set up a Lambda function to listen for changes in your Optimizely snippet, how to save that snippet to your S3 bucket, how to call that script from your website, and how to set up your webhook.

This article will help you sync the Optimizely snippet into an S3 bucket, and it therefore assumes you are using Cloudfront with an S3 origin.

Create a Lambda function

The first step in the process is to create a new Lambda function. This function will listen for the Optimizely webhook and update your local version of the snippet.

From the AWS interface, create a new Lambda function, starting with a blueprint microservice-http-endpoint

When you create the Lambda function, you can opt to use either NodeJS or Python3. The examples used in this sequence show Python3.

  1. Give your new function a descriptive name, such as optimizelywebhook

  2. Create a new IAM role, or use an existing IAM role for this function that has access to both:

  • Amazon S3 (policy: AmazonS3FullAccess), and

  • Amazon CloudWatch logs (policy: AWSLambdaBasicExecutionRole or CloudWatchLogsFullAccess)

  1. Next, create the function. This will enable you to edit your code.

  2. Replace YOUR-AWS-S3-BUCKET-NAME with the bucket where you'd like to store your copy of your Optimizely snippet.

Below is an example of an appropriate Lambda function:

import boto3
import json
from botocore.vendored import requests

def resp(err = None, res = {}):
   resp_body = {'message': str(err)} if err else res
   return {
       'statusCode': '400' if err else '200',
       'body': json.dumps(resp_body),
       'headers': {
           'Content-Type': 'application/json',
       },
   }

def Lambda_handler(event, context):
   err = None
   res = {}
   
   print('Received webhook: {}'.format(event['headers']['Host']))
   
   if event['httpMethod'] != 'POST':
       return resp(ValueError('Must be a post request'))
       
   # fetch snippet from Optimizely CDN
   try:
       snippet_metadata = json.loads(event['body'])
       snippet_origin   = snippet_metadata.get('data', {}).get('origin_url')
       project_id       = snippet_metadata.get('project_id')
       snippet_updated  = snippet_metadata.get('timestamp')
       snippet_contents = requests.get(snippet_origin).text
   except Exception as e:
       err = e
   
   # write snippet content to s3
   try:
       s3       = boto3.resource('s3')
       s3object = s3.Object('YOUR-AWS-S3-BUCKET-NAME', 'snippet/{}.js'.format(project_id))
       s3object.put(Body=snippet_contents, ACL='public-read', ContentType='application/javascript')
   except Exception as e:
       err = e
   
   return resp(err, {'message': 'success'})

This example configures the function to only accept POST requests, parse that request (based on a successful POST request), and save the Optimizely snippet to your AWS S3 Bucket. The snippet is saved as your-aws-s3-bucket-name.com/snippet/PROJECTID.js

  1. After saving your edits to the function, navigate to your API gateway trigger.

  1. Under the API Gateway section, take note of your API endpoint. You'll need this later for setting up your Optimizely webhook.

Configure the Optimizely webhook

  1. In Optimizely, open the project you'd like to self-host and navigate to Settings.

  2. Navigate to the Webhooks tab and click Create New Webhook…

  1. You will be prompted for a URL where a POST request can be sent each time your snippet is updated. Enter the URL of your Lambda API endpoint from step 6 above.

Configure a custom TTL (optional)

To configure a custom TTL for this script, you will need to change your cache setting in your Cloudfront distribution from Customize to Use Origin Cache Headers.

You will then be able to include a cache-control setting in the function that writes the Optimizely data to S3.

Example:

s3object.put(Body=snippet_contents, ACL='public-read', 
ContentType='application/javascript', CacheControl='max-age=120')


If you want your base Cloudfront TTL settings to apply to this script as well, leave object caching set to Customize.

Modify the Optimizely snippet

If the Optimizely snippet is already installed on your page, you'll need to remove it and replace it with the new script tag that references your self-hosting path.

If you are new to Optimizely, just add this new script tag in the appropriate spot inside the <head> tag on your page.

The format of this snippet should be:

<script src=”your-aws-s3-bucket-name.com/snippet/PROJECTID.js”></script>

Example:

<script src="https://cdn.optimizely.com/js/123456789.js"></script>

should now be:

<script src=”your-aws-s3-bucket-name.com/snippet/123456789.js”></script>

Repeat this step for any additional snippets you may have across your site.

Don't forget, the /snippet/PROJECTID.js portion is from the Lambda code, and should reflect what's in your Lambda function.