Skip to Content
BannersUpsellVehiclesBlockBanner

UpsellVehiclesBlockBanner

Displays vehicle recommendations in a horizontally scrolling strip, using an existing deal or inventory vehicle as the reference (the seed). Recommendations prefer the same vehicle class and can optionally mix deals and inventory.

Includes the common banner props. For Shopify products, use UpsellBlockBanner.

CMS setup

  1. Create a banner with typename UpsellVehiclesBlock.
  2. Set foreignEntityId to an existing vehicle identifier from the selected source. This is the vehicle identifier, not the CMS banner id.
  3. Choose Fahrzeug-Empfehlungsmodus: inventory for inventory vehicles or deal for deals. The default is deal; an inventory identifier must explicitly use inventory.
  4. Set Empfehlungs-Limit to the maximum number of cards to display. Default: 10; minimum: 1.
  5. Enable Cross-Sell aktivieren only if recommendations may include the other source.
  6. Configure the title, image fit, and common banner appearance, then add the banner to a page.

A blank seed identifier prevents the backend from returning the banner. A non-empty identifier that cannot be resolved produces a recommendation API 404. Normal banner activation and draft-preview rules still apply.

CMS fields and rendered props

CMS fieldRendered propMeaning / default
foreignEntityIdforeignEntityIdRequired for a usable banner; resolved by the selected source’s existing vehicle lookup
upsellVehiclesRecommendationModerecommendationModedeal (default) or inventory
upsellRecommendationLimitrecommendationLimitMaximum total cards, default 10, minimum 1
crossSellEnabledcrossSellEnabledAllow both sources; default false
imageBlockObjectFitimageObjectFitShared banner image-fit setting

showNavigation is no longer used for this banner. crossSellEnabled does not control arrows or scrolling.

Props

id●
string
required

CMS banner id; distinct from the reference vehicle identifier.

foreignEntityId●
string
required

Reference vehicle identifier resolved in the selected source.

recommendationMode●
'deal' | 'inventory'
required

Source of the reference vehicle. Defaults to deal in CMS configuration.

recommendationLimit●
number
required

Maximum total recommendations displayed, not the API page size. Default 10; minimum 1.

crossSellEnabled●
boolean
required

Allow deal and inventory candidates together. Defaults to false.

imageObjectFit●
'cover' | 'contain'

Shared image-fit setting passed to both inventory and deal cards.

Sources and vehicle classes

Source describes the listing: deal or inventory. Vehicle class describes the vehicle, such as Car or Motorbike. These are independent.

Seed sourcecrossSellEnabledEligible sources
inventoryfalseInventory only
dealfalseDeals only
EithertrueDeals and inventory

Enabling cross-sell makes the other source eligible; it does not guarantee a mixture or reserve slots for it. Same-class candidates from either enabled source compete on ranking.

Same-class priority and backfill

The seed is excluded from its own source. Candidates matching its normalized vehicle class are ranked first. Candidates of another class, including those with missing class data, are used only when the entire same-class pool contains fewer than one page of results. They fill the remaining slots up to one page, and never displace same-class results.

For a page size of 10:

Same-class candidatesResult
14Page one has 10; page two has 4. No cross-class backfill.
10One full page of same-class results.
6Six same-class results, then up to four fallback results.
0Up to ten fallback results.

There are no additional fallback pages. If the seed itself has no vehicle class, ordinary ranking applies to all candidates because a class comparison is unavailable.

Cross-class backfill works with crossSellEnabled=false within the selected source. A motorcycle inventory seed can therefore receive car inventory fallback without cross-sell. Car deals require crossSellEnabled=true.

The banner requests pages of min(6, recommendationLimit). Its normal fallback threshold is therefore six, even when its display limit is ten. Five same-class results can receive one fallback card; eight same-class results remain eight, with no fallback to reach ten. Direct API callers choose their own page size.

Rendering and loading

  • Inventory recommendations reuse the inventory archive card (CarListItem); deal recommendations reuse CarDealBlock through the deal archive adapter. Pricing, actions, and disclosures follow those existing card components.
  • Inventory cards support the consumption-information dialog when the required data is available.
  • Cards remain in a horizontal strip with scroll snapping and a hidden scrollbar. There is no wrapping archive grid or navigation toggle.
  • Card width follows a three-column archive’s maximum content width, rather than one third of the viewport: min(100%, (var(--max-width-content) - 3rem) / 3). A wide strip may show more than three cards; a narrow container caps each card at its available width.
  • Recommendations load in the browser, with session credentials included. Skeleton cards reserve space during loading and for the upcoming page.
  • The first page loads immediately. Further pages load when the end marker intersects the strip’s scroll area. Loading stops at the configured limit or the API’s last page.
  • Returned cards are deduplicated by source:id. The same id in two sources is treated as two listing identities.
  • Changing the seed, mode, limit, or cross-sell setting clears the loaded recommendations and resets horizontal scroll.
  • A failed request keeps already loaded cards. A later end-marker intersection can retry; there is no dedicated error or empty-state message. An empty result can leave the title visible without cards.

Recommendation ranking

The engine uses weighted attribute matching, not machine learning. Text attributes are normalized before exact comparison. Missing seed attributes do not contribute to the available weight; a missing candidate attribute cannot match.

AttributeWeightMatch rule
Price3Within an inclusive ±20% range on the same price basis
Brand3Exact normalized match
Vehicle class3Exact normalized match; also determines the priority group
Model id4Exact normalized match when the seed has a model id
Model name3Used instead of model id only when the seed has no model id
Fuel2Exact normalized match
Vehicle type/category2Exact normalized match

Price comparison prefers the seed’s purchase price. Only when the seed has no purchase price does it use its monthly price, against the candidate’s monthly price. Purchase and monthly amounts are never compared with each other. Prices are read in cents from gross offer values; inventory also supports its legacy purchase-price field.

Inventory class and category come from its vehicle fields. Deals read class and category/type from their optional line payload. Missing deal class data places that deal in the fallback group when the seed class is known.

Similarity and ranking score

similarity = matched attribute weight / available seed attribute weight score = similarity + history bonus

similarity ranges from 0 to 1, or is 0 when no seed attributes are available. Multiplying it by 100 gives a feature-match percentage, not a probability that the visitor will buy or prefer the vehicle. The API does not return a separate percentage.

score adds personalization and can reach 1.2. Within each class group, results sort by score descending, then by the number of unique matched signals, then by stable candidate order. The same-class group always precedes fallback, even if a fallback candidate has a higher score.

Session personalization

The engine reads up to 50 latest product-search events for the current session and uses deal/inventory events from that window. These are archive/search responses, not 50 clicks or 50 recommended vehicles.

History signalBonus
Candidate appeared in a previous archive result from the same source0.1, awarded once
Distinct search/filter term occurs in the candidate’s normalized search text0.05 per term, at most 0.1 total

The total bonus is capped at 0.2. Duplicate events and repeated terms do not accumulate more points. Result identifiers are source-specific; search terms can match across both sources. Search text contains brand, model, class, vehicle type, and fuel.

Without session history the bonus is zero. Merely displaying recommendations does not record another product-search event, so reloading the banner does not boost its own results. Appearing in an archive response is an exposure signal, not proof that the visitor clicked a card. Recommendation ranking does not currently use clicks or conversions.

API

GET /v1/recommendations/cars/inventory/2527110?page=1&pageSize=6&crossSellEnabled=true
ParameterLocationBehavior
modePathRequired: deal or inventory
idPathRequired: reference vehicle identifier
pageQueryOne-based page; default 1
pageSizeQueryDefault 10; maximum 50; also sets the fallback threshold
crossSellEnabledQueryOptional boolean true or false; default false

Keep pageSize unchanged while paging. recommendationLimit is a banner display limit, not an API query parameter. Archive filter/sort settings are not forwarded into recommendation candidate selection.

The endpoint is public and uses the default request throttle. Session context is optional. It returns Cache-Control: no-store, because rankings may be personalized. Invalid modes or boolean values fail validation; an unresolved seed returns 404.

Response

The HTTP response wraps the paginated result in data. Each recommendation contains the complete source-specific car payload. The example below abbreviates that payload; identifiers and scores are illustrative.

{ "data": { "data": [ { "source": "inventory", "id": "candidate-id", "similarity": 0.625, "score": 0.725, "matchedSignals": ["purchase-price", "vehicle-class", "fuel", "vehicle-type", "session-result"], "car": { "id": "candidate-id", "vehicleClass": "Motorbike" } } ], "resultCount": 1, "totalPages": 1, "hasPrevPage": false, "hasNextPage": false } }

Possible matched signals are purchase-price, monthly-price, brand, vehicle-class, model-id, model, fuel, vehicle-type, session-result, and session-search.

resultCount describes the eligible result set after seed exclusion and fallback selection, not the number of cards on the current page or the banner’s display limit. Requests beyond the last page return an empty recommendation array.

Limits and troubleshooting

The engine loads at most 300 candidates per enabled source, using the existing archive services. Class availability and ranking are evaluated inside that bounded pool, not across the entire catalog. Increasing the banner limit does not enlarge the candidate pool. Catalog or session changes between requests can change ordering; pagination is not a frozen snapshot.

There is no recommendation persistence, recommendation cache, source quota, price-increase requirement, or guarantee of an exact model match. The banner suggests alternatives; an “upsell” can have a lower price than the seed.

SymptomCheck
Banner missing entirelySeed id is non-empty; banner activation and page configuration are valid
Title but no cardsInspect the recommendation request; confirm the id belongs to the selected mode
Recommendation API returns 404Seed is unresolved; deal is the default even if an inventory id was entered
Fewer cards than the configured limitEligible pool may be smaller; fallback only fills one API page
Only inventory or only dealsCross-sell defaults to false; enabling it does not guarantee mixed results
Other vehicle classes appearSame-class pool is below one page, or the seed has no class
A deal is treated as fallbackIts line.vehicleClass may be missing or different
Results differ between visitorsSession history contributes a bounded personalization bonus
const banner: UpsellVehiclesBlockBanner = { typename: BannerTypename.UpsellVehiclesBlock, id: 'b_123', title: 'Weitere Fahrzeuge für dich', titleTag: 'h2', titleAlign: 'left', cssId: null, cssClasses: null, imageObjectFit: 'contain', foreignEntityId: '2527110', recommendationMode: UpsellRecommendationMode.Inventory, recommendationLimit: 10, crossSellEnabled: true };

Unlike Shopify upsells, vehicle upsells always use a vehicle seed and the local recommendation engine. They do not accept a manual product list or nested funnel banners, and recommendationMode is a source enum rather than Shopify’s boolean switch.

Related vehicle documentation: inventory archive, deal archive, inventory detail, and deal detail.

Last updated on