Skip to content

Extracting context for managed recommendations

When Hello Retail renders a managed Recommendation on your site, the recommendation algorithm often needs to know something about the page it is shown on: which product the visitor is looking at, its brand, where in the category tree the visitor is, or a custom value your filters depend on. Instead of requiring you to pass these values programmatically, a managed Recommendation can extract them directly from the page using a crawl config.

A crawl config is a small set of extraction rules written in a jQuery-inspired selector syntax. helloretail.js executes the rules in the visitor's browser, against the live DOM, right before the recommendation is requested. The extracted values are sent along with the request and become the recommendation's input context, every field is available to the algorithm as $input.<field>.

How it works

  1. helloretail.js finds the recommendation's placement on the page and prepares to load it.
  2. If the recommendation has a crawl config, each rule in it is evaluated against the page.
  3. The extracted values are sent to Hello Retail as the request context.
  4. The algorithm configured on the recommendation runs with that context: url, urls and productNumbers identify the products the recommendation is about (used by algorithms like related products and bought together), and every field can be referenced in filters and source conditions as $input.<field>.

If a recommendation has no crawl config, the context still contains the page URL, so if the URL matches a product URL in the product catalog, Product-based algorithms and filters still work. The crawl config is for everything beyond that.

The crawl config is edited on the recommendation itself in your Hello Retail Dashboard, under Recommendations → select a recommendation → Context for recommendation algorithm.

A first example

Say your product page marks up the brand and a color, and you want a "More from this brand" recommendation that also prefers the same color. This crawl config extracts both:

brand: $("[itemprop=brand]").text()
extraData.color: $("#product-info").data("color")
Part Meaning
brand, extraData.color The field name the value is stored under. Must be one of the known field names (see Field names); extraData.* accepts any custom name
$("[itemprop=brand]") A CSS selector, like jQuery's $(). Selects all matching elements on the page
.text() A processing method applied to the selection; here, the text content of the matched elements
.data("color") Reads the data-color attribute of the first matched element

In the recommendation's algorithm you can then add a filter such as brand equals $input.brand, or a condition on $input.extraData.color, and the values extracted from the page are used every time the recommendation loads.

The syntax

A crawl config is one rule per line:

fieldName: source.step().step()...

The source decides what data extracted from the page; the processing steps refine it.

Sources

title: $(".product-title")
currency: "EUR"
extraData.campaign: [$(".campaign-badge"), $(".sale-badge")]
extraData.pageUrl: url
Source Meaning
$("css selector") All elements matching the CSS selector. By default it is the result of querySelectorAll, the shop can be configured to use jQuery instead
"text" A fixed string literal
[expr, expr, ...] A list built from several expressions, each with its own source and processing steps

Processing steps

Each step is applied to the result of the previous one, left to right:

Step Meaning
.method() / .method(arg, ...) Calls a method; either one of the Hello Retail methods below, or any method the current value has natively (string methods like .replace(), .split(), .trim(), .toLowerCase(); array methods like .join(), .slice())
.name Reads a property, e.g. .length
[index] Picks one item from a list, e.g. [0]

Method arguments can be numbers (2, -1, 0.5), strings ("text") or regular expressions (/pattern/flags, with the flags g, i, m and s).

If a rule fails, the selector matches nothing and a later step cannot run, or a method throws, the rule simply produces no value. A crawl config never breaks the page.

Hello Retail methods

These methods are provided by helloretail.js.

Reading values from elements

Method Returns
.text() The concatenated text content of all matched elements
.attr("name") The named attribute of the first matched element
.data("name") The data-name attribute of the first matched element. Multi-word attributes use camelCase: data-product-id is read with .data("productId")
.html() The inner HTML of the first matched element
.val() The value of the first matched form element
.prop("name") The named DOM property of the first matched element

Narrowing a selection

Method Returns
.first() / .last() A selection containing only the first / last element
.eq(n) A selection containing only the element at index n
.get(n) The element at index n itself

Conditions

Method Returns
.exists() / .notExists() true / false depending on whether the selection matched anything. Useful for boolean fields like inStock
.matches(/pattern/) / .notMatches(/pattern/) true / false depending on whether the value, as a string, matches the pattern. Also accepts a plain string argument

Numbers

Method Returns
.multiply(factor) The value parsed as a number and multiplied by factor, e.g. .multiply(1.25) to add VAT
.sum() The sum of a list of numeric values

Working with lists

Method Returns
.fns("method", arg, ...) Calls the named method on each item and collects the results, a map operation. E.g. .fns("attr", "href") turns a list of links into a list of URLs
.insert(index, item, ...) The list with the items inserted at index (-1 appends)
.removeElements(index, count) The list with count items removed from index
.removeMatching("text") The list without the items equal to the string (or matching, when given a /regex/)
.asTags() Wraps each item in its own single-item list: [a, b] becomes [[a], [b]]. Used with hierarchies to treat each crumb as its own top-level hierarchy

How values are cleaned up

After the rules run, the extracted values are normalized before they are sent:

  • A selection of elements that reaches the end of a rule is converted to the text content of each element (or a single string, when a method like .text() or .attr() was already applied).
  • url and imgUrl are made absolute: //, /path and relative values get the page's protocol and domain prepended.
  • price and the other price fields are stripped of surrounding currency symbols and whitespace, so "DKK 1.299,00" style markup can be selected directly.
  • hierarchies must end up as a list of hierarchies, where each hierarchy is a list of levels. Anything else is discarded, see the example below.

Extracting hierarchies

A breadcrumb usually holds one hierarchy with several levels, so wrap the selection in [...]:

hierarchies: [$(".breadcrumb a")]

This produces e.g. [["Clothing", "Women", "Dresses"]], one hierarchy without three levels. Without the brackets the result would be a flat list of strings and would be discarded. If each matched element is instead its own independent category, use .asTags():

hierarchies: $(".category-tag").asTags()

which produces [["Sale"], ["News"]].

Field names

The left-hand side of a rule must be one of the known field names. The ones most relevant for Recommendations context:

Field Used for
url, urls, productNumbers Identify the products the recommendation is about. Algorithms like related products, bought together and others are looking at find products relative to these
hierarchies The category context, e.g. for filters like hierarchies matches $input.hierarchies
title, brand, price, currency, inStock, ean, productNumber, imgUrl, description, keywords Standard product fields, available to filters as $input.<field>
extraData.<name>, extraDataList.<name>, extraDataNumber.<name> Custom values, a single string, a list of strings, or a number. <name> is free-form, so this is the place for anything shop-specific