Problem Statement
We recently faced an issue while working on a Sitecore AI implementation hosted on Netlify.
Our setup was simple. We had deployed the frontend application on Netlify and enabled Sitecore AI embedded personalization. As part of the personalization strategy, we created different page variants based on the user’s country. The expectation was users from different countries should see personalized content to their location.
However, things did not work as expected.
No matter where the user was accessing the site from, the same version of the page was being shown. The personalization rules were not getting applied correctly. At first, it looked like a configuration issue in Sitecore AI, but after checking the rules and setup multiple times, everything seemed fine.
Root Cause Analysis
After digging deeper, we found the real problem.
Sitecore AI was not receiving the actual user’s country information. Instead, it was always picking up the country of the Netlify hosting server. In our case, the site was hosted in the UAE, so every request appeared as if it was coming from the UAE.
Because of this, even if a user accessed the site from Saudi Arabia (or any other country), Sitecore AI still treated them as a UAE user. As a result, the country-based personalization never triggered correctly.
In short, the personalization logic was working, but the input data (user location) was wrong. And because of that, the entire experience broke.
Solution
After understanding the problem, we focused on how Netlify was handling request headers.
We noticed that Netlify always sets the x-forwarded-for header using its edge network IP. Because of this, our logic was always picking that value and skipping any further checks. This caused a bigger issue — Sitecore was reading different edge node IPs on every request. As a result, the detected location kept changing, and users were getting different personalized variants on every page refresh.
To fix this, we changed our approach.
Instead of relying on x-forwarded-for, we decided to always use x-nf-client-connection-ip when it is available. This header gives the actual client IP. This small change ensured that the correct user location is passed every time.
Along with this, we added a middleware in our Next.js application.
We extended the existing PersonalizeMiddleware provided by Sitecore and It overrides one method — getExperienceParams — which is responsible for building the data object sent to Sitecore to decide which personalized variant to show.
class GeoPersonalizeMiddleware extends PersonalizeMiddleware {
protected getExperienceParams(req: NextRequest) {
const params = super.getExperienceParams(req);
const country = req.headers.get('x-country');
if (country) {
return { ...params, geo: { country } };
}
return params;
}
}super.getExperienceParams(req) — first calls the original Sitecore method to get the default params (referrer, UTM, etc.)
req.headers.get('x-country') — reads a header called x-country which Netlify automatically injects on every request with the visitor's detected country code (e.g. "AE", "SA")
If the x-country header exists, it adds a geo: { country } field into the params before sending to Sitecore
This made a big difference. Now Sitecore gets the correct country information on the very first request itself. Because of this, the geo-based personalization rules start working immediately, even before any cookies or user profile data are created.
We also handled one more important case.
Netlify sometimes sends requests from its own prerender system. These are not real users, but background requests used for caching and performance. Netlify marks these requests using a header called netlify-agent-category.
function isNetlifyPrerender(req: NextRequest): boolean {
const agentCategory = req.headers.get('netlify-agent-category') || '';
return agentCategory.includes('tooling') || agentCategory.includes('prerender');
}We added a simple check to detect such requests. If the request is coming from Netlify’s prerender system, we prevent caching for that response. This avoids serving incorrect or cached personalized content to real users.
if (isNetlifyPrerender(req)) {
response.headers.set('x-middleware-cache', 'no-cache');
response.headers.set('netlify-cdn-cache-control', 'no-store');
}x-middleware-cache: no-cache — tells Next.js middleware layer not to cache this response
In short, the fix had three key parts:
- Use the correct client IP instead of the edge IP
- Pass the user’s country explicitly to SitecoreAI
- Avoid caching issues caused by prerender requests
After applying these changes, the personalization started working correctly for users across different countries.

No comments:
Post a Comment