
This use case presents a different approach to price drop campaigns by separating the logic into two independent automations. Instead of processing all conditions and communication in a single workflow, the first automation is responsible for detecting price drops and generating enriched events, while the second handles communication based on these events.

This approach improves performance, simplifies logic, and gives more control over campaign execution.

Additionally, the campaign introduces product prioritization. Products are selected based on user intent in the following order:
1. Adding product to cart
2. Adding product to favorites
3. Visiting the product in the mobile app
4. Visiting the product on the website

As a result, users receive communication about the most relevant discounted products and the copy of the email is prepared based on the type of activity of the customer (adding to cart, adding to favorites, and so on).

The key advantages of this approach include:
- **Separation of concerns**: The event generation workflow handles all data collection and price comparison logic, while the communication workflow only handles routing and sending.
- **Snippet-based logic**: All product validation, price comparison, and exclusion logic is contained in a reusable snippet referenced in the Generate Event node.
- **Built-in exclusion mechanism**: Products that have already been communicated to a customer are excluded from subsequent sends, ensuring the campaign spreads across multiple days and intent categories.


  <div class="admonition admonition-note"><div class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg></div><div class="admonition-body"><div class="admonition-content">

  While this use case focuses on the **email** communication channel, the event generation workflow is designed to also serve as a foundation for other channels. The generated `results.priceDrop` event contains both email and push data, so you can build a companion mobile push workflow using the same event without modifying the detection logic. See the [What's next](#whats-next) section for details.

  </div></div></div>


## Prerequisites
---
- Implement a [tracking code](/docs/settings/tool/tracking_codes) on your website.
- [Create an item catalog](/docs/ai-hub/recommendations-v2/item-feed-requirements) containing information on the actual price of products (including the `effectivePrice` and `availability` attributes). It is recommended to use a feed-based catalog, as it contains the most up-to-date product data including current prices and availability.
- [Create an email template](/docs/campaign/e-mail/creating-email-templates) to be used in the price drop campaign. You can use a single template across all priority paths and dynamically change its content based on the interaction type. Alternatively, you can create separate templates for each journey (cart, favorites, visited) for more granular control and analytics.
- Ensure user marketing consent attribute (email - e.g. `newsletter_agreement`) is available.
- Integrate [transaction events](/developers/web/transactions-sdk).
- [Create and set up your email account](/docs/settings/configuration/email-account).
- Implement a [custom event](https://developers.synerise.com/DataManagement/DataManagement.html#operation/CustomEvent) `results.priceDrop` and register it in **Data Modeling Hub > Events** before use. The event must include the following parameters:
    - `eventdata` — containing product SKUs, counts, and exclusion data generated by the snippet.
    - `newsletterAgreement` — email marketing consent status.

    Optionally, you can add extra parameters (such as loyalty program membership) to support further personalization in your email templates.

## Process
---
In this use case, you will go through the following steps:

1. [Create aggregates](#create-aggregates) required for product collection and exclusion logic.
2. [Create the snippet with price drop detection logic](#create-the-snippet-with-price-drop-detection-logic).
3. [Create the workflow for detecting price drops and generating events](#create-the-workflow-for-detecting-price-drops).
4. [Create the workflow for sending email communications based on product intent](#create-the-workflow-for-sending-email-communications).


## Create aggregates
---
Several aggregates are needed to support the event generation logic. These aggregates collect product SKUs and prices from different interaction types, handle exclusions of already-purchased products, and feed into the snippet that runs inside the Generate Event node.

The aggregates are organized into the following groups:
- [Shared aggregates](#shared-aggregates) — purchase history, removal history, and global exclusion data.
- [Favorites aggregates](#favorites-aggregates) — products added to favorites.
- [Cart aggregates](#cart-aggregates) — products added to cart.
- [Mobile app viewed aggregates](#mobile-app-viewed-aggregates) — products viewed in the mobile app.
- [Desktop website viewed aggregates](#desktop-website-viewed-aggregates) — products visited on the website.


  <div class="admonition admonition-note"><div class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg></div><div class="admonition-body"><div class="admonition-content">

  All aggregates in this use case use a default period of **30 days**. This value can be adjusted to match your business needs and the event retention configured in your workspace. Longer periods capture more product interactions but may include outdated price data; shorter periods keep the data fresh but may miss older interactions.

  </div></div></div>


### Shared aggregates

#### Aggregate collecting recently purchased product SKUs
---
This aggregate collects SKUs of products the customer has purchased recently. It is used as a "Not in array" filter in other aggregates to exclude products the customer has already bought — there is no need to notify them about a price drop on something they already own.

1. Go to <img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/icons/decision-hub-icon.svg" alt="Analytics icon" class="icon" > **Behavioral Data Hub > Live Aggregates > Create aggregate**.
2. As the aggregate type, select **Profile**.
3. Enter the name of the aggregate, for example `Last 30 days purchased product SKUs`.
4. Click **Analyze profiles by** and select **Last Multi** and size: **30**.
5. From the **Choose event** dropdown list, select the **Bought product** event.
6. As the event parameter, select **$sku**.
7. Click the **+ where** button:
    - From the **Choose parameter** dropdown list, select the **$sku** parameter.
    - From the **Choose operator** dropdown list, select **Is not empty**.
8. Define the period to the last **30 days**.
9. Save the aggregate.

<figure>
<img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/use-cases/all-cases/_gfx/pricedrop-aggregate-bought-sku.png" alt="Configuration of the aggregate collecting recently purchased product SKUs" class="full">
<figcaption>Configuration of the aggregate collecting recently purchased product SKUs</figcaption>
</figure>

#### Aggregate collecting previous price drop event data (global exclusion)
---
This aggregate analyzes `eventdata` from previous `results.priceDrop` events. The snippet parses the `excluded` field from this data to prevent sending the same products again in subsequent campaign runs.

The key behavior here is that a product is only added to the exclusion list when it has been **actually communicated** to the customer. The fact that a `results.priceDrop` event was generated on a given day does not automatically mean the customer received a message — if no products had a price drop, the event will be empty and no exclusion occurs. This ensures that users are not blocked from future campaigns unnecessarily.

The aggregate uses a period setting (default: 30 days) which lets you control how long a product remains excluded after being communicated. After this period expires, the product becomes eligible again.

1. Go to <img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/icons/decision-hub-icon.png" alt="Analytics icon" class="icon" > **Behavioral Data Hub > Live Aggregates > Create aggregate**.
2. As the aggregate type, select **Profile**.
3. Enter the name of the aggregate, for example `Last price drop event data`.
4. Click **Analyze profiles by** and select **Last Multi** and size: **100 000**.
5. From the **Choose event** dropdown list, select the **results.priceDrop** event.
6. As the event parameter, select **eventdata**.
7. Click the **+ where** button:
    - From the **Choose parameter** dropdown list, select the **eventdata** parameter.
    - From the **Choose operator** dropdown list, select **Is not empty**.
8. Define the period to the last **30 days**.
9. Save the aggregate.

<figure>
<img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/use-cases/all-cases/_gfx/pricedrop-aggregate-exclusion-eventdata.png" alt="Configuration of the aggregate collecting previous price drop event data" class="full">
<figcaption>Configuration of the aggregate collecting previous price drop event data</figcaption>
</figure>

#### Aggregate collecting products removed from cart
---
This aggregate collects SKUs of all products the customer has removed from their cart. It is used as an exclusion filter in the cart SKU aggregate to ensure that products intentionally removed from the cart are not included in the price drop communication.

1. Go to <img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/icons/decision-hub-icon.svg" alt="Analytics icon" class="icon" > **Behavioral Data Hub > Live Aggregates > Create aggregate**.
2. As the aggregate type, select **Profile**.
3. Enter the name of the aggregate, for example `Remove from cart all`.
4. Click **Analyze profiles by** and select **Last Multi** and size: **100**.
5. From the **Choose event** dropdown list, select the `product.removeFromCart` event.
6. As the event parameter, select **$sku**.
7. Define the period to the last **30 days**.
8. Save the aggregate.

<figure>
<img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/use-cases/all-cases/_gfx/pricedrop-aggregate-remove-cart.png" alt="Configuration of the aggregate collecting products removed from cart" class="full">
<figcaption>Configuration of the aggregate collecting products removed from cart</figcaption>
</figure>


### Favorites aggregates

#### Aggregate collecting favorite product SKUs
---
This aggregate collects SKUs of products added to favorites that have not been purchased recently.

1. Go to <img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/icons/decision-hub-icon.svg" alt="Analytics icon" class="icon" > **Behavioral Data Hub > Live Aggregates > Create aggregate**.
2. As the aggregate type, select **Profile**.
3. Enter the name of the aggregate, for example `Favorite products with lower price - SKUs`.
4. Click **Analyze profiles by** and select **Last Multi** and size: **1000**.
5. From the **Choose event** dropdown list, select the **product.addToFavorite** event.
6. As the event parameter, select **$sku**.
7. Click the **+ where** button and add the following conditions:
    - `$sku` **Is not empty** — ensures the SKU parameter exists.
    - `finalUnitPrice` **Is not empty** — ensures the price parameter exists.
    - `$sku` **Not in array** → select the aggregate **Last 30 days purchased product SKUs**. This excludes products that the customer has already bought.
8. Define the period to the last **30 days**.
9. Save the aggregate.

<figure>
<img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/use-cases/all-cases/_gfx/pricedrop-aggregate-fav-sku.png" alt="Configuration of the aggregate collecting favorite product SKUs" class="full">
<figcaption>Configuration of the aggregate collecting favorite product SKUs</figcaption>
</figure>

#### Aggregate collecting favorite product prices
---
This aggregate collects the prices (`finalUnitPrice`) recorded at the time when products were added to favorites. These prices are later compared with current catalog prices in the snippet to detect price drops.

1. Go to <img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/icons/decision-hub-icon.svg" alt="Analytics icon" class="icon" > **Behavioral Data Hub > Live Aggregates > Create aggregate**.
2. As the aggregate type, select **Profile**.
3. Enter the name of the aggregate, for example `Favorite products with lower price - prices`.
4. Click **Analyze profiles by** and select **Last Multi** and size: **1000**.
5. From the **Choose event** dropdown list, select the **product.addToFavorite** event.
6. As the event parameter, select **finalUnitPrice**.
7. Click the **+ where** button and add the same conditions as in the SKU aggregate:
    - `$sku` **Is not empty**.
    - `finalUnitPrice` **Is not empty**.
    - `$sku` **Not in array** → select the aggregate **Last 30 days purchased product SKUs**.
8. Define the period to the last **30 days**.
9. Save the aggregate.

<figure>
<img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/use-cases/all-cases/_gfx/pricedrop-aggregate-fav-prices.png" alt="Configuration of the aggregate collecting favorite product prices" class="full">
<figcaption>Configuration of the aggregate collecting favorite product prices</figcaption>
</figure>


<div class="admonition admonition-important"><div class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg></div><div class="admonition-body"><div class="admonition-content">

It is critical that the conditions defined in the SKU and price aggregates for each interaction type are identical. The snippet pairs SKUs with prices by array index, so any mismatch in filtering conditions would cause incorrect price comparisons.

</div></div></div>


### Cart aggregates

#### Aggregate collecting cart product SKUs
---
This aggregate collects SKUs of products added to cart that have not been removed from cart or recently purchased.

1. Go to <img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/icons/decision-hub-icon.png" alt="Analytics icon" class="icon" > **Behavioral Data Hub > Live Aggregates > Create aggregate**.
2. As the aggregate type, select **Profile**.
3. Enter the name of the aggregate, for example `Cart products with lower price - SKUs`.
4. Click **Analyze profiles by** and select **Last Multi** and size: **1000**.
5. From the **Choose event** dropdown list, select the **product.addToCart** event.
6. As the event parameter, select **$sku**.
7. Click the **+ where** button and add the following conditions:
    - `$sku` **Is not empty** — ensures the SKU value exists.
8. Define the period to the last **30 days**.
9. Save the aggregate.

<figure>
<img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/use-cases/all-cases/_gfx/pricedrop-aggregate-cart-sku.png" alt="Configuration of the aggregate collecting cart product SKUs" class="full">
<figcaption>Configuration of the aggregate collecting cart product SKUs</figcaption>
</figure>

#### Aggregate collecting cart product prices
---
This aggregate collects the prices recorded at the time when products were added to cart.

1. Go to <img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/icons/decision-hub-icon.svg" alt="Analytics icon" class="icon" > **Behavioral Data Hub > Live Aggregates > Create aggregate**.
2. As the aggregate type, select **Profile**.
3. Enter the name of the aggregate, for example `Cart products with lower price - prices`.
4. Click **Analyze profiles by** and select **Last Multi** and size: **1000**.
5. From the **Choose event** dropdown list, select the **product.addToCart** event.
6. As the event parameter, select **$finalUnitPrice**.
7. Click the **+ where** button and add the following conditions:
    - `$finalUnitPrice` **Is not empty** — ensures the price value exists.
8. Define the period to the last **30 days**.
9. Save the aggregate.

<figure>
<img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/use-cases/all-cases/_gfx/pricedrop-aggregate-cart-price.png" alt="Configuration of the aggregate collecting cart product prices" class="full">
<figcaption>Configuration of the aggregate collecting cart product prices</figcaption>
</figure>

### Mobile app viewed aggregates


<div class="admonition admonition-note"><div class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg></div><div class="admonition-body"><div class="admonition-content">

The mobile app viewed aggregates use the **product.view** event and the `sku` parameter, while the desktop website viewed aggregates use the `page.visit` event and `product:retailer_part_no`. This difference reflects how product views are tracked on each platform. Make sure to use the correct event and parameter names for your implementation.

</div></div></div>


#### Aggregate collecting mobile app viewed product SKUs
---
This aggregate collects SKUs of products viewed in the mobile app that have not been recently purchased.

1. Go to <img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/icons/decision-hub-icon.svg" alt="Analytics icon" class="icon" > **Behavioral Data Hub > Live Aggregates > Create aggregate**.
2. As the aggregate type, select **Profile**.
3. Enter the name of the aggregate, for example `Mobile app viewed products - SKUs`.
4. Click **Analyze profiles by** and select **Last Multi** and size: **1000**.
5. From the **Choose event** dropdown list, select the **product.view** event.
6. As the event parameter, select **sku**.
7. Click the **+ where** button and add the following conditions:
    - `sku` **Is not empty** — ensures the SKU parameter exists.
    - `sku` **Not in array** → select the aggregate **Last 30 days purchased product SKUs**. This excludes products the customer has already bought.
8. Define the period to the last **30 days**.
9. Save the aggregate.

<figure>
<img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/use-cases/all-cases/_gfx/pricedrop-aggregate-mobile-sku.png" alt="Configuration of the aggregate collecting mobile app viewed product SKUs" class="full">
<figcaption>Configuration of the aggregate collecting mobile app viewed product SKUs</figcaption>
</figure>

#### Aggregate collecting mobile app viewed product prices
---
This aggregate collects the prices (`finalUnitPrice`) recorded at the time when products were viewed in the mobile app.

1. Go to <img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/icons/decision-hub-icon.svg" alt="Behavioral Data Hub icon" class="icon" > **Behavioral Data Hub > Live Aggregates > Create aggregate**.
2. As the aggregate type, select **Profile**.
3. Enter the name of the aggregate, for example `Mobile app viewed products - prices`.
4. Click **Analyze profiles by** and select **Last Multi** and size: **1000**.
5. From the **Choose event** dropdown list, select the **product.view** event.
6. As the event parameter, select **finalUnitPrice**.
7. Click the **+ where** button and add the following conditions:
    - `sku` **Is not empty**.
    - `sku` **Not in array** → select the aggregate **Last 30 days purchased product SKUs**.
8. Define the period to the last **30 days**.
9. Save the aggregate.

<figure>
<img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/use-cases/all-cases/_gfx/pricedrop-aggregate-mobile-price.png" alt="Configuration of the aggregate collecting mobile app viewed product prices" class="full">
<figcaption>Configuration of the aggregate collecting mobile app viewed product prices</figcaption>
</figure>

### Desktop website viewed aggregates

#### Aggregate collecting desktop website viewed product SKUs
---
This aggregate collects `product:retailer_part_no` values of products visited on the website that have not been recently purchased.

1. Go to <img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/icons/decision-hub-icon.svg" alt="Behavioral Data Hub icon" class="icon" > **Behavioral Data Hub > Live Aggregates > Create aggregate**.
2. As the aggregate type, select **Profile**.
3. Enter the name of the aggregate, for example `Desktop website viewed products - SKUs`.
4. Click **Analyze profiles by** and select **Last Multi** and size: **1000**.
5. From the **Choose event** dropdown list, select the `page.visit` event.
6. As the event parameter, select **product:retailer_part_no**.
7. Click the **+ where** button and add the following conditions:
    - `product:retailer_part_no` **Is not empty** — ensures the product ID exists.
    - `product:retailer_part_no` **Not in array** → select the aggregate **Last 30 days purchased product SKUs**. This excludes products the customer has already bought.
    - `product:price:amount` **Is not empty** — ensures the price parameter exists.
8. Define the period to the last **30 days**.
9. Save the aggregate.

<figure>
<img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/use-cases/all-cases/_gfx/pricedrop-aggregate-desktop-sku.png" alt="Configuration of the aggregate collecting desktop website viewed product SKUs" class="full">
<figcaption>Configuration of the aggregate collecting desktop website viewed product SKUs</figcaption>
</figure>

#### Aggregate collecting desktop website viewed product prices
---
This aggregate collects the prices (`product:price:amount`) recorded at the time when products were visited on the website.

1. Go to <img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/icons/decision-hub-icon.svg" alt="Behavioral Data Hub icon" class="icon" > **Behavioral Data Hub > Live Aggregates > Create aggregate**.
2. As the aggregate type, select **Profile**.
3. Enter the name of the aggregate, for example `Desktop website viewed products - prices`.
4. Click **Analyze profiles by** and select **Last Multi** and size: **1000**.
5. From the **Choose event** dropdown list, select the `page.visit` event.
6. As the event parameter, select **product:price:amount**.
7. Click the **+ where** button and add the following conditions:
    - `product:retailer_part_no` **Is not empty**.
    - `product:retailer_part_no` **Not in array** → select the aggregate **Last 30 days purchased product SKUs**.
    - `product:price:amount` **Is not empty**.
8. Define the period to the last **30 days**.
9. Save the aggregate.

<figure>
<img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/use-cases/all-cases/_gfx/pricedrop-aggregate-desktop-price.png" alt="Configuration of the aggregate collecting desktop website viewed product prices" class="full">
<figcaption>Configuration of the aggregate collecting desktop website viewed product prices</figcaption>
</figure>

## Create the snippet with price drop detection logic
---
The snippet is the core of this use case. It is stored in **Data Modeling Hub > Snippets** and referenced by its hash in the Generate Event node.

-

### Create the snippet

1. Go to <img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/icons/automation-hub-icon.png" alt="Automation Hub icon" class="icon" > **Data Modeling Hub > Snippets > Add snippet**.
2. Enter the name of the snippet, for example `Price drop detection logic`.
3. Paste the following Jinjava code:


   <pre><code class="language-jinja">{%- set final_objects_for_alert=[] -%}
   {%- set added_objects=[] -%}
   {%- set last_add_fav_skus=[] -%}
   {%- set last_add_fav_prices=[] -%}
   {%- aggregate 1227553d-114a-3c19-b618-6c3afc9d7a32 -%}
   {%- for items in aggregate_result -%}
   {%- do last_add_fav_skus.append(items) -%}
   {%- endfor -%}
   {%- endaggregate -%}
   {%- aggregate 1227553d-114a-3c19-b618-6c3afc9d7a32 -%}
   {%- for price in aggregate_result -%}
   {%- do last_add_fav_prices.append(price) -%}
   {%- endfor -%}
   {%- endaggregate -%}
   {%- for added in last_add_fav_skus -%}
   {%- do added_objects.append({'sku': added, 'price': last_add_fav_prices[loop.index0]}) -%}
   {%- endfor -%}
   {%- set final_price_alert_fav_skus=[] -%}
   {%- for item in added_objects -%}
   {%- catalogitemv2.(item.sku) allowEmpty=True -%}
   {%- set object = catalog_result -%}
   {%- if object.availability == 'true' -%}
   {%- set _catalog_price = catalog_result.get('effectivePrice') -%}
   {%- set catalog_price = _catalog_price | float -%}
   {%- set item_price = item.price|float -%}
   {%- set is_discounted = item_price &gt; catalog_price -%}
   {%- if is_discounted -%}
   {%- do final_price_alert_fav_skus.append(item) -%}
   {%- endif -%}
   {%- endif -%}
   {%- endcatalogitemv2 -%}
   {%- endfor -%}
   {%- set added_objects=[] -%}
   {%- set last_add_fav_skus=[] -%}
   {%- set last_add_fav_prices=[] -%}
   {%- aggregate 34f469d8-f83d-32e5-b0e1-10f73b0a0179 -%}
   {%- for items in aggregate_result -%}
   {%- do last_add_fav_skus.append(items) -%}
   {%- endfor -%}
   {%- endaggregate -%}
   {%- aggregate 4148b6aa-4488-39d1-81b8-a29ed5b23424 -%}
   {%- for price in aggregate_result -%}
   {%- do last_add_fav_prices.append(price) -%}
   {%- endfor -%}
   {%- endaggregate -%}
   {%- for added in last_add_fav_skus -%}
   {%- do added_objects.append({'sku': added, 'price': last_add_fav_prices[loop.index0]}) -%}
   {%- endfor -%}
   {%- set final_price_alert_cart_skus=[] -%}
   {%- for item in added_objects -%}
   {%- catalogitemv2.(item.sku) allowEmpty=True -%}
   {%- set object = catalog_result -%}
   {%- if object.availability == 'true' -%}
       {%- set _catalog_price = catalog_result.get('effectivePrice') -%}
       {%- set catalog_price = _catalog_price | float -%}
       {%- set item_price = item.price|float -%}
       {%- set is_discounted = item_price &gt; catalog_price -%}
       {%- if is_discounted -%}
       {%- do final_price_alert_cart_skus.append(item) -%}
       {%- endif -%}
   {%- endif -%}
   {%- endcatalogitemv2 -%}
   {%- endfor -%}
   {%- set added_objects=[] -%}
   {%- set last_add_fav_skus=[] -%}
   {%- set last_add_fav_prices=[] -%}
   {%- aggregate 51d1daac-8483-351f-ae01-ea0b5455fba0 -%}
   {%- for items in aggregate_result -%}
   {%- do last_add_fav_skus.append(items) -%}
   {%- endfor -%}
   {%- endaggregate -%}
   {%- aggregate 51d1daac-8483-351f-ae01-ea0b5455fba0 -%}
   {%- for price in aggregate_result -%}
   {%- do last_add_fav_prices.append(price) -%}
   {%- endfor -%}
   {%- endaggregate -%}
   {%- for added in last_add_fav_skus -%}
   {%- do added_objects.append({'sku': added, 'price': last_add_fav_prices[loop.index0]}) -%}
   {%- endfor -%}
   {%- set final_price_alert_desktop_skus=[] -%}
   {%- for item in added_objects -%}
   {%- catalogitemv2.(item.sku) allowEmpty=True -%}
   {%- set object = catalog_result -%}
   {%- if object.availability == 'true' -%}
       {%- set _catalog_price = catalog_result.get('effectivePrice') -%}
       {%- set catalog_price = _catalog_price | float -%}
       {%- set item_price = item.price|float -%}
       {%- set is_discounted = item_price &gt; catalog_price -%}
       {%- if is_discounted -%}
       {%- do final_price_alert_desktop_skus.append(item) -%}
       {%- endif -%}
   {%- endif -%}
   {%- endcatalogitemv2 -%}
   {%- endfor -%}
   {%- set added_objects=[] -%}
   {%- set last_add_fav_skus=[] -%}
   {%- set last_add_fav_prices=[] -%}
   {%- aggregate adb929ff-f56c-37d6-b5d8-61d88449d2e1 -%}
   {%- for items in aggregate_result -%}
   {%- do last_add_fav_skus.append(items) -%}
   {%- endfor -%}
   {%- endaggregate -%}
   {%- aggregate adb929ff-f56c-37d6-b5d8-61d88449d2e1 -%}
   {%- for price in aggregate_result -%}
   {%- do last_add_fav_prices.append(price) -%}
   {%- endfor -%}
   {%- endaggregate -%}
   {%- for added in last_add_fav_skus -%}
   {%- do added_objects.append({'sku': added, 'price': last_add_fav_prices[loop.index0]}) -%}
   {%- endfor -%}
   {%- set final_price_alert_mobile_skus=[] -%}
   {%- for item in added_objects -%}
   {%- catalogitemv2.(item.sku) allowEmpty=True -%}
   {%- set object = catalog_result -%}
   {%- if object.availability == 'true' -%}
       {%- set _catalog_price = catalog_result.get('effectivePrice') -%}
       {%- set catalog_price = _catalog_price | float -%}
       {%- set item_price = item.price|float -%}
       {%- set is_discounted = item_price &gt; catalog_price -%}
       {%- if is_discounted -%}
       {%- do final_price_alert_mobile_skus.append(item) -%}
       {%- endif -%}
   {%- endif -%}
   {%- endcatalogitemv2 -%}
   {%- endfor -%}
   {%- set seen = [] -%}
   {%- set excluded = [] -%}
   {%- aggregate b5fc6392-65f1-32d3-9ed1-a41f209ea4c5 -%}
   {%- for result in aggregate_result -%}
   {%- set raw = result|string -%}
   {%- set split1 = raw|split('excluded=[') -%}
   {%- if split1|length &gt; 1 -%}
       {%- set inside = split1[1]|split(']') -%}
       {%- for item in inside[0]|split(', ') -%}
       {%- set trimmed = item|trim -%}
       {%- if trimmed != '' and (trimmed in excluded == false) -%}
           {%- do excluded.append(trimmed) -%}
       {%- endif -%}
       {%- endfor -%}
   {%- endif -%}
   {%- endfor -%}
   {%- endaggregate -%}
   {%- set filtered_cart = [] -%}
   {%- for item in final_price_alert_cart_skus -%}
   {%- if item.sku != '' and (item.sku in excluded == false) and (item.sku in seen == false) -%}
   {%- do filtered_cart.append(item.sku) -%}
   {%- do seen.append(item.sku) -%}
   {%- endif -%}
   {%- endfor -%}
   {%- set filtered_fav = [] -%}
   {%- for item in final_price_alert_fav_skus -%}
   {%- if item.sku != '' and (item.sku in excluded == false) and (item.sku in seen == false) -%}
   {%- do filtered_fav.append(item.sku) -%}
   {%- do seen.append(item.sku) -%}
   {%- endif -%}
   {%- endfor -%}
   {%- set filtered_viewMobile = [] -%}
   {%- for item in final_price_alert_mobile_skus -%}
   {%- if item.sku != '' and (item.sku in excluded == false) and (item.sku in seen == false) -%}
   {%- do filtered_viewMobile.append(item.sku) -%}
   {%- do seen.append(item.sku) -%}
   {%- endif -%}
   {%- endfor -%}
   {%- set filtered_viewWeb = [] -%}
   {%- for item in final_price_alert_desktop_skus -%}
   {%- if item.sku != '' and (item.sku in excluded == false) and (item.sku in seen == false) -%}
   {%- do filtered_viewWeb.append(item.sku) -%}
   {%- do seen.append(item.sku) -%}
   {%- endif -%}
   {%- endfor -%}
   {%- set new_excluded = [] -%}
   {%- if filtered_cart|length &gt; 0 -%}
   {%- set new_excluded = filtered_cart -%}
   {%- elif filtered_fav|length &gt; 0 -%}
   {%- set new_excluded = filtered_fav -%}
   {%- elif filtered_viewMobile|length &gt; 0 -%}
   {%- set new_excluded = filtered_viewMobile -%}
   {%- elif filtered_viewWeb|length &gt; 0 -%}
   {%- set new_excluded = filtered_viewWeb -%}
   {%- endif -%}
   {%- set finalObj = {'emailCartSku': filtered_cart,'emailCartCount': filtered_cart|length,'emailFavSku': filtered_fav,'emailFavCount': filtered_fav|length,'emailViewMobileSku': filtered_viewMobile,'emailViewMobileCount': filtered_viewMobile|length,'emailViewWebSku': filtered_viewWeb,'emailViewWebCount': filtered_viewWeb|length,'excluded': new_excluded} -%}{{ finalObj }}</code></pre>




<div class="admonition admonition-important"><div class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg></div><div class="admonition-body"><div class="admonition-content">

Before using this snippet, you must:
- Go to config and replace boxes in the config with the actual aggregates you created in the previous steps. 
- Replace `YOUR_CATALOG_NAME` with the name of your item catalog (for example, `AI Feed - default`).

</div></div></div>


<figure>
<img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/use-cases/all-cases/_gfx/pricedrop-config2.png" alt="Configuration" class="full">
<figcaption>Configuratione</figcaption>
</figure>

4. Save the snippet for use in the Generate Event node.

### How the snippet works

The snippet processes each interaction type in sequence using a repeating pattern. For each type, it:

- **Loads two parallel arrays** from aggregates — SKUs and prices — for products the user interacted with.
- **Builds product objects** combining SKU and price.
- **Looks up each product in the catalog** using `catalogitemv2`. It checks two things:
    - Is the product still available (`availability == 'true'`)?
    - Is the current catalog price (`effectivePrice`) lower than the price recorded at the time of user interaction?
    Only products passing both checks qualify as price-dropped.

After processing all four interaction types, the snippet enters the **global filtering and exclusion phase**:

- **Loads previous exclusions** from the most recent `results.priceDrop` event's `eventdata` parameter. It parses the `excluded=[...]` field to get a list of SKUs that were already communicated.
- **Filters each category** by removing:
    - Products from the previous exclusion list.
    - Products already present in a higher-priority category (via the `seen` list), so the same SKU never appears in two categories.
- **Determines the new exclusion list**: Only products from the highest-priority non-empty category are added to `excluded`. This ensures the next campaign run skips these products and moves to the next priority level.

        
  <div class="admonition admonition-note"><div class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg></div><div class="admonition-body"><div class="admonition-content">

  The snippet also generates single-SKU fields per category (e.g. `pushCartSku`, `pushFavSku`) which are not used in this email workflow but can be consumed by a [companion push workflow](#whats-next).

  </div></div></div>

- **Prepares push variants**: For each category, takes only the last (most recent) product for push notifications (max 1 per category). These are included in the event data for use in a potential [mobile push workflow](#whats-next).

## Create the workflow for detecting price drops
---
This workflow is responsible for selecting the target audience, running the snippet that detects price drops across all interaction types, and generating an enriched event that contains all the necessary data for the communication workflow.

By using a snippet in the Generate Event node, this approach offloads logic from aggregates and email templates, resulting in better optimization and simpler template design.

1. Go to <img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/icons/automation-hub-icon.png" alt="Automation Hub icon" class="icon" > **Automation Hub > Workflows > New workflow**.
2. Enter the name of the workflow.

### Define the Audience trigger node
---


<div class="admonition admonition-note"><div class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg></div><div class="admonition-body"><div class="admonition-content">

The audience conditions described below are an example configuration. You should adjust the specific events, time ranges, and consent conditions to match your business requirements and campaign frequency.

</div></div></div>


1. Start the workflow with the **Audience** node. In the configuration of the node:
    1. Set the **Repeat runs** option to **repeatable** and configure the desired interval (for example, once a day or once a week).
    2. Select the time zone.
    3. In the **Audience** section, choose **New audience**.
    4. Click **Define conditions**.
    5. Add the following conditions connected by the **OR** operator:
        - From the **Choose filter** dropdown list, select the `page.visit` event.
        - From the **Choose filter** dropdown list, select the `product.addToFavorite` event.
        - From the **Choose filter** dropdown list, select the `product.addToCart` event.
        - From the **Choose filter** dropdown list, select the `product.view` event.
    6. Add an **AND** condition to ensure the user has not already received a price drop email recently:
        - From the **Choose filter** dropdown list, select the `message.send` event.
        - Change **Performed** to **Not performed**.
        - Click the **+ where** button, select the **diagramId** parameter, set **Equal** to the diagram ID of the [email communication workflow](#create-the-workflow-for-sending-email-communications).
        - Set the time range according to your desired sending frequency (for example, **last 7 days**).
    7. Add an **AND** condition to ensure the user has marketing consent:
        - From the **Choose filter** dropdown list, select the **newsletter_agreement** attribute.
        - Set the operator to **Equal** and the value to `enabled`.
    8. Confirm by clicking **Apply**.


   <div class="admonition admonition-important"><div class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg></div><div class="admonition-body"><div class="admonition-content">

   The exclusion condition based on `message.send` with a specific `diagramId` ensures that only users who have **actually received** a price drop email are excluded from the next run. This is more precise than excluding based on the `results.priceDrop` event, because the event is generated for all qualifying users — even those for whom no products had a price drop. Using event-based exclusion would unnecessarily block those users from entering the campaign on subsequent days.

   </div></div></div>


### Configure the Generate Event node
---
This node generates a `results.priceDrop` event on each customer's profile. The event contains all the data needed by the communication workflow, including discounted product SKUs grouped by interaction type, product counts for each category, and the user's email consent status.

1. Add the **Generate Event** node. In the configuration of the node:
    1. In the **Event name** field, enter `results.priceDrop`.
    2. In the **Body** section, enter the following structure:
        
       <pre><code class="language-json">{
             "eventdata": "{% snippet %} SNIPPET_HASH {% endsnippet %}",
             "newsletterAgreement": "{{ customer.newsletter_agreement }}",
               }</code></pre>



    Where:
    - `eventdata` — references the [snippet](#create-the-snippet-with-price-drop-detection-logic) created in the previous step. Replace `SNIPPET_HASH` with the actual snippet hash.
    - `newsletterAgreement` — captures the user's email consent status at the time of event generation.

    Optionally, you can add extra parameters to support further personalization in your email templates, such as loyalty program membership or customer tier.

    The `eventdata` parameter will be populated by the snippet. Below is an example of the generated output (the actual number of SKUs depends on each user's activity and which products have had a price drop):

    `emailCartSku=[SKU1,SKU2], emailCartCount=2, emailFavSku=[SKU3], emailFavCount=1, emailViewMobileSku=[SKU4], emailViewMobileCount=1, emailViewWebSku=[SKU5,SKU6,SKU7], emailViewWebCount=3, pushCartSku=[SKU1], pushCartCount=1, pushFavSku=[SKU3], pushFavCount=1, pushViewMobileSku=[SKU4], pushViewMobileCount=1, pushViewWebSku=[SKU5], pushViewWebCount=1, excluded=[SKU1,SKU2]`

    In this example, `emailCartSku` is the highest-priority non-empty category (the "winning" category), so the `excluded` list contains only the cart SKUs (`SKU1,SKU2`). Products from other categories (favorites, mobile viewed, web viewed) are not excluded yet and will be eligible for communication on subsequent days.

    The key fields in `eventdata` are:
    - `emailCartSku` / `emailCartCount` — SKUs and count of discounted cart products.
    - `emailFavSku` / `emailFavCount` — SKUs and count of discounted favorite products.
    - `emailViewMobileSku` / `emailViewMobileCount` — SKUs and count of discounted products viewed in the mobile app.
    - `emailViewWebSku` / `emailViewWebCount` — SKUs and count of discounted products viewed on the website.
    - `excluded` — list of product SKUs from the winning priority category, to be excluded from future sends.


3. Confirm by clicking **Apply**.

<figure>
<img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/use-cases/all-cases/_gfx/pricedrop-generate-event-config.png" alt="Configuration of the Generate Event node" class="full">
<figcaption>Configuration of the Generate Event node</figcaption>
</figure>

### Add the finishing node
---
1. Add the **End** node with **Finish other paths** enabled.
2. In the upper right corner, click **Save & Run**.

<figure>
<img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/use-cases/all-cases/_gfx/pricedrop-workflow1-overview.png" alt="The workflow for generating price drop events" class="full">
<figcaption>The workflow for generating price drop events</figcaption>
</figure>

## Create the workflow for sending email communications
---
This workflow listens for the `results.priceDrop` event generated by the first workflow and routes customers into different email communication paths based on product intent priority. It uses four parallel Profile Event trigger paths, each checking the `eventdata` parameter for the relevant product count:

- **Priority 1: Cart** — Send Email. Triggers when the number of cart products with a price drop is greater than 0.
- **Priority 2: Favorites** — Send Email. Triggers when cart count equals 0, but favorites count is greater than 0.
- **Priority 3: Last seen in mobile app** — Send Email. Triggers when cart and favorites counts equal 0, but mobile app viewed count is greater than 0.
- **Priority 4: Last seen on website** — Send Email. Triggers when cart, favorites, and mobile app counts all equal 0, but website viewed count is greater than 0.

The prioritization ensures that on a given day, a user enters only one path — the highest-priority one with available products. On subsequent days, the exclusion mechanism removes already-communicated products, causing the user to fall through to the next priority level.

**Example over multiple days:**
- **Day 1**: User has 4 cart products with a price drop **and** 4 favorite products with a price drop → enters the Cart path (highest priority), receives email with cart products. These products are added to the exclusion list. The communication about favorite products is skipped due to priority and waits for the next opportunity.
- **Day 2**: Cart products already excluded → system checks favorites. User has 4 favorite products, but 3 overlap with already-excluded cart products → receives email with 1 remaining favorite product.
- **Day 3**: Cart and favorites exhausted → system checks mobile app viewed products → email sent with viewed products if any have a price drop.

Using the same email template across all four paths with dynamic content is a recommended approach. You can pass additional parameters (such as the scenario name) to the template, which allows you to differentiate copy in the template itself and also track in analytics which scenario performs best. An additional benefit of using a single dynamic template is that when you need to make changes, you update it in one place instead of maintaining four separate templates.

### Working with event data in email templates
---
All four email paths in this workflow use the `eventdata` parameter from the `results.priceDrop` event to dynamically populate product content. In each Send Email node, you can access the relevant SKU list from the event context using [event parameter reuse](/docs/automation/event-params-reuse).

Since `eventdata` is a structured string, you need to parse it in the template to extract the SKU list for the appropriate interaction type. For example, for the cart path you would extract the `emailCartSku` field, for the favorites path the `emailFavSku` field, and so on. Once you have the SKU list, you can iterate over it, look up each product in the catalog, and display the product name, image, current price, and link.

1. Go to <img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/icons/automation-hub-icon.png" alt="Automation Hub icon" class="icon" > **Automation Hub > Workflows > New workflow**.
2. Enter the name of the workflow.

### Configure the Profile Event trigger for cart path (Priority 1)
---
1. As the first trigger path, add a **Profile Event** node and name it `prio 1: CART`. In the configuration of the node:
    1. Enable **Action limit** and set it to **1 time per Workflow**.
    2. From the **Choose event** dropdown menu, choose the `results.priceDrop` event.
    3. Click the **+ where** button and add the following conditions:
        - `newsletterAgreement` **Equal** `enabled`
        - `eventdata` **Contain** `emailCartCount=`
        - `eventdata` **Not contain** `emailCartCount=0`
    4. Confirm by clicking **Apply**.

<figure>
<img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/use-cases/all-cases/_gfx/pricedrop-profile-event-cart.png" alt="Configuration of the Profile Event node for cart path" class="full">
<figcaption>Configuration of the Profile Event node for cart path</figcaption>
</figure>


<div class="admonition admonition-note"><div class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg></div><div class="admonition-body"><div class="admonition-content">

The combination of **Contain** `emailCartCount=` and **Not contain** `emailCartCount=0` effectively checks that the cart product count exists and is greater than zero. This pattern is used consistently across all paths.

The `newsletterAgreement` **Equal** `enabled` condition acts as a safety check to ensure that only users with valid email consent enter the path, even if the audience node has already filtered for consent. This prevents edge cases where consent might have changed between audience evaluation and event generation.

</div></div></div>


### Add Send Email for cart path
---
1. Add the **Send Email** node.
    1. Select the email template prepared for the price drop campaign.
    2. Confirm by clicking **Apply**.

### Configure the Profile Event trigger for favorites path (Priority 2)
---
1. Add a second **Profile Event** node and name it `prio 2: FAV`. In the configuration of the node:
    1. Enable **Action limit** and set it to **1 time per Workflow**.
    2. From the **Choose event** dropdown menu, choose the `results.priceDrop` event.
    3. Click the **+ where** button and add the following conditions:
        - `newsletterAgreement` **Equal** `enabled`
        - `eventdata` **Contain** `emailCartCount=0` — ensures the cart path was not applicable (cart is empty).
        - `eventdata` **Contain** `emailFavCount=`
        - `eventdata` **Not contain** `emailFavCount=0`
    4. Confirm by clicking **Apply**.

<figure>
<img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/use-cases/all-cases/_gfx/pricedrop-profile-event-fav.png" alt="Configuration of the Profile Event node for favorites path" class="full">
<figcaption>Configuration of the Profile Event node for favorites path</figcaption>
</figure>

### Add Send Email for favorites path
---
1. Add the **Send Email** node.
    1. Select the email template prepared for the price drop campaign.
    2. Confirm by clicking **Apply**.

### Configure the Profile Event trigger for mobile app viewed path (Priority 3)
---
1. Add a third **Profile Event** node and name it `prio 3: LAST SEEN (APP)`. In the configuration of the node:
    1. Enable **Action limit** and set it to **1 time per Workflow**.
    2. From the **Choose event** dropdown menu, choose the `results.priceDrop` event.
    3. Click the **+ where** button and add the following conditions:
        - `newsletterAgreement` **Equal** `enabled`
        - `eventdata` **Contain** `emailCartCount=0` — cart is empty.
        - `eventdata` **Contain** `emailFavCount=0` — favorites are empty.
        - `eventdata` **Contain** `emailViewMobileCount=`
        - `eventdata` **Not contain** `emailViewMobileCount=0`
    4. Confirm by clicking **Apply**.

<figure>
<img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/use-cases/all-cases/_gfx/pricedrop-profile-event-app.png" alt="Configuration of the Profile Event node for mobile app viewed path" class="full">
<figcaption>Configuration of the Profile Event node for mobile app viewed path</figcaption>
</figure>

### Add Send Email for mobile app viewed path
---
1. Add the **Send Email** node.
    1. Select the email template prepared for the price drop campaign.
    2. Confirm by clicking **Apply**.

### Configure the Profile Event trigger for website viewed path (Priority 4)
---
1. Add a fourth **Profile Event** node and name it `prio 4: LAST SEEN (WEB)`. In the configuration of the node:
    1. Enable **Action limit** and set it to **1 time per Workflow**.
    2. From the **Choose event** dropdown menu, choose the `results.priceDrop` event.
    3. Click the **+ where** button and add the following conditions:
        - `newsletterAgreement` **Equal** `enabled`
        - `eventdata` **Contain** `emailCartCount=0` — cart is empty.
        - `eventdata` **Contain** `emailFavCount=0` — favorites are empty.
        - `eventdata` **Contain** `emailViewMobileCount=0` — mobile app viewed is empty.
        - `eventdata` **Contain** `emailViewWebCount=`
        - `eventdata` **Not contain** `emailViewWebCount=0`
    4. Confirm by clicking **Apply**.

### Add Send Email for website viewed path
---
1. Add the **Send Email** node.
    1. Select the email template prepared for the price drop campaign.
    2. Confirm by clicking **Apply**.

### Add the Merge Paths and finishing node
---
1. Connect all four paths to a **Merge Paths** node. This node combines separate paths into one and limits further processing, ensuring a customer only receives one email per workflow execution.
2. Add the **End** node.
3. In the upper right corner, click **Save & Run**.

<figure>
<img src="/api/docs/image/9994bf4f700ac60725ac3a71a9eeb985e07090a3/use-cases/all-cases/_gfx/pricedrop-workflow2-overview2.png" alt="The workflow for sending price drop email communications" class="full">
<figcaption>The workflow for sending price drop email communications</figcaption>
</figure>

## What's next
---
A companion workflow for **mobile push notifications** can be built using the same `results.priceDrop` event. The key differences from the email workflow described above are:

- **Event generation**: Add a `newsletterPush` parameter to the Generate Event body: `"newsletterPush": "{{ customer.receive_push_messages }}|{{ customer.snrs_has_mobile_push_devices }}"`. This captures push consent and device token status in the event so the push workflow can check them without querying the customer profile.
- **Communication channel**: Replace Send Email nodes with **Send Mobile Push** nodes in all paths.
- **Consent condition**: In each Profile Event trigger, change the consent check from `newsletterAgreement` **Equal** `enabled` to `newsletterPush` **Equal** `true|true`. The value `true|true` verifies two things: the first `true` confirms the user has granted push marketing consent (`receive_push_messages`), and the second `true` confirms they have an active mobile push device token (`snrs_has_mobile_push_devices`). Both conditions must be met for a push notification to be delivered.
- **Product data**: The `results.priceDrop` event already contains push-specific SKUs in dedicated parameters (`pushCartSku`, `pushFavSku`, `pushViewMobileSku`, `pushViewWebSku`) — each limited to a single product — so you can reference them directly in your push notification template via [event parameter reuse](/docs/automation/event-params-reuse), just like in the email template.

This means you only need to add one parameter to the event generation workflow — the snippet and all aggregates remain unchanged.

## Check the use case set up on the Synerise Demo workspace
---
You can check the configuration of each step directly in the Synerise Demo workspace:

**Workflows:**
- [Workflow for generating price drop events](https://app.synerise.com/automations/workflows/automation-diagram/b93d0800-b768-4849-83f2-88ba2e19cb24)
- [Workflow for sending email communications](https://app.synerise.com/automations/workflows/automation-diagram/5226c9ad-cab7-4afd-9c26-6e61ed542b09)

**Expressions:**
- [Add to cart sku/$sku](https://app.synerise.com/analytics/expressions/0ffb560f-d1ce-4713-9e7e-0392ec0f32d6)
- [Add to cart finalUnitPrice/$finalUnitPrice](https://app.synerise.com/analytics/expressions/f47ea9c9-a96e-4644-b787-5e80c1480d33)
- [Remove from cart sku/$SKU](https://app.synerise.com/analytics/expressions/4a2244aa-33e5-49b6-a87b-b38c7fdb0e9b)

**Shared aggregates:**
- [Last 30 days purchased product SKUs](https://app.synerise.com/analytics-v2/aggregates/eba019a7-65cf-32b4-bc68-0b48d4cb55f7)
- [Last price drop event data](https://app.synerise.com/analytics-v2/aggregates/b194da93-c703-3fd4-9802-da3be827478b)
- [Remove from cart all](https://app.synerise.com/analytics-v2/aggregates/eba019a7-65cf-32b4-bc68-0b48d4cb55f7)

**Favorites aggregates:**
- [Favorite products with lower price - SKUs](https://app.synerise.com/analytics-v2/aggregates/1227553d-114a-3c19-b618-6c3afc9d7a32)
- [Favorite products with lower price - prices](https://app.synerise.com/analytics-v2/aggregates/34f469d8-f83d-32e5-b0e1-10f73b0a0179)

**Cart aggregates:**
- [Cart products with lower price - SKUs](https://app.synerise.com/analytics-v2/aggregates/4148b6aa-4488-39d1-81b8-a29ed5b23424)
- [Cart products with lower price - prices](https://app.synerise.com/analytics-v2/aggregates/150153c4-141e-3f09-967e-debdb84c20fc)

**Mobile app viewed aggregates:**
- [Mobile app viewed products - SKUs](https://app.synerise.com/analytics-v2/aggregates/2a4204cf-daeb-32e5-9115-25bcb0d00648)
- [Mobile app viewed products - prices](https://app.synerise.com/analytics-v2/aggregates/b5fc6392-65f1-32d3-9ed1-a41f209ea4c5)

**Desktop website viewed aggregates:**
- [Desktop website viewed products - SKUs](https://app.synerise.com/analytics-v2/aggregates/51d1daac-8483-351f-ae01-ea0b5455fba0)
- [Desktop website viewed products - prices](https://app.synerise.com/analytics-v2/aggregates/adb929ff-f56c-37d6-b5d8-61d88449d2e1)

If you’re our partner or client, you already have automatic access to the **Synerise Demo workspace (1590)**, where you can explore all the configured elements of this use case and copy them to your workspace.  

If you’re not a partner or client yet, we encourage you to fill out the contact [form](https://demo.synerise.com/request) to schedule a meeting with our representatives. They’ll be happy to show you how our demo works and discuss how you can apply this use case in your business.

## Read more
---
- [Aggregates](/docs/analytics/aggregates)
- [Automation Hub](/docs/automation)
- [Catalogs](/docs/assets/catalogs/introduction-to-catalogs)
- [Email campaigns](/docs/campaign/e-mail)
- [Expressions](/docs/analytics/expressions)
- [Mobile push campaigns](/docs/campaign/Mobile)
- [Reusing event context from preceding nodes](/docs/automation/event-params-reuse)
- [Creating workflows](/docs/automation/creating-automation)
- [Jinjava inserts](/developers/inserts/insert-usage)
- [Snippets](/docs/assets/snippets)