#Set up personalization with Hygraph's Variants and frontend logic
This guide is ideal for anyone who’s new to personalization or looking to experiment with simple, practical ways to tailor content. Whether you’re exploring how to deliver more relevant interactions or just want to test out basic strategies, you’ll learn how to use Hygraph’s Variants together with frontend logic to create targeted content for different audience groups.
To get started, you can use the data you already have, such as purchase history, location, or browsing behavior, to create simple rules for personalization. This information could come from targeted email segments, dynamic website banners, or purchase and browsing history. Implementing personalization without investing in any additional tools shows its benefits and helps you see what resonates with your audience.
#Use cases
Personalized content helps improve engagement, relevance, and conversion rates. You can personalize content for your users in several ways.
Combining methods such as, campaign segmentation, direct input, and profile-based personalization, creates the most comprehensive strategy for delivering meaningful, user-focused experiences.
#Campaign segmentation
Show specific content to users depending on the campaign or referral link that brought the user to your website.
Setup
- Set up tracking parameters in your campaign URLs.
- Define logic that matches each campaign to the right content.
- Display targeted content or offers when users land on your site.
Example
If you’re running two coffee bean campaigns, one on Instagram aimed at home baristas and another on Etsy targeting coffee shop owners, you can determine which content to show based on their needs.
#User input
Collect your users' preferences when they arrive at your website.
Setup
- Prompt visitors to select the role or category they identify with when they arrive on your website.
- Store their answer in a persistent cookie or session variable.
- Use this stored preference to serve relevant content across pages and future visits.
Example
A visitor who selects “Coffee shop owner” will continue to see wholesale offers and bulk order options, while a “Home barista” might see guides and starter kits.
#User profile
If users have accounts or a history of past purchases, you can utilize that data to recommend and display personalized content tailored to their preferences and behavior.
Setup
- Collect information, such as preferences and demographics, from your users' accounts.
- Leverage purchase history or browsing behavior to recommend relevant products.
- Update content dynamically as the user’s activity evolves.
Example
A returning customer who previously purchased dark roast beans might be shown new arrivals in similar flavors or bundle deals with grinders.
#How it works
You can deliver personalized content to your users using Hygraph and your frontend logic.
- Identify the user’s role. Use your own frontend logic to determine a user’s role. This step does not require a Customer Data Platform (CDP).
- Map the role to a segment and variant in Hygraph. Each role corresponds to a segment in Hygraph, and each segment is linked to a specific content variant. This setup allows you to deliver the right content automatically, without relying on a separate personalization engine.
#Setup in Hygraph
- 
Enable Variant support for fields in your schema. You can enable variants for as many fields from the base content entry, per your requirement. It is not necessary to mark all schema fields as variant-enabled fields. - 
For the Articleschema, we have enabled variant support for theTitle,Summary,Content, andPicturefields.
 
- 
- 
Add Segments. In this example, we have two segments: - 
Segment Coffee Shop Ownerswith slugshops
- 
Segment Home Baristaswith slughome
 
- 
- 
Add Variants of the base entry and link it to Segments. - 
The base entry Understanding Coffee Bean Originsincludes two variants, one for theCoffee Shop Ownerssegment and the other for theHome Baristassegment.
 
- 
#Display personalized content
#Overview
The following is a high-level overview of the steps that you need to run through to display personalized content to your users:
- 
Retrieve the segment from the search parameters, a cookie, or the user’s profile via the customers database. 
- 
Extract the article idparameter from the route or request object.
- 
Fetch the article by ID and its variants that are linked to the segment. 
- 
If an article is found, overlay the variant fields on top of the base article. If no variant is found, return the article as is. If no article is found, throw an error. const segment = await getSegment(searchParams);const { id } = await params;let article = await getArticleById(id, segment);if (!article) {return {title: "Article Not Found",description: "The requested article could not be found.",};}article = applyVariant(article);
#Step-by-step process
- 
Retrieve the segment from the search parameters or cookies. export async function getSegment(searchParams: Promise<{ segment?: string }>,): Promise<string | undefined> {const { segment } = await searchParams;const cookieStore = await cookies();const cookieSegment = cookieStore.get("segment");return segment || cookieSegment?.value;}
- 
Query the variant content, and pass the segment slugas a filter.// Query article including variantsexport type ArticleType = {id: string;title: string;summary: string;variants: {title: string;summary: string;content: {raw: string;html: string;};picture: {thumbnailUrl: string;url: string;};}[];content: {raw: string;html: string;};picture: {thumbnailUrl: string;url: string;};createdAt: string;};// Get a single article by IDexport async function getArticleById(id: string,segment?: string,): Promise<ArticleType | null> {const query =`query ArticleByIdQuery($id: ID!, $segment: String) {article(where: {id: $id}) {idtitlesummarycontent {rawhtml}picture {thumbnailUrl: url(transformation: {image: {resize: {width: 800, height: 600}}document: {output: {format: webp}}})url: url(transformation: {image: {resize: {height: 1440}}document: {output: {format: webp}}})}createdAtvariants(where:{segments_some:{slug: $segment}}) {titlesummarycontent {rawhtml}picture {thumbnailUrl: url(transformation: {image: { resize: { width: 800, height: 600 } }document: { output: { format: webp } }})url: url(transformation: {image: { resize: { height: 1440 } }document: { output: { format: webp } }})}}}}`;try {const data = await fetchFromCMS(query, { id, segment });return data.article;} catch (error) {console.error(`Error fetching article with ID ${id}:`, error);return null;}}
- 
Now, merge the article values with variant values. The following code snippet builds a single dataobject by combining:- All the base article fields, and
- All the fields of its first variant, with variant fields overriding article fields if there’s a conflict.
 // Merges a variant onto the base entryexport function mergeVariant<T extends Record<string, any>>(data: T,variant?: Partial<T>,): T {if (!variant) {return data;}return {...data,...variant,};}
- 
Now, pick the first merged variant, and display it to your user. // Pick the first merged variantexport function applyVariant<T extends Record<string, any> & { variants: Array<Partial<T>> },>(data: T): T {return mergeVariant(data, data.variants[0]);}