An anonymous shopping experience is key to any B2C e-commerce website. There are occasional visitors to the e-commerce website who want to purchase items without creating a user account. A seamless shopping experience with anonymous (guest) shopping can significantly increase revenue and help convert a guest user to create an account.
OrderCloud, a headless e-commerce platform, supports anonymous shopping through anonymous user configuration and creation of a cart and order on behalf of an anonymous user.
In this blog, we will discuss how to configure OrderCloud and how to create an anonymous authentication token in XM Cloud Head App based on Next.js and Sitecore Content SDK to implement anonymous shopping.
OrderCloud Configuration for Anonymous Shopping
This article on the OrderCloud knowledge base kind of describes how to configure OrderCloud for generating an anonymous token, but it’s kind of outdated and doesn’t explain things at a deeper level.
API Client
The key to setting up your anonymous user starts with creating the API Client that will be used by the storefront (in OrderCloud terms, buyer site). You need to create a Buyer for storefront shoppers, a Security Profile (permission/roles) for storefront shoppers, and assign the Security Profile to the Buyer. Assign this Buyer to the API Client. Any user who belongs to this Buyer should be able to shop using their authenticated credentials. This takes care of authenticated user shopping.
For an anonymous user shopping, you need to create a user in the Buyer group, which will be used by OrderCloud as the Default Context user for anonymous shoppers who don’t have a user of their own in OrderCloud. Set this user in the API Client as the Default Context user and set “Is Anon Buyer” checked. This completes the OrderCloud configuration for anonymous shopping.

Anonymous Token
An anonymous user needs an anonymous token. How to get that? You can call the token endpoint and pass the above API Client to get the anonymous token. The following screenshot shows how to do it in Postman.

Once you get the token, if you decode it, you will see there is an orderid. This ID will be used when you create an anonymous cart using this anonymous token. This way, anonymous carts can be secured to appropriate guest users.
{
"jti": "BgLAYhOCBU-XsOoWu3cu3Q",
"usr": "anonuser",
"cid": "*************",
"orderid": "Ac574VWP7EKaTSW9kMHizg",
"u": "321041",
"usrtype": "buyer",
"role": [
"ProductReader",
"CategoryReader",
"MeAddressAdmin"
],
"nbf": 1759885677,
"exp": 1760491077,
"iss": "https://useast-sandbox.ordercloud.io",
"aud": "https://useast-sandbox.ordercloud.io"
}
Generate an Anonymous Token in the XM Cloud Head App
We will not use the REST API to generate the anonymous token. We will be using OrderCloud JavaScript SDK. The best place to generate an anonymous is in the XM Cloud HeadApp middleware. This way, a token can be generated and used both in server-side code and client-side code. We will generate the token in the middleware, set the token as an HttpOnly cookie with appropriate Samesite permission (lax). This will secure the token. The following is the updated middleware code that comes with Sitecore Content SDK. Here we are checking if the token cookie already exists or the token has expired, and generating a new token and saving it in the cookie.
import { type NextRequest, type NextResponse, type NextFetchEvent } from 'next/server';
import {
defineMiddleware,
MultisiteMiddleware,
PersonalizeMiddleware,
RedirectsMiddleware
} from '@sitecore-content-sdk/nextjs/middleware';
import sites from '.sitecore/sites.json';
import scConfig from 'sitecore.config';
import { ApiRole, Auth, Configuration } from 'ordercloud-javascript-sdk';
import { jwtDecode } from 'jwt-decode';
const multisite = new MultisiteMiddleware({
/**
* List of sites for site resolver to work with
*/
sites,
...scConfig.api.edge,
...scConfig.multisite,
// This function determines if the middleware should be turned off on per-request basis.
// Certain paths are ignored by default (e.g. files and Next.js API routes), but you may wish to disable more.
// This is an important performance consideration since Next.js Edge middleware runs on every request.
skip: () => false
});
const redirects = new RedirectsMiddleware({
/**
* List of sites for site resolver to work with
*/
sites,
...scConfig.api.edge,
...scConfig.redirects,
// This function determines if the middleware should be turned off on per-request basis.
// Certain paths are ignored by default (e.g. Next.js API routes), but you may wish to disable more.
// By default it is disabled while in development mode.
// This is an important performance consideration since Next.js Edge middleware runs on every request.
skip: () => false
});
const personalize = new PersonalizeMiddleware({
/**
* List of sites for site resolver to work with
*/
sites,
...scConfig.api.edge,
...scConfig.personalize,
// This function determines if the middleware should be turned off on per-request basis.
// Certain paths are ignored by default (e.g. Next.js API routes), but you may wish to disable more.
// By default it is disabled while in development mode.
// This is an important performance consideration since Next.js Edge middleware runs on every request.
skip: () => false
});
async function handleOrderCloudAnonymousAuth(request: NextRequest, response: NextResponse) {
const token = request.cookies.get('ordercloud.anonymousToken')?.value;
if (token) {
try {
const decodedToken = jwtDecode(token);
// Check if the 'exp' claim exists and if the token is expired.
// The 'exp' claim is in seconds, so we multiply by 1000 for milliseconds.
if (decodedToken.exp && decodedToken.exp * 1000 < Date.now()) {
console.log('OrderCloud token has expired. Fetching a new one.');
// Token is expired, so we will proceed to fetch a new one below.
} else {
// Token exists and is not expired, so we can continue.
return response;
}
} catch (error) {
console.error('Failed to decode token, fetching a new one.', error);
}
}
try {
const clientId = process.env.NEXT_PUBLIC_ORDERCLOUD_CLIENT_ID;
const apiUrl = process.env.NEXT_PUBLIC_ORDERCLOUD_API_URL;
if (!clientId || !apiUrl) {
throw new Error("Missing required OrderCloud environment variables.");
}
console.log('OrderCloud token not found. Attempting to fetch a new one...');
Configuration.Set({
baseApiUrl: apiUrl,
});
const scopes: ApiRole[] = ['ProductReader', 'CategoryReader', 'MeAddressAdmin'];
const authResponse = await Auth.Anonymous(clientId, scopes);
if (authResponse?.access_token) {
console.log('Successfully fetched new OrderCloud token.');
response.cookies.set('ordercloud.anonymousToken', authResponse.access_token, {
httpOnly: true,
secure: process.env.NODE_ENV !== 'development',
sameSite: 'lax',
path: '/',
});
console.log('OrderCloud token cookie has been set on the response.');
} else {
console.warn('OrderCloud auth response did not contain an access_token.');
}
} catch (error) {
console.error("Failed to get anonymous OrderCloud token:", error);
}
return response;
}
export async function middleware(req: NextRequest, ev: NextFetchEvent) {
const sitecoreResponse = await defineMiddleware(multisite, redirects, personalize).exec(req, ev);
return await handleOrderCloudAnonymousAuth(req, sitecoreResponse);
}
export const config = {
/*
* Match all paths except for:
* 1. /api routes
* 2. /_next (Next.js internals)
* 3. /sitecore/api (Sitecore API routes)
* 4. /- (Sitecore media)
* 5. /healthz (Health check)
* 7. all root files inside /public
*/
matcher: [
'/',
'/((?!api/|_next/|locations/|feaas-render|healthz|sitecore/api/|-/|favicon.ico|sc_logo.svg).*)'
]
};
Once we have the token, we can use it to create a cart or get the anonymous cart for the token if the cart already exists. OrderCloud will create a cart automatically when a line item is added to the cart if the cart doesn’t exist. This is often a preferred method because it minimizes the number of redundant carts.
In this anonymous shopping workflow, if at any time the user logs in to his/her account, the anonymous cart can be transferred to the logged account. We can do this by using
PUT ‘https://api.ordercloud.io/v1/me/orders?anonUserToken=string’ \ -H ‘Authorization: Bearer <logged_in_user_token>’
Or using an equivalent method in JavaScript SDK or OrderCloud .NET SDK. For more information about how to use the .NET SDK see my previous article.


















