Problem
If you are using Sitecore Search (formerly Discover), it automatically tracks user interactions inside its official React widgets.
For example:
- Clicking a search result
- Selecting a filter or facet
- Navigating through search pages
This works perfectly out of the box.
However, real-world websites often contain CMS-driven components that are outside of Sitecore Search widgets, such as:
- Hero banners
- Promotional carousels
- Content tiles
- Marketing CTAs
Imagine a Hero Carousel managed by content authors. A user clicks the banner and lands on the /search page.
From an analytics perspective, that banner influenced the user to start searching — but Sitecore Search has no record of this interaction.
This means your analytics miss an important signal.
To solve this, we can manually send click events to Sitecore Search using the Discover Events API.
Solution
Instead of relying only on built-in widgets, we can:
- Detect a click on any CMS component
- Build a Sitecore Search event payload
- Send it to the Discover Events API
This allows Sitecore Search to attribute the click to a custom widget source.
The best part is that this can be implemented with one reusable utility function, which works across your entire application.
Step 1 — Define Widget Identifiers
In Sitecore Search, every widget is identified by an rfk_id.
For custom components like banners or carousels, we simply create virtual widget IDs.
Create a constants file:
// src/helpers/searchWidgets.ts
export const searchWidgets = {
heroCarousel: 'rfk_SearchHeroCarousel',
Banner: 'rfk_SearchBanner',
};
These IDs should also be registered in the Sitecore Search dashboard so the analytics platform can recognize them.
Step 2 — Create a Reusable Event Utility
Now we create a small utility that builds the event payload and sends it to the Discover API.
import { PageController } from '@sitecore-search/react';
export const sendSearchClickEvent = async (rfkId: string) => {
try {
const context = PageController.getContext();
const payload = {
name: 'widget',
action: 'click',
uuid: context.getUserUuid(),
client_time_ms: Date.now(),
value: {
rfk_id: rfkId,
context: {
browser: {
user_agent: context.getBrowserUserAgent(),
},
page: {
uri: context.getPageUri(),
},
user: {
uuid: context.getUserUuid(),
}
},
},
};
await fetch(
`https://discover.sitecorecloud.io/event/${process.env.NEXT_PUBLIC_SEARCH_CUSTOMER_KEY}/v4/publish`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: process.env.NEXT_PUBLIC_SEARCH_API_KEY as string,
},
body: JSON.stringify(payload),
}
);
} catch (error) {
console.error('Sitecore Search event failed:', error);
}
};
This function automatically pulls the required context from PageController, including:
- Store context
- User UUID
- Current page URL
- Browser information
Step 3 — Fire the Event from Any Component
Now you can track clicks from any component in your application.
Example: Hero Banner
import { sendSearchClickEvent } from '@/utils/searchEvents';
import { searchWidgets } from '@/helpers/searchWidgets';
export Default () => {
return (
<div
onClick={() => {
sendSearchClickEvent(searchWidgets.heroCarousel);
}}
>
<img src={banner.image} alt={banner.title} />
</div>
)}
What Happens Behind the Scenes
The event flow looks like this:
User clicks CMS banner
↓
onClick handler triggers
↓
sendSearchClickEvent(rfkId)
↓
PageController provides context
(uuid, page URL, browser)
↓
Event sent to Discover API
↓
Sitecore Search records click attribution
Now your analytics can attribute searches to marketing content.
Requirements
Before using this approach, make sure:
- Sitecore Search SDK is initialized in your application
- Your rfk_id values are registered in the Sitecore Search dashboard
- Environment variables are configured
Example .env.local:
NEXT_PUBLIC_SEARCH_CUSTOMER_KEY=your_customer_key
NEXT_PUBLIC_SEARCH_API_KEY=your_api_key
Happy Coding 🎉


Leave a comment