Configuration
The unified extension has two configuration layers. UnifiedConfig controls how Bloomreach results are normalized — facet types, currency, image transforms. SearchApiConfig controls what data is requested from Bloomreach — currencies, extra fields, filter queries.
For the full list of every option and its type, see the Reference.
Setting Up the Extension
Using the search-bloomreach module (recommended)
If you installed the search-bloomreach module via the Alokai CLI, the unified extension is already configured. The module scaffolds a config.ts file in your sf-modules/search-bloomreach/ directory with sensible defaults for your platform.
The module also sets up both SDK modules (bloomreach for the raw API and bloomreachUnified for normalized data). You can skip ahead to learn what each config option does.
Manual setup
Use createUnifiedExtension to create and register the extension in your middleware config:
// apps/storefront-middleware/integrations/bloomreach-discovery/config.ts
import type { ApiClientExtension, Integration } from '@alokai/connect/middleware';
import type { MiddlewareConfig, UnifiedConfig } from '@vsf-enterprise/bloomreach-discovery-api';
import { createUnifiedExtension } from '@vsf-enterprise/bloomreach-discovery-api';
const unifiedApiExtension = createUnifiedExtension({
config: {
defaultCurrency: 'EUR',
facetConfig: [
{ names: ['colors'], type: 'COLOR' },
{ names: ['sizes'], type: 'SIZE' },
{ names: ['category'], type: 'CATEGORY' },
{ names: ['price'], range: true, type: 'PRICE' },
],
} satisfies UnifiedConfig,
isNamespaced: true,
normalizers: { addCustomFields: [{}] },
});
export const config = {
configuration: {
discoveryApi: {
accountId: Number(process.env.BLOOMREACH_DISCOVERY_ACCOUNT_ID),
authKey: process.env.BLOOMREACH_DISCOVERY_AUTH_KEY,
domainKey: process.env.BLOOMREACH_DISCOVERY_DOMAIN_KEY,
},
},
extensions: (extensions: ApiClientExtension[]) => [...extensions, unifiedApiExtension],
location: '@vsf-enterprise/bloomreach-discovery-api/server',
} satisfies Integration<MiddlewareConfig>;
SDK Module
After configuring the middleware, add the unified SDK module to your storefront:
import type { BloomreachUnifiedEndpoints } from '@sf-modules-middleware/search-bloomreach';
import { defineSdkModule } from '@vue-storefront/next';
export const bloomreachUnified = defineSdkModule(({ buildModule, config, getRequestHeaders, middlewareModule }) =>
buildModule(middlewareModule<BloomreachUnifiedEndpoints>, {
apiUrl: `${config.apiUrl}/bloomreach/unified`,
cdnCacheBustingId: config.cdnCacheBustingId,
defaultRequestConfig: { headers: getRequestHeaders() },
ssrApiUrl: `${config.ssrApiUrl}/bloomreach/unified`,
}),
);
Export from your modules index:
export * from './bloomreach';
For the raw Bloomreach Discovery API (autosuggest, recommendations, etc.), see the Manual Setup guide to set up the bloomreachDiscovery SDK module.
Understanding the Config
UnifiedConfig
This is the object you pass to createUnifiedExtension({ config: ... }). It controls normalization behavior:
defaultCurrency— fallback currency when thevsf-currencycookie is missing (defaults to'USD')facetConfig— declarative rules that map Bloomreach facet field names to storefront types likeCOLOR,SIZE,PRICE. This is how the storefront knows to render color swatches vs. checkboxesfacetFields— which facet fields to request. Omit to let Bloomreach return all available facetsexcludeFacets/filterFacets— control which facets appear in the responsecategoryRoot— root category ID for hierarchical category facetstransformImageUrl— hook to prepend a CDN host or transform image URLs
SearchApiConfig
This lives under configuration.discoveryApi.search in the middleware config. It controls what gets sent to Bloomreach:
configuration: {
discoveryApi: {
accountId: Number(process.env.BLOOMREACH_DISCOVERY_ACCOUNT_ID),
domainKey: process.env.BLOOMREACH_DISCOVERY_DOMAIN_KEY,
search: {
currencies: ['EUR', 'GBP', 'USD'],
facetVersion: '3.0',
productFields: ['custom_attr_1', 'custom_attr_2'],
},
},
}
currencies— list of indexed currencies. The extension automatically requests per-currency price fields likeprice_eur,sale_price_eurfacetVersion— set to'3.0'to get structured facet responses from BloomreachproductFields— additional fields to request beyond the defaults (pid,title,price, etc.)efq— a static filter query applied to every search (e.g.'availability:"In Stock"')
Dynamic Resolvers
Resolvers run on every request and adapt API parameters based on the incoming request context. They're useful for multi-language and multi-currency setups where the domain key or view ID depends on who's browsing.
Place them in the middleware configuration block, next to discoveryApi:
export const config = {
configuration: {
discoveryApi: { /* ... */ },
resolveDomainKey: (context) => {
const locale = context.config.normalizerContext?.locale ?? 'en';
return `store_${locale}`;
},
resolveViewId: (context) => {
const { currency, locale } = context.config.normalizerContext ?? {};
return currency && locale ? `${locale}_${currency.toLowerCase()}` : undefined;
},
},
// ...
} satisfies Integration<MiddlewareConfig>;
resolveDomainKey— override the staticdomainKeyper request. Useful when each locale has its own Bloomreach catalogresolveViewId— map locale + currency to a Bloomreach view for currency-specific pricingresolveTrackingParams— override tracking parameters (brUid2,url,refUrl). By default these are extracted from cookies and headers automatically
The resolver context gives you access to context.config.normalizerContext.locale (from the vsf-locale cookie), context.config.normalizerContext.currency (from the vsf-currency cookie), and context.req (the raw HTTP request).