Loading component...

Published on April 29, 2022Reading time: 5 min read

Customizing Coveo For Sitecore With Init


Portrait photo of Ryan Allan, article author

Ryan Allan

Tech Lead

Tech Lead

Ryan is a Sitecore-certified developer and Coveo expert with a track record of architecting large-scale solutions for enterprises, law firms, and utilities.

Loading component...

Related Articles

Dev

Then and now: what happened to search between Sitecore 8 and SitecoreAI

A long-time Sitecore developer's guide to what's changed, what's gone, and what finally works in the headless search era.

March 24, 20261 min read
Blog Card Placeholder
Sitecore

Utilities case study: A digital transformation celebration — the ENMAX story

How Fishtank and ENMAX delivered a full-scale digital transformation on SitecoreAI (formerly XM Cloud), and walked away with two industry awards.

March 23, 20261 min read

Loading component...

Digital solutions

Learn how to maximize your investment in Sitecore by working with us.

AI solutions

Dominate your industry. Work with us to digitally transform your business.

Fishtank's proprietary project accelerator. Save time and money. Build what matters.

Utilities

Energy

Education

Healthcare

Manufacturing

Professional services

Financial services

Non-profits and associations

About FishtankThe PlaybookSitecore SnackContact us

Solutions

  • Digital solutions
  • AI solutions
  • TIDAL for XM Cloud

About

  • About Fishtank
  • The Playbook
  • Sitecore Snack
  • Contact us

Insights

Work

Industries

  • Utilities
  • Energy
  • Education
  • Healthcare
  • Manufacturing
  • Professional services
  • Financial services
  • Non-profits and associations

Start typing to search...

Coveo for Sitecore has a method for customizing your UI and UX that doesn't involve changing the renderings, making custom components, or changing hive at all.

It can even be customized per language and answers the question "Where do I bind my events now?" that comes up when upgrading from older UI setups.

Where Is It?

It's the field called Initialization File Name on the search interface item for your search page. The Hive example search page puts this item in $searchpage/example/example-search-interfaces.

Initialization File Name in Sitecore

The the actual file location is in $instanceDirectory/Coveo/Hive/Init.

What Do We Do With It?

Here's the original file's javascript:

<script type="text/javascript">
    document.addEventListener("CoveoSearchEndpointInitialized", function() {
        @*
            setTimeout(function() { }, 0) defers the initialization just enough to execute other DOMContentLoaded or CoveoSearchEndpointInitialized events in the page.
            This is required by some components to allow them to register before initialization.
        *@
        setTimeout(function() {
            var searchInterface = document.getElementById("@Model.Id");
            @if (Html.Coveo().IsEditingInPageEditor()) {
                @: if (typeof(CoveoForSitecore) !== "undefined" && typeof(Sitecore) !== "undefined") {
                    @: CoveoForSitecore.initializeSearchInterfaceForExperienceEditor(searchInterface);
                @: }
            } else {
                @: if (typeof(CoveoForSitecore) !== "undefined") {
                    @: CoveoForSitecore.initSearchInterface(searchInterface);
                @: }
            }
        }, 0);
    });
</script>

 

This part is really basic; it just starts the Coveo interface, though notice it has a different start for Experience Editor.

Let's start with something simple. Say you have a lot of facets, and you want the UI to load up nice and clean. It'll be simpler for your users. Maybe you just want the page to be shorter, you've already limited the number of results to four because you're doing a graphic-heavy gallery presentation.

So let's collapse all the facets, and show only the headings.

First, we move the line defining the search interface to the start of the script element, and then bind a function to the afterComponentsInitilization event.

This makes sure the facets are ready to accept the collapse command.

var searchInterface = document.getElementById("@Model.Id");
Coveo.$$(searchInterface).on(Coveo.InitializationEvents.afterComponentsInitialization, function() {
	var facets = [...searchInterface.querySelectorAll(".CoveoDynamicFacet")]; //old style facets use .CoveoFacet, if you have those instead

	facets.forEach(facet => {
		var myFacetElement = Coveo.get(facet);
		myFacetElement.collapse();
	});
});

 

You could also use this to preselect the facets, like this: Interacting with facets.

What's Next?

There are a whole ton of events available now. Coveo has a big list here with a nice flowchart: Search Framework Events

For now, let's do two more examples, then wrap up. The first example is query filtering. One on project, users were pasting in dollar signs from text on the website, and that's special Coveo syntax. So we saw an error, and it doesn't actually affect the results. So we'll strip it out.

Building on the previous example, we'll add this just before the SetTimeout call.

Coveo.$$(searchInterface).on('doneBuildingQuery',
	function(e, args) {
		var q = args.queryBuilder.expression.parts[0];
	
		if(q && q.indexOf("$") !== -1){
			args.queryBuilder.expression.parts[0] = q.replace("$", ""); 
		}
	});

 

Here, q is the query text entered by the user, and we have some guard code in case it is an empty search. If you really wanted to, you can use this same code to inject search terms if you were on a customized search page.

We bind to the doneBuildingQuery event to make sure Coveo is done setting everything up for the query, and any other custom code you have is finished.

This is a place where per-language customization would be useful, too. That you do just by creating different files for each language and assigning the file name in the language version of the search interface.

Customizing Results

Let's say you have some analytics data about your user and want to customize the presentation of the results based on that. Maybe you add a border or a "look here" icon to certain results on your catalog search page.

Which event do you want? Well, there are two that are good for this. newResultDisplayed, which fires on rendering each new result, and newResultsDisplayed, which fires at the end of displaying all of the new results.

This one also goes right before the SetTimeout call. Always register your event handlers before the CoveoForSitecore.initSearchInterface call, otherwise, you can end up with race conditions, or if you are unlucky, it won't fire at all. This example also assumes your analytics data is already handy.

Coveo.$$(searchInterface).on('newResultDisplayed',
	function(e, args) {
		if(userData.raw.jobtitle.toLowerCase() == "developer" && args.result.raw.category.toLowerCase == "computer"){
			var iconLocation = args.item.QuerySelector(".icon-container");
			iconLocation.classList.add("special-interest");ƒ
		}
	});

 

This example uses hardcoded English strings for simplicity, but you could easily use Sitecore's dictionary strings here, or take advantage of the multi-language setting for the init files. All of the HTML of the item template is available here, fully filled in with data, so you can make any changes you need. If you need to change tabindex or aria-* settings for accessibility reasons, this is also the place to do it, after Coveo's default code has run.

Wrap up

That's it! Now you know how to add any customizations that depend on the state of all sorts of Sitecore data, make any styling that couldn't be done with pure CSS and handle different things for different languages.

Solutions

  • Digital solutions
  • AI solutions

Brands

  • TIDAL for SitecoreAI
  • Sitecore Snack
  • The Playbook

Fishtank lore

  • Work
  • Insights
  • About us
  • Contact us

Industries

Utilities
Professional services
Energy
Financial services
Healthcare
Education
Non-profits and associations
Manufacturing
Utilities
Professional services
Energy
Financial services
Healthcare
Education
Non-profits and associations
Manufacturing

2026 @All Rights Reserved. Privacy Policy.

FISHTANK