

# Recording real-time item interaction events
<a name="recording-item-interaction-events"></a>

 An *item interaction event* is an interaction between a user and an item in your catalog. For example, a user purchasing shoes or watching movie.

Record real-time item interaction events as you show your customer item recommendations. This builds out your interactions data and keeps your data fresh. And it tells Amazon Personalize about the current interests of your user, which can improve recommendation relevance. 

 You record item interaction events with the [PutEvents](API_UBS_PutEvents.md) API operation. Amazon Personalize appends the event data to the *Item interactions dataset* in your dataset group. If you record two events with exactly the same timestamp and identical properties, Amazon Personalize keeps only one of the events. You can record item interaction events using the AWS SDKs, AWS Amplify, or AWS Command Line Interface (AWS CLI). 

If you use Apache Kafka, you can use the *Kafka connector for Amazon Personalize* to stream item interactions in real time to Amazon Personalize. For information see [Kafka Connector for Amazon Personalize ](https://github.com/aws/personalize-kafka-connector/blob/main/README.md) in the *personalize-kafka-connector* Github repository.

 AWS Amplify includes a JavaScript library for recording item interaction events from web client applications, and a library for recording events in server code. For more information, see [Amplify documentation](https://docs.amplify.aws/). 

**Topics**
+ [Requirements for recording item interaction events and training a model](#recording-events-requirements)
+ [Creating an item interaction event tracker](event-get-tracker.md)
+ [Recording a single item interaction event](putevents-example.md)
+ [Recording multiple item interaction events with event value data](recording-events-example-event-value.md)
+ [Recording item interaction events with impressions data](putevents-including-impressions-data.md)
+ [Event metrics and attribution reports](event-metrics.md)

## Requirements for recording item interaction events and training a model
<a name="recording-events-requirements"></a>

To record item interaction events, you need the following:
+ A dataset group that includes an `Item interactions` dataset, which can be empty. If you went through the [Getting started tutorials](getting-started.md) guide, you can use the same dataset group and dataset that you created. For information on creating a dataset group and a dataset, see [Importing training data into Amazon Personalize datasets](import-data.md).
+ An event tracker.
+ A call to the [PutEvents](API_UBS_PutEvents.md) API operation.
+  If you use an AWS Lambda function to call the PutEvents operation, your function's execution role must have permission to perform the `personalize:PutEvents` action with the wildcard `*` in the `Resource` element. 

You can start out with an empty Item interactions dataset and, when you have recorded enough data, train the model using only new recorded events. For all use cases (Domain dataset groups) and recipes (Custom dataset groups), your interactions data must have the following before training: 
+ At minimum 1000 item interactions records from users interacting with items in your catalog. These interactions can be from bulk imports, or streamed events, or both.
+ At minimum 25 unique user IDs with at least two item interactions for each.

For quality recommendations, we recommend that you have at minimum 50,000 item interactions from at least 1,000 users with two or more item interactions each.

# Creating an item interaction event tracker
<a name="event-get-tracker"></a>

Before you can record item interaction events, you must create an item interaction event tracker. An *event tracker* directs new event data to the *Item interactions dataset* in your dataset group. 

You create an event tracker with the Amazon Personalize console or the [CreateEventTracker](API_CreateEventTracker.md) API operation. You pass as a parameter the Amazon Resource Name (ARN) of the dataset group that contains the target Item interactions dataset. For instructions on creating an event tracker using the Amazon Personalize console, see [Creating an event tracker (console)](importing-interactions.md#event-tracker-console). 

 An event tracker includes a *tracking ID*, which you pass as a parameter when you use the [PutEvents](https://docs.aws.amazon.com/personalize/latest/dg/API_UBS_PutEvents.html) operation. Amazon Personalize then appends the new event data to the Item interactions dataset of the dataset group you specify in your event tracker. 

**Note**  
You can create only one item interaction event tracker for a dataset group.

------
#### [ Python ]

```
import boto3

personalize = boto3.client('personalize')

response = personalize.create_event_tracker(
    name='MovieClickTracker',
    datasetGroupArn='arn:aws:personalize:us-west-2:acct-id:dataset-group/MovieClickGroup'
)
print(response['eventTrackerArn'])
print(response['trackingId'])
```

The event tracker ARN and tracking ID display, for example:

```
{
    "eventTrackerArn": "arn:aws:personalize:us-west-2:acct-id:event-tracker/MovieClickTracker",
    "trackingId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
```

------
#### [ AWS CLI ]

```
aws personalize create-event-tracker \
    --name MovieClickTracker \
    --dataset-group-arn arn:aws:personalize:us-west-2:acct-id:dataset-group/MovieClickGroup
```

The event tracker ARN and tracking ID display, for example:

```
{
    "eventTrackerArn": "arn:aws:personalize:us-west-2:acct-id:event-tracker/MovieClickTracker",
    "trackingId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
```

------
#### [ SDK for JavaScript v3 ]

```
// Get service clients module and commands using ES6 syntax.
import { CreateEventTrackerCommand } from "@aws-sdk/client-personalize";
import { personalizeClient } from "./libs/personalizeClients.js";

// Or, create the client here.
// const personalizeClient = new PersonalizeClient({ region: "REGION"});

// Set the event tracker's parameters.
export const createEventTrackerParam = {
  datasetGroupArn: "DATASET_GROUP_ARN" /* required */,
  name: "NAME" /* required */,
};

export const run = async () => {
  try {
    const response = await personalizeClient.send(
      new CreateEventTrackerCommand(createEventTrackerParam),
    );
    console.log("Success", response);
    return response; // For unit tests.
  } catch (err) {
    console.log("Error", err);
  }
};
run();
```

------
#### [ SDK for Java 2.x ]

```
public static String createEventTracker(PersonalizeClient personalizeClient, 
                                      String eventTrackerName, 
                                      String datasetGroupArn) {
        
    String eventTrackerId = null;
    String eventTrackerArn = null;
    long maxTime = 3 * 60 * 60; 
    long waitInMilliseconds = 30 * 1000;
    String status;
    
    try {
        CreateEventTrackerRequest createEventTrackerRequest = CreateEventTrackerRequest.builder()
            .name(eventTrackerName)
            .datasetGroupArn(datasetGroupArn)
            .build();
       
        CreateEventTrackerResponse createEventTrackerResponse = 
            personalizeClient.createEventTracker(createEventTrackerRequest);
        
        eventTrackerArn = createEventTrackerResponse.eventTrackerArn();
        eventTrackerId = createEventTrackerResponse.trackingId();
        
        System.out.println("Event tracker ARN: " + eventTrackerArn);
        System.out.println("Event tracker ID: " + eventTrackerId);

        maxTime = Instant.now().getEpochSecond() + maxTime;

        DescribeEventTrackerRequest describeRequest = DescribeEventTrackerRequest.builder()
            .eventTrackerArn(eventTrackerArn)
            .build();
        
        while (Instant.now().getEpochSecond() < maxTime) {

            status = personalizeClient.describeEventTracker(describeRequest).eventTracker().status();
            System.out.println("EventTracker status: " + status);

            if (status.equals("ACTIVE") || status.equals("CREATE FAILED")) {
                break;
            }
            try {
                Thread.sleep(waitInMilliseconds);
            } catch (InterruptedException e) {
                System.out.println(e.getMessage());
            }
        }
        return eventTrackerId;
    }
    catch (PersonalizeException e){
        System.out.println(e.awsErrorDetails().errorMessage());
        System.exit(1);
    }
    return eventTrackerId;
}
```

------

# Recording a single item interaction event
<a name="putevents-example"></a>

After you create an *Item interactions dataset* and an [event tracker](event-get-tracker.md) for your dataset group, you are ready to record item interaction events. The following example shows a `PutEvents` operation that passes one item interaction event. The corresponding schema is shown, along with an example row from the Item interactions dataset.

 Your application generates a unique `sessionId` when a user first visits your website or uses your application. You must use the same `sessionId` in all events throughout the session. Amazon Personalize uses the `sessionId` to associate events with the user before they log in (is anonymous). For more information, see [Recording events for anonymous users](recording-events.md#recording-anonymous-user-events).

The event list is an array of [Event](API_UBS_Event.md) objects. An `eventType` is required for each event. If you don't have event type data, you can provide a placeholder value to satisfy the requirement. 

The `trackingId` comes from the event tracker you created in [Creating an item interaction event tracker](event-get-tracker.md). The `userId`, `itemId`, and `sentAt` parameters map to the USER\$1ID, ITEM\$1ID, and TIMESTAMP fields of a corresponding historical `Interactions` dataset. For more information, see [Creating schema JSON files for Amazon Personalize schemas](how-it-works-dataset-schema.md).

**Corresponding dataset columns**

```
Dataset columns: USER_ID, ITEM_ID, TIMESTAMP, EVENT_TYPE
Example data: user123, item-xyz, 1543631760, click
```

**Code example**

------
#### [ SDK for Python (Boto3) ]

```
import boto3

personalize_events = boto3.client(service_name='personalize-events')

personalize_events.put_events(
    trackingId = 'tracking_id',
    userId= 'USER_ID',
    sessionId = 'session_id',
    eventList = [{
        'sentAt': 1719511760,
        'eventType': 'click',
        'itemId': 'ITEM_ID'
        }]
)
```

------
#### [ SDK for JavaScript v3 ]

```
// Get service clients module and commands using ES6 syntax.
import { PutEventsCommand } from "@aws-sdk/client-personalize-events";
import { personalizeEventsClient } from "./libs/personalizeClients.js";
// Or, create the client here.
// const personalizeEventsClient = new PersonalizeEventsClient({ region: "REGION"});

// Convert your UNIX timestamp to a Date.
const sentAtDate = new Date(1613443801 * 1000); // 1613443801 is a testing value. Replace it with your sentAt timestamp in UNIX format.

// Set put events parameters.
const putEventsParam = {
  eventList: [
    /* required */
    {
      eventType: "EVENT_TYPE" /* required */,
      sentAt: sentAtDate /* required, must be a Date with js */,
      eventId: "EVENT_ID" /* optional */,
      itemId: "ITEM_ID" /* optional */,
    },
  ],
  sessionId: "SESSION_ID" /* required */,
  trackingId: "TRACKING_ID" /* required */,
  userId: "USER_ID" /* required */,
};
export const run = async () => {
  try {
    const response = await personalizeEventsClient.send(
      new PutEventsCommand(putEventsParam),
    );
    console.log("Success!", response);
    return response; // For unit tests.
  } catch (err) {
    console.log("Error", err);
  }
};
run();
```

------
#### [ AWS CLI ]

```
aws personalize-events put-events \
    --tracking-id tracking_id \
    --user-id USER_ID \
    --session-id session_id \
    --event-list '[{
        "sentAt": 1719511760,
        "eventType": "click",
        "itemId": "ITEM_ID"
      }]'
```

------
#### [ SDK for Java 2.x ]

```
public static void putEvents(PersonalizeEventsClient personalizeEventsClient, 
                            String trackingId, 
                            String sessionId, 
                            String userId, 
                            String itemId,
                            String eventType) {
    
    try { 
        Event event = Event.builder()
            .sentAt(Instant.ofEpochMilli(System.currentTimeMillis() + 10 * 60 * 1000))
            .itemId(itemId)
            .eventType(eventType)
            .build();

        PutEventsRequest putEventsRequest = PutEventsRequest.builder()
            .trackingId(trackingId)
            .userId(userId)
            .sessionId(sessionId)
            .eventList(event)
            .build();

        int responseCode = personalizeEventsClient.putEvents(putEventsRequest)
            .sdkHttpResponse()
            .statusCode();
        System.out.println("Response code: " + responseCode);

        } catch (PersonalizeEventsException e) {
            System.out.println(e.awsErrorDetails().errorMessage());
        }
}
```

------

# Recording multiple item interaction events with event value data
<a name="recording-events-example-event-value"></a>

After you create an *Item interactions dataset* and an [event tracker](event-get-tracker.md) for your dataset group, you are ready to record item interaction events. The following example shows how to record multiple item interaction events with different event types and different event values.

 When you configure a solution, if your *Item interactions dataset* includes EVENT\$1TYPE and EVENT\$1VALUE fields, you can set a specific value as a threshold to exclude records from training. For more information, see [Choosing the item interaction data used for training](event-values-types.md). 

------
#### [ Python ]

```
import boto3
import json

personalize_events = boto3.client(service_name='personalize-events')

personalize_events.put_events(
    trackingId = 'tracking_id',
    userId= 'user555',
    sessionId = 'session1',
    eventList = [{
        'eventId': 'event1',
        'sentAt': 1553631760,
        'eventType': 'like',
        'properties': json.dumps({
            'itemId': 'choc-panama',
            'eventValue': 4
            })
        }, {
        'eventId': 'event2',
        'sentAt': 1553631782,
        'eventType': 'rating',
        'properties': json.dumps({
            'itemId': 'movie_ten',
            'eventValue': 3
            })
        }]
)
```

------
#### [ AWS CLI ]

```
aws personalize-events put-events \
    --tracking-id tracking_id \
    --user-id user555 \
    --session-id session1 \
    --event-list '[{
        "eventId": "event1",
        "sentAt": 1553631760,
        "eventType": "like",
        "properties": "{\"itemId\": \"choc-panama\", \"eventValue\": \"true\"}"
      }, {
        "eventId": "event2",
        "sentAt": 1553631782,
        "eventType": "rating",
        "properties": "{\"itemId\": \"movie_ten\", \"eventValue\": \"4\", \"numRatings\": \"13\"}"
      }]'
```

------
#### [ SDK for Java 2.x ]

```
public static void putMultipleEvents(PersonalizeEventsClient personalizeEventsClient, 
                            String trackingId, 
                            String sessionId, 
                            String userId, 
                            String event1Type, 
                            Float event1Value, 
                            String event1ItemId,
                            int event1NumRatings,
                            String event2Type, 
                            Float event2Value, 
                            String event2ItemId,
                            int event2NumRatings) {  
                                                    
    ArrayList<Event> eventList = new ArrayList<Event>();
                        
    try {
        Event event1 = Event.builder()
            .eventType(event1Type)
            .sentAt(Instant.ofEpochMilli(System.currentTimeMillis() + 10 * 60 * 1000))
            .itemId(event1ItemId)
            .eventValue(event1Value)
            .properties("{\"numRatings\": "+ event1NumRatings +"}")
            .build(); 

        eventList.add(event1); 

        Event event2 = Event.builder()
            .eventType(event2Type)
            .sentAt(Instant.ofEpochMilli(System.currentTimeMillis() + 10 * 60 * 1000))
            .itemId(event2ItemId)
            .eventValue(event2Value)
            .properties("{\"numRatings\": "+ event2NumRatings +"}")
            .build();

        eventList.add(event2);

        PutEventsRequest putEventsRequest = PutEventsRequest.builder()
            .trackingId(trackingId)
            .userId(userId)
            .sessionId(sessionId)
            .eventList(eventList)
            .build();

        int responseCode = personalizeEventsClient.putEvents(putEventsRequest)
            .sdkHttpResponse()
            .statusCode();
            
        System.out.println("Response code: " + responseCode);

    } catch (PersonalizeEventsException e) {
        System.out.println(e.awsErrorDetails().errorMessage());
    }
}
```

------

**Note**  
The properties keys use camel case names that match the fields in the Interactions schema. For example, if the field 'NUM\$1RATINGS' is defined in the Interactions schema, the property key should be `numRatings`.

# Recording item interaction events with impressions data
<a name="putevents-including-impressions-data"></a>

If you use the [User-Personalization](native-recipe-new-item-USER_PERSONALIZATION.md) recipe or add the IMPRESSIONS field to your schema for a dataset in a Domain dataset group, you can record impressions data in your PutEvents operation. Impressions are lists of items that were visible to a user when they interacted with (for example, clicked or watched) a particular item. Amazon Personalize uses impressions data to guide exploration, where recommendations include items with less interactions data or relevance. For information on the *implicit* and *explicit* impressions Amazon Personalize can model, see [Impressions data](interactions-datasets.md#interactions-impressions-data). 

**Important**  
If you provide conflicting implicit and explicit impression data in your `PutEvents` requests, Amazon Personalize uses the explicit impressions by default.

To record the Amazon Personalize recommendations you show your user as impressions data, include the `recommendationId` in your [PutEvents](API_UBS_PutEvents.md) request and Amazon Personalize derives the implicit impressions based on your recommendation data.

To manually record impressions data for an event, list the impressions in the [PutEvents](API_UBS_PutEvents.md) command's `impression` input parameter. The following code sample shows how to include a `recommendationId` and an `impression` in a PutEvents operation with either the SDK for Python (Boto3) or the SDK for Java 2.x. If you include both, Amazon Personalize uses the explicit impressions by default.

------
#### [ SDK for Python (Boto3) ]

```
import boto3

personalize_events = boto3.client(service_name='personalize-events')

personalize_events.put_events(
    trackingId = 'tracking_id',
    userId= 'userId',
    sessionId = 'sessionId',
    eventList = [{
        'eventId': 'event1',
        'eventType': 'rating',
        'sentAt': 1553631760,
        'itemId': 'item id',
        'recommendationId': 'recommendation id',
        'impression': ['itemId1', 'itemId2', 'itemId3']
        }]
)
```

------
#### [ SDK for Java 2.x ]

Use the following `putEvents` method to record an event with impressions data and a recommendationId. For the impressions parameter, pass the list of itemIds as an ArrayList.

```
public static void putEvents(PersonalizeEventsClient personalizeEventsClient, 
                                String trackingId, 
                                String sessionId, 
                                String userId, 
                                String eventType, 
                                Float eventValue, 
                                String itemId,
                                ArrayList<String> impressions,
                                String recommendationId) {

    try { 
        Event event = Event.builder()
            .eventType(eventType)
            .sentAt(Instant.ofEpochMilli(System.currentTimeMillis() + 10 * 60 * 1000))
            .itemId(itemId)
            .eventValue(eventValue)
            .impression(impressions)
            .recommendationId(recommendationId)
            .build();

        PutEventsRequest putEventsRequest = PutEventsRequest.builder()
            .trackingId(trackingId)
            .userId(userId)
            .sessionId(sessionId)
            .eventList(event)
            .build();

        int responseCode = personalizeEventsClient.putEvents(putEventsRequest)
            .sdkHttpResponse()
            .statusCode();
        System.out.println("Response code: " + responseCode);

    } catch (PersonalizeEventsException e) {
        System.out.println(e.awsErrorDetails().errorMessage());
    }
}
```

------

# Event metrics and attribution reports
<a name="event-metrics"></a>

To monitor the type and number of events sent to Amazon Personalize, use Amazon CloudWatch metrics. For more information, see [Monitoring Amazon Personalize with Amazon CloudWatch](personalize-monitoring.md). 

 To generate CloudWatch reports that show the impact of recommendations, create a metric attribution and record user interactions with real-time recommendations. For information on creating a metric attribution, see [Measuring the impact of Amazon Personalize recommendations](measuring-recommendation-impact.md). 

 For each event, include recommendation ID of the recommendations you showed the user. Or include the event source, such as a third party. Import this data to compare different campaigns, recommenders, and third parties. You can import at most 100 event attribution sources. 
+  If you provide a `recommendationId`, Amazon Personalize automatically determines the source campaign or recommender and identifies it in reports in an EVENT\$1ATTRIBUTION\$1SOURCE column. 
+  If you provide both attributes, Amazon Personalize uses only the `eventAttributionSource`. 
+  If you don't provide a source, Amazon Personalize labels the source `SOURCE_NAME_UNDEFINED` in reports. 

 The following code shows how to provide an `eventAttributionSource` for an event in a PutEvents operation. 

```
response = personalize_events.put_events(
    trackingId = 'eventTrackerId',
    userId= 'userId',
    sessionId = 'sessionId123',
    eventList = [{
        'eventId': 'event1',
        'eventType': 'watch',
        'sentAt': '1667260945',
        'itemId': '123',
        'metricAttribution': { 
            'eventAttributionSource': 'thirdPartyServiceXYZ'
        }
    }]
)
statusCode = response['ResponseMetadata']['HTTPStatusCode']
print(statusCode)
```

The following code shows how to provide a `recommendationId` for an event in a PutEvents operation.

```
response = personalize_events.put_events(
    trackingId = 'eventTrackerId',
    userId= 'userId',
    sessionId = 'sessionId123',
    eventList = [{
        'eventId': 'event1',
        'eventType': 'watch',
        'sentAt': '1667260945',
        'itemId': '123',
        'recommendationId': 'RID-12345678-1234-1234-1234-abcdefghijkl'
    }]
)
statusCode = response['ResponseMetadata']['HTTPStatusCode']
print(statusCode)
```