Match catalog items to a custom attribute array
When each user keeps a list of saved product names on their profile, use a catalog selection plus Liquid to show only catalog rows that appear in that list—for example, a wishlist email.
About this example
Flash & Thread stores each customer’s saved product names in a string array custom attribute (saved_product_names). Their catalog holds full product details (category, price, image URL, inventory).
Catalog selections can filter catalog columns against static or Liquid values, including array fields on catalog rows. They do not filter a catalog row against values stored in a user profile array. To personalize from the user’s list, return a broad set of catalog items with a selection, then use Liquid to keep only rows that match the profile array.
This pattern:
- Assigns the user’s array custom attribute to a Liquid variable.
- Calls
catalog_selection_itemsfor a pre-filtered catalog selection (up to 50 items). - Loops over
itemsand usescontainsto match each catalog field (for example,nameorid) against the array.

This pattern works only when the selection’s result set (up to 50 catalog rows) can plausibly contain each user’s saved items—for example, small catalogs, or catalogs where filters narrow the selection tightly enough to cover a typical list. If a user’s saved items fall outside the 50 rows returned, the loop finds no matches and the message renders nothing for those items—no filter resolves this in the general case, because the selection can’t match against the user’s profile array.
Considerations
- Test Liquid and catalog data in a staging workspace before you send to customers.
- Because a selection returns at most 50 catalog rows, add filters (for example, in stock, active category, or price band) that keep each user’s likely saved items within that result set.
- This example uses a string array on the user profile.
- For an array of objects, match on a property inside each object (for example,
product_id) and adjust thecontainscheck or use aforloop over objects. See Array of objects. containsbehavior depends on attribute type; for arrays, usecontainsrather than==. See Conditional logic.- Match on stable identifiers (for example, catalog
id) when product names can change or duplicate. - The Liquid snippets in this article are examples. Validate rendering in your channels (email HTML, push, and so on).
Setup
This example assumes:
| Asset | Details |
|---|---|
| Custom attribute | saved_product_names — string array (for example, ["linen_shirt", "trail_jacket", "canvas_tote"]) |
| Catalog | apparel_products with columns id, category, name, price, inventory, image_url |
| Selection | in_stock_apparel on apparel_products, results limit 50, with filters that exclude irrelevant rows (for example, inventory greater than 0) |
Step 1: Create the catalog and selection
- Import or sync product rows into a catalog named
apparel_products. - Create a selection (for example,
in_stock_apparel) that returns as many relevant rows as you need, up to the 50 item limit. - Add selection filters to drop rows you never want in the message (out of stock, wrong category, and so on).
For selection setup, see Selections.
Step 2: Add Liquid in your message
Assign the profile array, load the selection, and loop with contains:
1
2
3
4
5
6
7
8
9
10
{% assign saved_product_names = custom_attribute.${saved_product_names} %}
{% catalog_selection_items apparel_products in_stock_apparel %}
{% for item in items %}
{% if saved_product_names contains item.name %}
Product: {{ item.name }}
Category: {{ item.category }}
Price: ${{ item.price }}
Image: {{ item.image_url }}
{% endif %}
{% endfor %}
Replace item.name with item.id (or another column) if your array stores IDs instead of display names. Add spacing or HTML between fields for your channel. In ${{ item.price }}, the $ is a literal currency symbol that prints before the Liquid output—it isn’t part of Braze’s ${} personalization syntax.
To generate this Liquid automatically, open the Add Personalization modal (Catalog Items > Use a selection). See Using catalogs.
Step 3: Preview and test
Send test messages to profiles with different saved_product_names values. Confirm only matching catalog rows appear and that an empty array produces no product lines.