---
title: "Signals now supports calculated properties | Snowplow Signals"
description: "Combine fields from the same event into one attribute value, computed in-stream and backfilled over your history."
source: https://signals.snowplow.io/blog/calculated-properties
---

[Blog](https://signals.snowplow.io/blog) / Product 

# Signals now supports calculated properties

AK [Agnes Kiss](https://signals.snowplow.io/blog/authors/agnes-kiss) , Data Engineer Oct 7, 2026 · 3 min read 

Your tracking is in place and events are flowing. Now your team wants your website to show a same-day delivery banner to shoppers who usually browse from London, England, before the page renders. `geo_city` alone can’t tell London, England from London, Ontario. Your events already carry `geo_country` too, but a Signals attribute, the value kept up to date for each user, needs the two as one value, like `GB-London`.

Calculated properties now handle that for you in Signals. You combine the fields in the attribute definition with `concat`, `sum`, `product`, `min`, `max`, or `coalesce`, and Signals computes the value.

Music only, with the explanation on screen. 43 sec 

## How calculated properties work

Three rules apply to any calculated property:

1. **What you can combine.** Snowplow’s out-of-the-box atomic fields, such as `geo_country`, and properties from event and entity schemas, including your own custom ones, in any mix.
2. **When Signals computes it.** In-stream as each event arrives. With a [backfill](https://docs.snowplow.io/docs/signals/attributes/attribute-groups/#backfill-attributes), it also covers the events already in your warehouse, so a new attribute starts with history.
3. **How it feeds the aggregation.** Each event gets its own value, like `GB-London`, and the attribute’s aggregation then runs across all of a user’s events.

## Example: finding the right London

Take a shopper who browses from London, Ontario. An attribute built on `geo_city` alone returns `London`, so they see a same-day delivery offer that can’t reach them.

![Diagram. On the left, geo_city on its own: the value London could mean London, England or London, Ontario. On the right, a concat of geo_country and geo_city: GB plus London gives GB-London for London, England, and CA plus London gives CA-London for London, Ontario, so the delivery banner reaches the right shoppers.](https://signals.snowplow.io/images/blog/calculated-properties/which-london.png)

The obvious fix is a second attribute for the most frequent country, but that breaks too. A shopper from London, England who spends a week on vacation in Paris and Lyon can end up with France as their most frequent country and London as their most frequent city. Their attributes return `FR` and `London`, so the banner’s check for `GB` and `London` fails, and they miss an offer they could use.

![Diagram. A London shopper back from vacation has GB and London 3 times, FR and Paris 2 times, and FR and Lyon 2 times. With two separate attributes, the most frequent country is FR with 4 events and the most frequent city is London with 3 events, giving FR plus London, which matches none of the events. With one calculated property, concat produces GB-London, FR-Paris, and FR-Lyon on each event, and most_frequent returns GB-London, a place the user browsed from.](https://signals.snowplow.io/images/blog/calculated-properties/usual-location.png)

A calculated property joins `geo_country` and `geo_city` on each event, so the attribute counts real places: `CA-London` for the Ontario shopper, and `GB-London` for the one back from vacation.

You can build this attribute in three ways.

### In the Console UI

Tick `geo_country` and `geo_city` in the attribute’s property picker. A panel appears where you set their order, the operation, and a separator.

![The property picker in Snowplow Console with geo_country and geo_city ticked in the Atomic tab. The calculated property panel above shows both as reorderable chips, the concat operation selected, and a hyphen as the separator.](https://signals.snowplow.io/images/blog/calculated-properties/console-panel.png)

With `concat` and a hyphen, each event contributes a value like `GB-London`, and a `most_frequent` aggregation returns the one that comes up most.

### With an AI agent

Ask the Snowplow Assistant in Console, or any agent connected to the Snowplow MCP server:

_“Create an attribute with the country and city a user browses from most often.”_ 

### In the Python SDK

```
from snowplow_signals import Attribute, AtomicProperty, CalculatedProperty

usual_location = Attribute(
    name="usual_location",
    description="Country and city pair a user browses from most often",
    type="string",
    events=[],
    aggregation="most_frequent",
    property=CalculatedProperty(
        operation="concat",
        separator="-",
        properties=[
            AtomicProperty(name="geo_country"),
            AtomicProperty(name="geo_city"),
        ],
    ),
)
```

## What’s in this release

There are six operations to choose from, each shown with an example personalization use:

1. **concat** joins values into a string, with an optional separator: `mkt_source` and `mkt_medium` give `google-cpc`, to tailor the landing message to the channel a user arrived from.
2. **sum** adds numbers: `subtotal`, `tax`, and `shipping` give an order’s total, which a `sum` aggregation turns into lifetime spend for loyalty offers.
3. **product** multiplies numbers: `price` and `quantity` on an add-to-cart event give the value of the items added, for a free-shipping nudge.
4. **min** takes the smallest value: the lower of `member_price` and `standard_price` is the price to show a member.
5. **max** takes the largest value: the higher of `list_price` and `compare_at_price` is the original price to show next to a discount.
6. **coalesce** returns the first property that has a value: `sale_price`, then `list_price`, on a purchase event gives what a user actually paid, for price-sensitive offers.

Calculated properties are available in the Console UI, through the Snowplow Assistant and the MCP server, and in the Python SDK from `snowplow-signals` 0.4.9.

> To build your own, see the [calculated properties documentation](https://docs.snowplow.io/docs/signals/attributes/attributes/#calculated-properties).

AK 

[Agnes Kiss](https://signals.snowplow.io/blog/authors/agnes-kiss) 

Data Engineer, Snowplow

Follow Agnes for more on real-time customer context.

[LinkedIn](https://www.linkedin.com/in/agneskiss123/) [More from Agnes → ](https://signals.snowplow.io/blog/authors/agnes-kiss) 

Start on the free tier

Add the SDK and watch an attribute updating against your own traffic in the first session. The free tier runs on the real engine: no card, no sales call.

[Start free](https://signals.snowplow.io/start) 

Share this post

✕

Click the image to zoom in. Esc closes. Scroll to pan. Click the image to zoom out. 

In this post

* [How calculated properties work](#how-calculated-properties-work)
* [Example: finding the right London](#example-finding-the-right-london)
* [What’s in this release](#whats-in-this-release)

Start on the free tier

Add the SDK and watch an attribute updating against your own traffic in the first session. The free tier runs on the real engine: no card, no sales call.

[Start free](https://signals.snowplow.io/start)
