Contact us

Smart recommendations for Commerce PT2

Senior Developer
Valtech Netherlands

October 05, 2016

A little while ago I wrote a post about how you could use the Recommendations API from Microsoft Cognitive Services to give your visitors smart recommendations. This time, as promised, I will go into the details of my implementation a bit.

I must say that I am quite content with the results of the recommendations that are returned. If you have used it, let me know how what you think of the Recommendations API. I also think the pricing is quite OK. 10.000 transactions for free, a 100.000 for $75

Anyway, the project consists of a core library and two scheduled jobs. One scheduled job to export your catalogue items, one to export the usage statistics and trigger a build.

The core library contains all the models, a wrapper for the API calls a helper with some methods to adapt commerce content to content that the API can use and a base RecommendationService.

This RecommendationService is a base class, you will need to do your own implementation in your commerce project, as no catalogue is the same. If you don’t override the methods, you have the basic version, without feature in your model e.g. The service is used by the jobs to send the catalogue and usage stats, and you can use it to get the recommendations for a user of for an item.

The most basic implementation you can do is

[ServiceConfiguration(typeof(IRecommendationService), Lifecycle = ServiceInstanceScope.Singleton)]

    public class QuicksilverRecommendationService : RecommendationService


        public QuicksilverRecommendationService(

            RecommendationsApiWrapper recommendationsApiWrapper, 

            RecommendationSettingsRepository recommendationSettingsRepository, 

            IContentLoader contentLoader, 

            ReferenceConverter referenceConverter,

            IOrderRepository orderRepository, 

            ILogger log )

            : base(











This will give you the following methods to override


List<CatalogItem> GetCatalogItems(DateTime since);

List<EntryContentBase> GetItemRecommendations(string itemIds);

List<T> GetItemRecommendations<T>(string itemIds);

List<EntryContentBase> GetItemRecommendations(string itemIds, int numberOfResults);

List<T> GetItemRecommendations<T>(string itemIds, int numberOfResults);

List<UsageItem> GetUsageItems(DateTime since);

List<EntryContentBase> GetUserRecommendations();

List<T> GetUserRecommendations<T>();

List<EntryContentBase> GetUserRecommendations(int numberOfResults);

List<T> GetUserRecommendations<T>(int numberOfResults);

void SendUsageEvent(int quantity, string code, decimal unitPrice, EventType eventType);

void SendUsageEvent(decimal quantity, string code, decimal unitPrice, EventType eventType);


In Quicksilver e.g. you could get the CatalogItems like this


public override List<CatalogItem> GetCatalogItems(DateTime since)


            List<CatalogItem> catalogItems = new List<CatalogItem>();

            IEnumerable<ContentReference> descendents =


            foreach (ContentReference contentReference in descendents)


                FashionVariant variation;

                if (!this.ContentLoader.TryGet(contentReference, out variation))




                if (variation.Created < since)




                NodeContent node =


                CatalogItem catalogItem = new CatalogItem


                                                  ItemID = variation.Code,

                                                  ItemName = variation.Name,

                                                  ProductCategory = node == null ? "undefined" : node.Name,

                                                  Description = string.Empty,

                                                  Features = new Dictionary<string, string>() { { "color", variation.Color }, { "size", variation.Size } }




            return catalogItems;



The GetCatalogItems method in the base just gets all variations. If you don’t want to enrich your model with features, you can leave it as is. To add features to your model you can add them like I did above. For all the base methods in the service, have a look on GitHub

You also can/need to configure some things. For now in the appSettings.

Add an account key to your appsettings: <add key=”recommendations:accountkey” value=”YourKey” />

If you want to use the ‘Frequently Bought Together build’ change the key in the appSettings: <add key=”recommendations:useftbbuild” value=”true” />.

If the baseuri for the API changes, update the key in the appSettings: <add key=”recommendations:baseuri” value=”″ />

If you want to use a different model name, update the key in the appSettings: <add key=”recommendations:modelname” value=”OptimizelyCommerce” />

If you want to use a different display name for the catalogue, update the key in the appSettings: <add key=”recommendations:catalogdisplayname” value=”Optimizely Commerce catalog” />

If you want to use a different display name for the usages, update the key in the appSettings: <add key=”recommendations:usagedisplayname” value=”Optimizely Commerce catalog usages” />

The Catalogue export job creates the model for you if there is no model yet and uses the RecommendationService to get the items and sends them to the API.

The Usage export job uses the RecommendationService to get the usage statistics ands sends them to the API. It also triggers a build to start the “learning process” of your model.

All code is on GitHub as always. You can get the NuGet packages or zipped files from the releases tab, or from MyGet.

Am not quite sure if I should put this on the Optimizely NuGet feed, as it’s quite experimental. Let me know if you would like that.

Next up will be that you don’t have to make a choice between a recommendations build or a FBT build. And of course creating business rules for your model from within Optimizely.

Article originally published on Optimizely Development Blog: Smart Recommendations for Commerce 

Contact us

Let's reinvent the future