How to display specific interaction data
For this example, we would like to have a custom list in the Experience Profile where it listed the triggered page event when the site visitor downloaded a PDF file.
End result:
How to set this up
- Setup a page event
- Assign the page event to media items
- Setup a custom tab in the Experience Profile
- Register a new processors for Experience Profile
- Wire things together
Source code link is available at the end of this post.
First we need to create a page event through the content editor, we can do so by going to the /sitecore/system/Settings/Analytics/Page Events
In the below screenshot I’ve created a page event called “Download PDF File”
How to assign page event to a media item
There’s a tutorial on how to this on Sitecore documentation site
I’m using a page event rather than goal for this POC because this event “download a pdf” doesn’t necessarily lead to a conversion but more about the actions that the site visitors took that we want to be aware of.
In the screenshot below I’ve assigned the pdf files in the media library with my custom page event.
Now if there’s a site visitors that download the specified files on the website, Sitecore will trigger the page event and store the information in MongoDB which later on we will extract and display it in the Experience Profile.
How to setup the custom tab in Experience Profile
The content tree
We define three column to be displayed on the ListControl rendering.
The full list of the renderings
The SubPageCode rendering links to a javascript file downloadedpdffiles.js which will be executed when this item is loaded into the tab.
We can control the page size -the amount of records returned by the server- in the GenericDataProvider properties.
How to register a new processors for the Experience Profile
Jonathan Robbin’s blog post explain it nicely on what this processors is doing.
Schema.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
using System; using Sitecore.Cintel.Reporting; namespace Sitecore.TC.ExperienceProfile.CIntel.Reporting.Contact.DownloadedPdfFiles { public static class Schema { public static string ViewName = "DownloadedPdfFiles"; public static ViewField<string> FileName = new ViewField<string>("FileName"); public static ViewField<string> FileItemPath = new ViewField<string>("FileItemPath"); public static ViewField<string> PageName = new ViewField<string>("PageName"); public static ViewField<string> PageItemPath = new ViewField<string>("PageItemPath"); public static ViewField<DateTime> DownloadedOn = new ViewField<DateTime>("DownloadedOn"); } } |
ConstructDownloadedPdfFilesDataTable.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
using System.Data; using Sitecore.Cintel.Reporting; using Sitecore.Cintel.Reporting.Processors; namespace Sitecore.TC.ExperienceProfile.CIntel.Reporting.Contact.DownloadedPdfFiles { public class ConstructDownloadedPdfFilesDataTable : ReportProcessorBase { public override void Process(ReportProcessorArgs args) { args.ResultTableForView = new DataTable(); args.ResultTableForView.Columns.Add(Schema.FileName.ToColumn()); args.ResultTableForView.Columns.Add(Schema.FileItemPath.ToColumn()); args.ResultTableForView.Columns.Add(Schema.PageName.ToColumn()); args.ResultTableForView.Columns.Add(Schema.PageItemPath.ToColumn()); args.ResultTableForView.Columns.Add(Schema.DownloadedOn.ToColumn()); } } } |
PopulateDownloadedPdfFilesWithXdbData.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
using System; using System.Data; using System.Globalization; using Sitecore.Cintel.Reporting; using Sitecore.Cintel.Reporting.Processors; namespace Sitecore.TC.ExperienceProfile.CIntel.Reporting.Contact.DownloadedPdfFiles { /// <summary> /// Responsible to populate the result table with the data coming from xDB /// </summary> public class PopulateDownloadedPdfFilesWithXdbData : ReportProcessorBase { private readonly Guid _downloadPdfFilePageEventItemId = new Guid("{C7C9427A-0EC3-4DBB-BF80-6864489102AC}"); public override void Process(ReportProcessorArgs args) { var queryResult = args.QueryResult; var resultTableForView = args.ResultTableForView; foreach (var sourceRow in queryResult.AsEnumerable()) if (!RowShouldBeSkipped(sourceRow)) { var dataRow = resultTableForView.NewRow(); var mediaPath = sourceRow.Field<string>("Pages_PageEvents_DataKey"); var mediaItem = Context.Database.GetItem(mediaPath); if (mediaItem != null) { dataRow.SetField(Schema.FileName.Name, mediaItem.DisplayName); dataRow.SetField(Schema.FileItemPath.Name, mediaPath); } var pageItemId = sourceRow.Field<Guid>("Pages_Item__id"); var pageItem = GetItemFromCurrentContext(pageItemId); if (pageItem != null) { dataRow.SetField(Schema.PageName.Name, pageItem.DisplayName); dataRow.SetField(Schema.PageItemPath.Name, pageItem.Paths.FullPath); } var datetime = sourceRow.Field<DateTime>("Pages_PageEvents_DateTime").ToLocalTime(); dataRow.SetField(Schema.DownloadedOn.Name, datetime.ToString(CultureInfo.CurrentUICulture)); resultTableForView.Rows.Add(dataRow); } } /// <summary> /// Skip processing the current row if it's the page event that we want to process /// </summary> /// <param name="row"></param> /// <returns></returns> private bool RowShouldBeSkipped(DataRow row) { return row.Field<Guid?>("Pages_PageEvents_PageEventDefinitionId").GetValueOrDefault() != _downloadPdfFilePageEventItemId; } } } |
Register our custom processors
TC.Sitecore.ExperienceProfile.Reporting.config
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<?xml version="1.0" encoding="utf-8"?> <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"> <sitecore> <pipelines> <group groupName="ExperienceProfileContactViews"> <pipelines> <downloadedpdffiles> <processor type="Sitecore.TC.ExperienceProfile.CIntel.Reporting.Contact.DownloadedPdfFiles.ConstructDownloadedPdfFilesDataTable, Sitecore.TC.ExperienceProfile" /> <processor type="Sitecore.Cintel.Reporting.Processors.ExecuteReportingServerDatasourceQuery, Sitecore.Cintel"> <param desc="queryName">visit-events-query</param> </processor> <processor type="Sitecore.TC.ExperienceProfile.CIntel.Reporting.Contact.DownloadedPdfFiles.PopulateDownloadedPdfFilesWithXdbData, Sitecore.TC.ExperienceProfile" /> <processor type="Sitecore.Cintel.Reporting.Processors.ApplySorting, Sitecore.Cintel"/> <processor type="Sitecore.Cintel.Reporting.Processors.ApplyPaging, Sitecore.Cintel"/> </downloadedpdffiles> </pipelines> </group> </pipelines> </sitecore> </configuration> |
notice that the sorting and paging is already built in the framework.
Register our custom result transformer
TC.Sitecore.ExperienceProfile.Client.config
1 2 3 4 5 6 7 8 9 10 11 |
<?xml version="1.0"?> <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"> <sitecore> <pipelines> <initialize> <!-- Creates a set of http endpoints that expose our custom fields on a contact. --> <processor type="Sitecore.TC.ExperienceProfile.CIntel.Endpoint.Plumbing.InitializeRoutes, Sitecore.TC.ExperienceProfile" patch:after="*[last()]" /> </initialize> </pipelines> </sitecore> </configuration> |
As with the previous post, when the DownloadedPdfFilesPanel item is loaded we will trigger an API call to request the data to be displayed in the list control
The javascript file that’s responsible to do this is the downloadedpdffiles.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
define(["sitecore", "/-/speak/v1/experienceprofile/DataProviderHelper.js", "/-/speak/v1/experienceprofile/CintelUtl.js"], function (sc, providerHelper, cintelUtil) { var app = sc.Definitions.App.extend({ initialized: function () { var tableName = "downloadedpdffiles"; // Case Sensitive! var localUrl = "/intel/" + tableName; providerHelper.setupHeaders([ { urlKey: localUrl + "?", headerValue: "none" } ]); var url = sc.Contact.baseUrl + localUrl; providerHelper.initProvider(this.DownloadedPdfFilesDataProvider, tableName, url, this.DownloadedPdfFilesTabMessageBar); providerHelper.subscribeSorting(this.DownloadedPdfFilesDataProvider, this.DownloadedPdfFiles); providerHelper.getListData(this.DownloadedPdfFilesDataProvider); } }); return app; }); |
The difference here compared to the previous post when triggering the API call is that we specify the /intel/downloadedpdffiles in the url which Sitecore recognize to be a special route. This route will try to run donwnloadedpdffiles pipelines that we define earlier in the config file.
An example of the API response
http://habitat.dev.local/sitecore/api/ao/v1/contacts/02b2e6c4-d38a-4e30-a18e-b4a31b63907d/intel/downloadedpdffiles?&pageSize=3&pageNumber=1
Source code is available in Github
Hi Rahadian,
Can you please share the knowledge about speak dialogue pages?
its very urgent for me.