Vue Storefront is now Alokai! Learn More
Configuration

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

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:

storefront-unified-nextjs/sdk/modules/bloomreach.ts
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 the vsf-currency cookie is missing (defaults to 'USD')
  • facetConfig — declarative rules that map Bloomreach facet field names to storefront types like COLOR, SIZE, PRICE. This is how the storefront knows to render color swatches vs. checkboxes
  • facetFields — which facet fields to request. Omit to let Bloomreach return all available facets
  • excludeFacets / filterFacets — control which facets appear in the response
  • categoryRoot — root category ID for hierarchical category facets
  • transformImageUrl — 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 like price_eur, sale_price_eur
  • facetVersion — set to '3.0' to get structured facet responses from Bloomreach
  • productFields — 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 static domainKey per request. Useful when each locale has its own Bloomreach catalog
  • resolveViewId — map locale + currency to a Bloomreach view for currency-specific pricing
  • resolveTrackingParams — 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).