personalize
The personalize() function is the cornerstone of each personalized template, whether used in email or Site Personalization Manager. Based on your chosen recommendation algorithm and additional configuration options, personalize() returns an array of the best-matching content or products for the user whose template is currently being rendered.
list personalize( object data )
The data JSON object contains all configuration parameters, which are described in the Parameters table below.
Example Configurations
{content = personalize({
"algorithm" : "context",
"context_key_type" : "url",
"context_key" : "http://example.com/item.html",
"include_tags_all" : [ "boots", "child" ],
"exclude_tags_any" : [ "black" ]
})}
|
{content = personalize({
"algorithm" : "interest",
"content": content,
"size": 20,
"include_tags_all" : [ "boots", "child" ]
})}
Note: content is a reference to the content array name in the feed. The array name for most feeds is 'content', but can vary with use of a custom feed or merged feeds. |
personalize
is a replacement for the legacy horizon_select function, which offers only one recommendation algorithm. That algorithm is accessible to personalize by setting the algorithm to interest.
Available Algorithms
personalize
offers a choice of the following algorithms, all of which return the best-matching content items for a given user based on their criteria listed below. For all algorithms except interest, the content is sourced directly from your Content Library, unless you provide a specific feed to use as an alternative. Results are returned in ranked order starting with the strongest match.
Name | Description | Availability | Method Type |
---|---|---|---|
Popular | The most popular items from across your Content Library based on purchases across all time. If your account does not contain purchase data, the most-viewed items are used. This can be used for ecommerce or media. | • SPM • Email* | Ranking |
Trending | The items that have gained in popularity in the past week, based on their number of purchases. | • SPM • Email* | |
Context | Given a specific url, the context algorithm returns the items from your content library which are most often viewed or purchased by other users who viewed or purchased the given item. This is based on the history all views and purchases.Does not leverage specific user data for recommendation purposes, so is appropriate for unknown users. Works great for abandoned cart reminders to display similar items. | • SPM • Email* | Collaborative filtering (Wisdom of the crowd) |
Purchased | The Purchased algorithm is a user specific recommendation set based on a customer's purchase history.Given all of the products a user has bought, the items most similar to those items are returned. | • SPM • Email* | |
Viewed | The Viewed algorithm returns a set of recommendations based on an individual user's pageview history.Given the URLs that a user has visited, the algorithm returns a set of items that the customer is predicted to like based on similarity scores of the items they have browsed. | • SPM • Email* | |
Interest | This selection enables the same algorithm used by the Zephyr function horizon_select() to return items in the feed with tags that match the user's interest profile. Does not directly access the Content Library, instead requiring a data feed. This feed can be sourced from your Content Library or an external source that uses the same schema. For more information, see Data Feeds.Uses the feed that is assigned to the template or an alternative content array, for example, a variable containing feed content that you have filtered within your Zephyr code. | • SPM • Email | Interest (Content-based filtering) |
Random | A randomized selection of content from a data feed. This feed can be sourced from your Content Library or an external source that uses the same schema. For more information, see Data Feeds.Uses the feed that is assigned to the template or an alternative content array, for example, a variable containing feed content that you have filtered within your Zephyr code. | • SPM | Random |
Custom | Use your own custom algorithm to serve recommendations to your users. Call in up to 100 specific Content Library items -- by URL, SKU, title, or content_id -- which your own algorithm may have preselected for the given user and added to their user profile as an array of content identifiers. Your personalize function will pass this information as a custom_key_type and array of custom_keys.For example, store an array of URLs or SKUs that you have recommended for each user on their profile under the custom profile field (a.k.a. var) "recommendations", then, in your personalize function, pass the custom_key value "profile.vars.recommendations". The system will look up this custom array of content identifiers and return all content metadata for display. | • SPM • Email* | Custom |
*Please contact Support if you would like to enable this algorithm for email.
Parameters
Pass any parameters as a JSON object into the personalize() zephyr function. For example:
personalize({
"algorithm" : <string>,
"size" : <int>,
"context_key_type" : <string>, "context_key" : <string>,
"include_tags_any" : <array>, "include_tags_all" : <array>,
"content" : <name of array>
})
Notes
- Line breaks are supported within the personalize function, as shown above, however, this is not the case for other Zephyr functions.
- The ability to specify tags for filtering is especially useful with Site Personalization Manager: based on the context in which the page is being viewed (e.g. a site category/section), you can dynamically pass in variables/tags on page load in order to affect the content that is displayed. Note, however, that tag filtering is also available when creating a content feed for use with the interest algorithm, and can also be done manually in your template's Zephyr code using filter() and filter_content().
- For all algorithms that use your Content Library as their source, when an item's URL changes, that item is considered a new item, and will start over with zero pageviews, purchases, and context. Assuming the URL was the only change, the new item will also be a "duplicate" of the old one until you delete the previous URL from the Content Library.
- The value of include_tags_any or include_tags_all may be an array of strings or a single string containing comma-separated tags.
Include and Exclude Tags
The include and exclude tag parameters can be used in different combinations.include _tags_any
and include_tags_all
Using the two include parameters together creates an AND statement.
{my_content = personalize({
"algorithm": "popular",
"size": 20,
"include_tags_any": ["shoes", "sneakers", "boots"],
"include_tags_all" : ["mens", "onsale"]
})}
The example will return 20 popular items tagged with shoes OR sneakers OR boots AND tagged with both mens AND onsale.
exclude_tags_any
and exclude_tags_all
Using the two exclude parameters together creates and OR statement.
{my_content = personalize({
"algorithm": "popular",
"size": 20,
"exclude_tags_any": ["out-of-stock", "on-sale"],
"exclude_tags_all" : ["explicit", "adult"]
})}
The example will return 20 popular pieces of content, excluding any content tagged out-of-stock OR onsale OR tagged both explicit AND adult. So a piece of content will always be excluded it if contains the "on-sale" tag, regardless of the other excluded tags.
Parameter | Available for Algorithms | Required | Default Value | Description |
---|---|---|---|---|
algorithm | All | Yes | N/A | Specify which algorithm to use for returning item recommendations:
context , viewed , purchased , interest , trending , popular , random , or custom .Note that interest and random require a feed containing tags for each item, while the rest of the algorithms do not require a feed and can pull directly from your Content Library. |
size | All | Yes | N/A | The maximum number of items you wish to return in the resulting content array. The size specified is a limit and not guaranteed to be the quantity returned; fewer items may be returned depending on the selected algorithm/parameters and the available data in your Content Library.
Note: The personalize function will only return up to 100 results at a time. |
content | interest, random | No | content | Applies only to the interest and random algorithms. Default content value is the content of the feed assigned to the template. Specify an alternative content array if, for example, you transform content within your Zephyr code to create a different source array to pass to personalize().
Note: If using exclude_tags_any with the interest algorithm, content must be set to "content":"content" |
context_key | All | Conditionally | <current page URL> | Identifier (URL, SKU, title, or ID) of the content item to use as a basis for finding similar items using the context algorithm.Required for email templates using the context algorithm.In SPM, by default, the context algorithm will use the URL of the current page as item context unless you specify an alternative context_key and/or context_key_type . |
context_key_type | All | No | url | The type of identifier you want to use as your context_key. The value of this parameter must be one of the following:url , sku , title , or content_id . url or sku are recommended. content_id is only accessible in generated Content Feeds. There is no need to specify context_key_type if your context_key is the item URL, as this is the default context_key_type . |
custom_keys | All | Conditionally | N/A | Identifier (URL, SKU, title, or ID) of the content item(s) to use as a basis for finding similar items using the custom algorithm. Include as an array, for example, [ "http://example.com/product.html" ] or [ "http://example.com/product1.html", "http://example.com/product2.html" ] . Required for email templates using the custom algorithm. In SPM, by default, the context algorithm will use the URL of the current page as item context unless you specify an alternative custom_keys array. |
custom_key_type | All | No | url | The type of identifier you want to use as your custom_key. The value of this parameter must be one of the following:url , sku , title , or content_id . url or sku are recommended. content_id is only accessible in generated Content Feeds.There is no need to specify custom_key_type if your custom_key is the item URL, as this is the default custom_key_type . |
remove_recently_viewed | All | No | false | If true , filter out content that the user has previously viewed. Viewed content is removed after the recommendations have been returned, so when this parameter is true , there is the possibility of returning fewer than the desired number of recommendations. This parameter looks at a user's last 30 pageviews. |
include_tags_any | All | No | N/A | At least one of these specified tags must be present on an item for it to be included in the resulting content array. (I.e., filter by tags using OR logic.) Can be used in conjunction with include_tags_all .Tags may be specified as an array of strings or a single string of comma-separated values. |
include_tags_all | All | No | N/A | All of these specified tags must be present on an item for it to be included in the resulting content array. (I.e., filter by tags using AND logic.) Can be used in conjunction with include_tags_any .Tags may be specified as an array of strings or a single string of comma-separated values. |
exclude_tags_any | All | No | N/A | If at least one of these specified tags is present on an item, it will not be included in the resulting content array. Tags may be specified as an array of strings or a single string of comma-separated values. |
exclude_tags_all | All | No | N/A | All of these specified tags must be present on an item for it to be excluded from the resulting content array. (I.e., filter by tags using AND logic.) Can be used in conjunction with exclude_tags_any .Tags may be specified as an array of strings or a single string of comma-separated values. |
include_vars | All except interest, random | No | false | In addition to the default content fields, include all custom content vars for each returned content item. |
require_price | All except interest, random | No | false | If true , only include content with a price field |
require_image | All except interest, random | No | false | If true , only include content with an image. |
require_tags | All except interest, random | No | false | If true , only include content that has at least one tag. |
allow_expired | All except interest, random | No | false | If true , include content that is past its expire_date. |
min_price | All except interest, random | No | N/A | Filter for products with a price >= min_price (in cents). |
max_price | All except interest, random | No | N/A | Filter for products with a price <= max_price (in cents). |
max_days_old | All except interest, random | No | N/A | Filter for products that have a created date <= (<today> minus max_days_old ). |
min_purchases | All except interest, random | No | N/A | Filter for products that have at least min_purchases . |
min_views | All except interest, random | No | N/A | Filter for products that have at least min_views . |
sort_field | All | No | N/A | The field you wish to sort by. Possible values: "date" , "expire_date" , "price" , "purchase_price" , "purchase_qty" , "inventory" , "views" , "popular" , "trending"
The content fields "date" , "expire_date" , "price" , "purchase_price" , "purchase_qty" , "inventory" , are all fields on the Content object.
Only "views" , "popular" , "trending" are algorithm scores that may not necessarily exist on the Content object, but should still be sortable in numerical order, if they exist. |
sort_ascending | All | No | true | If false , will sort in descending order. |
Examples
Content Matching Users' Profile Vars
Use Case: You have individual categories users can follow, each denoted by their own custom field, and on a data feed, you want to match this user field against a "sailthru.category" content variable in order to create a personalized bucket of content for users. You also want a backup section in case someone isn't following a certain category.
Zephyr:
On the User Profile:
In the Setup:
{*Creating an assignment called userContent, which will go through each "category" content var, find if you have that same user var with the value of 1, and add it to a "userContent" array*}{userContent = filter_content(content, lambda c: profile.vars[c.vars.sailthru_category] == 1)}{*Personalize the order in which industries appear based on interest tags, pulling the top 3*}{personalizedContent = personalize({ "content" : userContent, "algorithm" : "interest", "size" : 3 })}
In the Code:
{if length(userContent) > 0}
<p>Based on your preferences, here are stories you'll enjoy:</p>
{foreach personalizedContent as c}
<p>From the {c.vars.sailthru_category} category: <a href={c.url}>{c.title}</a></p>
{/foreach}
{else}
Want personalized recommendations? Tell us what you like <a href="http://example.com/preferences">here</a> to start following a certain category!</p>
{/if}
Output: (Based on the above user profile)Here are stories from your selected categories:
From the news category: Spider-Man: Threat or Menace? From the tech category: Get Your First Look at the New iPhone at the Times Square Apple Store From the news category: Alexander Harris elected to Los Angeles House of Representatives
(If nothing matches)Want personalized recommendations? Tell us what you like here to start following a certain category!
Explanation: This script uses the filter_content() function to iterate through each user profile variable to see if each user has a variable on their profile that matches the value of a content variable on a data feed. For instance, in the Media feed, the values for each sailthru.category custom variable are: media, tech, news, news, and fashion. On the example user profile, the user has "tech", "media", and "news" are custom fields that equal "1" (i.e. they are "subscribed" to those categories). Within the filter_content() script, the value of the profile.var (aka custom field) dynamically populates as it iterates through each item in the feed. For instance, for the first item in the Media feed ("Stephen Kings's New Book..."), the sailthru.category value is "media". The script check each user profile to see if "profile.vars.media == 1". If it does, that piece of content is added to a "userContent" variable, which is an array of items from the feed. If not, the item is skipped. For this particular user, since they're following each category represented in the feed besides "fashion", only the last article is skipped. Next, a local variable called "personalizedContent" is created, which uses the personalize() function to pick the top three stories from the "userContent" object based on individual user interest. Finally, in the Code, an "if" statement checks if there's more than 0 pieces of content in that userContent object (i.e. there's an item in the feed that matches a category a user is subscribed to). If so, display the category, title, and URL. If not, show a prompt encouraging users to update their preferences and choose categories to follow.Recommend Content Based on Past Purchases
Use Case: You want to check a data feed for any items a user may have already purchased. If they have, call out those specifically in their own "Because you purchased..." section and find non-purchased items for a "We recommend section."Zephyr:
{content = personalize({ "algorithm" : "popular", "size" : 100 })} {nonPurchased = purchased_items(content,false,90)} We recommend for you: {foreach slice(nonPurchased,0,3) as c} {c.title}<br/> {/foreach}
Output: We recommend for you: Item 1 Item 2 Item 3
Explanation: This script uses the personalize() function to create a content object of 100 items based on what's currently popular in your Content Library. The script then uses the purchased_items() function to check if the user has purchased any of those items in the past 90 days. If they haven't, the item is added to a "nonPurchased" content object. Next, a foreach loop iterates through this object, and using the slice() function, displays the top three items.
Dynamically Filter from a User Tag
If a user has a favorite topic variable on their profile in a tag-friendly format (ex. topic-movies), you can filter dynamically like so:{content = personalize({
"algorithm" : "trending",
"size" : 10,
"include_tags_all" : [ profile.vars.favorite_topic ]
})}
If the value isn't formatted appropriately (i.e. not all lowercase and dash-delimited), you can use Zephyr functions such as lower() and replace() to do so