Cloudflare Workers
Why this is important
When customers look to achieve fast performance, elastic scale, enhanced security, and infrastructure efficiency of their web properties, they turn to Jamstack. The static websites provide this promise. Where static sites typically fail to deliver is when you need to alter the web experience of each individual visitor. The marketing users want to keep personalization and A/B testing capabilities, so they can continuously optimize the web experience and increase the conversions.
While there are client-side tools that work on the DOM-level, this approach predates the modern virtual DOM-based front-end libraries and frameworks, like React and Vue. This causes constant conflict for DOM (HTML), which results in flicker, content swaps, poor UX for your visitors in general, as well as a negative impact on Core Web Vitals.
This is when the digital architects turn back to the server-side rendering. Depending on the specific parameters of the solution, this may set you back in terms of infrastructure overhead and even performance. Going back from the Jamstack paradigm to more traditional server-side rendering can come with some trade-offs.
This is where the edge-side processing of static sites comes to the rescue. Powered by the edge compute capability of a Content Delivery Network, this functionality allows to continue generating static pages at build-time (Jamstack) but also provides the ability to modify page contents before it reaches the users' browser.
This allows keeping the best of both worlds: stellar performance, scale, and security characteristics that Jamstack is great for, and run personalization and A/B testing.
Enter Cloudflare Workers
Cloudflare Workers have been around for quite some time, and it is one of the primary mature services developers use for anything related to edge compute.
What makes Cloudflare quite special is that it can be the new static site origin with Cloudflare Pages or KV storage, but it can also be used as the edge layer in front of an existing server-side rendering origin (think legacy CMS web server), or a static file storage (like Azure Blob Storage, or AWS S3).
Universal approach for SSG and SSR
Even though we will use a statically generated site as the origin, since it's easier, the Cloudflare Worker can rewrite the server-side rendered origin and cache the results at the edge, so this setup can work without Jamstack.
With a statically generated site ("Jamstack"):
or in front of a SSR server:To learn more about Cloudflare Workers, visit this official documentation.
Uniform and Cloudflare Workers
Uniform Context comes with the edge-side SDK and plugs natively into Cloudflare Workers allowing business users to manage both personalization and A/B testing without developer involvement. The personalization and A/B testing runs in front of the statically generated pages, outside of the browser, which conquers the flicker, content swaps and Cumulative Layout Shift issues. This capability is what we will be referring to as Edge-side personalization.
To learn more about Edge-side vs. Server-side personalization, check out this doc.
Blazing fast page load without flicker
This is a real webpagetest.org test showing 600ms page complete without any UX issues:

Quick demo
Open this pre-deployed demo site to experience Uniform personalization running on Cloudflare Workers, check it out:

Experience these scenarios
- Open the For Developers page and go back home. Notice the hero changed to show a different message.
- Do a full page reload. Notice the page is stable, and no flicker!
- Now, try disabling JavaScript in your browser dev tools. Refresh the page. Notice the personalization still occurs? This is edge-side execution in action.
- Re-enable JavaScript to continue with the demo.
- Click Forget me to reset the Uniform signal scores. Visit For marketers and return to the home page, notice a different variant. This is personalization based on behavior collected at the edge.
- Go to Registration and complete fake registration. Go back to home. Notice a different hero is shown. This is a cookie-based signal in action. Click Forget me to reset the Uniform signal scores.
- Now visit the Campaign page. Notice
?utm_campaign=unfrmconfis added to the URL and a different hero is shown? This is a query string-based signal in action.
Use cases
The following use cases are possible with Uniform Context + Cloudflare Workers:
- GEO-based personalization based on Cloudflare Geo data.
Our Cloudflare integration extends your project with Cloudflare-specific quirks, allowing to create signals based on any Geo attribute Cloudflare provides..
- Personalize based on device characteristics that are available at the Cloudflare edge.
- Personalize on any data present on the HTTP request:
utm_campaignor any query string-based personalization- Cookie-based personalization
- Uniform A/B testing
- Personalization based on session context (user preferences, profile, shopping history, etc.).
- CDP-based personalization (or any API-based data context provider for that matter).
This will require fetching this data from the Edge Functions and supplying the values into Uniform Context quirks.
Getting started
Pre-requisites
- An account with Cloudflare.
- Access to Github.
- Node.js installed locally.
- In order to run Cloudflare Workers locally, you would need to use Cloudflare Wrangler CLI. Run
npm install -g wranglerto install.
Step 1: Working locally
Private npm packages needed
This guide requires access to private Uniform npm packages, requiring an npm token issued by one of the Uniform representatives. Set the token as NPM_TOKEN environment variable (recommended), or replace the token reference in .npmrc file in application root.
- If you are an existing customer, please contact support.
- If you are evaluating Uniform, please contact us here.
It's a sample app
You are about to use a sample app geared towards this specific tutorial. It setup with the essentials only, therefore not recommended to be used as a foundation to build a production site. This sample app is using a "fake CMS", so it's should be easy to get started.
Step 1.1 Prepare the baseline static app
Clone this repo:
git clone https://github.com/uniformdev/examples.gitcd examples/base-appRun
npm installto install all dependencies.Run
npm run ci:buildto run full static export of this Next.js site.Run
npx serve outand ensure the site runs on http://localhost:5000Deploy this site to any public static CDN. Use whatever you already have. If you Netlify, run
netlify deploy --prod --dir out, the CLI will ask you to confirm this action.
Grab the public URL
After the deployment succeeds, you will need a public URL of this statically generated site to configure the Cloudflare Worker during the next step.
Step 1.2 Run the Cloudflare worker locally
cd examples/cloudflare-workernpm installLocate
wrangler.tomland set the following attributes:name: set the name of the workeraccount_id: the Cloudflare account id that can be retrieved from the Cloudflare dashboard.- set the
ORIGIN_URLenvironment variable to the value of the publicly accessible static site deployed during Step 1.1 earlier:
name = "myfirstworker"
...
account_id = "YOUR CLOUDFLARE ACCOUNT ID"
[vars]
ORIGIN_URL = "mystaticsite.netlify.app"IMPORTANT
When setting
ORIGIN_URL, drophttps://, and no trailing slashes, so:ORIGIN_URL = "mystaticsite.netlify.app"not
ORIGIN_URL = "https://mystaticsite.netlify.app"Run
wrangler devto start the worker locally.Open
http://127.0.0.1:8787/?utm_campaign=unfrmconf, you are expected to see the personalized hero with the "Call for papers" content.Now disable JavaScript in Chrome dev tools and reload the page. You should still see personalized hero without any JavaScript execution in the browser.
That's essentially proving you are working within the edge-side mode locally!
Step 2: Deploy your app
Run
wrangler buildto build the worker.Run
wrangler publishto deploy it.You may need to perform
wrangler loginin order to publish.Once it is deployed, the URL will be shown to you in the command line. Open up the front-end of the site and go through the same scenarios as before to test drive personalization.
- Try disabling the JS in your Browser dev tools to see personalization taking place on the Cloudflare side.
Success!
Congratulations, you have your edge-side personalizable site up and running on Cloudflare Workers!
Next steps:
If you'd like to understand the internals more, proceed to the deep dive section below.
Optional deep dive
If you would like to reconstruct this whole setup from scratch, this section walks through all the moving pieces. You can use this section to review the sample app we cloned earlier. After going through this doc, you should be able to integrate this capability into your own web application.
Step 1: Setup your web app
Feel free to skip this step and use the "base-app" from the getting started section above, if you want to fast track to the worker internals in Step 2.
Fist, get a Next.js app running with Uniform SDK.
You would need a vanilla Next.js app instrumented to Uniform Context SDK basics. If you don't have one running yet, we recommend completing this tutorial here.
Enable the edge-side mode bu following the steps in this doc.
Don't forget
Make sure you set
outputType="edge"on your<UniformContext />:<UniformContext outputType="edge" ...>
...
</UniformContext>Run static build that involved two phases -
next buildandnext exportDeploy the contents of the
outfolder to a publicly accessible server, or a static CDN. This could be anything, even a static web server, Azure Blob Storage, AWS S3, etc. You will need a public URL.
Step 2: Add Uniform SDK to the Cloudflare Worker
Now let's wire up the magical Cloudflare Worker!
Private npm packages needed
This guide requires access to private Uniform npm packages, requiring an npm token issued by one of the Uniform representatives. Set the token as NPM_TOKEN environment variable (recommended), or replace the token reference in .npmrc file in application root.
- If you are an existing customer, please contact support.
- If you are evaluating Uniform, please contact us here.
If you don't have an existing Cloudflare worker you are integrating with, start with a TypeScript starter from the official Cloudflare Quickstarts here:
npm init cloudflare my-app https://github.com/cloudflare/worker-typescript-templatecd my-appto change directory into your newly cloned project root.Install the following three Uniform SDK packages:
npm install @uniformdev/cli @uniformdev/context-edge @uniformdev/context-edge-cloudflareAdd the
.envfile with your Uniform project id and API key:UNIFORM_API_KEY=YOUR_API_KEY
UNIFORM_PROJECT_ID=YOUR_PROJECT_IDAdd the following npm script to your package.json:
"scripts": {
...
"download:manifest": "uniform context manifest download --output ./src/context-manifest.json"
}This script handles the download of the Uniform Context manifest as a local json file, which will be imported by the worker code.
Modify your
wrangler.tomlwith the following changes:name: set the name of the worker- build->command: add the
npm run download:manifestto the command, so manifest is downloaded duringwrangler build. account_id: the Cloudflare account id that can be retrieved from the Cloudflare dashboard.- set the
ORIGIN_URLenvironment variable to the value of the publicly accessible static site deployed during Step 1 earlier:
name = "myfirstworker"
...
account_id = "YOUR CLOUDFLARE ACCOUNT ID"
[build]
command = "npm install && npm run download:manifest && npm run build"
[vars]
ORIGIN_URL = "mystaticsite.netlify.app"IMPORTANT
When setting
ORIGIN_URL, drophttps://, and no trailing slashes, so:ORIGIN_URL = "mystaticsite.netlify.app"not
ORIGIN_URL = "https://mystaticsite.netlify.app"In
tsconfig.json, set"resolveJsonModule": trueundercompilerOptions.This allows importing the Uniform Context manifest as a json resource from teh worker code.
Locate the handler file in
/src/handler.tsand replace it with the following implementation:- step 1: importing Uniform SDK
- step 2: importing the Uniform manifest that stores personalization and A/B testing configuration
- step 3: short-circuiting if the ORIGIN_URL is not set
- step 4: instantiating the Cloudflare Edge Handler
- step 5: instantiating the context for the edge-side personalization
- step 6: awaiting for the handler to process the request
/src/handler.ts// step 1: importing Uniform SDK:
import { createEdgeContext } from '@uniformdev/context-edge'
import { createCloudflareProxyEdgeHandler } from '@uniformdev/context-edge-cloudflare'
// step 2: importing the Uniform manifest that stores personalization and A/B testing configuration
import { ManifestV2 } from '@uniformdev/context'
import manifest from "./context-manifest.json";
export async function handleRequest(request: Request): Promise<Response> {
//@ts-ignore
// step 3: short-circuiting if the ORIGIN_URL is not set:
if (!ORIGIN_URL) {
console.error('ORIGIN_URL environment is not defined')
return new Response('Configuration Error', {
status: 500,
})
}
// step 4: instantiating the Cloudflare Edge Handler
const handler = createCloudflareProxyEdgeHandler()
// step 5: instantiating the context for the edge-side personalization
const context = createEdgeContext({
request,
manifest: manifest as ManifestV2,
})
// step 6: awaiting for the handler to process the request
const { response } = await handler({
context,
request,
//@ts-ignore
originUrl: new URL(`https://${ORIGIN_URL}`).origin,
})
return response
}Run
wrangler buildto build the worker.Run
wrangler publishto deploy it.You may need to perform
wrangler loginin order to publish.Once it is deployed, the URL will be shown to you in the command line. Open up the front-end of the site and go through the same scenarios as before to test drive personalization.
- Try disabling the JS in your Browser dev tools to see personalization taking place on the Cloudflare side.
You've made it!
That's it! You made it to the end of this walkthrough, and you should be able to active the Uniform edge-side personalization and A/B testing on any static site now using Cloudflare Workers!
Other things you can do
- Activate this with Cloudflare Pages or Worker Sites, or with any other static origin.
- Install the Cloudflare integration for your Uniform project, which brings a set of quirks (Geo and Device characteristic), allowing to personalize on those attributes at the edge.
- Customize the worker to do more stuff, like fetching visitor data from an API and set the context quirks, this will allow you to personalize on these values, for example:
const { response } = await handler({
context,
request,
originUrl: new URL(`https://${ORIGIN_URL}`).origin,
quirks: {
'audience': 'Luxury Shoppers'
}
})