personalize

The personalize() function is the cornerstone of each personalized template, whether used in email or Site Personalization Manager. Based on your chosen Sailthru 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

  • Use the context algorithm
    • Return the top 5 (default quantity) items most-commonly bought by users who bought the item at the current/specified URL
  • Include only items with tags boots and child
  • Exclude items with tag black
{resultArray = personalize({
  "algorithm" : "context",
  "context_key_type" : "url",
  "context_key" : "http://example.com/item.html",
  "include_tags_all" : [ "boots", "child" ],
  "exclude_tags_any" : [ "black" ]
})}
  • Use the interest algorithm
    • Return the top 20 items from the current feed that have interest tags best matching the known interests of the current user
  • Include only items with tags boots and child
{resultArray = personalize({
    "algorithm" : "interest",
    "size": 20,
    "include_tags_all" : [ "boots", "child" ]
})}

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 Sailthru 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 in the recent past. If your account does not contain purchase data, the most-viewed items are used. • SPM
• Email*
Ranking
Trending The items that have gained in popularity in the past week, based on their number of purchases. (Commerce sites only.) • 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 anonymous 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)
Prediction
Requires Prediction Manager subscription
The products a user is most likely to buy based on machine-learning models that incorporate signals from the user’s interests, collaborative filtering, and engagement activity. (Only available with a Prediction Manager subscription.)Predictions are updated daily, and each day we ingest new user activity to update the machine-learning models as well as the specific product predictions for each user. • SPM Predictive
(Machine learning)
Random A randomized selection of content from a data feed • SPM Random
Custom Use your own custom algorithm to serve recommendations to your users. Call in 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”. Sailthru will look up this custom array of content identifiers and return all content metadata for display. • SPM
• Email*
Custom

*Please ask your Customer Success representative 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>,
   "use_pinning" : <string>,
   "content" : <name of array>
})

Notes

  • Line breaks are not supported within Zephyr functions. Do not include line breaks in your object.
  • 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 Sailthru 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.
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, prediction, interest, trending, popularrandom, 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 number of items you wish to return in the resulting content array.
content All No content Applies only to the interest algorithm. 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().
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_idurl or sku are recommended. content_id is only accessible in Sailthru-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:urlskutitle, or content_idurl or sku are recommended. content_id is only accessible in Sailthru-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.
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.

include_vars All except interest, random No FALSE In addition to Sailthru’s default content fields, include all custom content vars for each returned content item.
use_pinning All No TRUE If false, ignore pinned item locations if any are specified on the feed.
require_price All except interest, random No FALSE If true, only include content with a price field
require_images 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.

Examples

Display the Intersection of User-Interested and Trending Content

Use Case: Using collaborative filtering, you wish to find all items that are “trending” in your Content Library, but you only want to display the top three of those items to users based on user interest data from your Content Library. Used in conjunction with the personalize() function.

Zephyr:

{**Find 100 items a user is interested in and 100 items that are popular**}
{interestContent = personalize({"algorithm":"interest","size":100})}
{popularContent = personalize({"algorithm":"popular", "size":100})}

{**Desired number of items**}
{recNum = 10}

{**FInd the intersect of the popular and interested items**}
{personalizedContent = content_intersect(interestContent,popularContent)}

{**Create a backup length if there are less than the number of desired item**}
{backupLength = recNum - length(personalizedContent)}

{**If the length of backup items is greater than 0, find unique content in the interestContent object to backfill the remaining items**}

{if backupLength > 0}

{usedcontent = []}
{personalizedContent = filter(personalizedContent, lambda c: (contains(usedcontent, c.url) ? false : push("usedcontent", c.url) || true))}
{backupContent = filter(interestContent, lambda c: (contains(usedcontent, c.url) ? false : push("usedcontent", c.url) || true))}

{backupContent = personalize({
"algorithm" : "interest",
"size": backupLength,
"content" : backupContent
})}

{personalizedContent = personalizedContent + backupContent}

{/if}

{**Run personalization**}
{personalizedContent = personalize({
"algorithm" : "interest",
"size": 10,
"content" : personalizedContent
})}

In the Code:

<p>Here are hot items we think you'll love</p>
{foreach personalizedContent as c}
{c.title}<br/>
{/foreach}

Output:

Here are hot items with think you’ll love

Item 1

Item 2

Item 3

Explanation:

This script uses the personalize() function to recommend content based on two algorithms: Interest (based on on-site browsing) and what’s popular (pieces of content that have the most purchases or the most pageviews). It starts by creating two content objects based on those algorithms: One called “interestContent”, which finds 100 items a user has displayed personal interest in; and one called “popularContent”, which is the 100 globally most popular items. Ultimately, you want an overlap of ten items to show to each user (i.e., ten items that they are interested in that are also most popular), and that recommendation length is set in the “recNum” assignment. Next, in order to find the overlap between the two, the content_intersect() function is used to find how much content exists between “interestContent” and “popularContent”, which creates a new content object called “personalizedContent”. Next, there’s a check of the length of this object (i.e., exactly how many items existed in both sections). This number is subtracted from the “recNum” value, which creates the “backupLength”. This means if there are only three matching items between the interested and popular content objects, the backupLength is “7”, meaning the script will now find seven additionally items to recommend. 

To check whether or not backup content is necessary, the next part of the script uses an “if” statement to check if the backupLength is greater than 0. If it is, a dedupe script is run, which uses the contains() function to check the title of every item in a data feed against an array called “usedcontent.” If the title of the item exists in the array, the filter() function removes it from the feed (this means that the title already occurred once, and it is a duplicated item). In this example, the filter is performed twice: Once on the “personalizedContent” object, and once on the original “interestContent” object. This second filter is used to create a “backupContent” object, which is the content a user is interested in that’s not in the “popularContent” object. The personalize() function is then run on the “backupContent” object baesd on user interest, and the value of the “backupLength” number (i.e. the number of additional items needed to make it to 10) will determine how many additional items to return. “personalizedContent” is then reassigned to be the other “personalizedContent” object plus the “backupContent”. If there were 10 items or more in the original “personalizedContent” object, then no backup content gets added.

Finally, personalize() is run on “personalizedContent” to get the top ten items for each user, which is then looped through using a “foreach” loop and displayed in the template.

Set a Limit on the Number of Items Shown from a Certain Category

Use Case:

You want to ensure that users aren’t shown content based on the same “author” too many times. Instead, you want to limit it to two items max.

Zephyr:

In the Setup:

{max_per_author = 2}
{display_count = 3}

{* Sorts entire content array in interest order, ensuring that most relevant items will be kept for each user *}
{content = personalize({"algorithm": "interest", "content": content, "size": length(content)})}

{* Filter removes any items in excess of max_per_category *}
{author_counts = {}}
{content = filter_content(content, lambda c: ((contains(keys(author_counts), c.author) && author_counts[c.author] >= max_per_author) ? false : ((contains(keys(author_counts), c.author) ? (author_counts[c.author] = author_counts[c.author] + 1) : (author_counts[c.author] = 1)) || true)))}

{* Slice desired number of items for display. Content already sorted in interest order. *}
{content = slice(content, 0, display_count)}

In the Code:

Picked for You!
{foreach content as c}
<a href={c.url}>{c.title}</a> by {c.author}!
<br/>
{/foreach}

Output:

Picked for You!

Alexander Harris elected to Los Angeles House of Representatives by Willow Rosenberg
Get Your First Look at the New iPhone at the Times Square Apple Store by Willow Rosenberg
Spider-Man: Threat or Menace? by J. Jonah Jameson

Show/Hide Code Explanation

This script starts by setting two local variables: a “max_per_author” variable and a “display_count” variable, which are easily editable on a send-by-send basis. In this instance, the “max_per_author” value is set to 2, and the “display_count” is set to 3. It then uses the personalize() algorithm to find all the content the user is interested in. The length() function takes a count of every piece of content in the feed to tell the personalize() function how many items to personalize. By doing the entire length, the content feed is completely reogranized for each user.

Next, an empty object is created, called “author_counts.” In order to fill the object with data, the filter_content() function filters through the content object, using the keys() function in conjunction with the contains() function to check if any “key” (i.e. an author name) is contained within the author_counts object and if the author_count for that particular key is greater than or equal to the author count. Using the Media feed as an example, it’d check if “Willow Rosenberg” is in the object, and if so, if that value is in there more than twice. If so, the script won’t take any further action, but if not, perform another check: If the author_count object already contains that author, then set the value of that author to add “1” to the current value. For instance, if “Willow Rosenberg” were in there once already, the key/value pairing would be “Willow Rosenberg (key) = 1 (value).” Otherwise, if the author_object did not currently contain an instance of that author, the author name is set as the key, with “1” being set as the value. For instance, “Willow Rosenberg = 1″. Since this script iterates through each piece of content, once it gets to “Willow Rosenberg” again as an author, the key/value pair is updated to “Willow Rosenberg = 2″. If it finds that author a third time, it’s removed from the content object for that user.

The content array is then sliced to pull the top items for each user, using the slice() function. The slice starts at position 0 (i.e. the first item in the array) and ends at the value set in the “display_count” variable (in this instance, 3, meaning that content will be the top three items for each user. Finally, a foreach loops iterates through this content array, displaying the title, URL, and author name for each user’s top three pieces of content.

Show Feed Items that Match Terms in Custom Interest Array (With Fallback Content)

Use Case: You have an array of authors a user is following, and on a data feed, you want to match this user variable against a “sailthru.author” content variable in order to create a personalized bucket of content for users. You also want fallback content if there’s no applicable content to show the user.

Zephyr/Code:

Show/hide sample e-commerce feed used for this example
{
"feed": {
	"name": "Ecommerce Feed",
		"url": "http://feed.sailthru.com/ws/feed?id=ecomm"
},
	"content": [
		{
		"title": "To Kill a Mockingbird",
		"description":"The unforgettable novel of a childhood in a sleepy Southern town and the crisis of conscience that rocked it.",
		"date": 1489437759,
		"image": "http://example.com/fiction/tokillamockingbird-full.jpg",
		"weight": 75,
		"tags": [
			"site-store",
			"genre-mystery-thriller",
			"author-harper-lee",
			"classics",
			"fiction",
			"price-11-20"
				],
		"author": "Harper Lee",
		"price": 1500,
		"inventory": 200,
		"vars": {
			"sailthru_genre":"mysteries-and-thrillers",
			"sailthru_category":"books",
			"membership_price":"12.99"
			},
		"url": "http://example.com/fiction/tokillamockingbird/?utm_medium=site",
		"images": {
			"full": {
				"url": "http://example.com/fiction/tokillamockingbird-full.jpg"
					},
			"thumb": {
				"url": "http://example.com/fiction/tokillamockingbird-thumb.jpg"
					}
				}
	},
	{
		"title": "Salem's Lot",
		"description":"Ben Mears has returned to Jerusalem's Lot -- but things are more sinister than he remembers.",
		"date": 1474547794,
		"image": "http://example.com/books/fiction/salemslot-full.jpg",
		"weight": 30,
		"tags": [
			"site-store",
			"genre-horror",
			"author-stephen-king",
			"vampires",
			"fiction",
			"price-5-10"
				],
		"author": "Stephen King",
		"price": 999,
		"inventory": 1567,
		"vars": {
			"sailthru_genre":"horror-and-suspense",
			"sailthru_category":"books",
			"membership_price":"8.15"
			},
		"url": "http://example.com/fiction/salemslot/",
		"images": {
			"full": {
				"url": "http://example.com/books/fiction/salemslot-full.jpg"
					},
			"thumb": {
				"url": "http://example.com/books//fiction/salemslot-thumb.jpg"
					}
				}
	},
	{
		"title": "Women's Leather Jacket",
		"description":"A classic look that never goes out of style with an exposed metal closure that zips at the cuff.",
		"date": 1474547794,
		"image": "http://example.com/fashion/womens/outerwear/leatherjacket-full.jpg",
		"weight": 55,
			"tags": [
			"site-store",
			"womens-clothing",
			"outerwear",
			"material-leather",
			"color-brown",
			"price-201-300"
				],
		"price": 45000,
		"inventory": 1720,
		"vars": {
			"sailthru_color": "brown",
			"sailthru_material":"leather",
			"membership_price":"325.75"
				},
		"url": "http://example.com/fashion/womens/outerwear/leatherjacket/",
		"images": {
			"full": {
				"url": "http://example.com/fashion/womens/outerwear/leatherjacket-full.jpg"
					},
			"thumb": {
				"url": "http://example.com/fashion/womens/outerwear/leatherjacket-thumb.jpg"
					}
				}
	},
	{
		"title": "Invisible Monsters: A Novel",
		"description":"Love, betrayal, petty larceny, and high fashion fuel this deliciously comic novel from the author of Fight Club.",
		"date": 1474547794,
		"image": "http://example.com/books/fiction/invisiblemonsters-full.jpg",
		"weight": 30,
		"tags": [
			"site-store",
			"genre-mystery-thriller",
			"author-chuck-palahniuk",
			"post-modern",
			"fiction",
			"price-5-10"
				],
		"author": "Chuck Palahniuk",
		"price": 899,
		"inventory": 678,
		"vars": {
			"sailthru_genre":"mysteries-and-thrillers",
			"sailthru_category":"books"
			},
		"url": "http://example.com/fiction/invisiblemonsters/",
		"images": {
			"full": {
				"url": "http://example.com/books/fiction/invisiblemonsters-full.jpg"
					},
			"thumb": {
				"url": "http://example.com/books//fiction/invisiblemonsters-thumb.jpg"
					}
				}
	},
	{
		"title": "Men's Chelsea Boots",
		"description": "Look great with jeans or a suit with these slick, black boots.",
		"date": 1474547794,
		"image": "http://example.com/fashion/mens/shoes/chelsea-boots-full.jpg",
		"weight": 40,
			"tags": [
			"site-store",
			"mens-clothing",
			"shoes",
			"material-suede",
			"color-black",
			"price-101-150"
				],
		"price": 14000,
		"inventory": 15,
		"vars": {
			"sailthru_color": "suede",
			"sailthru_material":"leather",
			"membership_price":"115.50"
				},
		"url": "http://example.com/fashion/mens/shoes/chelsea-boots/",
		"images": {
			"full": {
				"url": "http://example.com/fashion/mens/shoes/chelsea-boots-full.jpg"
					},
			"thumb": {
				"url": "http://example.com/fashion/mens/shoes/chelsea-boots-thumb.jpg"
					}
				}
	},
	{
		"title": "From the Fashion Blog: The Most Comfortable Socks You'll Ever Own",
		"description":"They'll literally change your life. Find out where and how to get them!",
		"date": 1489092159,
		"expire_date": 1520628159,
		"image": "http://example.com/fashion/most-comfortable-socks-full.jpg",
		"weight": 25,
		"tags": [
			"site-store",
			"vertical-fashion",
			"type-footwear",
			"author-richard-wilkins",
			"socks",
			"unisex-clothing"
			],
		"author": "Richard Wilkins",
		"vars": {
			"sailthru_category": "fashion",
			"sailthru_storyid": 87422
				},
		"url": "http://example.com/fashion/most-comfortable-socks/",
		"images": {
			"full": {
				"url": "http://example.com/fashion/most-comfortable-socks-full.jpg"
					},
			"thumb": {
				"url": "http://example.com/fashion/most-comfortable-socks-thumb.jpg"
					}
				}
	}
	]
}

On the User Profile:

zephyr example following array stephen king et al

In the Setup:

{*Creating an assignment called your_authors, which is anyone who matches the value of the author var in the content*}
{yourAuthors = filter_content(content, lambda c: contains(profile.vars.following, c.author))}
{*Personalize the order in which authors appear based on interest tags*}
{if length(yourAuthors) > 0}
{yourAuthors = personalize({
 "content" : yourAuthors,
 "algorithm" : "interest",
 "size" : length(yourAuthors)
})}
{else}
{content = personalize({
 "content" : content,
 "algorithm" : "interest",
 "size" : 5
})}
{/if}

In the Code:

<!--Showing new stories if the 'your_authors' array is greater than zero-->
 {if length(yourAuthors) > 0}
 <p>Top books from your favorite authors!</p>
 {foreach yourAuthors as c}
 <p><a href={c.url}>{c.title}</a> by {c.author}</p>
 {/foreach} 
<!--Checking if the user has the following var but with at least one author-->
 {else if(contains(profile.vars,following)) && length(profile.vars.following) > 0}<p>Nothing new from who you're following
 <a href="http://example.com/preferences/">Click here to follow more!</a></p>
But here are some we think you'd like:
{content = personalize({
 "content" : content,
 "algorithm" : "interest",
 "size" : 5
})}
 {foreach content as c}
 <p><a href={c.url}>{c.title}</a> by {c.author}</p>
 {/foreach}
<!--Remaining users who aren't following anyone-->
 {else}
{content = personalize({
 "content" : content,
 "algorithm" : "interest",
 "size" : 5
})}
 <p>You're not following anyone! <a href="http://example.com/preferences/">Click here to start!</a></p>
And here are some we think you'd like to get you started:
 {foreach content as c}
 <p><a href={c.url}>{c.title}</a> by {c.author}</p>
 {/foreach}
 {/if}

Output:

Top books from your favorite authors!

Salem’s Lot by Stephen King
Invisible Monsters by Chuck Palahniuk

Show/Hide Code Explanation

This script uses the filter_content() function in conjunction with the contains() function to find the overlap of the values of a profile variable called “following” (representing authors a user is “subscribed” to), checking for overlap in the content array for any “author” value on each item. Any overlapped items gets added to the “yourAuthors” array. For instance, the example user profile is following Stephen King, Chuck Palahniuk, and Kurt Vonnegut. The first two appear as values for the “author” parameter on two items in the Media feed and are thus added to this user’s “yourAuthor” array.

Next, a check is done on the yourAuthors array to see if it’s greater than 0  (i.e., the user has authors that they’re following who are in the feed). If so, the yourAuthors array is rearranged by the personalize() function to be in order of most interested item to least interested item. Using the length() function on the yourAuthors array tells the personalize() script how many times it should run (in this instance, twice, as there are only two items in the yourAuthors array, meaning length(yourAuthors) = 2). If the user does not have any items in this array, then the personalize() script is run to find 5 items for the entire feed.

In the Code of the template, an “if” statement checks if the length of “yourAuthors” is greater than 0, If it is, loop through each author and show the appropriate content. The next statement uses an “else if” and a contains() function to see if the user has the following var on their profile (by checking all of their profile vars and seeing if following is “contained” in there). If that evaluates to true and the length of the profile user variable is greater than 0 (i.e. there’s at least one author that the user is following), then we can logically determine that the user is following an author, but that author isn’t in the feed. As a result, the content displayed returns 5 items based on user interest data while displaying a message that there isn’t anything new from authors they are following and to start following more.

The last bucket of users are ones who aren’t following any others at all. For these users, the content displayed returns 5 items based on user interest data while displaying a message encouraging them to start following authors for more personalized recommendations.

Display Content with Vars Matching Users’ Interest/Subscription Variables

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:

zephyr example tech media news number 1

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.

Display Content Recommended 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.

Top