Getting started

First thing you need is your database at Recombee and the corresponding secret key. Create the free instant account at recombee.com, if you don’t have one yet.

We provide client libraries (SDKs) for Java, Ruby, Python,.NET and PHP, which make the integration very easy. If you want to use the API directly, then you need to implement authentication – the procedure is explained in the Authentication (HMAC) section along with examples in multiple programming languages.

As was stated in the Introduction, recommendation domain consists of items, users and user-item interactions. Interactions will be the first subject that we’ll look at.

Sending interactions

Interactions are the most valuable information for the algorithms in recommender engine. There are multiple kinds of interactions in the system, but we will use just the following two for now:

  • detail-view - it will be sent to the system every time a user views a detail of an item
  • purchase - it will be sent every time a user purchases an item. Note that this interaction is used also in cases which are not literally purchases as a purchase is for example viewing a video in case of an IPTV platform or replying to an advertisement in case of a job agency.

A detail view of item xyz by user 2c169e575644d840838e is sent to the recommender with the following query:

POST /myDb/detailviews/ HTTP/1.0
Host: rapi.recombee.com
Content-type: application/json

Body:
{
  "itemId": "xyz",
  "userId": "2c169e575644d840838e",
  "timestamp": "2014-07-20T02:49:45+02:00",
  "cascadeCreate": true
}
require 'recombee_api_client'
include RecombeeApiClient

client = RecombeeClient.new('myDb', secret_token)
client.send(AddDetailView.new('2c169e575644d840838e', 'xyz', {'timestamp' => '2014-07-20T02:49:45+02:00', 'cascadeCreate' => true}))
RecombeeClient client = new RecombeeClient("myDb", secretToken);
client.send(new AddDetailView("2c169e575644d840838e", "xyz")
    .setTimestamp(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2016-12-09 13:05:06") )
    .setCascadeCreate(true));
from recombee_api_client.api_client import RecombeeClient
from recombee_api_client.api_requests import *

client = RecombeeClient('myDb', secret_token)
client.send(AddDetailView("2c169e575644d840838e", "xyz", timestamp="2014-07-20T02:49:45+02:00", cascade_create=True))
<?php
use Recombee\RecommApi\Client;
use Recombee\RecommApi\Requests as Reqs;

$client = new Client("myDb", secret_token);
$client -> send(new Reqs\AddDetailView("2c169e575644d840838e", "xyz", ['timestamp' => "2014-07-20T02:49:45+02:00", 'cascadeCreate' => true]));
?>
using Recombee.ApiClient;
using Recombee.ApiClient.ApiRequests;
using Recombee.ApiClient.Bindings;

var client = new RecombeeClient("myDb", secretToken);
var datetime = DateTime.Parse("2014-07-20T02:49:45+02:00", null, System.Globalization.DateTimeStyles.RoundtripKind);
client.Send(new AddDetailView("2c169e575644d840838e", "xyz", timestamp: datetime, cascadeCreate: true));
var recombee = require('recombee-api-client');
var rqs = recombee.requests;

var client = new recombee.ApiClient('myDb', secretToken);
client.send(new rqs.AddDetailView('2c169e575644d840838e', 'xyz', {timestamp: '2014-07-20T02:49:45+02:00', cascadeCreate: true}),
    (err, response) => {
    //...
    }
);

Where

  • myDb is name of your database :)
  • itemId is an unique identifier of the item, it may consist of digits, Latin letters, underscores, colons and minus signs.
  • userId is an unique identifier of the user. It might be for example a session ID for anonymous users.
  • timestamp is a UNIX timestamp or ISO 8601 date time of the view. If not specified, current time is used.
  • cascadeCreate tells the system that it should create the item or the user if it doesn’t exist in the system yet. We don’t have to explicitly manage the user and item database in the system for now thanks to this parameter.

Sending a purchase is very similar:

POST /myDb/purchases/ HTTP/1.0
Host: rapi.recombee.com
Content-type: application/json

Body:
{
  "itemId": "xyz",
  "userId": "2c169e575644d840838e",
  "timestamp": 1348162550,
  "cascadeCreate": true
}
client.send(AddPurchase.new('2c169e575644d840838e', 'xyz', {'timestamp' => '2015-09-10T04:29:55+02:00', 'cascadeCreate' => true}))
client.send(new AddPurchase("2c169e575644d840838e", "xyz")
    .setTimestamp(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2016-12-09 14:15:17"))
    .setCascadeCreate(true));
client.send(AddPurchase("2c169e575644d840838e", "xyz", timestamp="2015-09-10T04:29:55+02:00", cascade_create=True))
<?php
$client -> send(new Reqs\AddPurchase("2c169e575644d840838e", "xyz", ['timestamp' => "2015-09-10T04:29:55+02:00", 'cascadeCreate' => true]));
?>
datetime = DateTime.Parse("2015-09-10T04:29:55+02:00", null, System.Globalization.DateTimeStyles.RoundtripKind);
client.Send(new AddPurchase("2c169e575644d840838e", "xyz", timestamp: datetime, cascadeCreate: true));
client.send(new rqs.AddPurchase('2c169e575644d840838e', 'xyz', {timestamp: '2015-09-10T04:29:55+02:00', cascadeCreate: true}),
    (err, response) => {
    //...
    }
);

The quality of the recommendations heavily depends on the amount of the sent interactions so it may take some time before interactions are gathered and the best quality recommendations are produced. Submitting historical interactions should reduce the time.

Especially in the e-shops is very common that a user comes to the site as an anonymous user (identfied by a session id) and logs into regular account later. Then it’s useful to merge the anonymous user with the regular account, in order to enrich the regular account with interactions made before logging in. Use merge users request for this.

Getting recommendations

Now we can get some recommendations for the users. There are two types of recommendation:

  • user-based recommendation - System recommends items to a given user depending on his/her personal taste. This case can be used for example on your homepage.
  • item-based recommendation - System recommends items that are somehow related to a given item. System can take into account also a target user, so this case is useful for example in a detail page of a product, because item-based will give the user a list of related items that he/she might be also interested in.

Getting 5 user-based recommendations for user 2c169e575644d840838e is very easy:

GET /myDb/users/2c169e575644d840838e/recomms/?count=5
recommended = client.send(UserBasedRecommendation.new('2c169e575644d840838e', 5))
Recommendation[] recommended = client.send(new UserBasedRecommendation("2c169e575644d840838e", 5));
recommended = client.send(UserBasedRecommendation('2c169e575644d840838e', 5))
<?php
$recommended = $client -> send(new Reqs\UserBasedRecommendation("2c169e575644d840838e", 5));
?>
IEnumerable<Recommendation> recommended = client.Send(new UserBasedRecommendation("2c169e575644d840838e", 5));
client.send(new rqs.UserBasedRecommendation('2c169e575644d840838e', 5),
    (err, recommendations) => {
    //...
    }
);

An array with IDs of recommended items is returned. For example ["item-865", "item-460", "item-121", "item-1555", "item-683"].

Getting item-based recommendations based on item xyz which is viewed by user 2c169e575644d840838e is also easy:

GET /myDb/items/xyz/recomms/?count=10&targetUserId=2c169e575644d840838e
recommended = client.send(ItemBasedRecommendation.new('xyz', 10, 'targetUserId' => '2c169e575644d840838e'))
Recommendation[] recommended = client.send(new ItemBasedRecommendation("xyz", 10).setTargetUserId("2c169e575644d840838e"));
recommended = client.send(ItemBasedRecommendation('xyz', 10, target_user_id='2c169e575644d840838e'))
<?php
$recommended = $client -> send(new Reqs\ItemBasedRecommendation("xyz", 10, ["targetUserId" => "2c169e575644d840838e"]));
?>
IEnumerable<Recommendation> recommended = client.Send(new ItemBasedRecommendation("xyz", 10, targetUserId: "2c169e575644d840838e"));
client.send(new rqs.ItemBasedRecommendation('xyz', 10, {targetUserId: '2c169e575644d840838e'}),
    (err, recommendations) => {
    //...
    }
);

The recommendation requests have several parameters – more details here. Most notable are filter and booster parameters which can be used for modeling business rules using our simple language ReQL.

If the given user or item does not exists in the system yet (for example because the item catalog is updated periodically only once a day) the default behavior is to return an error (HTTP 404). If you rather want to always get some recommendations use cascadeCreate=true - if the given item does not exist, recommender will create the item and for example return some bestsellers. Other useful settings include for example parameters for rotating the given recommendations (important especially when generating periodical email recommendations).

Managing item catalog

So far we have learned how to send interactions and get recommendations, that are based on those interactions. It should work pretty well, especially if there is a lot of traffic and therefore a lot of interactions. But it still can be improved! Very helpful is sending information about the items (e.g., names, descriptions, categories) to the system.

The quality of recommendations should rise mainly for items with few interactions (for example newly added items). Sent data about items can be also used for filtering and boosting recommendation results with the Introduction to ReQL.

Adding item properties

Firstly you have to define properties of items that you want to submit to the system. Setting an item property is somehow equivalent to adding a column to the table of items, so you can later assign a concrete value of the property to each item. The properties may be of various types:

  • string
  • int - integer number
  • double - floating point number
  • boolean
  • timestamp - UTC timestamp
  • set - a set of strings

For example setting an item property that will hold description of an item is done by the following request:

PUT /myDb/items/properties/description?type=string
client.send(AddItemProperty.new('description', 'string'))
client.send(new AddItemProperty("description", "string"));
client.send(AddItemProperty('description', 'string'))
<?php
$client -> send(new Reqs\AddItemProperty("description", "string"));
?>
client.Send(new AddItemProperty("description", "string"));
client.send(new rqs.AddItemProperty('description', 'string'),
    (err, response) => {
    //...
    }
);

And here is few more examples of creating item properties:

PUT /myDb/items/properties/title?type=string
PUT /myDb/items/properties/price?type=double
PUT /myDb/items/properties/categories?type=set
PUT /myDb/items/properties/deleted?type=boolean
client.send(AddItemProperty.new('title', 'string'))
client.send(AddItemProperty.new('price', 'double'))
client.send(AddItemProperty.new('categories', 'set'))
client.send(AddItemProperty.new('deleted', 'boolean'))
client.send(new AddItemProperty("title", "string"));
client.send(new AddItemProperty("price", "double"));
client.send(new AddItemProperty("categories", "set"));
client.send(new AddItemProperty("deleted", "boolean"));
client.send(AddItemProperty('title', 'string'))
client.send(AddItemProperty('price', 'double'))
client.send(AddItemProperty('categories', 'set'))
client.send(AddItemProperty('deleted', 'boolean'))
<?php
$client -> send(new Reqs\AddItemProperty("title", "string"));
$client -> send(new Reqs\AddItemProperty("price", "double"));
$client -> send(new Reqs\AddItemProperty("categories", "set"));
$client -> send(new Reqs\AddItemProperty("deleted", "boolean"));
?>
client.Send(new AddItemProperty("title", "string"));
client.Send(new AddItemProperty("price", "double"));
client.Send(new AddItemProperty("categories", "set"));
client.Send(new AddItemProperty("deleted", "boolean"));
client.send(new rqs.AddItemProperty('title', 'string'))
.then((response) => {
    return client.send(new rqs.AddItemProperty('price', 'double'));
})
.then((response) => {
    return client.send(new rqs.AddItemProperty('categories', 'set'));
})
.then((response) => {
    return client.send(new rqs.AddItemProperty('deleted', 'boolean'));
})
.catch((error) => {
    // ...
});

The default value of the created properties is null.

Sending item values

Suppose we have created all the properties from preceding example. Now we can set the values of these properties for a particular item xyz. It is done by following request:

POST /myDb/items/xyz HTTP/1.0
Host: rapi.recombee.com
Content-type: application/json

Body:
{
  "title": "Television TV2305",
  "description": "HD resolution LED TV",
  "price": 200,
  "categories": ["Electronics", "Televisions"],
  "deleted": false,
  "!cascadeCreate": true
}
client.send(SetItemValues.new('xyz',
  # values
  {
     'title' => 'Television TV2305',
     'description' => 'HD resolution LED TV',
     'price' => 200,
     'categories' => ['Electronics', 'Televisions'],
     'deleted' => false
  },
  # optional parameters
  {
    'cascadeCreate' => true
  }
  ))
client.send(new SetItemValues("xyz",
            new HashMap<String, Object>() {{
                put("title", "Television TV2305");
                put("description","HD resolution LED TV");
                put("price", 200);
                put("categories", new String[]{"Electronics", "Televisions"});
                put("deleted", false);
            }}
        ).setCascadeCreate(true));
client.send(SetItemValues('xyz',
    {
      "title": "Television TV2305",
      "description": "HD resolution LED TV",
      "price": 200,
      "categories": ["Electronics", "Televisions"],
      "deleted": False
    },
    cascade_create=True
))
<?php
$client -> send(new Reqs\SetItemValues("xyz",
    // values
    [
      "title" => "Television TV2305",
      "description" => "HD resolution LED TV",
      "price" => 200,
      "categories" => ["Electronics", "Televisions"],
      "deleted" => false
    ],
    //optional parameters
    [
      "cascadeCreate" => true
    ]
));
?>
client.Send(new SetItemValues("xyz",
    new Dictionary<string, object>() {
        {"title", "Television TV2305"},
        {"description","HD resolution LED TV"},
        {"price", 200},
        {"categories", new string[] {"Electronics", "Televisions"}},
        {"deleted", false}
    },
    cascadeCreate: true
));
client.send(new rqs.SetItemValues('xyz',
    // values
    {
     title: 'Television TV2305',
     description: 'HD resolution LED TV',
     price: 200,
     categories: ['Electronics', 'Televisions'],
     deleted: false
    },
    // optional parameters
    {
    cascadeCreate: true
    }
    ),
    (err, response) => {
        //...
    }
);

The cascadeCreate indicates that the item of the given itemId should be created if it does not exist in the database.

You can check that the values have been successfully set in the graphical user interface.

Sending a whole large catalog via single requests may be quite slow – batch requests should be used for much faster execution.

Filtering

Submitted properties can be used in filtering and boosting. For example getting recommendations consisting only of items which are not deleted and belong to category Electronics can be done with filter not 'deleted' and "Electronics" in 'categories'.

GET /myDb/users/2c169e575644d840838e/recomms/?count=5&filter=not%20%27deleted%27%20and%20%22Electronics%22%20in%20%27categories%27
recommended = client.send(UserBasedRecommendation.new('2c169e575644d840838e', 5,
                            'filter' => "not 'deleted' and \"Electronics\" in 'categories'" ))
Recommendation[] recommended = client.send(new UserBasedRecommendation("2c169e575644d840838e", 5)
                                .setFilter("not 'deleted' and \"Electronics\" in 'categories'"));
recommended = client.send(UserBasedRecommendation('2c169e575644d840838e', 5,
                            filter="not 'deleted' and \"Electronics\" in 'categories'"))
<?php
$recommended = $client -> send(new Reqs\UserBasedRecommendation("2c169e575644d840838e", 5,
                            ["filter" => "not 'deleted' and \"Electronics\" in 'categories'"]));
?>
var recommended = client.Send(new UserBasedRecommendation("2c169e575644d840838e", 5, filter: "not 'deleted' and \"Electronics\" in 'categories'"));
client.send(new rqs.UserBasedRecommendation('2c169e575644d840838e', 5,
                {filter: "not 'deleted' and \"Electronics\" in 'categories'",
                 rotationRate: 0}),
    (err, recommendations) => {
        //...
    }
);