Skip to main content
whitep4nth3r logo

Add personalization to static HTML with Netlify Edge Functions — no browser JavaScript required

Check out the video tutorial and accompanying walk-through.

⚠️ This post is over two years old and may contain some outdated technical information. Please proceed with caution!

Personalization — the process of creating customized experiences for visitors to a website — is a hot topic on the web in 2022. In a crowded world of digital experiences clambering for our attention, businesses are turning to personalization to connect more deeply with their customers, and ultimately, generate more sales and growth.

And shipping less client-side JavaScript is an even hotter topic. New and emerging front-end frameworks such as Astro and Eleventy are pushing the boundaries of the JavaScript framework era of the late 2010s, making it their core mission to ship less and less JavaScript by default, and bring developers’ focus back to a lean, native and performant web.

The great news is that with Netlify Edge Functions you can achieve dynamic personalization with no client-side JavaScript — resulting in a great developer experience, and an even better end-user outcome. There’s also no need introduce the overhead of a front-end framework simply to gain this ability in your projects.

In this video tutorial, I show you how to use Netlify Edge Functions to intercept an HTTP request on a static HTML page, transform the response on the fly by injecting the geolocation data of the request, and return the updated response to the browser.

Click the video above to play

Deploy the tutorial code to Netlify

If you want to dive in immediately, you can fork the tutorial’s code repository on GitHub, and deploy the site to your own Netlify account in seconds. Click on the Deploy to Netlify button below, and take it for a spin!

Deploy to Netlify Button

Build it from scratch

Alternatively, if you’d like to build out the code from scratch, you can follow the guide below to create a simplified version of the project, without the hello world Edge Function included in the video tutorial.

Prerequisites

Before getting started, check you’ve got the tools you’ll need to complete the tutorial.

Setup a project to serve static HTML files

In a new project directory, create a public directory. And inside that, add an index.html, and a file named hello-template.html.

Add some basic boilerplate to the index.html file (if you’re using VSCode you can type ! followed by tab in an HTML file to generate some HTML boilerplate), or you can copy and paste the file from the tutorial repository.

Next, add some similar boilerplate to hello-template.html, as well as some placeholder content that we’ll replace using an Edge Function in the next step. We’re going to be replacing the placeholder with some geolocation data, so I’ve named my placeholder LOCATION_UNKNOWN.

A screenshot of VSCode, showing two html files in a public directory. The visible code is the hello template file with the location data placeholder.

Next, we’re going to set up the project to serve those two static HTML files from the public directory using Netlify’s file-based configuration. At the root of your project, add a netlify.toml file. This is a configuration file that specifies how Netlify builds and deploys your site — including redirects, branch settings, edge function routing and more.

Add the following code to netlify.toml to instruct Netlify to serve your static files from the public directory.

[build]
publish = "/public"

Let’s check everything’s wired up. In a terminal window at the root of your project, run the following command to start up a development server with the Netlify CLI:

netlify dev

When the development server is up and running, head on over to your browser, and you’ll see your index.html on http://localhost:8888, and hello-template.html on http://localhost:8888/hello-template. You’re now ready to transform this static HTML file with an Edge Function!

A browser screenshot, showing the hello template file with the placeholder location unknown

Transform an HTTP response with an Edge Function

We’re going to write an Edge Function to intercept a request to hello-template using a URL query parameter (?method=transform), grab the geolocation data of the request, and transform the HTTP response to include the city and country name.

You can write Edge Functions using JavaScript or TypeScript. In this tutorial, we’re going to write Edge Function code in JavaScript. Edge Function files live in a special directory so that Netlify knows how to bundle them when you deploy your site. At the root of your project, create a netlify directory, and inside that add an edge-functions directory. Create a new file inside the edge-functions directory and name it transform-hello-template.js.

A screenshot of VSCode, showing the transform hello template js file added into an edge functions directory, inside a netlify directory.

Before we write the Edge Function code, let’s wire up the file to the development environment. In your netlify.toml file, add the following code, below the build settings. This tells Netlify to run the transform-hello-template function when a user requests the hello-template page in the browser. Stop and start your development server so the CLI picks up the changes in netlify.toml.

# netlify.toml

[[edge_functions]]
path = "/hello-template"
function = "transform-hello-template"

In transform-hello-template.js, add the following code. And let’s unpack what it does.

// netlify/edge-functions/transform-hello-template.js

export default async (request, context) => {
const url = new URL(request.url);

// Look for the "?method=transform" query parameter
// return if we don't find it
if (url.searchParams.get("method") !== "transform") {
return;
}

// Get the page content that will be served next
// In this tutorial, it will be the content from hello-template
const response = await context.next();
const page = await response.text();

// Search for the placeholder
const regex = /LOCATION_UNKNOWN/i;

// Get the location from the Context object
const location = `${context.geo.city}, ${context.geo.country.name}`;

// Replace the content with the current location
const updatedPage = page.replace(regex, location);

// Return the response
return new Response(updatedPage, response);
};

We start by exporting a default async function. Edge Functions take two parameters, request — which represents the incoming HTTP request, and context — which is a Netlify specific API that exposes geolocation data, lets you work with cookies, rewrites, site information and more.

First, we parse the URL from the request. Then, we look for the method=transform query parameter on the URL, using url.searchParams.get(). If we don’t find the required query parameter on the URL, we return and exit out of the Edge Function early, which will serve the hello-template with the placeholder unchanged.

If we do find ?method=transform on the URL, we use context.next() to grab the next request in the HTTP chain — in this case it’s our hello-template file — and then we grab the text content of the page, assigning it to the variable page. Next, we use a regular expression to search for the placeholder in the text of hello-template, which we want to replace with geolocation data.

Geolocation data is available on the context object, as context.geo. Using JavaScript string interpolation, we can construct a friendly, readable string comprising the city and country name, which we then use to replace the string matched by the regular expression.

Finally, we return a new HTTP Response containing the updated page. Navigate to the following URL in your browser: http://localhost:8888/hello-template?method=transform — and you’ll see the placeholder updated with Edge-powered geolocation data! Personalization with no JavaScript: achievement unlocked! 🏆

A screenshot of the finished result in the browser, where the placeholder template has been updated with Manchester, United Kingdom

Add git version control

Now that we have the project working locally, we have a number of options for how we deploy it to Netlify. In this tutorial, we’ll connect to a new git repo so that we get CI/CD all rolled in and configured for free.

Initialize a new git repository by running the following command:

git init

Stage and commit your files:

git add . # stage your files
git commit -m 'Initial commit' # commit your files with a commit message

The next steps will take you through adding your repository to GitHub via the GitHub CLI — but you can push your project to GitHub however you’re most comfortable.

Run the following command in your terminal to create a new repository that’s connected to your GitHub account:

gh repo create

When prompted on the kind of repository you'd like to create, select: Push an existing local repository to GitHub. Follow the remaining prompts to fill out the relevant project details. Now, you’re ready to deploy to Netlify!

Deploy to Netlify using the Netlify CLI

If you're not already logged in to the Netlify CLI, run the following command in your terminal, and follow the prompts to authorize with Netlify (a browser window will open).

netlify login

Next, run the following command to initialize a new project on Netlify.

netlify init

Fill out the following prompts to set up the new project:

  • What would you like to do? Create & configure a new site

  • Team: YOUR_TEAM

  • Site name (optional): CHOOSE_UNIQUE_SITE_NAME

The following prompts will be pre-filled given that we’ve provided a netlify.toml file in the repository. Hit enter to use the defaults.

  • Your build command (hugo build/yarn run build/etc): (we're not using a framework or a build script, so this stays blank!)

  • Directory to deploy (blank for current dir): (public)

  • Netlify functions folder: (netlify/functions)

Wait a few seconds… and your new site is deployed! 🎉

Run the following commands in your terminal to open the site in your browser, and open the Netlify admin panel.

netlify open:site # open the site in your browser
netlify open:admin # open the Netlify admin panel in your browser

And you’re done! Now you can test out your no-JavaScript-personalization-at-the-edge by sending the site URL to your friends, and showing off your new, shiny skills!

Final thoughts

When we talk about the new-found power that Edge Functions bring us as developers and users of the web, the question that often comes to mind is, “Should I put everything on The Edge, now?” Whilst the answer is usually, “It depends,” it’s always worth framing these new tools and technologies as additions to the evolving web ecosystem rather than replacements of existing capabilities.

Whilst The Edge certainly gives us a different set of advantages over serverless functions — most notably being able to run code from the closest server location possible to any user around the world — there are times when you might need control over where your code runs in the cloud, perhaps at the closest location to your database services, for example. In any case, Edge Functions are a brilliant use case for reducing client-side JavaScript in the browser, whilst still being able to provide a personalized experience for users of the web.

And I, for one, am excited about what else is to come.

Originally posted on www.netlify.com

Like weird newsletters?

Join 337+ subscribers in the Weird Wide Web Hole to find no answers to questions you didn't know you had.

Subscribe

Salma is looking at you, with a rather large smile. She's pointing across herself up to her left, with a very tatooed arm. She's wearing a black shirt and black rimmed glasses.

Salma Alam-Naylor

I'm a live streamer, software engineer, and developer educator. I help developers build cool stuff with blog posts, videos, live coding and open source projects.

Related posts

10 May 2022

What is Jamstack?

Let's explore Jamstack, “Jamstack-adjacent” technologies, and how you can get started building on the Jamstack.

Web Dev 7 min read →

26 Apr 2022

We're all living on it. But what exactly is The Edge?

But what is The Edge? What are Edge Functions? And why does it matter?

Serverless 7 min read →