Universal vs. Vertical Search | Yext Hitchhikers Platform
Universal and vertical search each support different features. Here’s a reference table to show the differences:
Universal Search | Vertical Search | |
---|---|---|
Single search bar searching across all the different verticals and providing one unified search results page. This would typically be the main search bar on a website. | Searches only a single vertical, which is typically limited to a single entity type or group of related entity types (e.g., locator, FAQ search, event calendar). | |
Supports Synonyms | ||
Supports Yext & Custom Backends | ||
Allows results from multiple verticals | ||
Supports Facets and Static Filters | ||
Supports Hardcoded Prompts | ||
Supports Popular Queries | ||
Supports Pagination | ||
Supports Backend Sorting | ||
Supports Frontend Sorting | ||
Supports Vertical Intents |
Before diving into building an experience, it’s important to understand the difference between vertical and universal search.
The Yext Search layout is very similar to Google. With Google you have your “main” search results page, but under the search bar there are other tabs like “images”, “maps”, and “news”. These tabs are what we call Verticals. These verticals are visible on the main (sniversal) Search page, but you can also click into them and see a separate search result page dedicated to those types of results.
For example:
The above shows the universal search results page on Google (represented by the “All” tab). The user can browse the results on that page or optionally click into a different tab like “Images”:
Upon clicking into an alternate vertical tab like “Images”, the user only sees images in the results.
Vertical Search
Vertical Search is a search page that only shows results from a single backend (vertical). For example, a vertical Search page might show a list of locations or a list of events.
A vertical Search page should use the
<VerticalResults/>
component for displaying results. Additionally, the search state must have the verticalKey
property set.
When you setup your search experience in the Yext platform, you configure each vertical separately. This allows you to use different search algorithms and filter options for each vertical.
Here’s an example configuration for a Products
vertical:
"verticals": {
"products": {
"entityTypes": [
"product"
],
"name": "Products",
"facets": {
"fields": [
{
"fieldId": "price.value",
"ranges": {
"algorithm": "DYNAMIC",
"bucketCount": 4
},
"sortCriteria": "ASC"
}
]
},
"searchableFields": {
"builtin.entityType": {
"nlpFilter": true
},
"keywords": {
"phraseMatch": true
},
"name": {
"semanticTextSearch": true
},
"price.value": {
"facet": true
},
"richTextDescription": {
"documentSearch": true
},
"size": {
"nlpFilter": true
}
},
"sortBys": [],
"source": "YEXT"
}
Vertical Search is also paginated. The vertical Search API will return 20 results by default but can be set to return a max of 50 results at a time. Adding the Pagination
component makes it easy to toggle between different pages of results.
Toggle Vertical Search
When a search is triggered by the SearchBar
component, it will make universal Search API call by default. To use vertical Search instead set the verticalKey
in the search state.
You can do this by either passing it as a prop when you initially declare your <SearchHeadlessProvider />
:
return (
<SearchHeadlessProvider
apiKey="YOUR_API_KEY"
experienceKey="YOUR_EXPERIENCE_KEY"
locale="en"
verticalKey={verticalKey}
>
<App />
</SearchHeadlessProvider>
);
Or by manually setting it with the useSearchActions
hook:
const searchActions = useSearchActions();
useEffect(() => {
searchActions.setVertical("artists");
}, []);
Rendering Vertical Search Results
Once the verticalKey
is set, it’s easy to render results with the VerticalResults
and StandardCard
components.
function App() {
return (
<div className="flex justify-center px-4 py-6">
<div className="w-full max-w-5xl">
<SearchBar />
<VerticalResults CardComponent={StandardCard} />
<Pagination />
</div>
</div>
);
}
When results are returned, the Pagination
component allows the user to advance to the next page of results.
Using a Custom Card
The CardComponent
prop can be used to pass a component to vertical results for a more custom layout.
const ArtistCard = ({ result }: CardProps) => {
const artistName = result.name;
const imageUrl = result.rawData.primaryPhoto?.image.url;
return (
<div className="flex flex-col items-center p-4">
<div className="rounded-full">
<img src={imageUrl} className="object-contain w-32 rounded-full pb-4" />
</div>
<div className="font-semibold">{artistName}</div>
</div>
);
};
function App() {
return (
<div className="flex justify-center px-4 py-6">
<div className="w-full max-w-5xl">
<SearchBar />
<VerticalResults
customCssClasses={{
results: "grid md:grid-cols-2 lg:grid-cols-4 gap-4 grid-cols-1",
}}
CardComponent={ArtistCard}
allowPagination={false}
/>
</div>
</div>
);
}
Universal Search
Universal Search is a search page that combines results from multiple different backends (verticals) together. For example, a universal Search page might combine locations, events, people and FAQs into one search experience.
When using universal Search, each vertical is still independent. This means that the query is searched across each vertical at once, applying the algorithms configured for each of those verticals, and then returning the verticals in order of relevance.
Furthermore, each vertical can style its results independently. A “products” vertical might display results as a grid, where an “FAQ” vertical might display results as collapsible sections. On top of styling, verticals can also use completely separate search algorithms and logic to return results.
A universal Search page should use the
<UniversalResults />
component for displaying results. Generally, universal search is labeled with the All
tab in the navigation.
Facets/static filters are only applicable to a single vertical. Since universal Search combines multiple verticals together on one page, we do not support faceting/filtering on Universal pages.
Universal Search is also not paginated. It’s common to include a “View All” button at the top of each vertical that navigates to a specific vertical search page.
Rendering Universal Search Results
When a universal search runs, the results appear in the universal section of the search state separated into verticals.
The sections are ordered by their relevance to the search query. For example, imagine you have an artists and _musicevents vertical. A search query for “red hot chili peppers” would return the artists vertical first followed by the _musicevents vertical. There would be a lot of boilerplate code to parse out each vertical from the universal results in the search state, but thankfully, we can use the UniversalResults
component.
Here, you can see the minimum configuration for the UniversalResults
component where each vertical you want to see in the Universal Search is a key in the verticalConfigMap
prop.
<UniversalResults
verticalConfigMap={{
artists: {},
events: {},
}}
/>
By default, the UniversalResult
component will use the StandardSection
and StandardCard
components to layout each vertical.
verticalConfigMap
You can add custom sections and cards to the verticalConfigMap
prop to change the appearance of each Search vertical. Below, you can see an example of using the same custom card component as before and a new custom section to create a unique layout for the artists vertical.
const ArtistCard = ({ result }: CardProps) => {
const artistName = result.name;
const imageUrl = result.rawData.photoGallery?.[0].image.url;
return (
<div className="flex flex-col items-center p-4">
<div className="rounded-full">
<img src={imageUrl} className="object-contain w-32 rounded-full pb-4" />
</div>
<div className="font-semibold">{artistName}</div>
</div>
);
};
const GridSection = ({ results, CardComponent, header }: SectionProps) => {
if (!CardComponent) {
return <div>Missing Card Component</div>;
}
return (
<div>
<div>{header}</div>
<div className="grid md:grid-cols-2 lg:grid-cols-4 gap-4 grid-cols-1">
{results.map((r) => (
<CardComponent result={r} />
))}
</div>
</div>
);
};
function App() {
return (
<div className="flex justify-center px-4 py-6">
<div className="w-full max-w-5xl">
<SearchBar />
<Pagination />
<UniversalResults
verticalConfigMap={{
artists: {
label: "Artists",
CardComponent: ArtistCard,
SectionComponent: GridSection,
},
music_events: {
label: "Events",
},
}}
/>
</div>
</div>
);
}