Pre-launch API. The concepts described here are settled, but the API shape is not: request and response fields, parameters and defaults can still change. Build against it, and talk to your Luigi's Box contact before you put an integration into production.
Each rule pairs a record_match — which products it applies to — with one effect.
{ "name": "Bury clearance stock", "record_match": { "operator": "and", "conditions": [ { "field": "clearance", "operator": "eq", "value": true } ] }, "effect": { "type": "bury", "strength_pct": 0.6, "mode": "hard" }}A rule’s name is required and is for you: it is what someone reads in six months when
they find results they cannot explain.
The four effects
Section titled “The four effects”| Effect | What it does | Fields |
|---|---|---|
pin | Place the product at a fixed position | position (1-indexed), mode, decay_window |
ban | Remove the product from results entirely | — |
boost | Raise the product’s ranking | strength_pct (0–1), mode, decay_window |
bury | Lower the product’s ranking | strength_pct (0–1), mode, decay_window |
They divide into two kinds:
pinandbanare absolute. A pin puts a product at a position; a ban removes it. Both are decisions about the output rather than about how strongly a product scores.boostandburyare relative. They change how strongly a product scores and let the results re-sort. Both are decisions about tendency.
position is 1-indexed: 1 is the top slot. The product is inserted there and everything
below shifts down — nothing is dropped.
A pin naming one product places that product. A pin whose selector names several
products — a list of IDs, or a criterion like brand eq "northwear" — places whichever of
them ranks highest, and several such pins fill their positions with distinct products. So
“pin our best Northwear product to slot 1” is one rule, not a lookup you have to do
yourself.
A pinned product does not have to match the query. A campaign triggered by the query “wine” can pin a box of chocolates for Valentine’s Day: the product is fetched and placed even though the search would never return it. A pin naming one product has nothing to place when that product does not exist or a ban removes it. A pin selecting by criteria, or by a list of IDs, moves down its matches instead: a ban takes its top match out of the running and the next one takes the slot, so it places nothing only once no match is left.
A pin naming exactly one product also ignores the shopper’s filters by default: it shows the product even when the active filters would exclude it. A pin selecting by criteria, or by a list of IDs, only places a product that passes those filters.
Set respect_user_filters to true on the effect to turn that off, and the pin is filtered
like any other product — it places nothing when the shopper’s filters exclude what it names.
Use it when a product must not be shown past a filter: an age-restricted or regulated item
the shopper has filtered away should stay away.
{ "type": "pin", "position": 1, "respect_user_filters": true }Boost and bury
Section titled “Boost and bury”strength_pct is a strength between 0 and 1, not a number of positions. How far a
product actually moves depends on how tightly packed the results around it are, so a boost
does not lift a product over results that match the query substantially better.
Start around 0.3 for a nudge and 0.7 for a strong push, then look at the result.
Boost and bury act on products the results already contain. A product that would not have been retrieved for this request is not boosted into it — a boost changes the order of an answer, it does not change what the answer is about. If you need a product to appear on a request it does not match, that is a pin.
Boost and bury never cancel out: when both would apply to one product, one wins outright and the other is discarded. At equal specificity the bury wins — see Resolving conflicts.
Hard and soft mode
Section titled “Hard and soft mode”pin, boost and bury can fade. mode: "hard" (the default) applies the effect at full
strength for the campaign’s whole run. mode: "soft" fades it out — full strength at the
start, tapering to nothing. A ban is always hard: there is no half of a product removed.
{ "type": "boost", "strength_pct": 0.5, "mode": "soft", "decay_window": "P3D" }What fading means depends on the effect. A soft boost or bury weakens its score modifier until it stops moving the product at all. A soft pin loosens its hold on the position: the product starts at the slot the pin names and drifts back toward where it would have ranked on its own, instead of dropping back there in one step when the campaign ends.
{ "type": "pin", "position": 1, "mode": "soft", "decay_window": "P3D" }decay_window is an ISO 8601 duration: P3D is three days, PT12H twelve hours. It is
only valid with mode: "soft", and must be positive. Leave it out and the fade lasts the
whole campaign.
The fade counts from starts_at and needs both starts_at and ends_at: a soft effect in
a campaign without both bounds behaves like a hard one and never fades. Once the fade
reaches zero the rule stops applying for the rest of the campaign.
Soft mode is how you launch a new product hard and let it earn its own place, instead of ending a campaign with a cliff.
Pin wins over boost on the same product
Section titled “Pin wins over boost on the same product”Pins are placed after scores are adjusted, so a pin overrides any movement a boost gave the same product. A product boosted to position 2 and then pinned to 1 ends up at 1 — and a product boosted upward while another product is pinned above it lands one slot lower than the boost alone would suggest.
Pin for a position, boost for a tendency. When both apply to one product, the pin decides.
Selecting products
Section titled “Selecting products”record_match uses the same condition syntax
as a trigger, over catalog fields rather than trigger. fields. It selects by identity
or by criteria, and the difference decides who wins a conflict:
By identity — the most specific kind of rule:
{ "field": "@id", "operator": "in", "value": ["product/sku-4410", "product/sku-4411"] }By criteria — matches whatever fits, now and later:
{ "field": "brand", "operator": "eq", "value": "brand/northwear" }Prefer criteria. A rule on clearance = true keeps meaning the right thing as stock turns
over; a list of IDs has to be maintained as stock changes.
“Product” here means any catalog object the surface serves. The same selectors and effects
apply to categories, brands or articles, and the ID carries the type: category/shoes works
like product/sku-1001.
For a pin, a list of several IDs counts as criteria, not identity: a pin claims one
position, so several IDs mean “whichever of these ranks highest”. Pin a single product when
it must win a conflict on specificity.
Operators follow the field’s type: gt, gte, lt, lte and range need a numeric
field; eq, neq, in, not_in and exists work on any field, as long as the literal
matches that field’s type. Break either rule — an operator the type does not support, or a
literal of the wrong type — and the save fails with 422. matches is not available in
record_match at all.
A selector is a little more permissive than a trigger, so read the
operator table as the trigger’s
set rather than this one’s: membership works on a boolean here, where a trigger admits only
eq, neq and exists. {"field": "clearance", "operator": "in", "value": [true]} is
accepted in a selector and rejected in a trigger.
The missing-attribute rule bites here more than
anywhere: a rule matching {"field": "@category", "operator": "neq", "value": "category/shoes"} also fires on every product with no category at all.
An empty selector
Section titled “An empty selector”For ban, boost and bury, a selector with no conditions is a scope-wide effect — blunt,
but coherent, and occasionally what you want. For pin it is rejected: a pin places one
product at one position, so a pin that names no product asks for a placement without saying
what to place.
Matching against the trigger
Section titled “Matching against the trigger”A rule’s value can reference the trigger instead of a literal — “products whose brand is
the same as the anchor’s brand”:
{ "field": "brand", "operator": "eq", "value": { "trigger_ref": "trigger.brand" }}That is one rule that works for every brand, instead of one rule per brand. The operator
has to match the reference’s cardinality: a reference resolving to a single value takes
eq or neq, one resolving to a list takes in or not_in. On a search request there is
no anchor to read the attribute from, so a rule referencing trigger.brand matches no
product there.
For a list-valued trigger attribute, pick which elements to use with path and select —
first, last, all, first_n, last_n, at_index, all_but_first, all_but_last.
first_n and last_n need an n; at_index needs an index. The default is the first
element of the outer list and all elements within it.
See also
Section titled “See also”- Resolving conflicts — who wins when rules collide
- Triggers — the condition syntax, and which requests fire
- Filters — the operator vocabulary and the missing-attribute rule
Was this page helpful?
Thanks.