Detail and recommendations
What you're building: a page that renders one record from Algolia, with a row of related items underneath.
Two separate features that usually appear together. Detail renders one record. Recommendations ask Algolia what else to show.
Detail
- Applies toA Section wrapping the record
Marks the detail region.
- Applies toThe detail wrapper
Which index to load the record from.
Inside the wrapper, bind fields exactly as in a result card:
<section wf-algolia-element="detail" wf-algolia-index="products">
<h1 wf-algolia-text="name"></h1>
<img wf-algolia-image="hero" wf-algolia-alt="name" />
<div wf-algolia-html="description"></div>
</section>
Which record
The script has to work out which record to load. In order:
- — a literal ID on the element
- — where to read it from, such as a URL segment or query parameter
- — match a field other than
objectID
On a Webflow CMS template page the usual approach is to bind the objectID value to a CMS field, so each generated page carries its own.
Detail page missing wf-algolia-index— no index on the wrapperDetail page: no objectID found in URL or attributes— nothing identified the recordDetail page: object not found for— the ID resolved but no record matched
The third usually means the record exists in Webflow but has not synced to Algolia yet.
Repeating fields
For an array field — sizes, tags, related links — mark a wrapper and one child . The item is cloned per entry.
Recommendations
- Applies toA Section below the detail
Marks the recommendation region.
- Applies toThe recommend wrapper
Which Algolia Recommend model to query.
- Applies toThe recommend wrapper
Which index the model was trained on.
- Applies toA Div inside the wrapper
Where recommendations render.
A recommendation section needs all four of a model, an index, a grid and a template. Missing any one produces a single console message:
[wf-algolia] recommend section missing model, index, grid, or template
Sections are handled one at a time and independently. A section that is missing something only skips itself: every other recommendation block on the page still renders.
The six models
takes one of six values. Which extra attributes a section needs depends entirely on which one you pick.
| Model | Answers | Also needs |
|---|---|---|
related-products | "More like this one" | A seed record |
looking-similar | "Looks like this one" (visual similarity) | A seed record |
frequently-bought-together | "People bought these together" | A seed record |
trending-items | "Popular right now" | Nothing |
trending-facets | "Popular categories right now" | wf-algolia-facet-name |
recommended-for-you | "Picked for this visitor" | wf-algolia-user-token |
A section whose model is misspelled is skipped with
recommend: unknown model "…". A section missing the input its model requires
is hidden rather than left empty, and says which input was missing.
Seed records
The three "like this one" models need a record to work from. They resolve it the same way the detail section does: , then , then . On a CMS template page, binding the objectID to a CMS field is usually all it takes.
The seed record is filtered out of its own results, so a "related products" row never opens with the product already on screen.
To seed from several records at once, list them on as a comma-separated list:
<section
wf-algolia-element="recommend"
wf-algolia-model="frequently-bought-together"
wf-algolia-index="products"
wf-algolia-objectids="SKU-1,SKU-2,SKU-3"
></section>
Algolia charges per Recommend request, and a list of three objectIDs is three requests, not one. The script warns once when it sees the attribute. Use it deliberately, on a cart page rather than on every product page.
Trending by category
trending-items is happy with no scope at all, and returns what is popular
across the index. To scope it to one category, set
and
together. One without the other is
ignored, with a console warning, because a half-specified scope is far more
likely to be a mistake than an intention.
trending-facets is the odd one out: it returns facet values, not records. Its
template binds rather than
your record fields, and it needs to
know which facet to rank.
<section
wf-algolia-element="recommend"
wf-algolia-model="trending-facets"
wf-algolia-index="products"
wf-algolia-facet-name="category"
>
<div wf-algolia-element="recommend-grid">
<a wf-algolia-element="template">
<div wf-algolia-text="facetValue"></div>
</a>
</div>
</section>
Personalised recommendations
recommended-for-you needs to know who the visitor is.
takes either a literal token or
cookie:NAME, which reads the value out of that cookie at render time:
<section
wf-algolia-element="recommend"
wf-algolia-model="recommended-for-you"
wf-algolia-index="products"
wf-algolia-user-token="cookie:_ALGOLIA"
></section>
cookie:NAME only reads Algolia's own _ALGOLIA cookie, or one you name in
our namespace: anything starting wf-algolia- or wf_algolia_. Any other
name is refused, the console says which, and the section hides. That keeps a
page attribute from being turned into a way to read a session or auth cookie.
recommended-for-you is the one model that reads a visitor identifier in order
to work, so it waits for consent the same way Insights event tracking does.
Until consent is given the section stays hidden, the cookie is not read, and no
request is made.
Grant it either way:
<!-- your site already has a legal basis to track -->
<script ... data-insights-consent="granted"></script>
// or from your cookie banner, when the visitor accepts
window.WfAlgolia.setInsightsConsent(true);
The section loads the moment consent arrives, so a banner accepted after the page has loaded works with no reload.
This applies whether or not you turned on data-insights. Personalisation and
event tracking are separate features and you can use either on its own, but
both wait here. What the identifier is and where it goes is listed in
Security and privacy.
If the cookie is absent, refused, or the token resolves to nothing, the section hides itself and says so. That is the right behaviour for a personalised row: a visitor with no history gets nothing rather than a row of strangers' picks.
Narrowing what comes back
- takes an Algolia filter string and
applies it to the recommendations, so an in-stock-only row is one attribute.
Every model accepts it except
trending-facets, which has no records to filter. - applies when the model has too
little data to answer, so the row degrades to a sensible listing instead of
disappearing. Every model accepts it except
frequently-bought-together, which has no fallback stage in Algolia. Setting it there warns and is ignored.
Tuning
- — how many to show
- — minimum confidence score, as a whole number from 0 to 100. Anything else is ignored.
Algolia Recommend learns from traffic. On a new index, or one without Insights events, a correctly built section renders nothing at all. That is the model, not your markup — check Dashboard → Recommend before debugging attributes.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Detail page renders empty | No objectID could be resolved | Check the URL and the objectid attributes |
object not found for | The record has not synced to Algolia | Re-run the sync |
| Recommendations never appear | The model is untrained | Check Dashboard → Recommend |
recommend: unknown model | The model name is misspelled | Use one of the six exact model names |
| Only one recommendation shows | No template inside the grid to clone | Add one |
no seed objectID resolved | A seed model could not identify a record | Set one of the wf-algolia-objectid-* attributes |
trending-facets: missing wf-algolia-facet-name | No facet named to rank | Add wf-algolia-facet-name |
recommended-for-you: missing wf-algolia-user-token | No token, or the named cookie is absent | Check the cookie name and that it is set before the script runs |
recommended-for-you: waiting for visitor consent | Consent has not been given yet | Declare data-insights-consent="granted" or call WfAlgolia.setInsightsConsent(true) from your banner |
| The section vanishes entirely | Its model's required input was missing | Read the console: it names which one |
| Facet-name scope is ignored | Only one of the facet-name / facet-value pair is set | Set both, or neither |