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.
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!
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.
- Node.js (LTS recommended)
- GitHub CLI
- Netlify CLI
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
.
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!
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
.
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, and 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 example, 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! 🏆
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.