--- title: "Personalization with Related Data" slug: "personalization-with-related-data" description: "Use related data in Mapp Engage messages: reference linked and unlinked data sets and show content with conditions based on related records." status: "update" updated: 2026-11-04T13:53:18Z published: 2026-11-04T13:53:18Z canonical: "docs.mapp.com/personalization-with-related-data" --- > ## Documentation Index > Fetch the complete documentation index at: https://docs.mapp.com/llms.txt > Use this file to discover all available pages before exploring further. # Personalization with Related Data ## Overview Related data sets store additional records for your contacts, for example purchases, bookings, or store locations. You can use this data in messages in three ways: - **Insert a value**: A placeholder inserts the value of a column, for example the name of a product. - **List several records**: A `ForEach` loop inserts content for each record, for example all products of an order. - **Show content conditionally**: A personalization rule checks the records of a contact and shows content only if a condition is met, for example an offer for customers who bought shoes. For placeholders and loops, see [Use Related Data in a Message](/v1/docs/use-related-data-in-a-message). This page explains how the data is referenced and how you use it in conditions. --- ## How the Data Is Referenced The notation depends on whether the related data set is linked to a contact attribute: - **Linked data set**: `user.relatedAttribute['Purchases']` returns the records whose key matches the attribute value of the contact. - **Unlinked data set**: `ecx:related('Purchases', key)` returns the records for a key that you specify, for example a fixed value or an attribute. In a unique data set, each key has exactly one record. You add the column to the reference, for example `user.relatedAttribute['Purchases']['Article']`. In a non-unique data set, a key can have several records. You process them with a `ForEach` loop or with functions. The name of the data set is not case-sensitive. Values that you compare in filters are case-sensitive. --- ## Conditions with Related Data A condition in a personalization rule must return true or false. Filter functions such as `ecx:filter` return records, not a Boolean value. To use them in a condition, count the records with `ecm:countMapElements` and compare the result with `> 0`. Conditions with functions are written in code. See [Code View for Personalization Rules](/v1/docs/code-view). ### Example: Customers who bought shoes The linked data set `Purchases` has a column `ArticleType`. Customers who bought shoes get an offer for shoe accessories. All other customers get a general offer: ```plaintext <%InsertIf expression="${ecm:countMapElements(ecx:filter(user.relatedAttribute['Purchases'], 'ArticleType', '==', 'Shoes')) > 0}"%> Special offer on shoe accessories! <%/InsertIf%> <%InsertElse%> Check out our latest deals! <%/InsertElse%> ``` The value `Shoes` must match the stored value exactly. To ignore upper and lower case, use the operator `containsignorecase` instead of `==`. It also matches values that only contain the term, for example `Running shoes`. ### Example: Purchases in the last 30 days Customers who bought something in the last 30 days get an exclusive offer. `ecm:addInterval` calculates the date 30 days ago, and `ecx:formatDate` converts it into the format that the filter compares with: ```plaintext <%InsertIf expression="${ecm:countMapElements(ecx:filter(user.relatedAttribute['Purchases'], 'Date', '>=', ecx:formatDate(ecm:addInterval(date.Today, '-30d'), 'yyyy-MM-dd', ecm:timeZone('Europe/Berlin'), '', false))) > 0}"%> Exclusive deal for recent buyers! <%/InsertIf%> ``` Replace the time zone with the one of your system. For the date functions, see [Extract and Format Dates and Times](/v1/docs/extract-and-format-dates-and-times). For all filter functions, see [Sort or Filter Data Records](/v1/docs/sort-or-filter-data). --- ## Best Practices - Keep conditions as simple as possible. Each condition is evaluated for every recipient at sendout. - Add a default `InsertElse` block so that contacts without matching records also get content. - Save rules that you use often and reuse them in other messages. See [Personalization Rules](/v1/docs/personalization-rules-insertif-insertelse). - Test the rule in the message preview with contacts that have matching records, other records, and no records at all. See [Message Preview (Email)](/v1/docs/email-message-preview). --- ## Related Topics - [Functions for Filtering Related Data Sets](/v1/docs/functions-for-filtering-related-data-sets) - [Personalization Rules Syntax](/v1/docs/syntax-of-personalization-rules) - [Personalize Emails with eCommerce and Related Data](/v1/docs/personalize-emails-with-ecommerce-and-related-data) ## Related - [Use Related Data in a Message](/use-related-data-in-a-message.md)