IMPORTANT NOTE: Please keep in mind that due to network failures or other unexpected issues an error may occur while getting the recommendation from or while adding events to the recommendation engine. This error can cause a program exception which always has to be handled in the proper way. Without handling the possible exceptions your code may terminate at an unexpected place and your site will operate abnormally. Even if you do not get a valid list of recommended items as a result of the recommendation request take care about hiding the recommendation widget or filling it with relevant items. Please ensure the safe error handling. Gravity does not take any responsibility for any damages caused by the lack or deficiency of error handling

๐Ÿšง

Each website has their own kind of items, with their own metadata and their own type of events. Please consult with your integration engineer about what applies to your case, and tailor the parameters described here as such.


A full PHP documentation is available as well.

Client setup

  1. Download our PHP client and add it to your site.
  2. For new integrations PHP 7+ use GravityClient php7-client. Related PHP Package Repository is here, use beta. There is no tag (tagged version) in repository, as it was never officially released. However composer should be able to pull it when allowed to use non stable deps (set: "minimum-stability": "dev").
  3. The standard PHP client should NOT be used in new integrations. Only if you have something legacy pre PHP 7.
  4. The recommendation engine accessed by a GravityClient object. The client configuration parameters like the URL of the recommendation engine, the user name and password were set by a GravityClientConfig object.

To create a GravityClient object would look like the following:

function createGravityClient() {
    $config = new GravityClientConfig();
    $config->remoteUrl = 'https://<CUSTOMERID>-<SERVERLOCATION>.gravityrd-services.com/grrec-<CUSTOMERID>-war/WebshopServlet';
    $config->user = 'CustomersUserName';
    $config->password = 'CustomersPassword';
    return new GravityClient($config);
}

Add events

Each website has its own subset of valid event types. Here is the list of recommended event types that our system accepts. Event types that you must integrate are part of the integration document. Each event has data fields, which usually have to be filled with the appropriate value. Event fields are the following:

Field nameDescription
eventTypeThe type of the event specifies the user action that triggered the event.
userIdThe identifier of the user whose action is logged
itemIdThe identifier of the item related to the users action.
timeThe UNIX timestamp of the event in seconds.
recommendationIdThis has to be filled if the action is related to a recommendation got from the recommendation engine. The recommendation id is always passed along the list of recommended items.
cookieIdTo be able to identify guest users or registered users who are not logged in we always require to set the cookie id for every event.

Additional informations are stored in name-values. The set of name-values are not predefined we only have a list of recommended name-values for the various event types but new name-values can be defined by our customers as well.

The call of add event would look like the following:

$event = new GravityEvent();
// the type identifier of the event
$event->eventType = 'BUY';
// the unique item identifier
$event->itemId = 'IdOfTheBoughtBook';
// the unique user identifier
$event->userId = 'testUser1';
// the unique cookie id which should be the same for one specific user all the time
$event->cookieId = 'abcdef123456789';
// the time when the user actually bought the book
$event->time = time();
    
// NameValue for reporting the actual price of the book.
// The value can be a floating point number but in decimal representation.
$unitPrice = new GravityNameValue("unitPrice","60.5");
// The quantity is greater then 1 only if the user bought multiple times the same book.
$quantity = new GravityNameValue("quantity","1");
// The OrderId is for identifying the shopping cart.
// It's used to connect the books bought together.
$orderId = new GravityNameValue("orderId","order_123456789");
    
// Setting the events NameValues.
$event->nameValues = array($unitPrice,$quantity,$orderId);
    
// Collecting the events and calling the remote method.
$eventsToAdd = array($event);
$async = false;
try {
    $client->addEvents($eventsToAdd, $async);
} catch (GravityException $e) {
    printf("Error happened by sending the event! <br />");
    printf("Message: $e->getMessage() Fault info: $e->faultInfo <br />");
}

๐Ÿ“˜

addEvents(...) can be called in asynchronous and synchronous way. We suggest to use asynchronous call.
With asynchronous call you'll get shorter response times specially while adding multiple events at the same time.
The synchronous call is slower but it ensures that the sent events are added to the recommendation engine's database or it reports an error otherwise.

๐Ÿ“˜

recommendationId is for passing the id of the recommendation which resulted that the users action (e.g. the user bought a book from the 'Recommended for you' box).

๐Ÿ“˜

Testing if everything were saved: It is possible to check if all the events and its name-values were saved. You only have to log in into the Control panel and you can browse the stored information on the event page.

Add or update items

The concept of items is defined here. Below it's how to add/update items programmatically via PHP calls. You should also set all of the item parameters in case of an update.

$item = new GravityItem();
$item->itemId = '123';
$item->title = 'Nokia';
$item->hidden = false;
$item->nameValues = array(new GravityNameValue('price', '2000'),
                          new GravityNameValue('categoryId', '105'),
                          new GravityNameValue('screenSize', '4.7'));
$isAsync = true;
try {
    $client->addItem($item, $isAsync);
} catch (GravityException $e) {
    printf("Error happened by adding item! <br />");
    printf("Message: $e->getMessage() Fault info: $e->faultInfo <br />");
}

Delete items

The concept of items is defined here. Below it's how to delete items programmatically via PHP calls. Deletion can be also done by using addItems function but the hidden parameter should be set to true. You should also set all of the item paramaters in case of a deletion.

$item = new GravityItem();
$item->itemId = '123';
$item->title = 'Nokia';
$item->hidden = true;
$item->nameValues = array(new GravityNameValue('price', '2000'),
                          new GravityNameValue('categoryId', '105'),
                          new GravityNameValue('screenSize', '4.7'));
$isAsync = true;
try {
    $client->addItem($item, $isAsync);
} catch (GravityException $e) {
    printf("Error happened by adding item! <br />");
    printf("Message: $e->getMessage() Fault info: $e->faultInfo <br />");
}

Add or update users

$user = new GravityUser();
$user->userId = '123';
$user->hidden = false;
$user->nameValues = array(new GravityNameValue('gender', 'male'),
                          new GravityNameValue('zip', '213324'),
                          new GravityNameValue('country', 'Germany'));
try {
    $client->addUser($user, true);
} catch (GravityException $e) {
    printf("Error happened by adding user! <br />");
    printf("Message: $e->getMessage() Fault info: $e->faultInfo <br />");
}

Get item recommendation

๐Ÿšง

IMPORTANT NOTE:

Please keep in mind that trough network error or through other unexpected issues may an error occurs while getting the recommendation from or while adding events to the recommendation engine. This error can cause a program exception which always has to be handled in the proper way. Without handling the possible exceptions your code may terminate at an unexpected place and your site will operate abnormally. Even if you do not get a valid list of recommended items as a result of the recommendation request take care about hiding the recommendation widget or filling it with relevant items. Please ensure the safe error handling. Gravity does not take any responsibility for any damages caused by the lack or deficiency of error handling

๐Ÿšง

No rendering is done by the recommendation engine, it provides only raw data. We ensure short answer time for the recommendation requests, nevertheless asynchronous rendering is recommended.

The output of the recommendation engine is a list of items, and may be acquire via the GravityClient object.

// the unique user identifier
$userId = "testUser1";
// the unique cookie id
$cookieId = "abcdef123456789";
    
// the context of the recommendation is represented by a complex object
$recommendationContext = new GravityRecommendationContext();
// Scenario id is indicating that the recommended items will be displayed
// on the main page and it uses personalized recommendation logic.
$recommendationContext->scenarioId = "MAIN_PAGE_PERSONAL";
// the number of recommended items
$recommendationContext->numberLimit = 10;
// the time of the recommendation is requested for
$recommendationContext->recommendationTime = time();
    
// requesting the recommendation
$itemRecommendation = null;
try {
    $itemRecommendation =
            $client->getItemRecommendation($userId, $cookieId, $recommendationContext);
} catch (GravityException $e) {
    printf("Error happened by getting the item recommendation! <br />");
    printf("Message: $e->getMessage() Fault info: $e->faultInfo <br />");
}
    
// iterating through the returned items
if ($itemRecommendation != null) {
    $count = 0;
    foreach ($itemRecommendation->itemIds as $itemId) {
        $count++;
        printf($count . ". recommended item is: $itemId <br />");
    }
}

By parameterizing the GravityRecommendationContext object there are several possibilities to customize what item metadata information (and how many) is returned in the answer GravityItemRecommendation object.

General use cases

Similar item recommendations

If you want display recommendations on the item details pages the identifier of the item the page is about has to be set beside setting the appropriate scenarioId:

// Scenario id is indicating that the recommended items will be displayed
// on the item details page.
$recommendationContext->scenarioId = "ITEM_PAGE";
// Setting the id of the item the details page is about.
$pageItemId = new GravityNameValue("currentItemId","ItemID_9999999");
$recommendationContext->nameValues = array($pageItemId);

In this case the current item will be considered while generating the recommendation.

Filter items already displayed on page

Usually it is not desired to show the same item multiple times on the same screen. To force the recommendation engine not to recommend items already visible on the page you have to pass their identifiers along the recommendation request:

// array containing the ids of items displayed on the page
$pageItemIds = array("item1", "item2", "...");
// creating the appropriate NameValues and adding them to the recommendation context
$recommendationContext->nameValues = array();
foreach ($pageItemIds as $itemId) {
    $recommendationContext->nameValues[] = new GravityNameValue("itemOnPage",$itemId);
}

If you have multiple Gravity recommendations on a single page then we suggest to use the getItemRecommendationBulk function which handles the filtering for the already recommended items.

Filter items from recommendation

The items can be filtered based of meta data attached to them. The filtering is controlled with name-value. In the next example we only allow books indicated as "new" to be recommended. This example works only if the item catalog contains a name-value with name "isNew" and with possible values "0" or "1".

// for filtering the recommended items a NameValue starting with "filter." has to be set
$filter = new GravityNameValue("filter.isNew","1");
$recommendationContext->nameValues = array($filter);

Specify item metadata to return with recommendations

If you need some more information about the recommended items as its identifiers it can be included into the GravityItemRecommendation if the requested information was contained in the item catalog and it was requested in the GravityRecommendationContext context.

For example if its hard for the bookstore to generate the URL for the cover image of the recommended books it can be requested in the GravityRecommendationContext:

// setting the NameValues which has to be contained in the answer
$recommendationContext->resultNameValues[] = "imageUrl";
   
// requesting the recommendation
$itemRecommendation = null;
try {
    $itemRecommendation =
            $client->getItemRecommendation($userId, $cookieId, $recommendationContext);
} catch (GravityException $e) {
    printf("Error happened by getting the item recommendation! <br />");
    printf("Message: $e->getMessage() Fault info: $e->faultInfo <br />");
}
    
// reading the recommended items with the imageUrl-s
if ($itemRecommendation != null) {
    foreach ($itemRecommendation->items as $item) {
        $imageUrl = "";
        $itemNameValues = $item->nameValues;
        foreach ($itemNameValues as $itemNameValue) {
            if ("imageUrl" == $itemNameValue->name) {
                $imageUrl = $itemNameValue->value;
            }
        }
        printf("ItemId: $item->itemId ImageUrl: $imageUrl <br />");
    }
}

Personalized search results

For personalized search results you should set up the search keywords (searchString) and the filtering parameters, such as filter.categoryId. The pagingOffset paramater can be used for set up the offset for paging.

// scenarioId is indicating that the recommendation is used for search result ordering
$recommendationContext->scenarioId = "SEARCH_RESULT";
// the number of items listed in the search result
$recommendationContext->numberLimit = 50;
// the offset of the paging
$pagingOffset = new GravityNameValue("pagingOffset","0");
// the keywords in the search query
$searchString = new GravityNameValue("searchString","laptop bag");
// the current categoryId used for filtering the results
$filterCategoryId = new GravityNameValue("filter.categoryId","3456");
$recommendationContext->nameValues = array($pagingOffset, $searchString, $filterCategoryId);

Get bulk item recommendation

๐Ÿšง

No rendering is done by the recommendation engine, it provides only raw data. We ensure short answer time for the recommendation requests, nevertheless asynchronous rendering is recommended.

The bulk item recommendation can be used if more than one recommendation box is appered on one page. By using this we can filter out the result of the first recommendation from the second recommendation result.

// the unique user identifier
$userId = "testUser1";
// the unique cookie id
$cookieId = "abcdef123456789";
  
// the context of the first (personalized) recommendation
$recommendationContextPers = new GravityRecommendationContext();
// Scenario id is indicating that the recommended items will be displayed
// on the main page and it uses personalized recommendation logic.
$recommendationContextPers->scenarioId = "MAIN_PAGE_PERSONAL";
// the number of recommended items
$recommendationContextPers->numberLimit = 10;
// the time of the recommendation is requested for
$recommendationContextPers->recommendationTime = time();
// the context of the second (popular items) recommendation
$recommendationContextPop = new GravityRecommendationContext();
// Scenario id is indicating that the recommended items will be displayed
// on the main page and it uses personalized recommendation logic.
$recommendationContextPop->scenarioId = "MAIN_PAGE_POPULAR";
// the number of recommended items
$recommendationContextPop->numberLimit = 5;
// the time of the recommendation is requested for
$recommendationContextPop->recommendationTime = time();
  
  
   
// the recommendation context array
$recommendationContextArray = array(
    0 => $recommendationContextPers,
    1 => $recommendationContextPop
);
   
// requesting the recommendation
$itemRecommendations = null;
try {
    $itemRecommendations = $client->getItemRecommendationBulk($userId, $cookieId, $recommendationContextArray );
} catch (GravityException $e) {
    printf("Error happened by getting the item recommendation! <br />");
    printf("Message: $e->getMessage() Fault info: $e->faultInfo <br />");
}
// iterating through the returned items
if ($itemRecommendations != null) {
    foreach ($itemRecommendations as $itemRecommendation) {
        $count = 0;
        printf("recommendationId: ");
        printf($itemRecommendation->recommendationId);
  
        foreach ($itemRecommendation->itemIds as $itemId) {
            $count++;
            printf($count . ". recommended item is: $itemId <br />");
        }
    }
}

Privacy-related

Query user metadata

try {
    $user=$client->getUserByUserId("119123");
    print("UserId:".$user->userId."<br/>");
    print("nameValues: <br/>");
    foreach ($user->nameValues as $nameValue ) {
        print(" ".$nameValue->name. " : ".$nameValue->value."<br/>");
    }
} catch (GravityRecEngException $e) {
    printf("Error happened by getting the user metadata! <br/>");
    printf("Message: $e->getMessage() Fault info: $e->faultInfo <br/>");
}

or by cookieId:

try {
    $user=$client->getUserByCookieId("119123");
    print("CookieId:".$user->cookieId."<br/>");
    print("nameValues: <br/>");
    foreach ($user->nameValues as $nameValue ) {
      print("  ".$nameValue->name. " : ".$nameValue->value."<br/>");
    }
} catch (GravityRecEngException $e) {
    printf("Error happened by getting the user metadata! <br/>");
    printf("Message: $e->getMessage() Fault info: $e->faultInfo <br/>");
} 

Query event history

$limit=100; // limit upper limit for returned events. If 0 or negative a default limit will be used
try {
    $events=$client->getEventsByUserId("123456",$limit);
    foreach ($events as $event) {
      print("eventType: $event->eventType itemId: $event->itemId time:  ");
      print(gmdate('Y-m-d H:i:s', $event->time));
      print("<br/>");
  }
} catch (GravityRecEngException $e) {
    printf("Error happened by getting the user events! <br/>");
    printf("Message: $e->getMessage() Fault info: $e->faultInfo <br/>");
} 

or by cookieId:

$limit=100; // limit upper limit for returned events. If 0 or negative a default limit will be used
try {
    $events=$client->getEventsByCookieId("5afaa23bac-acacac323232",$limit);
    foreach ($events as $event) {
      print("eventType: $event->eventType itemId: $event->itemId time:  ");
      print(gmdate('Y-m-d H:i:s', $event->time));
      print("<br/>");
  }
} catch (GravityRecEngException $e) {
    printf("Error happened by getting the user events! <br/>");
    printf("Message: $e->getMessage() Fault info: $e->faultInfo <br/>");
}

Delete full event history

try {
    $client->optOutCookie("5afaa23bac-acacac323232");
} catch (GravityRecEngException $e) {
    printf("Error happened by deleting the event history");
    printf("Message: $e->getMessage() Fault info: $e->faultInfo <br/>");
}

Delete full user metadata and event history

try {
    $client->optOutUser("1234567");
} catch (GravityRecEngException $e) {
    printf("Error happened by deleting the event history and user metadata!");
    printf("Message: $e->getMessage() Fault info: $e->faultInfo <br/>");
}