{ "metadata": { "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.3-final" }, "orig_nbformat": 2, "kernelspec": { "name": "conda_python3", "display_name": "conda_python3" } }, "nbformat": 4, "nbformat_minor": 2, "cells": [ { "source": [ "# Omnichannel Personalization with Segment\n", "\n", "This module uses Amazon Personalize to generate and associate personalized product recommendations for users then execute an omnichannel personalization campaign using Segment. \n", "\n", "Estimated time: 30 minutes\n", "\n", "## Prerequisites\n", "\n", "The content of this workshop is presented with the assumption that you have either completed the Personalization workshop or those resources have been pre-provisioned in your AWS environment. If you are unsure and attending an AWS managed event such as a workshop, check with your event lead.\n", "\n", "This module also requires access to a Segment account with Personas provisioned. If you are unsure and attending a Segment managed event such as a workshop, check with your event lead. If you are running this workshop independently and do not have a Segment account with Personas provisioned, please contact your Segment representative or follow this link to sign up for Segment.\n", "\n", "## Segment Overview\n", "\n", "Segment is a customer data platform (CDP) that helps you collect, clean, and control your customer data. Segment provides several types of Sources which you can use to collect your data, and which you can choose from based on the needs of your app or site. For websites, you can use a javascript library to collect data. If you have a mobile app, you can embed one of Segment’s Mobile SDKs, and if you’d like to create messages directly on a server (if you have, for example a dedicated .NET server that processes payments), Segment has several server-based libraries that you can embed directly into your backend code. With Segment, you can also use cloud-sources to import data about your app or site from other tools like Zendesk or Salesforce, to enrich the data sent through Segment. By using Segment to decouple data collection from data use, you can create a centralized data supply chain based on organized and modular data.\n", "\n", "![Segment Overview](images/segment/segment_overview.png)\n" ], "cell_type": "markdown", "metadata": {} }, { "source": [ "## Setup\n", "\n", "For this exercise, we are going to start by creating a Python data source within Segment. Log in to Segment. From the Segment app home screen, click the Add Source button.\n", "\n", "![Add a source in Segment](images/segment/add_source.png)\n", "\n", "Find the Python source and click Add Source.\n", "\n", "![Add a Python source in Segment](images/segment/add_source_2.png)\n", "\n", "Once you’ve created and named the new Python Source, you will be presented with a write key:\n", "\n", "![Add a Python source in Segment](images/segment/add_source_3.png)\n", "\n", "Copy your write key into the string below, and run the next cell:" ], "cell_type": "markdown", "metadata": {} }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Enter your Segment write key here\n", "\n", "segment_write_key = 'THIS_WILL_BE_YOUR_WRITE_KEY'\n" ] }, { "source": [ "Now that we’ve configured our data collection infrastructure, we will configure Segment to allow our Python Personalize Source to feed data to Personas. Personas is a powerful personalization platform within Segment that enables you to create omni-channel customer profiles, to build and enrich audiences, and to synchronize user data and audiences across your stack. \n", "\n", "First, navigate to Personas by clicking this icon in the navbar:\n", "\n", "![Navigate to Personas](images/segment/navigate_to_personas.png)\n", "\n", "Then, since it is our first time using Personas, Segment is going to walk us through a brief setup process. Click get started to begin the process.\n", "\n", "![Set up Personas](images/segment/personas_space_config.png)\n", "\n", "Next, we'll name our Personas Space. Name your space anything you'd like. Spaces are used to isolate user profile sets into separate environments (dev, prod, etc.) Once you've named your space, click into your newly created space, and click 'Get Started' to begin configuring your space. We will use the out of the box settings, but in a production environment, this is where you would configure custom identity matching settings.\n", "\n", "![Set up Personas](images/segment/personas_space_config_2.png)\n", "\n", "![Set up Personas](images/segment/personas_space_config_3.png)\n", "\n", "![Set up Personas](images/segment/personas_space_config_4.png)\n", "\n", "![Set up Personas](images/segment/personas_space_config_5.png)\n", "\n", "![Set up Personas](images/segment/personas_space_config_6.png)\n", "\n", "![Set up Personas](images/segment/personas_space_config_7.png)\n", "\n", "Once you've finished that process, click the Connect Sources button. \n", "\n", "![Set up Personas](images/segment/personas_space_config_8.png)\n", "\n", "Then choose the Python Personalise source and click the Connect Sources button.\n", "\n", "![Add a Python source in Segment](images/segment/add_source_5.png)\n", "\n", "## Get Recommendations from Amazon Personalize and Send them to Segment\n", "\n", "Now that Segment is configured, let’s pull data from our Personalize demo and send it to Segment. First, you will need to get the name of the load balancer for the Retail Demo Store recommendations service you deployed at the beginning of the Retail Demo Store workshop.\n", "The following code will query the AWS account you are using for this workshop, get a list of load balancers, and find the one that belongs to the Retail Demo Store and has the tag recommendations. This URL will be stored in the recommendations_elb_domain_name variable after you run this code." ], "cell_type": "markdown", "metadata": {} }, { "source": [ "import boto3\n", "\n", "elbv2 = boto3.client('elbv2')\n", " \n", "recommendations_elb_domain_name = None\n", " \n", "elbs_paginator = elbv2.get_paginator('describe_load_balancers')\n", "for elbs_page in elbs_paginator.paginate():\n", " for elb in elbs_page['LoadBalancers']:\n", " tags_response = elbv2.describe_tags(ResourceArns = [ elb['LoadBalancerArn'] ])\n", " for tag_desc in tags_response['TagDescriptions']:\n", " for tag in tag_desc['Tags']:\n", " if tag['Key'] == 'RetailDemoStoreServiceName' and tag['Value'] == 'recommendations':\n", " recommendations_elb_domain_name = elb['DNSName']\n", " break\n", " if recommendations_elb_domain_name:\n", " break\n", " if recommendations_elb_domain_name:\n", " break\n", " if recommendations_elb_domain_name:\n", " break\n", " \n", "assert recommendations_elb_domain_name is not None, 'Unable to find Recommendations service ELB'\n", " \n", "print('Recommendations DNS name: {}'.format(recommendations_elb_domain_name))" ], "cell_type": "code", "metadata": {}, "execution_count": null, "outputs": [] }, { "source": [ "In order to understand how Segment is ingesting these recommendations, it is helpful to take a look at the responses that are returned from the recommendations service.\n", "\n", "The code below will invoke your recommendations service, and return a response for one of the users that exists in the Retail Demo Store user database. You can change the user_id below to any valid ID." ], "cell_type": "markdown", "metadata": {} }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import requests\n", "import json\n", "\n", "user_id = 10\n", "response = requests.get('http://{}/recommendations?userID={}&fullyQualifyImageUrls=1&numResults=4'.format(recommendations_elb_domain_name, user_id))\n", "print(json.dumps(response.json(), indent = 2))" ] }, { "source": [ "The return value from the recommendation service should look like this:\n", "\n", "```javascript\n", "[\n", " {\n", " \"product\": {\n", " \"id\": \"2\",\n", " \"url\": \"http://recs.cloudfront.net/#/product/2\",\n", " \"sk\": \"\",\n", " \"name\": \"Striped Shirt\",\n", " \"category\": \"apparel\",\n", " \"style\": \"shirt\",\n", " \"description\": \"A classic look for the summer season.\",\n", " \"price\": 9.99,\n", " \"image\": \"http://recs.cloudfront.net/images/apparel/1.jpg\",\n", " \"featured\": \"true\"\n", " }\n", " },\n", " {\n", " \"product\": {\n", " \"id\": \"1\",\n", " \"url\": \"http://recs.cloudfront.net/#/product/1\",\n", " \"sk\": \"\",\n", " \"name\": \"Black Leather Backpack\",\n", " \"category\": \"accessories\",\n", " \"style\": \"bag\",\n", " \"description\": \"Our handmade leather backpack will look great at the office or out on the town.\",\n", " \"price\": 109.99,\n", " \"image\": \"http://recs.cloudfront.net/images/accessories/1.jpg\",\n", " \"featured\": \"true\"\n", " }\n", " },\n", "\n", " ...\n", "]\n", "```\n", "\n", "Setting up a similar service in your deployment of Amazon Personalize will give you the ability to surface product recommendations directly into Segment to power other services that require real-time user personalization such as a mobile application or a web application. \n", "\n", "The recommendation service deployed in the workshop queries a Personalize campaign with the `user_id` that you provide. Personalize will return a list of recommended product IDs for the user. The service then looks up the catalog ID for each product and decorates the response with the product URL, image, name, etc. These attributes should be available in your catalog management system. In the case of the Retail Demo Store, there is a catalog service that provides (simulated) catalog items for the workshop. The advantage of a service like this is that your target services like Segment do not need to do an additional lookup in order to get the information they require in order to surface a recommendation to a user, such as product name, product category and the image associated with the product.\n", "\n", "Next, we will use the aforementioned service to pull our demo user recommendations and push them into Segment. We’re going to install Segment’s Python library, then create demo user profiles within Segment and pull in recommendations for each user from Amazon Personalize:\n" ], "cell_type": "markdown", "metadata": {} }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import sys\n", "!{sys.executable} -m pip install analytics-python\n", "import analytics\n", "\n", "analytics.write_key = segment_write_key\n", "\n", "servicediscovery = boto3.client('servicediscovery')\n", "\n", "# Look up the Retail Demo Store users service so we can look up user IDs to send to Segment\n", "response = servicediscovery.discover_instances(\n", " NamespaceName='retaildemostore.local',\n", " ServiceName='users',\n", " MaxResults=1,\n", " HealthStatus='HEALTHY'\n", ")\n", "\n", "users_service_instance = response['Instances'][0]['Attributes']['AWS_INSTANCE_IPV4']\n", "print('Users Service Instance IP: {}'.format(users_service_instance))\n", "\n", "for id in range(10, 20):\n", "\n", " # Look up the user by their ID in the Retail Demo Store users service\n", " response = requests.get('http://{}/users/id/{}'.format(users_service_instance, id))\n", " retail_demo_store_user = response.json()\n", " name = f'{retail_demo_store_user[\"first_name\"]} {retail_demo_store_user[\"last_name\"]}'\n", " email = retail_demo_store_user['email']\n", " persona = retail_demo_store_user['persona']\n", " \n", " # Segment will take an identify() call to map a user to the Retail Demo Store login database\n", " analytics.identify('personalize_user_'+str(id), {\n", " 'email': email,\n", " 'name': name,\n", " 'persona': persona\n", " })\n", "\n", " # Get the recommendations for this user\n", " response = requests.get('http://{}/recommendations?userID={}&fullyQualifyImageUrls=1&numResults=10'.format(recommendations_elb_domain_name, id))\n", "\n", " # Send a Segment track() call for each product recommendation for this user\n", " for product_recomendation in response.json():\n", " analytics.track('personalize_user_'+str(id), 'Product Recommended', {\n", " 'product_id': product_recomendation['product']['id'],\n", " 'product_url': product_recomendation['product']['url'],\n", " 'product_name': product_recomendation['product']['name'],\n", " 'product_category': product_recomendation['product']['category'],\n", " 'product_style': product_recomendation['product']['style'],\n", " 'product_description': product_recomendation['product']['description'],\n", " 'product_price': product_recomendation['product']['price'],\n", " 'product_image': product_recomendation['product']['image']\n", " })" ] }, { "source": [ "## Create a user trait for each user in Segment to calculate the most recommended product category in the last 30 days\n", "\n", "Now that our users and their associated Amazon Personalize recommendations are in Segment, let’s inspect a user profile to understand the data structure. From the Segment Personas Explorer (/personas/explorer) click into one of the user profiles we’ve created and inspect the user traits and associated events we just created:\n", "\n", "![Segment Personas](images/segment/personas.png)\n", "\n", "In order to leverage these recommendations for omnichannel personalization, let’s add a trait to each user profile that calculates the most recommended category for each user in the last 30 days. Segment calls these Computed Traits. Computed Traits allow you to quickly create user or account-level calculations that Segment keeps up-to-date over time - learn more about Computed Traits here.\n", "\n", "In Personas, click into the computed traits section (/personas/traits), and click Create Computed Trait.\n", "\n", "![Segment Personas](images/segment/personas_2.png)\n", "\n", "Select Most Frequent, and click Configure.\n", "\n", "![Segment Personas](images/segment/personas_3.png)\n", "\n", "Then, we will create our computed trait based off of the Product Recommended events we’ve generated. In the Select an event name section, choose Product Recommended. In the Select an event property section, choose product_category. In a production implementation, you may consider selecting a time window of 30 days to ensure the trait remains relevant based on recent Product Recommended events.\n", "\n", "![Segment Personas](images/segment/personas_4.png)\n", "\n", "Preview the trait, and click Select Destinations to continue the creation process. In the live workshop, we don’t have any destinations configured, but this is where you can decide which of Segment’s 300+ integrations you want to sync this Computed Trait and each associated user profile. Finish creating the Computed Trait by naming it amazon_personalize_affinity_category, checking the box to compute the trait without enabled destinations, and clicking Create Computed Trait.\n", "\n", "![Segment Personas](images/segment/personas_5.png)\n", "\n", "![Segment Personas](images/segment/personas_6.png)\n", "\n", "## Create an audience within Segment to target X affinity category\n", "\n", "Next, we will use these traits to execute an example of a real world use case. Let’s say we want to run a promotional campaign that targets users with an affinity for housewares. We decided to use Braze for email and push, Google Ads, Facebook Ads, Optimizely for A/B testing and Amplitude for analytics as well as make the user profile available via REST API. In this scenario, we can use Segment to define our target audience and keep that target audience synchronized with each of our channel tools and API mentioned above.\n", "\n", "Navigate to the audience builder in Personas (personas/spaces/default/audiences) and click the New Audience button.\n", "\n", "![Segment Personas Audience](images/segment/personas_audience.png)\n", "\n", "Define an audience that targets users with an amazon_personalize_affinity_category computed trait that equals housewares.\n", "\n", "\n", "![Segment Personas Audience](images/segment/personas_audience_2.png)\n", "\n", "\n", "![Segment Personas Audience](images/segment/personas_audience_3.png)\n", "\n", "\n", "![Segment Personas Audience](images/segment/personas_audience_4.png)\n", "\n", "After clicking Select Destinations, if you had destinations you wanted to send your data connected to Segment, you would select those in order to start the synchronization process between Segment and your destinations. For this exercise, you may not have any destinations hooked up if you’re attending a workshop. If you did have destinations configured, it would look similar to the screenshot below:\n", "\n", "\n", "![Segment Personas Audience](images/segment/personas_audience_5.png)\n", "\n", "Once defined, Segment will sync your audience with each tool and dynamically add and remove users from the audience in each tool over time. For reference, if you wanted to synchronize the end tools we discussed to receive this user audience data, you can follow this documentation:\n", "\n", "- Braze: https://segment.com/docs/connections/destinations/catalog/braze/\n", "- Google Ads: https://segment.com/docs/connections/destinations/catalog/google-ads-classic/\n", "- Facebook Ads: https://segment.com/docs/connections/destinations/catalog/personas-facebook-custom-audiences/\n", "- Optimizely: https://segment.com/docs/connections/destinations/catalog/optimizely-full-stack/\n", "- Amplitude: https://segment.com/docs/connections/destinations/catalog/amplitude/ \n", "- REST API: https://segment.com/docs/personas/profile-api/" ], "cell_type": "markdown", "metadata": {} } ] }