| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| === Web Tracker |
| |
| This extension is providing the web tracker to start collecting visitors data on your website. |
| The tracker is implemented as an integration of https://github.com/segmentio/analytics.js[analytics.js] for Unomi. |
| |
| ==== Getting started |
| |
| Extension can be tested at : `http://localhost:8181/tracker/index.html` |
| |
| In your page include unomiOptions and include code snippet from `snippet.min.js` : |
| |
| [source] |
| ---- |
| <script type="text/javascript"> |
| var unomiOption = { |
| scope: 'realEstateManager', |
| url: 'http://localhost:8181' |
| }; |
| window.unomiTracker||(window.unomiTracker={}),function(){function e(e){for(unomiTracker.initialize({"Apache Unomi":unomiOption});n.length>0;){var r=n.shift(),t=r.shift();unomiTracker[t]&&unomiTracker[t].apply(unomiTracker,r)}}for(var n=[],r=["trackSubmit","trackClick","trackLink","trackForm","initialize","pageview","identify","reset","group","track","ready","alias","debug","page","once","off","on","personalize"],t=0;t<r.length;t++){var i=r[t];window.unomiTracker[i]=function(e){return function(){var r=Array.prototype.slice.call(arguments);return r.unshift(e),n.push(r),window.unomiTracker}}(i)}unomiTracker.load=function(){var n=document.createElement("script");n.type="text/javascript",n.async=!0,n.src=unomiOption.url+"/tracker/unomi-tracker.min.js",n.addEventListener?n.addEventListener("load",function(n){"function"==typeof e&&e(n)},!1):n.onreadystatechange=function(){"complete"!==this.readyState&&"loaded"!==this.readyState||e(window.event)};var r=document.getElementsByTagName("script")[0];r.parentNode.insertBefore(n,r)},document.addEventListener("DOMContentLoaded",unomiTracker.load),unomiTracker.page()}(); |
| </script> |
| ---- |
| |
| `window.unomiTracker` can be used to send additional events when needed. |
| |
| Check analytics.js API https://segment.com/docs/sources/website/analytics.js/[here]. |
| All methods can be used on `unomiTracker` object, although not all event types are supported by Unomi intergation. |
| |
| ==== How to contribute |
| |
| The source code is in the folder javascript with a package.json, the file to update is `analytics.js-integration-apache-unomi.js` apply your modification in this file then use the command `yarn build` to compile a new JS file. |
| Then you can use the test page to try your changes `http://localhost:8181/tracker/index.html`. |
| |
| ==== Tracking page views |
| |
| In the initialize call, the tracker will generate an implicit page view event, which by default will be populated with |
| the following information: |
| |
| [source,javascript] |
| ---- |
| window.digitalData.page = window.digitalData.page || { |
| path: location.pathname + location.hash, |
| pageInfo: { |
| pageName: document.title, |
| pageID : location.pathname + location.hash, |
| pagePath : location.pathname + location.hash, |
| destinationURL: location.href |
| } |
| } |
| ---- |
| |
| Now if you want to provide your own custom page information for the initial page view, you can simply do it like this: |
| |
| [source,`javascript] |
| ---- |
| unomiTracker.initialize({ |
| scope: 'myScope', |
| url: 'http://unomi:8181', // we use an empty URL to make it relative to this page. |
| initialPageProperties: { |
| path: path, |
| pageInfo: { |
| destinationURL: location.href, |
| tags: ["tag1", "tag2", "tag3"], |
| categories: ["category1", "category2", "category3"] |
| }, |
| interests: { |
| "interest1": 1, |
| "interest2": 2, |
| "interest3": 3 |
| } |
| } |
| }); |
| ---- |
| |
| ` |
| |
| Also note that the FIRST call to unomiTracker.page() will be IGNORED because of this initial page view.This is the |
| way that the Analytics.js library handles it.So make sure you are aware of this when calling it.This is to avoid having |
| two page views on a single call and to be compatible with old versions that did use the explicit call. |
| |
| By default the script will track page views, but maybe you want to take control over this mechanism of add page views |
| to a single page application.In order to generate a page view programmatically from Javascript you can use code similar |
| to this : |
| |
| [source] |
| ---- |
| <script type="text/javascript"> |
| // This is an example of how to provide more details page properties to the view event. This can be useful |
| // in the case of an SPA that wants to provide information about a view that has metadata such as categories, |
| // tags or interests. |
| path = location.pathname + location.hash; |
| properties = { |
| path: path, |
| pageInfo: { |
| destinationURL: location.href, |
| tags : [ "tag1", "tag2", "tag3"], |
| categories : ["category1", "category2", "category3"], |
| }, |
| interests : { |
| "interest1" : 1, |
| "interest2" : 2, |
| "interest3" : 3 |
| } |
| }; |
| console.log(properties); |
| // this will trigger a second page view for the same page (the first page view is in the tracker snippet). |
| window.unomiTracker.page(properties); |
| </script> |
| ---- |
| |
| Here is a more detail view of what you may include in the pageInfo object : |
| |
| .PageInfo Properties |
| |=== |
| |Name|Description |
| |
| |pageID |
| |A unique identifier in string format for the page. Default value : page path |
| |
| |pageName |
| |A user-displayed name for the page. Default value : page title |
| |
| |pagePath |
| |The path of the page, stored by Unomi. This value should be the same as the one passed in the `page` property of the |
| object passed to the unomiTracker call. Default value : page path |
| |
| |destinationURL |
| |The full URL for the page view. This doesn't have to be a real existing URL it could be an internal SPA route. Default value : page URL |
| |
| |referringURL |
| |The referringURL also known as the previous URL of the page/screen viewed. Default value : page referrer URL |
| |
| |tags |
| |A String array of tag identifiers. For example `['tag1', 'tag2', 'tag3']` |
| |
| |categories |
| |A String array of category identifiers. For example `['category1', 'category2', 'category3']` |
| |
| |=== |
| |
| The `interests` object is basically list of interests with "weights" attached to them.These interests will be accumulated |
| in Apache Unomi on profiles to indicate growing interest over time for specific topics.These are freely defined and |
| will be accepted by Apache Unomi without needing to declare them previously anywhere (the same is true for tags and |
| categories). |
| |
| ==== Tracking form submissions |
| |
| Using the web tracker you can also track form submissions. In order to do this a few steps are required to get a form's |
| submission to be tracked and then its form values to be sent as events to Apache Unomi. Finally setting up a rule to |
| react to the incoming event will help use the form values to perform any action that is desired. |
| |
| Let's look at a concrete example. Before we get started you should know that this example is already available to |
| directly test in Apache Unomi at the following URL : |
| |
| http://localhost:8181/tracker |
| |
| Simply modify the form values and click submit and it will perform all the steps we are describing below. |
| |
| So here is the form we want to track : |
| |
| [source] |
| ---- |
| <form id="testFormTracking" action="#" name="testFormTracking"> |
| <label for="firstName">First name</label> |
| <input type="text" id="firstName" name="firstName" value="John"/> |
| |
| <label for="lastName">Last name</label> |
| <input type="text" id="lastName" name="lastName" value="Doe"/> |
| |
| <label for="email">Email</label> |
| <input type="email" id="email" name="email" value="johndoe@acme.com"/> |
| |
| <input type="submit" name="submitButton" value="Submit"/> |
| </form> |
| ---- |
| |
| As you can see it's composed of three fields - firstName, lastName and email - as well as a submit button. In order to |
| track it we can add directly under the following snippet : |
| |
| [source] |
| ---- |
| <script type="text/javascript"> |
| window.addEventListener("load", function () { |
| var form = document.getElementById('testFormTracking'); |
| unomiTracker.trackForm(form, 'formSubmitted', {formName: form.name}); |
| }); |
| </script> |
| ---- |
| |
| What this snippet does is retrieve the form using its element ID and then uses the unomiTracker to track form submissions. |
| Be careful to always use in the form event name a string that starts with `form` in order for the event to be sent back |
| to Unomi. Also the form name is also a mandatory parameter that will be passed to Unomi inside a event of type `form` under |
| the `target.itemId` property name. |
| |
| Here is an example of the event that gets sent back to Apache Unomi: |
| |
| [source] |
| ---- |
| { |
| "itemId" : "cd627012-963e-4bb5-97f0-480990b41254", |
| "itemType" : "event", |
| "scope" : "realEstateManager", |
| "version" : 1, |
| "eventType" : "form", |
| "sessionId" : "aaad09aa-88c2-67bd-b106-5a47ded43ead", |
| "profileId" : "48563fd0-6319-4260-8dba-ae421beba26f", |
| "timeStamp" : "2018-11-23T16:32:26Z", |
| "properties" : { |
| "firstName" : "John", |
| "lastName" : "Doe", |
| "email" : "johndoe@acme.com", |
| "submitButton" : "Submit" |
| }, |
| "source" : { |
| "itemId" : "/tracker/", |
| "itemType" : "page", |
| "scope" : "realEstateManager", |
| "version" : null, |
| "properties" : { |
| "pageInfo" : { |
| "destinationURL" : "http://localhost:8181/tracker/?firstName=Bill&lastName=Gates&email=bgates%40microsoft.com", |
| "pageID" : "/tracker/", |
| "pagePath" : "/tracker/", |
| "pageName" : "Apache Unomi Web Tracker Test Page", |
| "referringURL" : "http://localhost:8181/tracker/?firstName=John&lastName=Doe&email=johndoe%40acme.com" |
| }, |
| "attributes" : [ ], |
| "consentTypes" : [ ], |
| "interests" : { } |
| } |
| }, |
| "target" : { |
| "itemId" : "testFormTracking", |
| "itemType" : "form", |
| "scope" : "realEstateManager", |
| "version" : null, |
| "properties" : { } |
| }, |
| "persistent" : true |
| } |
| ---- |
| |
| You can see in this event that the form values are sent as properties of the event itself, while the form name is sent |
| as the `target.itemId` |
| |
| While setting up form tracking, it can be very useful to use the Apache Unomi Karaf SSH shell commands : `event-tail` |
| and `event-view` to check if you are properly receiving the form submission events and that they contain the expected |
| data. If not, check your tracking code for any errors. |
| |
| Now that the data is properly sent using an event to Apache Unomi, we must still use it to perform some kind of actions. |
| Using rules, we could do anything from updating the profile to sending the data to a third-party server (using a custom- |
| developped action of course). In this example we will illustrate how to update the profile. |
| |
| In order to do so we will deploy a rule that will copy data coming from the event into a profile. But we will need to |
| map the form field names to profile names, and this can be done using the `setPropertyAction` that's available out of the |
| box in the Apache Unomi server. |
| |
| There are two ways to register rules : either by building a custom OSGi bundle plugin or using the REST API to directly |
| send a JSON representation of the rule to be saved. We will in this example use the CURL shell command to make a call to |
| the REST API. |
| |
| [source] |
| ---- |
| curl -X POST -k -u karaf:karaf https://localhost:9443/cxs/rules \ |
| --header "Content-Type: application/json" \ |
| -d @- << EOF |
| { |
| "itemId": "form-mapping-example", |
| "itemType": "rule", |
| "linkedItems": null, |
| "raiseEventOnlyOnceForProfile": false, |
| "raiseEventOnlyOnceForSession": false, |
| "priority": -1, |
| "metadata": { |
| "id": "form-mapping-example", |
| "name": "Example Form Mapping", |
| "description": "An example of how to map event properties to profile properties", |
| "scope": "realEstateManager", |
| "tags": [], |
| "enabled": true, |
| "missingPlugins": false, |
| "hidden": false, |
| "readOnly": false |
| }, |
| "condition": { |
| "type": "formEventCondition", |
| "parameterValues": { |
| "formId": "testFormTracking", |
| "pagePath" : "/tracker/" |
| } |
| }, |
| "actions": [ |
| { |
| "type": "setPropertyAction", |
| "parameterValues": { |
| "setPropertyName": "properties(firstName)", |
| "setPropertyValue": "eventProperty::properties(firstName)", |
| "setPropertyStrategy": "alwaysSet" |
| } |
| }, |
| { |
| "type": "setPropertyAction", |
| "parameterValues": { |
| "setPropertyName": "properties(lastName)", |
| "setPropertyValue": "eventProperty::properties(lastName)", |
| "setPropertyStrategy": "alwaysSet" |
| } |
| }, |
| { |
| "type": "setPropertyAction", |
| "parameterValues": { |
| "setPropertyName": "properties(email)", |
| "setPropertyValue": "eventProperty::properties(email)", |
| "setPropertyStrategy": "alwaysSet" |
| } |
| } |
| ] |
| } |
| EOF |
| ---- |
| |
| As you can see in this request, we have a few parameters that need explaining: |
| |
| - `-k` is used to accept any certificate as we are in this example using a default Apache Unomi server configuration that |
| comes with its predefined HTTPS certificates |
| - `-u karaf:karaf` is the default username/password for authenticating to the REST API. To change this value you should |
| edit the `etc/users.properties`file and it is required to modify this login before going to production. |
| |
| Finally the rule itself should be pretty self-explanatory but there are a few important things to note : |
| |
| - the `itemId` and `metadata.id` values should be the same |
| - the `scope` should be the same as the scope that was setup in the tracker initialization |
| - the `formId` parameter must have the form name value |
| - the `pagePath` should be the pagePath passed through the event (if you're not sure of its value, you could either using |
| network debugging in the browser or use the `event-tail` and `event-view` commands in the Apache Unomi Karaf SSH shell). |
| - the setPropertyAction may be repeated as many times as desired to copy the values from the event to the profile. Note that |
| the `setPropertyName` will define the property to set on the profile and the `setPropertyValue` will define where the |
| value is coming from. In this example the name and the value are the same but that is no way a requirement. It could |
| even be possible to using multiple `setPropertyAction` instances to copy the same event property into different profile |
| properties. |
| |
| To check if your rule is properly deployed you can use the following SSH shell command : |
| |
| `unomi:rule-view form-mapping-example` |
| |
| The parameter is the `itemId` of the rule. If you want to see all the rules deployed in the system you can use the |
| command : |
| |
| `unomi:rule-list 1000` |
| |
| The `1000` parameter is the limit of number of objects to retrieve. As the number of rules can grow quickly in an Apache |
| Unomi instance, it is recommended to put this value a bit high to make sure you get the full list of rules. |
| |
| Once the rule is in place, try submitting the form with some values and check that the profile is properly updated. One |
| recommend way of doing this is to use the `event-tail` command that will output something like this : |
| |
| [source] |
| ---- |
| ID |Type |Session |Profile |Timestamp |Scope |Persi| |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| cef09b89-6b99-4e4f-a99c-a4159a66b42b|form |aaad09aa-88c2-67bd-b106-5a47ded43ead|48563fd0-6319-4260-8dba-ae421beba26f|Fri Nov 23 17:52:33 CET 2018 |realEstateManag|true | |
| ---- |
| |
| You can directly see the profile that is being used, so you can then simply use the |
| |
| `unomi:profile-view 48563fd0-6319-4260-8dba-ae421beba26f` |
| |
| command to see a JSON dump of the profile and check that the form values have been properly positioned. |