Upgrade from v2 to v3
Upgrade from v2 to v3
This is for:
DeveloperThe Coveo Platform platform is constantly evolving. Headless v3 introduces changes and innovations that align with the latest evolution of the Coveo Platform.
The following are breaking changes from Headless v2 to v3
|
Migration to Coveo Event Protocol
Coveo Event Protocol becomes the new default protocol.
In other words, the Engine configration.analytics.analyticsMode
default value is now next
rather than legacy
.
If you’re using the default value in v3 and aren’t ready to migrate to the new protocol, set the value to legacy
to keep using the Coveo UA protocol.
Only Coveo for Commerce supports EP at the moment.
For every other kind of implementation, set |
const engine = buildSearchEngine({
configuration: {
// ...rest of configuration
analytics: {analyticsMode: 'legacy'},
}
})
Removal of analyticsClientMiddleware
function
As part of the migration to support Coveo Event Protocol (EP), Headless won’t support the analyticsClientMiddleware
property when EP is enabled.
Headless Version 2
const engine = buildSearchEngine({
configuration: {
// ...rest of configuration
analytics: {
analyticsClientMiddleware: (eventName: string, payload: Record<string, unknown>) => {
// ...
}
}
}
})
There’s no alternative when using EP, as EP is meant to be more streamlined, which results in cleaner data and more powerful machine learning models.
When using the legacy Coveo UA protocol, you can continue using analyticsClientMiddleware
.
Headless Version 3
const engine = buildSearchEngine({
configuration: {
// ...rest of configuration
analytics: {
analyticsMode: 'legacy',
analyticsClientMiddleware: (eventName: string, payload: any) => {
// ...
}
}
}
})
Organization endpoints
Organization endpoints is a feature that improves separation of concerns, resiliency, and makes multi-region and data residency deployments smoother. Starting with Headless v3, the usage of organization endpoints will be enforced automatically, as opposed to optional in v2.
Headless Version 2
import {buildSearchEngine} from '@coveo/headless';
const engine = buildSearchEngine({
configuration: {
// ...
organizationId: '<ORGANIZATION_ID',
organizationEndpoints: getOrganizationEndpoints('<ORGANIZATION_ID')
}
})
Headless Version 3
import {buildSearchEngine} from '@coveo/headless';
const engine = buildSearchEngine({
configuration: {
// ...
organizationId: '<ORGANIZATION_ID',
}
})
For HIPAA organizations, rather than specifying hipaa
argument in the getOrganizationEndpoints
function, set the environment
property to hipaa
in your engine configuration.
Headless Version 2
import {buildSearchEngine} from '@coveo/headless';
const engine = buildSearchEngine({
configuration: {
// ...
organizationId: '<ORGANIZATION_ID',
organizationEndpoints: getOrganizationEndpoints('<ORGANIZATION_ID', 'hipaa')
}
})
Headless Version 3
import {buildSearchEngine} from '@coveo/headless';
const engine = buildSearchEngine({
configuration: {
// ...
organizationId: '<ORGANIZATION_ID',
environment: 'hipaa',
}
})
For most implementations, this is the extent of the changes.
If you were using the organizationEndpoints
property to send requests to your own proxy that would then relay requests to Coveo APIs, however, more changes will be required.
Headless v3 introduces the search.proxyBaseUrl
, analytics.proxyBaseUrl
, and commerce.proxyBaseUrl
engine configuration options for such cases.
Headless Version 2
import {buildSearchEngine} from '@coveo/headless';
const engine = buildSearchEngine({
configuration: {
// ...
organizationId: 'my-org-id',
organizationEndpoints:
{
...getOrganizationEndpoints('my-org-id'),
search: 'https://myproxy.com/search',
}
}
})
Headless Version 3
import {buildSearchEngine} from '@coveo/headless';
const engine = buildSearchEngine({
configuration: {
// ...
organizationId: 'my-org-id',
search: {
proxyBaseUrl: 'https://myproxy.com/search',
},
}
})
If you were using the getOrganizationEndpoints
function for some other purpose, you can use the new getOrganizationEndpoint
, getAdministrationOrganizationEndpoint
, getSearchApiBaseUrl
or getAnalyticsNextApiBaseUrl
functions instead.
Headless Version 2
const organizationEndpoints: getOrganizationEndpoints('<ORGANIZATION_ID>');
const searchEndpoint = organizationEndpoints.search;
// ...
Headless Version 3
const searchEndpoint = getSearchApiBaseUrl('<ORGANIZATION_ID>');
// ...
platformUrl
property
The platformUrl
property, which was previously deprecated, has been removed from all engine configuration options.
This property was originally used to specify Organization endpoints, but the organizationEndpoints
property has since replaced it.
As organization endpoints are now mandatory, the platformUrl
property is no longer needed.
Node version support
The minimum version of Node.js supported by Headless is now 20.
This is strictly for clients bundling and building their front-end application through a Node based toolchain and including Headless as a project dependency.
Exports
Headless exports multiple entry points each meant to support different use cases and environments. To improve the inter-operability of Headless with different industry standard tools, and to guide those tools to properly use the appropriate entry points depending on the use case, Headless will start enforcing and specifying export fields in package.json. This means that implementation relying on non-public modules of the package will stop functioning.
Headless Version 3
// This will be blocked entirely
import {nonPubliclyDocumentedFunction} from '@coveo/headless/dist/nonPublicFile.js';
// Will throw an error, or won't compile
nonPubliclyDocumentedFunction();
Also, it means you need to set moduleResolution": "bundler"
in your tsconfig.json
file to access secondary entry points such as @coveo/headless/commerce
or @coveo/headless/ssr
.
See TypeScript module resolution for more information.
abab
dependency
The deprecated abab
npm package has been removed from Headless dependencies.
If you were using it through Headless, you’ll need to include it in your project dependencies directly.
TestUtils
In v2, some internal TestUtils
functions were exported, but weren’t meant for public use.
Those functions are no longer exported in v3.
createAction
, createAsyncThunk
and createReducer
Those Redux Toolkit functions are no longer re-exported by Headless. If you’re using them, import then directly from Redux.
Modified behaviors
DidYouMean queryCorrectionMode
The queryCorrectionMode
default value is now next
rather than legacy
.
This means that the default behavior of the didYouMean
controller will be to use a query suggestions model for query correction rather than the legacy index mechanism.
GeneratedAnswer sendFeedback
The feedback
parameter of the sendFeedback
method was changed.
In v2, it could have either the GeneratedAnswerFeedback
or GeneratedAnswerFeedbackV2
type, which were defined as follows:
Headless Version 2
export type GeneratedAnswerFeedback =
| 'irrelevant'
| 'notAccurate'
| 'outOfDate'
| 'harmful';
export type GeneratedAnswerFeedbackOption = 'yes' | 'unknown' | 'no';
export type GeneratedAnswerFeedbackV2 = {
helpful: boolean;
documented: GeneratedAnswerFeedbackOption;
correctTopic: GeneratedAnswerFeedbackOption;
hallucinationFree: GeneratedAnswerFeedbackOption;
readable: GeneratedAnswerFeedbackOption;
details?: string;
documentUrl?: string;
};
In v3, only the GeneratedAnswerFeedback
type is accepted, which was the previous GeneratedAnswerFeedback2
.
Headless Version 3
export type GeneratedAnswerFeedbackOption = 'yes' | 'unknown' | 'no';
export type GeneratedAnswerFeedback = {
helpful: boolean;
documented: GeneratedAnswerFeedbackOption;
correctTopic: GeneratedAnswerFeedbackOption;
hallucinationFree: GeneratedAnswerFeedbackOption;
readable: GeneratedAnswerFeedbackOption;
details?: string;
documentUrl?: string;
};
You must therefore adjust your code to use the new GeneratedAnswerFeedback
type.
Headless Version 2
const feedback: GeneratedAnswerFeedback = 'irrelevant';
generatedAnswer.sendFeedback(feedback);
Headless Version 3
const feedback: GeneratedAnswerFeedback = {
readable: 'unknown',
correctTopic: 'unknown',
documented: 'yes',
hallucinationFree: 'no',
helpful: false,
};
generatedAnswer.sendFeedback(feedback);
The undocumented logGeneratedAnswerFeedback
action was also modified the same way, accepting only GeneratedAnswerFeedbackV2
input, which was renamed to GeneratedAnswerFeedback
.
The undocumented logGeneratedAnswerDetailedFeedback
action was removed in v3.
Types
The undocumented SearchBoxSuggestionsEvent
type now takes in a search box controller and bindings as input.
Headless Version 2
const event: SearchBoxSuggestionsEvent,
Headless Version 3
const event: SearchBoxSuggestionsEvent<SearchBoxController, AnyBindings>,
Removals
Relevance Generative Answering (RGA) rephrase
option
Many actions, properties, types and methods related to the Relevance Generative Answering rephrase
option were removed or modified in v3, since the option itself is no longer supported.
-
All
rephrase
methods were removed from all*-generated-answer
controllers. -
The undocumented
logRephraseGeneratedAnswer
analytics action was removed. -
The undocumented
rephraseGeneratedAnswer
search action cause was removed. -
The
GeneratedResponseFormat.answerStyle
was removed from the GeneratedAnswerstate
. -
The
GeneratedAnswerStyle
type was removed. -
The undocumented
updateResponseFormat
action now only accepts thecontentFormat
option, and not the answer style.
Sub-packages
Both product-recommendations
and product-listing
sub-packages are removed in v3.
Use the new commerce
package instead.
See Headless for commerce.
Properties and methods
The following were removed in v3:
-
buildCaseAssistQuickview
, which was a duplicate export ofbuildQuickview
has been removed. -
buildCaseAssistInteractiveResult
, which was a duplicate export ofbuildInteractiveResult
has been removed. -
browserPostLogHook
, which used to be exposed in the engine configuration options, has been removed. It wasn’t doing anything. -
The quickview
onlyContentURL
initialization option has been removed fromQuickview
andCaseAssistQuickview
controllers because it was always set totrue
.Relatedly, the
content
state attribute has been removed from those controllers, as it was always empty. -
The undocumented
showMoreSmartSnippetSuggestion
andshowLessSmartSnippetSuggestion
search page events have been removed. -
CategoryFacet
state
propertiesparents
andvalues
have been removed. UsevaluesAsTrees
andselectedValueAncestry
instead.While
values
was a flat list of all values,valuesAsTrees
contains the root facet values, whose children, if any, are accessible viavaluesAsTrees[i].children[j]
.selectedValueAncestry
is similar toparents
, but it also includes the selected value itself.Depending on your implementation, the changes may or may not be transparent.
Headless Version 2
private renderParents() { return ( this.state.hasActiveValues && ( <div> Filtering by: {this.renderClearButton()} {this.state.parents.map((parentValue, i) => { const isSelectedValue = i === this.state.parents.length - 1; return ( <span key={this.getUniqueKeyForValue(parentValue)}> → {!isSelectedValue ? ( <button onClick={() => this.controller.toggleSelect(parentValue)} > {parentValue.value} </button> ) : ( <span>{parentValue.value}</span> )} </span> ); })} </div> ) ); } private renderActiveValues() { return ( <ul> {this.state.values.map((value) => ( <li key={this.getUniqueKeyForValue(value)}> <button onClick={() => this.controller.toggleSelect(value)}> {value.value} ({value.numberOfResults}{' '} {value.numberOfResults === 1 ? 'result' : 'results'}) </button> </li> ))} </ul> ); }
Headless Version 3
private renderParents() { return ( this.state.hasActiveValues && ( <div> Filtering by: {this.renderClearButton()} {this.state.valuesAsTrees.map((parentValue, i) => { const isSelectedValue = i === this.state.valuesAsTrees.length - 1; return ( <span key={this.getUniqueKeyForValue(parentValue)}> → {!isSelectedValue ? ( <button onClick={() => this.controller.toggleSelect(parentValue)} > {parentValue.value} </button> ) : ( <span>{parentValue.value}</span> )} </span> ); })} </div> ) ); } private renderActiveValues() { return ( <ul> {this.state.selectedValueAncestry.map((value) => ( <li key={this.getUniqueKeyForValue(value)}> <button onClick={() => this.controller.toggleSelect(value)}> {value.value} ({value.numberOfResults}{' '} {value.numberOfResults === 1 ? 'result' : 'results'}) </button> </li> ))} </ul> ); }
Actions
logExpandToFullUI
parameters
The LogExpandToFullUI
action no longer uses the caseId
and caseNumber
parameters.
They are rather fetched automatically from the Headless engine state.
The fullSearchComponentName
and triggeredBy
parameters have been removed.
They had no effect.
InsightCaseContextSection
actions
These undocumented actions have been removed.
Types
The undocumented CommerceSearchBoxSuggestionsEvent
type has been removed in V3.
If you were using this type, switch to the undocumented SearchBoxSuggestionsEvent
type, which now accepts a search box controller and bindings as input.
Headless Version 2
const event: SearchBoxSuggestionsEvent,
Headless Version 3
const event: SearchBoxSuggestionsEvent<SearchBoxController, AnyBindings>,