Tracking Custom Click Events in Sitecore Search Using PageController

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:

  1. Detect a click on any CMS component
  2. Build a Sitecore Search event payload
  3. 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:

  1. Sitecore Search SDK is initialized in your application
  2. Your rfk_id values are registered in the Sitecore Search dashboard
  3. 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

I’m Ravi

Site Logo

a passionate software engineer focused on building modern digital experiences using technologies like Sitecore, Next.js, and modern JavaScript frameworks.

Let’s connect

Design a site like this with WordPress.com
Get started