Listing Injections
What are listing injection?
Boxalino offers the possibility to inject contents and questions in a list (typically a products listing).
This means that, instead of having (let’s say) a grid of 6x4 products, the grid could be extended to be 7x4 or 8x4 with 4 (or 8) cells occupied by injected contents.
Their position can be configured dynamically and is typically distributed throughout the grid (for example, first content appears in row 2 column 3, second on row 4 column 2, etc.).
Their size can vary spanning over 1 or more columns as well as 1 or more rows (while respecting your grid layout constraints).
This is an important feature for the following reasons:
Users will tend to engage with a list of products much more than elements on top or below it, therefore injecting content inside the list is quite important to get their attention
Users might not be aware of important information (typically communicated with banners) or interesting reads (typically blog entries) which, if injected into a product list, might get their attention much more
Mobile users require much more efforts to select a facet (often, it requires to open a panel, search for the facet name, open it and search for the facet value), by injecting relevant questions inside the list in relevant places, the system can help them filter their list much more conveniently (this function can also be used to gather more profiling information about the user)
How does it work?
First, the injection contents container must be configured as children of the product listing in the narrative.
As here, for example, below the first element indicating what template should be used for each product of the list, two container of contents (banners and blogs) have been added (such container work like any other bx-hits container with their accessor indicating what widget provides the dynamic content).
In addition, the product listing (the same one) must have in its content an “injection” parameter which provides a JSON string configuration for the injection.
In order to set the orange value, put string {{template-injection_listing}} if you don’t have the dynamic expression feature active.
For your testing, you can also simply copy & paste a minified json of your configuration in the injection field, so you don’t have to configure the injection in BigQuery by yourself.
As here, it is typical that the JSON will not be put as a static string in the injection parameter, but instead will be loaded by Boxalino from Google BigQuery. This will be done with a template resource that Boxalino can configure for you.
What is the result?
As a result, the content containers will be removed from the children of the product listing (banner-injection and blog_slider in the first screen-shot) and the products will be returned as normally, but some additional content will be injected throughout the list. As here in the second position, between a first and a second product:
{
"blocks": [
{
"blocks": [
{
"template":"product",
"bx-hit": {
"id": "155524",
"title": "The title of the product",
},
"blocks": []
},
{
"template":"blog",
"bx-hit": {
"id": "blog_123",
"title": "The title of the blog"
},
"injection": {
"position": {
"position": "1",
"cols": "2",
"rows": "1",
"type": "fixed",
"parameters": [],
"segments": []
}
},
"blocks": []
},
{
"template":"product",
"bx-hit": {
"id": "155525",
"title": "The title of another product",
},
"blocks": []
}
//...
]
}
]
}
The injected content will be a block matching the child Layout block of the content container blocks (as usual) and will have an extra “injection” parameter giving additional information about the injected content.
Notably, this injection parameter has a “position” parameter indicating the injected position (e.g.: index 1 here as it is injected before the position 1 (first position being 0)) as well as the size of the injected block in the listing, in the “rows” and “cols” parameters. Here a “cols” of 2 indicate that the content should span over two columns as per this layout:
It is important to take notice that the position and size of the content are provided according to a configuration model which can respect your layout constraints.
So, such an injection would not happen if your mobile layout would bee 2 columns per row in the mobile as it would break the flow (see next section).
Injection configuration model
It is not required to read further if you are only interested to know how to integrate the listing injections and leave the configuration of the injection model to Boxalino which is the typical case. We provide the following information to explain how the full process works, but it will get more complex and you can stop there if you only want to integrate injections in your front-end product listings
As indicated above, while you can define a static stringified JSON in the Narrative parameter “injection” directly, it is not recommended. Instead a better practice is to defined a dynamic expression loading it with a resource template.
The Model has the following parameters
Parameter | Description | Example value |
---|---|---|
type | configuration model type (currently only ‘standard’) | standard |
version | configuration version (currently only 1) | 1 |
sub_version | configuration sub version (currently only 1) | 1 |
layout | constraints about your layout (e.g.: how many cols per device) |
|
layout[*].name | key for the layout case (e.g.: for the device) | ua-deviceCategory |
layout[*].value | value for the layout case (e.g: for mobile) | Smartphone/Desktop |
layout[*].cols | number of columns per row in this device (e.g.: 2 for mobile, 4 for desktop) | 2 |
injection | information about the injections to be made |
|
injection.minimum | minimum number of injections (an injection has the number of element defined in the size) | 1 |
injection.maximum | maximum number of injections (an injection has the number of element defined in the size) | 1 |
injection.size | size of an injections (here 4 elements, which means 1 row for the desktop and 2 rows for the mobile in case of example layout[*].cols above) | 4 |
positions | information about which positions should be filled in the listing |
|
positions[*].id | unique string identifier of the position | 1 |
positions[*].positions | list of specific positions (which can be different per device for instance) |
|
positions[*].positions[*].position | index where the content should be injected | 2 |
positions[*].positions[*].cols | size of the content in columns | 1 |
positions[*].positions[*].rows | size of the content in rows | 1 |
positions[*].positions[*].type | type of position (currently only fixed) | fixed |
positions[*].positions[*].parameters | additional parameters (optional) | format: array<struct<name string, array<string>>> |
positions[*].positions[*].segments | segments on which this position applies | [{"name": "ua-deviceCategory" |
positions[*].parameters | additional parameters (optional) | format: array<struct<name string, array<string>>> |
content | the content which should be injected |
|
content[*].selector_type | selector type to indicate how to recognize which of the content container should be detected (by default detection done by block parameter) | parameter |
content[*].selector_name | indicate on which parameter name the content selector should apply (typically selector is done on a template parameter) | template |
content[*].selector_value | indicate on which parameter value the content selector should apply (so here we indicate that the selector should take the bloc container template) | blog-container |
content[*].type | type of content (so far always container) | container |
content[*].position_ids | list of unique position identifiers to be filled with this content source (must match identifiers defined in positions[*].id) | ['1','2'] |
content[*].page_offsets | indicate how much offset should be applied per page (if -1, content is only injected in the first page) | -1 |
content[*].conditions | advanced conditional logic | see section Advanced Conditions below |
content[*].parameters | additional parameters (optional) | format: array<struct<name string, array<string>>> |
Example
Here is an example of the configuration model with 3 injected contents:
First banner in position 5 (or 6 on the mobile)
First blog in position 13
Second banner in position 16 (with a cols of 2, so spanning over 2 columns)
{
"type": "standard",
"version": "1",
"sub_version": "1",
"layout": [
{
"name": "ua-deviceCategory",
"value": "Smartphone",
"cols": "2"
},
{
"name": "ua-deviceCategory",
"value": "Desktop",
"cols": "4"
}
],
"injection": {
"mininum": "1",
"maximum": "1",
"size": "4"
},
"positions": [
{
"id": "0",
"positions": [
{
"position": "6",
"cols": "1",
"rows": "1",
"type": "fixed",
"parameters": [],
"segments": [
{
"name": "ua-deviceCategory",
"value": "Smartphone"
}
]
},
{
"position": "5",
"cols": "1",
"rows": "1",
"type": "fixed",
"parameters": [],
"segments": [
{
"name": "ua-deviceCategory",
"value": "Desktop"
}
]
}
],
"parameters": []
},
{
"id": "1",
"positions": [
{
"position": "13",
"cols": "1",
"rows": "1",
"type": "fixed",
"parameters": [],
"segments": [
{
"name": "ua-deviceCategory",
"value": "Smartphone"
},
{
"name": "ua-deviceCategory",
"value": "Desktop"
}
]
}
],
"parameters": []
},
{
"id": "2",
"positions": [
{
"position": "16",
"cols": "2",
"rows": "1",
"type": "fixed",
"parameters": [],
"segments": [
{
"name": "ua-deviceCategory",
"value": "Smartphone"
},
{
"name": "ua-deviceCategory",
"value": "Desktop"
}
]
}
],
"parameters": []
}
],
"content": [
{
"selector_type": "parameter",
"selector_name": "template",
"selector_value": "banner-container",
"type": "container",
"position_ids": [
"0",
"2"
],
"page_offset": "-1",
"parameters": []
},
{
"selector_type": "parameter",
"selector_name": "template",
"selector_value": "blog-container",
"type": "container",
"position_ids": [
"1"
],
"page_offset": "-1",
"parameters": []
}
]
}
How to configure the Dynamic Expression & Template Resource
The Dynamic Expression of the product listing Block of the narrative can be configured as a Script → Template Resource variable as here:
The Template Resource should be defined before (here injection_listing) and should come (typically) from a Real-Time Correlation, here are the typical parameters (in Menu : Advanced > Template Resources).
The values to indicate for the Values, type and valuesKey should be confirmed by Boxalino as they depend on the data which is loaded from Google BigQuery, but the values indicated here are the default values and can typically be used.
Injecting Facets
The prior sections indicate how to inject content, but it might also be interesting to inject facets.
In this case, you can reuse the same facet container Layout Block you use for your search and navigation filters, but you need to add one new Facet Layout Block, here is an example:
Then you can set the facet container and new facet Layout containers in your narrative as children of the list container after the product block as you would do for content injection, here is an example:
Finally, you might wnt to add parameters to your facet (for example to have a different label per facet with a question) as follows:
If you follow this pattern to put your main language as a parameter (e.g.: “question”) and sublanguages with _LAN then the system will return the current language automatically in the facet parameters on the main name (so a request in French would here return the facet parameter as “question”: “Quelle couleur…” in case your request language was ‘fr’).
The API response will return in the injected facet block a “bx-facet” parameter with the same structure as the bx-facets you already use for the filters on the left, but only with 1 facet (instead of all of them).
The values which are to be shown to the user has the parameter “show”: true (you can ignore the other ones).
{
"bx-facet": {
"field": "brand",
"values": [
{
"value": "First brand",
"hitCount": 18,
"show": true,
"order": 0
}
...
Advanced Conditions
Listing Conditions can also support advanced real-time conditions (as part of the “content” field) to implement custom behaviors in the listing injections.
The conditions parameter is a list of conditions, each with the following format:
Parameter | Description | Example value |
---|---|---|
condition.clauses | a list of clauses for the condition to be true or false |
|
condition.clauses[*].type | the type of condition, curently only hits-field is supported | hits-field |
condition.clauses[*].index | the hit index to consider in the clause | 0 |
condition.clauses[*].field | the name of the hit field to consider in the clause | selected_title, brand, … |
condition.claues[*].operator | an operator for the condition | matches exactly |
condition.clauses[*].values | the list of value to check | ‘null’ |
condition.clauses[*].andLogic | if the check of the values should be and or if it should be or | false |
condition.andLogic | if the check of all the clauses should be any or all | false |
condition.trueCommands / falseCommands | a list of commands to execute in case the condition is evaluated as true or false |
|
condition.*Commands[*].name | the command name, currently only move-hit and static-hit are supported | move-hit => switch the position of two hits static-hit => set a static value to the injection instead of a dynamic one |
condition.*Commands[*].parameters | the parameters for the commands | the two ‘indexes’ to switch for move-hit the json stringified value to set in the bx-hit for static-hit |
Example #1:
the idea is to detect if the first hit is the drop of the week (promo_6_fuer_5 is not null) and, if so, to switch it with the hit on position 2 and set a static injection bx-hit : {"static": "PROMO_6_FUER_5"}