Structuring your content with Sanity.io means you can query content based on signals from your visitors, such as their location. Personalisation is a tricky problem with static sites and the jamstack, this demo will show you how it can be done with Sanity.io, Next.js, and Vercel.
How do Localise and Personalize Content with Sanity.io and Next.js
AI Generated Video Summary
Sanity.io provides a content platform for structured content that replaces traditional CMS. Their solution allows businesses to structure and query content anywhere using the Sanity studio and open source React application. The talk focuses on solving the challenge of sending personalized data to users in a static website environment using Next.js Vercel for hosting and Sanity for content querying and delivery. The Sanity studio allows for modeling pages, articles, and banners, with banners being shown to visitors based on their country. The solution involves using Grok queries to fetch the right banner based on country information, demonstrating personalization based on localization and dynamic content querying.
1. Introduction to Sanity and the Problem
Hello, I'm Simeon, a solution engineer at sanity.io. We provide a content platform for structured content that replaces traditional CMS. Our solution allows you to structure and query your business's content anywhere, using the sanity studio and open source React application. We work with large companies to leverage the best of the modern web stack. Today, we will solve the challenge of sending personalized data to users in a static website environment. Our solution involves Next.js Vercel for hosting and Sanity for content querying and delivery. Let's explore the solution we've built.
Hello, I'm Simeon, a solution engineer here at sanity.io. Sanity is a content platform for structured content and it replaces the need for a traditional CMS for your website and instead allows you to structure all of your business's content and query that wherever you like. You're able to use the sanity studio and open source React application, which you can host where you like or deploy onto our infrastructure and really set up the best editing experience for your team that makes sense to your workflow and your needs.
We work with a lot of large companies that want to leverage the very best of a modern web stack. Now the problem that we're going to solve today is that before Jamstack took over the entire world, we used to serve websites from servers and those servers contained a lot of information about your visitors as they came to each page. But now that we statically build a lot of pages ahead of time and serve them on globally distributed CDNs, those static files are exactly the same, so how do you send a personalized piece of data to a user based on some information that we have? Well, we've got a solution today that we think's quite tidy. It involves Next.js Vercel for the hosting and Sanity, of course, for the content querying and delivery, but this is an idea that could be worked across many different platforms and serverless function hosts. So let's take a look at the solution as we've built it today.
2. Sanity Studio and Banner Component
The Sanity studio allows you to model pages, articles, and banners. Banners are shown to visitors based on their country. The banner component fetches the banner URL using an API route. It sets up state and tracks the date when the banner is seen. The API route checks for country information, allowing manual override or checking headers and IP information.
Here we have the Sanity studio of a fake online candy retailer. Now, your studio might look somewhat different to ours, but this is the one that we've modelled with pages, articles, but most importantly, let's take a look at banners.
Then we've got a string field here for the title, a text field for the content, and an image field where we've pulled in a delightful picture of the UK here from an Unsplash asset source. So that's the banner we want to serve to visitors, and let's take a look at what that's going to look like. I've already visited this page before, so I don't get sent that banner, but if I was to come into a new incognito window, here I get served that banner because this is where I'm at. So how does this work? Let's jump into some code.
We're going to very quickly take a look at this. The concepts here are quite straightforward, and perhaps we'll be able to make this code available as well. But here is the banner component that we're looking at. So you can see at the very top, the get banner URL here is going to fire off to the api route. API routes are a way of running server-side logic on a Next.js website. But again, most JAMstack technologies have similar concepts around running serverless functions to modify pages. And I've built in a fallback here that during development, I can simply set the country in a query string, or otherwise, if I'm in production, go and hit that get banner API route directly.
Now, a banner component here is going to set up some state, and it's also going to track using this sticky state hook, which is all that's doing is making sure we log some information to local storage. And we're going to store the date of when I saw this banner. And it would be possible to extend this component to say, if I haven't seen this banner for, say, 24 hours, it might get served again. So what we're going to do here when the component mounts is first fetch this banner URL. And if the status is not correct, we're going to set that the banner has been seen or if it's empty for whatever reason, we don't want to do that. But if the banner information does get returned properly, then we want to set that into the component and then set that the banner has been seen. And if we have if we don't have any data because we've seen this before or the fetch failed and return no data, then this component does nothing. However, if we do get banner data, then we've got some frame of motion and some tailwind to style that component being loaded into view there with nice animation and styling. So let's have a look at our API route. So as the request comes in to this API route, it is going to check first of all, what country information do we have? First of all, it's going to check, did we manually override this? Perhaps there'd be use cases to manually set the country here. Otherwise, we can check the headers on certain plans. On Vercel, you do get information about the country based on the IP. There are NPM packages as well that allow you to do that. And a lot of other providers will send along that information with requests, such as where the user is.
3. Grok Query for Banner Retrieval
If we have country information, we use a Grok query to fetch the right banner. Grok allows powerful and expressive queries. We check for banner documents with the same country field as the variable passed in. The response data is modified to send relevant data, including a reference to the image. This demonstrates personalization based on localization and the ability to dynamically query content based on user behavior.
So again, if we don't have the country, we want to eject from that request. However, if we do have country information, here's our Grok query to be able to go and get the right banner. Grok is the query language that is created for querying data from Sanity. It allows us to do really powerful and expressive queries. And in this case, it's quite straightforward.
We're looking for any document of the type banner, and we're going to check of all the banner documents, which ones have the same country field information as the country variable that we're passing into the query. And you can see there's a function here as well to make sure that we transform both of those to uppercase to help with the matching process in case we get lowercase information or if the document happened to be written in a different way.
The second parameter here in our fetch is that country information that's being passed in as a variable. If there doesn't happen to be a banner for the country that we're visiting from, we'll return nothing, otherwise we return this data. And if we were to take a look at what that response looks like, this is the data that goes back to the component. We can modify this to send less data or more relevant data. You can see here this is all that got sent through. The image is actually loaded by an image building library so we don't have to go and retrieve the entire image information there, but just the reference and then build that image out from there. And that's how we get these banners onto the homepage or any page where we wanted to serve those actually.
So that's sort of scraping the surface of personalization just by using the metric of localization. But it's a demonstration of if you have information about a visitor on the website, say the article they're reading or the articles they've clicked on or what they've spent more time looking at, and your content is then structured to understand those signals, you can then dynamically write queries that takes the signals of your users' behavior and then queries content that's relevant to them. If you'd like to know more, you can come to sanity.io.