Personyze Personyze developer docs
Open Personyze
Guides

Conditional prices

Discount a product when it is recommended together with another one.

Personyze developer documentation Questions: support@personyze.com

A conditional price is a discount on one product that only applies when it is shown together with another product. It is how you express "buy the camera and the lens, and the lens is 20% off" — and Personyze's recommendation widgets can then display the combined price of the pair.

You will find it in the product catalog as the Conditional prices column.

How it is stored

Every product row carries a cond_prices column: a JSON object whose keys are the internal ids of other products, and whose values are the discount that applies to this product when it appears with that one.

{"CAMERA-100": "20%", "TRIPOD-7": "15.00", "BAG-2": "0"}

Read that on the lens product as: if the lens is shown alongside CAMERA-100, the lens costs 20% less; alongside TRIPOD-7 it costs 15.00; alongside BAG-2 it is free.

The catalog also exposes a prices column, which is simply the three price fields bundled together for convenience:

prices = [price, sale_price, cond_prices]

That triple is what the pricing function takes as its argument.

The rules are per product and one-directional

cond_prices on the lens says what happens to the lens. It says nothing about what the camera costs. If you want both halves of a pair discounted, you set a rule on each product, pointing at the other.

That is also why the pair's total is the sum of two separate lookups — see below.

Discount formats

The value is a string, and its form decides how it is read:

Value Meaning Example
Ends with % Percentage off the pre-discount price "20%" on a 50.00 product → 40.00
A number ≥ 0 The resulting price, not the amount taken off "15" → the product costs 15.00
"0" Free → 0.00

The percentage is taken from the product's pre-discount price, which is the greater of price and sale_price when both are set. Results are rounded to two decimals.

A number is an absolute replacement price, not a reduction. "15" means "costs 15", not "15 off" — this is the detail most people get wrong on first use.

When no rule matches

If the other product is not a key in cond_prices, the product is priced normally: the lower of price and sale_price when both are set, otherwise whichever one is present. So a product with conditional prices behaves exactly like any other product until it is paired with something in its list.

Using it in a recommendation widget

Inside an action's HTML, the price is resolved with the discount() template function:

discount(<product>->prices, <other product>->internal_id)

The first argument is the prices triple of the product you are pricing; the second is the internal id of the product it is being paired with. So to show a recommended product's price in the context of the product the visitor is currently looking at:

${discount(rec->prices, main->internal_id)}

And the total for the pair is the two directions added together:

${discount(rec->prices, main->internal_id) + discount(main->prices, rec->internal_id)}

A widget typically compares the conditional price against price_before_discount to decide whether to show a strike-through original, and treats a result of 0 as "free":

${if discount(rec->prices, main->internal_id) = 0}
    Free with this purchase
${end}

Viewing the rules in the panel

Open the product catalog and look at the Conditional prices column. For a product that has rules, the panel lists each partner product with its id and title, the partner's conditional price, the raw discount entry, and the resulting pair total.

Limitations worth knowing

Rules key on a product's internal id, not on a category. The lookup is a direct match against the other product's internal_id. There is no category-level or expression-based conditional price — "any product in Accessories" has to be expressed as one entry per product.

Conditional prices cannot be set through the REST products object. The products endpoint routes any column it doesn't recognise into the product's custom fields, and cond_prices is not in its list. Posting cond_prices through the API therefore creates a custom field named cond_prices and leaves the real column untouched — silently, with no error. Set conditional prices in the panel.

Keep the partner ids in step with your catalog. A key pointing at an internal id that no longer exists is simply never matched; nothing warns you about it.