How to compute custom columns in product feeds (without changing your catalog)

Build calculated columns in your easySales Dynamic feed — minimum prices, second-currency prices, available stock — using a characteristic, a column, and a Feed Rule formula. Your catalog stays untouched.

Sooner or later every merchant who runs a Dynamic feed hits the same wall: the partner wants a column that doesn't exist on the products. A repricing partner wants a min_price floor. A B2B distributor wants eur_price alongside the local one. A 3PL wants available_stock — physical stock minus what's already promised on open orders. The columns aren't on the catalog. The numbers aren't worth storing on every product. But the partner won't accept the file without them.

This is what computed columns in the easySales Dynamic feed are for. You define the column in the feed, write a small formula, and easySales calculates the value on every regeneration. Your product catalog stays clean. Nothing is saved on the products themselves.

Why merchants build computed columns

A "computed column" is a column whose value is calculated at the moment the feed is generated — not stored anywhere. It exists for the file you publish, and only for that file.

Three patterns come up over and over:

  • Floors and ceilings. A repricing partner wants the lowest price you'll accept. You don't want to store that as a product attribute (it changes per channel, per campaign, per margin policy). A formula derives it from acquisition price + margin on every export.
  • Cross-currency feeds. A partner outside your home market wants prices in their currency. Storing a parallel price column per market doesn't scale; converting on the fly does.
  • Computed availability. A partner needs to see what's actually orderable, not what's on the shelf. stock - reserved_stock is one column subtraction away.

The shared trait: the value is a function of other product values, recomputed every time the feed regenerates. Storing it on each product would mean updating every product every time the inputs change — a maintenance burden you don't need.

How a computed column works in easySales

Three pieces, each five seconds of work:

  1. A characteristic — the slot the value lives in. You create it once, give it a name, and leave it empty across all products.
  2. A Dynamic feed column — the wiring that puts the characteristic into the output file.
  3. A Feed Rule with a formula action — the calculation that fills the slot at export time.
Diagram showing the three pieces of a computed feed column in easySales: a characteristic acting as a slot, a Dynamic feed column wiring it to the output, and a Feed Rule formula filling the slot at render time.
Three pieces, one well-defined job each: a characteristic as the slot, a Dynamic feed column as the wiring, a Feed Rule formula as the value.

The slot stays empty in your catalog. The rule fills it during the export. The column renders the filled value in the file. Three small pieces, one well-defined job each. Add the rule, regenerate, the value appears. Remove the rule, regenerate, the value is gone — without any product ever changing.

Step 1: Create the characteristic

Open Catalog → Characteristics and create a new characteristic. Give it a clear name — the one your partner expects in the file is a fine choice.

Examples: Minimum price, EUR price, Available stock.

You don't need to fill values on any product. The whole point is that this characteristic is a destination for a formula, not a real product attribute. Save it and move on.

Screenshot of the Catalog → Characteristics page in easySales with a newly-created characteristic named Minimum price, no product values yet.
Create the characteristic, give it a clear name, leave it empty. The formula will fill it.

A few naming tips:

  • Pick names you'll recognise six months from now. Minimum sale price (RO) beats min_price_ro_v2.
  • If the same value will be used in several feeds, use one characteristic across all of them. Computed values are scoped per feed (the rule lives on the feed), so the same characteristic can hold different computed values in different feeds without colliding.
  • Avoid characteristics that already have product data on them. If Voltage is a real catalog field, don't reuse it as a computed slot — pick a different name. Computed values overwrite the existing pivot in memory; you'd lose the real values for the duration of the feed render.

Step 2: Add it to your Dynamic feed

Open the Dynamic feed. In the column builder, add a new row, pick Characteristic from the column dropdown, then pick the characteristic you just created from the chained selector.

The column will render in the output file. The cell value comes from whatever the rule computes for each product.

Screenshot of the Dynamic feed column builder in easySales with a Characteristic-typed column for Minimum price, Rename field set to min_price.
Add the characteristic as a column, then use the Rename field to match what the partner expects in the file.

If your partner expects a specific name for that column — min_price instead of Minimum price, price_eur instead of EUR price — use the Rename field next to the column. The renamed value is what shows up in the CSV header / JSON key / XML element name; everything else in the UI stays the way you wrote it for yourself. Rename works on every Dynamic feed column, computed or not — it's the same field anywhere a partner expects a different name than the one easySales uses internally.

Step 3: Write the Feed Rule that computes the value

Switch to the Feed rules tab on the same feed. Add a rule:

  • If: ALWAYS (or a condition — see below).
  • Then: pick the characteristic you created as the property, pick formula as the operator, then write the formula.
Screenshot of the Feed Rule editor in easySales — property set to characteristic Minimum price, action set to formula, formula round(acquisition_price * 1.15, 2) typed in.
A Feed Rule with a characteristic target and a formula action. Pick the characteristic, write the formula, save.

The formula editor has a chip palette with the variables you can pull in:

  • ${product.product_sale_price}, ${product.product_full_price} — the listed prices, without VAT.
  • ${product.product_acquisition_price} — your cost.
  • ${product.product_tax_rate} — the per-product tax rate as a whole number (e.g. 19, 20, 21). Divide by 100 to convert it to a multiplier — 1 + ${product.product_tax_rate} / 100 returns 1.21 for a 21% rate, which is what you'd multiply a net price by to get the gross price.
  • ${product.product_characteristic:<name>} — read another characteristic by its name (case-sensitive). Useful for chaining: write one characteristic with a base value, reference it from the next characteristic's formula.
  • ${product.product_meta_field:<key>} — read a custom product meta field by its key.
  • ${product.product_price_group:<id>} — read a contracted price-group price for this product.
  • ${other.currency_rate:FROM:TO} — live exchange rate between two ISO currency codes (e.g. USD:EUR, EUR:GBP).
  • round(<expression>, <decimals>) — round the result to a fixed precision.

Operators: +, -, *, /, parentheses for grouping. Standard arithmetic.

Some columns aren't surfaced as formula variables on purpose — stock, reserved_stock, weight, and the various non-price columns. To compute a value from those, use the arithmetic action operators on a Feed Rule (overwrite, subtract, multiply by, add) instead of formula. The Available stock recipe below shows the pattern.

Save the rule. The next regeneration runs it for every product, fills the characteristic in memory, and renders the value in the file. The product catalog is never touched — your characteristics page stays as empty as you left it.

If you only want the formula to apply to certain products (one category, products with stock, products on a specific brand), add conditions on the If side: characteristic-based, column-based, category-based — anything the rule builder supports.

Real-world recipes

Minimum allowed selling price for a repricing partner

A repricing partner needs a floor — the price below which they shouldn't go. You don't want to store this on every product (it changes when costs or margin policy shifts), so you compute it.

  • Characteristic name: Minimum price
  • Output column rename: min_price
  • Formula: round(${product.product_acquisition_price} * 1.15, 2) — acquisition + 15% margin.

Adjust the multiplier per channel by writing different rules in different feeds. Same characteristic, different formulas, different output files. The catalog never sees any of it. The screenshot in Step 3 above shows this exact rule configured.

Price in a second currency for a cross-border partner

Your partner is in a different market and wants prices in their currency. easySales has a built-in currency-rate function so you don't keep a parallel price list.

  • Characteristic name: EUR price
  • Output column rename: price_eur
  • Formula: round(${product.product_sale_price} * ${other.currency_rate:USD:EUR}, 2) — replace USD:EUR with the FROM and TO currencies that match your case.

Currency rates refresh automatically on a daily cadence — easySales pulls them from a central rate source so you don't maintain a parallel table. If your partner needs a stable rate for a contracted period (rather than the live one), reach out to support and we'll work out the right setup for your case.

Screenshot of the Feed Rule editor in easySales — property set to characteristic EUR price, action formula, formula sale_price * currency_rate(USD:EUR) rounded to 2 decimals.
A second-currency computed column: the formula multiplies sale price by the live USD-to-EUR rate, rounded to 2 decimals.

Available stock (physical minus reserved)

A partner sees the stock you publish; if it's the on-shelf number and you have open orders, you'll oversell. The right number to publish is available-to-promise: physical stock minus what's reserved on open orders.

stock and reserved_stock aren't surfaced as formula variables, so this recipe doesn't use the formula operator at all. Instead, you chain two arithmetic actions on the same characteristic — the first writes the base, the second adjusts it.

  • Characteristic name: Available stock
  • Output column rename: available_stock
  • Action 1: target = Available stock, operator = overwrite with, source = column stock. (Sets the characteristic to the product's stock value.)
  • Action 2 (added below the first, same rule): target = Available stock, operator = subtract, value source = field, column = reserved_stock. (Subtracts the reserved-stock column from the running value.)

Two actions, one rule, top to bottom. The first writes the base; the second adjusts it. You can chain a third action (add / subtract against a literal number) if your fulfilment math needs a fixed safety-stock buffer on top.

Screenshot of the Feed Rule editor in easySales with two chained actions on the Available stock characteristic — overwrite with stock column, then subtract reserved_stock column.
Two chained actions, one rule. The first writes the base; the second subtracts the reserved quantity.

Renaming any column on output

The Rename field appears next to every column in the Dynamic feed builder, not just computed ones. Use it whenever your partner expects a different name than easySales' internal one — price instead of full_price, cost instead of sale_price, inventory instead of stock.

Two notes:

  • The rename applies to the file output: the CSV header, the JSON key, and the XML element name. The UI elsewhere keeps using easySales' names so you and your team don't get lost.
  • XML element names have stricter rules than CSV or JSON. If your rename contains spaces or punctuation, easySales sanitises it for XML automatically — Min price (RON) becomes min_price_ron in <min_price_ron> tags. CSV headers and JSON keys keep your rename verbatim.

If two columns rename to the same output name, the feed builder blocks save and shows you which one collides. Pick a unique name and it'll save.

When NOT to use a computed column

  • Real product attributes. If the data lives naturally on the product (Colour, Size, Voltage, EAN), use a regular characteristic and store it. Computed columns are for values that don't belong on the catalog.
  • Per-channel category mappings. If your partner needs a Google Shopping category id, a Skroutz category code, or anything that maps your category to theirs, use the channel-specific feed builder — it's pre-validated and saves you the mapping work. Dynamic feed is the open-ended option for partners we don't have a dedicated builder for. See What Is a Product Feed? for the channel-feed primer.
  • Static fixed values. If every product gets the same value (condition: new, availability: in_stock), use the set to value action on a regular column rather than synthesising a characteristic — it's one less moving part.

If you're not sure whether a column should be computed, store, or fixed, support can look at your specific case. Most "computed-or-stored?" questions resolve in two minutes once you sketch the use case.

No card required
14 days free
You can cancel anytime

Build the columns your partners actually want

Open Feeds → Dynamic in easySales and ship a partner-ready file with computed columns in minutes. New here? Try easySales free for 14 days, no credit card needed.

Frequently asked questions

No. Computed columns are evaluated in memory while the feed is rendering, then discarded. Open the products page after the feed regenerates and you'll see the same characteristic values you had before — empty, in the typical setup. The catalog never changes. This is by design: it lets you publish many different computed columns to many different feeds without your product data turning into a mess.

No. The characteristic is just a slot the formula writes into at render time. Most computed-column setups create a brand-new characteristic and never give it values on any product. If the characteristic does have values on some products and you write a rule that overwrites it, the rule wins — for that one feed render — and the original values stay intact in the catalog.

Product fields: sale_price, full_price, sale_price_with_tax, full_price_with_tax, acquisition_price, tax_rate, stock, reserved_stock, weight. Other characteristics by name: ${product.product_characteristic:&lt;Name&gt;}. Currency conversion: ${other.currency_rate:FROM:TO} returns the live exchange rate between two currency codes. The round() function rounds an expression to a given decimal precision. Standard arithmetic operators (+, -, *, /) and parentheses for grouping work as expected. The formula editor exposes all of these as click-to-insert chips so you don't have to remember the exact syntax.

The default cadence is hourly, and the file regenerates only when your partner reads it (so dormant feeds don't waste resources). On every regeneration the formula re-evaluates against the current product data — a price change on a product flows through to the computed column on the next render automatically. For ERP catalog exports you can ask support to dial it down to daily; for fast-moving partner sync, support can dial it up.

Yes. The Feed Rule has both an If side and a Then side. Put any condition on the If side — characteristic equals X, category contains Y, brand is Z, stock greater than 0 — and the formula only runs for matching products. Other products skip the rule and the computed column shows up empty in the output for them. Combine multiple rules to handle different product groups with different formulas.

In the Dynamic feed column builder, every column row has a Rename field next to the column dropdown. Type the name your partner expects ("price", "min_price", "cost", whatever) and that name shows up as the CSV header / JSON key / XML element name in the generated file. Rename works on every column, computed or not. XML element names get sanitised automatically if your rename has spaces or punctuation; CSV and JSON keep what you typed verbatim.

Yes. The simplest path is to add sale_price_including_tax or full_price_including_tax directly as a Dynamic feed column — they're plain columns in the column dropdown and they already carry the VAT-inclusive value. No formula needed. If you need a custom shape (sale price plus VAT plus a margin, or VAT-inclusive in a second currency), reach for a formula: round(${product.product_sale_price} * (1 + ${product.product_tax_rate} / 100), 2) reproduces the with-tax math by hand. Note that ${product.product_tax_rate} returns a whole number like 19 or 21 — divide it by 100 before adding 1 to get the right multiplier.

Was this guide helpful?