Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions tutorials/recommendations-with-shaped-ai/conclusion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
position: 8
title: Conclusion
---

# Conclusion

In this tutorial, we have explored the **Shaped.ai** solution accelerator for feeding Shaped.ai with Snowplow data, enabling customers to update recommendations for their end-users in real-time.

We successfully have built a real-time system for processing event data including:
- Initial training data for Shaped.ai, to jump-start a base recommendation system with seminal data;
- Continuously feeding AWS Personalization recommendation engine with new data once this new data is generated in real-time.

This tutorial can be extended to utilize Snowplow event data for other real-time use cases, such as:
- Web Engagement analytics;
- Ad performance tracking.

## Next Steps
- Extend tracking: extend the solution to track more granular user interactions or track on a new platform such as mobile
- Expanding use cases: Shaped.ai can be used not just for recommendations, but also for hyperpersonalization based on customers' history
168 changes: 168 additions & 0 deletions tutorials/recommendations-with-shaped-ai/impression-integration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
---
title: Impression Integration
position: 7
---

To "close the loop" and allow Shaped.ai to improve the performance of it's recommendations, we need to feed it back information about how they perform.

We want it to know which of its recommendations actually got clicked so it can account for that in its models and optimize the performance of individual recommendations.

For this to work, we need to track the recommendation IDs and clicks of the widgets we render based on its suggestions.

To do this, we need several adjustments to what we've built so far. We need to change:

- The site tracking to track the clicks (we will also track impressions generally so we can track performance)
- The Snowbridge config to account for the click events

## Tracking Impressions

First up we update our recommendation widget snippet to track the impressions and clicks.

We will use the [Element Tracking plugin](https://github.com/snowplow/snowplow-javascript-tracker/pull/1400) to implement this.

```javascript
snowplow("addPlugin", "/cdn/shop/t/3/assets/element-tracker.umd.min.js", ["snowplowElementTracking", "SnowplowElementTrackingPlugin"]);

// set up impression tracking
snowplow("startElementTracking", {
elements: {
name: "recommendation-impression", // name our configuration something logical
selector: "[data-recommendation-id]", // selector will vary based on the widget implementation
expose: { when: "element", minPercentage: .5 }, // once per widget, only once it is 50% in view
component: true, // mark it as a component so we can get clicks
details: { dataset: ["recommendationId"] }, // extract the recommendation ID
contents: {
name: "recomendation-item",
selector: "[data-item-id]",
details: { dataset: ["itemId"] } // also extract the shown item IDs
}
}
});

// set up click tracking
snowplow("getComponentListGenerator", function (_, componentGeneratorWithDetail) {
document.addEventListener("click", function(e) {
if (e.target.closest("a") && e.target.closest("[data-recommendation-id]")) {
const target = e.target.closest("a");
const details = componentGeneratorWithDetail(target);
snowplow("trackLinkClick", { element: target, context: details });
}
}, false);
});
```

With this configuration, whenever our custom recommendations widget is in-view, we will fire an `expose_element` event like the following:

```json
{
"schema": "iglu:com.snowplowanalytics.snowplow/expose_element/jsonschema/1-0-0",
"data": {
"element_name": "recommendation-impression"
}
}
```

This event will have an `element` entity describing our widget, including the recommendation/impression ID, like so:

```json
{
"schema": "iglu:com.snowplowanalytics.snowplow/element/jsonschema/1-0-0","data": {
"element_name": "recommendation-impression",
"width": 1600,
"height": 229.4166717529297,
"position_x": 160,
"position_y": 531.5,
"doc_position_x": 160,
"doc_position_y": 3329,
"element_index": 1,
"element_matches": 1,
"originating_page_view": "3d775590-74c6-4d0a-85ee-4d63d72bda2d",
"attributes":[
{
"source": "dataset",
"attribute": "recommendationId","value": "RID-24-4a6a-8380-506b189ff622-CID-529b19"
}
]
}
}
```

And it will also contain `element_content` entities for each item in the widget, capturing their product IDs, like the following:

```json
{
"schema": "iglu:com.snowplowanalytics.snowplow/element_content/jsonschema/1-0-0",
"data": {
"element_name": "recomendation-item",
"parent_name": "recommendation-impression",
"parent_position": 1,
"position": 1,
"attributes": [
{
"source": "dataset",
"attribute": "itemId",
"value": "48538191331628"
}
]
}
}
```

In addition, if the links in the widget are clicked, we'll generate a regular `link_click` event -- but because our widget is defined as a component, it will extract the same entities as an impression and include those, too.

These `link_click` events are what we need to detect and forward to Shaped.ai.

## Snowbridge Impressions and Clicks

Now that we need to know about `link_click`, we need to include those in our filter:

```hcl
regex = "^(snowplow_ecommerce_action|action|view_item|transaction_item|create_order)$" # before

regex = "^(snowplow_ecommerce_action|action|view_item|transaction_item|create_order|link_click)$" # after
```

Our custom transform then needs to be aware of them:

```javascript
case 'link_click': // recommendation clicks
ep.Data.event_type = "Click";

const element = event.contexts_com_snowplowanalytics_snowplow_element_1 || [];
const content = event.contexts_com_snowplowanalytics_snowplow_element_content_1 || [];

if (!element.length) return SKIP_EVENT; // unrelated link_click
if (!content.length) return SKIP_EVENT; // unrelated link_click

let impressionId = null;

element.forEach((e) => {
if (e.element_name !== "recommendation-impression") return; // some other element/component
if (e.attributes) {
e.attributes.forEach((a) => {
if (a.source === "dataset" && a.attribute === "recommendationId") {
impressionId = a.value;
}
});
}
});

if (!impressionId) return SKIP_EVENT; // couldn't find impression info

const items = [];

content.forEach((ec) => {
if (ec.parent_name !== "recommendation-impression") return;
items.push(ec.attributes[0].value);
});

ep.Data.item_ids = items; // for simplicity we will pretend the first item was the clicked one
ep.Data.impression_id = impressionId;
break;
default:
return SKIP_EVENT;
```

Snowbridge will now send our clicked recommendation events to Shaped.ai.

Shaped.ai will now be able to optimize its recommendations based on how they perform.
25 changes: 25 additions & 0 deletions tutorials/recommendations-with-shaped-ai/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
title: Introduction
position: 1
---

[Shaped.ai](https://shaped.ai) is a ML-based solution to provide personalization, recommendations, and search optimization capabilities to end-users. It can use Snowplow data [to build different use cases](https://docs.shaped.ai/docs/use_cases/overview/).

Shaped.ai offers a [REST API](https://docs.shaped.ai/docs/api), as well as [SDKs for Python and JavaScript](https://docs.shaped.ai/docs/overview/install-sdk), a [CLI in Python](https://docs.shaped.ai/docs/overview/installing-shaped-cli), and a [UI/UX interface (the dashboard)](https://dashboard.shaped.ai/).

This accelerator demonstrates how Snowplow data can be used to feed Shaped.ai models. Any version of Snowplow that supports Snowbridge can be used, such as [Snowplow Local](https://github.com/snowplow-incubator/snowplow-local). For testing purposes, we recommend generating events using one of our examples that work with our out-of-the-box ecommerce events, like our [**Snowplow ecommerce store**](https://github.com/snowplow-industry-solutions/ecommerce-nextjs-example-store).

## Key technologies

* Snowplow: event tracking pipeline (Collector, Enrich, Kinesis sink)
* [Snowbridge](/docs/api-reference/snowbridge/): event forwarding module, part of Snowplow
* AWS Kinesis: message broker, set by Shaped.ai team, to receive events from Snowbridge

### Event capture and ingestion with Snowplow

- E-store front-end and Snowplow JavaScript tracker: user activity is captured as Snowplow ecommerce events
- Snowplow to Shaped.ai: the Snowplow pipeline validates the events, enriches them with device and geolocation data, then forwards them into Shaped.ai AWS Kinesis instance

## Acknowledgements

Thank you to the [Shaped.ai](https://shaped.ai) team for all the support while building this accelerator.
8 changes: 8 additions & 0 deletions tutorials/recommendations-with-shaped-ai/meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"title": "Build a recommendations system with Shaped.ai",
"label": "Solution accelerator",
"description": "Use Snowplow data to build a recommendations system with Shaped.ai.",
"useCases": ["Real-time personalization"],
"technologies": ["Shaped.ai"],
"snowplowTech": ["Snowbridge"]
}
Loading