Skip to main content

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

  1. Open the For Developers page and go back home. Notice the hero changed to show a different message.
  2. Do a full page reload. Notice the page is stable, and no flicker!
  3. Now, try disabling JavaScript in your browser dev tools. Refresh the page. Notice the personalization still occurs? This is edge-side execution in action.
  4. Re-enable JavaScript to continue with the demo.
  5. 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.
  6. 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.
  7. Now visit the Campaign page. Notice ?utm_campaign=unfrmconf is 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:

  1. 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..

  2. Personalize based on device characteristics that are available at the Cloudflare edge.
  3. Personalize on any data present on the HTTP request:
    • utm_campaign or any query string-based personalization
    • Cookie-based personalization
  4. Uniform A/B testing
  5. Personalization based on session context (user preferences, profile, shopping history, etc.).
  6. 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

  1. An account with Cloudflare.
  2. Access to Github.
  3. Node.js installed locally.
  4. In order to run Cloudflare Workers locally, you would need to use Cloudflare Wrangler CLI. Run npm install -g wrangler to 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.

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

  1. Clone this repo:

    git clone https://github.com/uniformdev/examples.git
  2. cd examples/base-app

  3. Run npm install to install all dependencies.

  4. Run npm run ci:build to run full static export of this Next.js site.

  5. Run npx serve out and ensure the site runs on http://localhost:5000

  6. Deploy 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

  1. cd examples/cloudflare-worker

  2. npm install

  3. Locate wrangler.toml and set the following attributes:

    • name: set the name of the worker
    • account_id: the Cloudflare account id that can be retrieved from the Cloudflare dashboard.
    • set the ORIGIN_URL environment 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, drop https://, and no trailing slashes, so:

    ORIGIN_URL = "mystaticsite.netlify.app"

    not

    ORIGIN_URL = "https://mystaticsite.netlify.app"
  4. Run wrangler dev to start the worker locally.

  5. Open http://127.0.0.1:8787/?utm_campaign=unfrmconf, you are expected to see the personalized hero with the "Call for papers" content.

  6. 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

  1. Run wrangler build to build the worker.

  2. Run wrangler publish to deploy it.

    You may need to perform wrangler login in order to publish.

  3. 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.

  1. 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.

  2. 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>
  3. Run static build that involved two phases - next build and next export

  4. Deploy the contents of the out folder 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.

  1. 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-template
  2. cd my-app to change directory into your newly cloned project root.

  3. Install the following three Uniform SDK packages:

    npm install @uniformdev/cli @uniformdev/context-edge @uniformdev/context-edge-cloudflare
  4. Add the .env file with your Uniform project id and API key:

    UNIFORM_API_KEY=YOUR_API_KEY
    UNIFORM_PROJECT_ID=YOUR_PROJECT_ID
  5. Add 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.

  6. Modify your wrangler.toml with the following changes:

    • name: set the name of the worker
    • build->command: add the npm run download:manifest to the command, so manifest is downloaded during wrangler build.
    • account_id: the Cloudflare account id that can be retrieved from the Cloudflare dashboard.
    • set the ORIGIN_URL environment 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, drop https://, and no trailing slashes, so:

    ORIGIN_URL = "mystaticsite.netlify.app"

    not

    ORIGIN_URL = "https://mystaticsite.netlify.app"
  7. In tsconfig.json, set "resolveJsonModule": true under compilerOptions.

    This allows importing the Uniform Context manifest as a json resource from teh worker code.

  8. Locate the handler file in /src/handler.ts and 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
    }
  9. Run wrangler build to build the worker.

  10. Run wrangler publish to deploy it.

    You may need to perform wrangler login in order to publish.

  11. 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

  1. Activate this with Cloudflare Pages or Worker Sites, or with any other static origin.
  2. 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.
  3. 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'
    }
    })