Coveo Headless vs Atomic: Which is Right for You?

Get a comprehensive breakdown of each solution's advantages and limitations and find out which one is the best fit for your project.

April 24, 2023

By David Austin

Coveo has come a long way since the days of the JavaScript UI (JSUI). It’s highly recommended that if you’re using the JSUI that you consider implementing alternatives. When it comes to Coveo for Sitecore, you’ve been able to use JSUI but you’ve also been able to take advantage of Hive. Personally, I’ve always been a fan of JSUI. Thanks to utilizes like Coveo Turbo, being able to quickly spin up a JSUI interface to debug a pipeline or assist a client with some design issues. It was always my go-to. And while technically you still can use both, I’d look at implementing either Coveo Headless or Coveo Atomic to future-proof your solution.

Both offerings have made improvements in their architecture, implementation and performance considerably in the last year. If you check out the release notes of each, it’s obvious that there is considerable investment behind them. Therefore both are considerably safe choices when looking to implement as part of your next project.

But which is the best fit? Is there one? Let’s break down what each one offers, its benefits and limitations, and see if we can help you make a solid choice.

One thing I will mention, these offerings are very similar in that while Coveo Headless is a platform of sorts, Coveo Atomic is BUILT on Headless. It just gets you from A to B, that much faster.

Coveo Headless vs Coveo Atomic

Coveo Headless

So, first, what is Headless? Well, in short, it’s the library that you use to build Coveo applications on top of. As I stated above, Coveo Atomic is built using Coveo Headless.

Below is an example of what Coveo Headless, when combined with Material UI, can look like, but I’ll emphasize you can make it whatever you want.

Coveo Headless vs Coveo Atomic

There is one fundamental piece that makes Headless work, and that’s the engine. The engine’s state is constantly being updated while a user interacts with various features in the application.

Under the hood of Coveo Headless are its interactions with the Coveo APIs, such as the Coveo Search API, Platform API, REST API, etc. Just to name a few. If you want a complete view of that immense world, check out the API Overview.

I’ve got a comparison below detailing the pros and cons of using Headless, but you have to look at what you’re building. Are you building a solution that for example, may not look like a traditional search page? Are you building a site that you want to seamlessly add results based on the content on a particular page? These are the kinds of things you can build with Headless quite simply.

Installing Headless

Make sure you have NPM and Node (> v12) and are building a project (hopefully TypeScript) that is based upon React, Angular, NextJs or Vue.js.

Run the following command:

npm install @coveo/headless

Setting Up

Moving past the install, the next question will be, what type of engine are you going to be working with? Are you working with:

  • Search Engine
  • Recommendation Engine
  • ProductRecommendation Engine
  • ProductListing Engine
  • CaseAsist Engine, or
  • Insight Engine

Each has a very different purpose and each has a specific set of components that you would work with.

Let’s say you wanted to start off with the Search Engine as you want to create a search interface and result of your site. Everything revolves around the engine. The state, events, all of it. Locate the Engine.ts file, open it, and update the contents with the following code:

import { buildSearchEngine, getOrganizationEndpoints } from '@coveo/headless';

export const headlessEngine = buildSearchEngine({
  configuration: {
    organizationId: '<ORG_ID>',
    organizationEndpoints: getOrganizationEndpoints('<ORG_ID>')
    accessToken: '<ACCESS_TOKEN>',
    renewAccessToken: <CALLBACK>,
  }
});

If you were going to work with the Recommendation Engine because you’re trying to create components that provide content based upon a user’s journey, then you’d replace this file with the following code:

import { buildRecommendationEngine, getOrganizationEndpoints } from '@coveo/headless';

export const headlessRecommendationEngine = buildRecommendationEngine({
  configuration: {
    organizationId: '<ORG_ID>',
    organizationEndpoints: getOrganizationEndpoints('<ORG_ID>')
    accessToken: '<ACCESS_TOKEN>',
    renewAccessToken: <CALLBACK>,
  }
});

You can see where this is going. Each component you build will utilize these types of engines to access the platform. And each engine type has it’s own appropriate components.

Some components can be used across various engines; some are specific to that engine. That said, this is Headless, so there’s nothing saying you can’t create your own components that utilize various ones altogether.

Component Breakdown

When it comes to breaking down the component list, you’ll need to understand that, unlike Atomic, you’re going to be interacting with both controllers and if you desire even further control, then there are actions for each component. There are forty some controllers and thirty some actions.

For example, capturing analytics when working with the Recommendation engine might look something like this when trying to capture when a recommendation item that has been displayed has been clicked on.

const logClick = (recommendation: Result) => {
    if (!engine) {
      return;
    }

    const { logRecommendationOpen } = loadClickAnalyticsActions(engine);
    engine.dispatch(logRecommendationOpen(recommendation));
  };

Customizing Components

The beauty with these are you can use plain CSS or you can throw in some Tailwind. Really the choice is yours. Here’s what a simple component might look like in Headless if you were to use Tailwind for styling.

import { HeadlessFacetProps } from './Facet';
import Facet from './Facet';
export interface FacetProps {
  facets: HeadlessFacetProps[];
}
const Facets = (props: FacetProps): JSX.Element => {
  return (
    <div
      id="js-searchpage-facets"
      className="hidden absolute top-2 p-1 pb-0 sm:p-0 border border-nu-grey-dark sm:border-0 w-full sm:top-auto bg-white sm:relative sm:flex sm:flex-col"
    >
      {props.facets.map((facet, index) => {
        return (
          <div key={index}>
            <Facet {...facet} />
          </div>
        );
      })}
    </div>
  );
};

export default Facets;

Now take that concept and expand it to every other component you need to implement and you get an idea on the scale. There’s a lot of moving parts. Each component works and reacts differently depending upon the state of the engine.

Don’t be discouraged though. Once you’ve got a working Headless setup, customizing it for each client is a lot simpler and you’ll find you’re reusing components throughout different builds.

Coveo Atomic

Alternatively, Coveo Atomic is a component-based solution enabling businesses and individuals a way of quickly going from A to Z without considerable development required. Unlike Headless where you work directly with the controllers and actions of a component, in *Atomic,* you strictly work with the component itself.

Coveo Headless vs Coveo Atomic

Installing Atomic

There are two methods for utilizing **Atomic**. It really depends on how are planning on integrating the search components. Are they apart of a larger application or are they separate? Are you trying to do something quick or as a final product?

NPM

If you’re building a headless application or is part of a larger framework, going the NPM route is probably you’re safe bet.

npm install @coveo/atomic

CDN

Without a doubt, if you’re needing a search page quick, and put it up somewhere to show a client quick results, then use the CDN approach. With a Coveo source and API key pre-configured you can have results showing up in less than 10 minutes.

<script type="module" src="https://static.cloud.coveo.com/atomic/v2/atomic.esm.js"></script>
<link rel="stylesheet" href="https://static.cloud.coveo.com/atomic/v2/themes/coveo.css"/>

Setting Up

At the root of Atomic’s structure is the <atomic-search-interface> component. This will look something like this:

<body>
  <atomic-search-interface id="abc-company-search">
    <atomic-search-box></atomic-search-box>
    ...
  </atomic-search-interface>
</body>

From here on you will assemble the rest of the components. Just like the engine in Headless, you need to initialize your search. So let’s do that now, reference a JavaScript file in your HTML and use the code below. Given your access token is visible, I highly recommend connecting the access token to a search hub and having that search hub control (via a condition) which Query Pipeline to run. This limits your organizations exposure.

(async () => {
  await customElements.whenDefined('atomic-search-interface');
  const searchInterface = document.querySelector('#abc-company-search');

  await searchInterface.initialize({
    accessToken:'<ACCESS_TOKEN>',
    organizationId: '<ORG_ID>'
    organizationEndpoints: await searchInterface.getOrganizationEndpoints('<ORG_ID>'),
  });

  searchInterface.executeFirstSearch();
})();

Components Available for Atomic

There are presently fifty (50) components available for Coveo Atomic. You can see the full list of Atomic components here. While that seems like an extraordinary number, you should understand that a lot of the components are utilized in combination with one another. Just like in Headless.

If you’d like to see a complete working example, Coveo has put together a working Atomic example.

Customizing Coveo Atomic

I could see, as having experienced it in its infancy, styling can be a stumbling block when it comes to Coveo Atomic. It is, after all not the typical way to stylize and customize how a component looks. This is largely because many of the components come pre-styled, and some utilize the shadow DOM. That doesn’t prevent the components from being customized entirely, but you’re forced to use “parts,” aka the::part() pseudo-element. The other is by taking advantage of the themes. Comparing it to JSUI, it protects components and ensures they continue working during the customization process. You can find these parts by inspecting the rendered DOM and look for #shadow-root and then inside the elements within, you’ll find part and the values are used as selectors. Here’s an example:

atomic-search-box::part(wrapper) {
 justify-content: left;
}

What are themes? Well, they’re just a set of variables that allow you to customize the attributes of each component. You do this by updating the :root pseudo-class. For example:

:root {
 --atomic-primary: #787878;
}

Those variables can then be used within parts like so:

 background-color: var(--atomic-neutral);

Read the full list of Atomic Themes here.

Other times, for example, the atomic-result-template, we need to put styles within the tag. Styles entered inside the template affect the template. If you were to add the same style in the stylesheet, it wouldn’t affect the template.

<atomic-result-list>
    <atomic-result-template>
      <template>
        <style>
                // custom styling here
      </style>
      <atomic-result-section-title>
                <atomic-result-link></atomic-result-link>
            </atomic-result-section-title>
    </template>
  <atomic-result-template>
<atomic-result-list>

Comparing Headless and Atomic

FEATURE COVEO HEADLESS COVEO ATOMIC
Search Algorithms Pros: Ability to customize the search experience, queries, and filtering through APIs, customizable for complex use cases.

Cons: Requires considerable development startup. But, once you’ve got a base done, each project thereafter can leverage what you’ve learned and built.
Pros: Pre-built algorithms optimized for personalized search, easy to implement.

Cons: Less customizable for complex use cases.
Customization Pros: Using APIs and SDKs, highly configurable search experiences can produce personalized search solutions.

Cons: Demands more technical know-how and development work.
Pros: Benefits include a quicker time to market and pre-built search components that can be integrated and altered.

Cons: Little opportunity to design original search experiences.
Personalization Pros: Customization options that can be tailored to corporate needs are accessible through APIs. You’re able to mix and match solutions to meet your need.

Cons: Implementation requires extra development work and is prone to needing routine maintenance.
Pros: Machine learning-based personalization features are built-in and simple to use.

Cons: It may not be as customizable for sophisticated personalization use cases.
Analytics and Reporting Pros: Easy to set up, robust built-in analytics and reporting features. Customizable to corporate needs, analytics and reporting tools are available through the Platform.

Cons: Implementation requires extra development work.
Pros: Easy to set up, robust built-in analytics and reporting features. Customizable to corporate needs, analytics and reporting tools are available through the Platform.

Cons: Minimal personalization for certain business requirements.
Integration Pros: API-first approach for easy integration into any technology stack, supports various platforms and languages.

Cons: Requires more development effort to implement.
Pros: Pre-built components provide less flexibility but a quicker time to market, which is appropriate for simple search experiences.

Cons: Minimal personalization for certain business requirements.
Flexibility Pros: Highly flexible and modular solutions for creating custom search experiences can meet unique business needs. Cons: Requires more development effort to implement.

Con: All the flexibility can come at the cost of routine maintenance.
Pros: Less flexibility but faster time-to-market with pre-built components, good for simple search experiences.

Cons: Limited customization for unique business needs.

In Summary

Having worked with both of the above, it really comes down to a fit for purpose. Headless is by far the most powerful and customizable of the two and what we tend to lean to when incorporating Coveo into a custom front-end application for a client. Atomic is absolutely fantastic, going from nothing to a fully-fledged solution in nothing flat and perfect for delivering a proof-of-concept to a client to demonstrate what their content could look like, driven by Coveo.



Image of Fishtank employee David Austin

David Austin

Development Team Lead | Sitecore Technology MVP x 3

David is a decorated Development Team Lead with Sitecore Technology MVP and Coveo MVP awards, as well as Sitecore CDP & Personalize Certified. He's worked in IT for 25 years; everything ranging from Developer to Business Analyst to Group Lead helping manage everything from Intranet and Internet sites to facility management and application support. David is a dedicated family man who loves to spend time with his girls. He's also an avid photographer and loves to explore new places.