Commit e3bd2bff authored by Evan Read's avatar Evan Read

Merge branch 'ee-docs-tracking-updates' into 'master'

Add centralized documentation for event tracking

See merge request gitlab-org/gitlab!17008
parents 24d5eac0 68066d45
...@@ -142,6 +142,12 @@ description: 'Learn how to contribute to GitLab.' ...@@ -142,6 +142,12 @@ description: 'Learn how to contribute to GitLab.'
- [Externalization](i18n/externalization.md) - [Externalization](i18n/externalization.md)
- [Translation](i18n/translation.md) - [Translation](i18n/translation.md)
## Event tracking guides
- [Introduction](event_tracking/index.md)
- [Frontend tracking guide](event_tracking/frontend.md)
- [Backend tracking guide](event_tracking/backend.md)
## Build guides ## Build guides
- [Building a package for testing purposes](build_test_package.md) - [Building a package for testing purposes](build_test_package.md)
......
# Backend tracking guide
GitLab provides `Gitlab::Tracking`, an interface that wraps the [Snowplow Ruby Tracker](https://github.com/snowplow/snowplow/wiki/ruby-tracker) for tracking custom events.
## Tracking in Ruby
Custom event tracking and instrumentation can be added by directly calling the `GitLab::Tracking.event` class method, which accepts the following arguments:
| argument | type | default value | description |
|:-----------|:-------|:---------------------------|:------------|
| `category` | string | 'application' | Area or aspect of the application. This could be `HealthCheckController` or `Lfs::FileTransformer` for instance. |
| `action` | string | 'generic' | The action being taken, which can be anything from a controller action like `create` to something like an Active Record callback. |
| `data` | object | {} | Additional data such as `label`, `property`, `value`, and `context` as described [in our Feature Instrumentation taxonomy](https://about.gitlab.com/handbook/product/feature-instrumentation/#taxonomy). These will be set as empty strings if you don't provide them. |
Tracking can be viewed as either tracking user behavior, or can be utilized for instrumentation to monitor and visual performance over time in an area or aspect of code.
For example:
```ruby
class Projects::CreateService < BaseService
def execute
project = Project.create(params)
Gitlab::Tracking.event('Projects::CreateService', 'create_project',
label: project.errors.full_messages.to_sentence,
value: project.valid?
)
end
end
```
### Performance
We use the [AsyncEmitter](https://github.com/snowplow/snowplow/wiki/Ruby-Tracker#52-the-asyncemitter-class) when tracking events, which allows for instrumentation calls to be run in a background thread. This is still an active area of development.
# Frontend tracking guide
GitLab provides `Tracking`, an interface that wraps the [Snowplow Javascript Tracker](https://github.com/snowplow/snowplow/wiki/javascript-tracker) for tracking custom events. There are a few ways to utilizing tracking, but each generally requires at minimum, a `category` and an `action`. Additional data can be provided that adheres to our [Feature instrumentation taxonomy](https://about.gitlab.com/handbook/product/feature-instrumentation/#taxonomy).
| field | type | default value | description |
|:-----------|:-------|:---------------------------|:------------|
| `category` | string | document.body.dataset.page | Page or subsection of a page that events are being captured within. |
| `action` | string | 'generic' | Action the user is taking. Clicks should be `click` and activations should be `activate`, so for example, focusing a form field would be `activate_form_input`, and clicking a button would be `click_button`. |
| `data` | object | {} | Additional data such as `label`, `property`, `value`, and `context` as described [in our Feature Instrumentation taxonomy](https://about.gitlab.com/handbook/product/feature-instrumentation/#taxonomy). |
## Tracking in HAML (or Vue Templates)
When working within HAML (or Vue templates) we can add `data-track-*` attributes to elements of interest. All elements that have a `data-track-event` attribute will automatically have event tracking bound on clicks.
Below is an example of `data-track-*` attributes assigned to a button:
```haml
%button.btn{ data: { track: { event: "click_button", label: "template_preview", property: "my-template" } } }
```
```html
<button class="btn"
data-track-event="click_button"
data-track-label="template_preview"
data-track-property="my-template"
/>
```
Event listeners are bound at the document level to handle click events on or within elements with these data attributes. This allows for them to be properly handled on rerendering and changes to the DOM, but it's important to know that because of the way these events are bound, click events shouldn't be stopped from propagating up the DOM tree. If for any reason click events are being stopped from propagating, you'll need to implement your own listeners and follow the instructions in [Tracking in raw Javascript](#tracking-in-raw-javascript).
Below is a list of supported `data-track-*` attributes:
| attribute | required | description |
|:----------------------|:---------|:------------|
| `data-track-event` | true | Action the user is taking. Clicks must be prepended with `click` and activations must be prepended with `activate`. For example, focusing a form field would be `activate_form_input` and clicking a button would be `click_button`. |
| `data-track-label` | false | The `label` as described [in our Feature Instrumentation taxonomy](https://about.gitlab.com/handbook/product/feature-instrumentation/#taxonomy). |
| `data-track-property` | false | The `property` as described [in our Feature Instrumentation taxonomy](https://about.gitlab.com/handbook/product/feature-instrumentation/#taxonomy). |
| `data-track-value` | false | The `value` as described [in our Feature Instrumentation taxonomy](https://about.gitlab.com/handbook/product/feature-instrumentation/#taxonomy). If omitted, this will be the elements `value` property or an empty string. For checkboxes, the default value will be the element's checked attribute or `false` when unchecked. |
| `data-track-context` | false | The `context` as described [in our Feature Instrumentation taxonomy](https://about.gitlab.com/handbook/product/feature-instrumentation/#taxonomy). |
## Tracking within Vue components
There's a tracking Vue mixin that can be used in components if more complex tracking is required. To use it, first import the `Tracking` library and request a mixin.
```javascript
import Tracking from '~/tracking';
const trackingMixin = Tracking.mixin({ label: 'right_sidebar' });
```
You can provide default options that will be passed along whenever an event is tracked from within your component. For instance, if all events within a component should be tracked with a given `label`, you can provide one at this time. Available defaults are `category`, `label`, `property`, and `value`. If no category is specified, `document.body.dataset.page` is used as the default.
You can then use the mixin normally in your component with the `mixin`, Vue declaration. The mixin also provides the ability to specify tracking options in `data` or `computed`. These will override any defaults and allows the values to be dynamic from props, or based on state.
```javascript
export default {
mixins: [trackingMixin],
// ...[component implementation]...
data() {
return {
expanded: false,
tracking: {
label: 'left_sidebar'
}
};
},
}
```
The mixin provides a `track` method that can be called within the template, or from component methods. An example of the whole implementation might look like the following.
```javascript
export default {
mixins: [Tracking.mixin({ label: 'right_sidebar' })],
data() {
return {
expanded: false,
};
},
methods: {
toggle() {
this.expanded = !this.expanded;
this.track('click_toggle', { value: this.expanded })
}
}
};
```
And if needed within the template, you can use the `track` method directly as well.
```html
<template>
<div>
<a class="toggle" @click.prevent="toggle">Toggle</a>
<div v-if="expanded">
<p>Hello world!</p>
<a @click.prevent="track('click_action')">Track an event</a>
</div>
</div>
</template>
```
## Tracking in raw Javascript
Custom event tracking and instrumentation can be added by directly calling the `Tracking.event` static function. The following example demonstrates tracking a click on a button by calling `Tracking.event` manually.
```javascript
import Tracking from `~/tracking`;
const button = document.getElementById('create_from_template_button');
button.addEventListener('click', () => {
Tracking.event('dashboard:projects:index', 'click_button', {
label: 'create_from_template',
property: 'template_preview',
value: 'rails',
});
})
```
## Tests and test helpers
In Karma tests, you can use the following:
```javascript
import { mockTracking, triggerEvent } from 'spec/helpers/tracking_helper';
describe('my component', () => {
let trackingSpy;
beforeEach(() => {
const vm = mountComponent(MyComponent);
trackingSpy = mockTracking('_category_', vm.$el, spyOn);
});
it('tracks an event when toggled', () => {
triggerEvent('a.toggle');
expect(trackingSpy).toHaveBeenCalledWith('_category_', 'click_edit_button', {
label: 'right_sidebar',
property: 'confidentiality',
});
});
});
```
# Event tracking
At GitLab, we encourage event tracking so we can iterate on and improve the project and user experience.
We do this by running experiments, and collecting analytics for features and feature variations. This is:
- So we generally know engagement.
- A way to approach A/B testing.
As developers, we should attempt to add tracking and instrumentation where possible. This enables the Product team to better understand:
- User engagement.
- Usage patterns.
- Other metrics that can potentially be improved on.
To maintain consistency, and not adversely effect performance, we have some basic tracking functionality exposed at both the frontend and backend layers that can be utilized while building new features or updating existing features.
We also encourage users to enable tracking, and we embrace full transparency with our tracking approach so it can be easily understood and trusted. By enabling tracking, users can:
- Contribute back to the wider community.
- Help GitLab improve on the product.
## Implementing tracking
Event tracking can be implemented on either the frontend or the backend layers, and each can be approached slightly differently since they have slightly different concerns.
In GitLab, many actions can be initiated via the web interface, but they can also be initiated via an API client (an iOS applications is a good example of this), or via `git` directly. Crucially, this means that tracking should be considered holistically for the feature that's being instrumented.
The data team should be involved when defining analytics and can be consulted when coming up with ways of presenting data that's being tracked. This allows our event data to be considered carefully and presented in ways that may reveal details about user engagement that may not be fully understood or interactions where we can make improvements. You can [contact the data team](https://about.gitlab.com/handbook/business-ops/data-team/#contact-us) and consult with them when defining tracking strategies.
### Frontend
Generally speaking, the frontend can track user actions and events, like:
- Clicking links or buttons.
- Submitting forms.
- Other typically interface-driven actions.
See [Frontend tracking guide](frontend.md).
### Backend
From the backend, the events that are tracked will likely consist of things like the creation or deletion of records and other events that might be triggered from layers that aren't necessarily only available in the interface.
See [Backend tracking guide](backend.md).
## Enabling tracking
Tracking can be enabled at:
- The instance level, which will enable tracking on both the frontend and backend layers.
- User level, though user tracking can be disabled on a per-user basis. GitLab tracking respects the [Do Not Track](https://www.eff.org/issues/do-not-track) standard, so any user who has enabled the Do Not Track option in their browser will also not be tracked from a user level.
We utilize Snowplow for the majority of our tracking strategy, and it can be enabled by navigating to:
- **Admin area > Settings > Integrations** in the UI.
- `admin/application_settings/integrations` in your browser.
The following configuration is required:
| Name | Value |
| ------------- | ------------------------- |
| Collector | `snowplow.trx.gitlab.net` |
| Site ID | `gitlab` |
| Cookie domain | `.gitlab.com` |
Once enabled, tracking events can be inspected locally by either:
- Looking at the network panel of the browser's development tools
- Using the [Snowplow Chrome Extension](https://chrome.google.com/webstore/detail/snowplow-inspector/maplkdomeamdlngconidoefjpogkmljm).
## Additional libraries
Session tracking is handled by [Pendo](https://www.pendo.io/), which is a purely client library and is a relatively minor development concern but is worth including in this documentation.
# Event tracking ---
redirect_to: '../event_tracking/index.md'
---
GitLab provides `Tracking`, an interface that wraps This document was moved to [another location](../event_tracking/frontend.md).
[Snowplow](https://github.com/snowplow/snowplow) for tracking custom events.
It uses Snowplow's custom event tracking functions.
The tracking interface can be imported in JS files as follows:
```javascript
import Tracking from `~/tracking`;
```
## Tracking in HAML or Vue templates
To avoid having to do create a bunch of custom javascript event handlers, when working within HAML or Vue templates, we can add `data-track-*` attributes to elements of interest. This way, all elements that have a `data-track-event` attribute to automatically have event tracking bound.
Below is an example of `data-track-*` attributes assigned to a button in HAML:
```haml
%button.btn{ data: { track_event: "click_button", track_label: "template_preview", track_property: "my-template", track_value: "" } }
```
We can then setup tracking for large sections of a page, or an entire page by telling the Tracking interface to bind to it.
```javascript
import Tracking from '~/tracking';
// for the entire document
new Tracking().bind();
// for a container element
document.addEventListener('DOMContentLoaded', () => {
new Tracking('my_category').bind(document.getElementById('my-container'));
});
```
When you instantiate a Tracking instance you can provide a category. If none is provided, `document.body.dataset.page` will be used. When you bind the Tracking instance you can provide an element. If no element is provided to bind to, the `document` is assumed.
Below is a list of supported `data-track-*` attributes:
| attribute | required | description |
|:----------------------|:---------|:------------|
| `data-track-event` | true | Action the user is taking. Clicks should be `click` and activations should be `activate`, so for example, focusing a form field would be `activate_form_input`, and clicking a button would be `click_button`. |
| `data-track-label` | false | The `label` as described [in our Feature Instrumentation taxonomy](https://about.gitlab.com/handbook/product/feature-instrumentation/#taxonomy). |
| `data-track-property` | false | The `property` as described [in our Feature Instrumentation taxonomy](https://about.gitlab.com/handbook/product/feature-instrumentation/#taxonomy). |
| `data-track-value` | false | The `value` as described [in our Feature Instrumentation taxonomy](https://about.gitlab.com/handbook/product/feature-instrumentation/#taxonomy). If omitted, this will be the elements `value` property or an empty string. For checkboxes, the default value will be the element's checked attribute or `false` when unchecked. |
## Tracking in raw Javascript
Custom events can be tracked by directly calling the `Tracking.event` static function, which accepts the following arguments:
| argument | type | default value | description |
|:-----------|:-------|:---------------------------|:------------|
| `category` | string | document.body.dataset.page | Page or subsection of a page that events are being captured within. |
| `event` | string | 'generic' | Action the user is taking. Clicks should be `click` and activations should be `activate`, so for example, focusing a form field would be `activate_form_input`, and clicking a button would be `click_button`. |
| `data` | object | {} | Additional data such as `label`, `property`, and `value` as described [in our Feature Instrumentation taxonomy](https://about.gitlab.com/handbook/product/feature-instrumentation/#taxonomy). These will be set as empty strings if you don't provide them. |
Tracking can be programmatically added to an event of interest in Javascript, and the following example demonstrates tracking a click on a button by calling `Tracking.event` manually.
```javascript
import Tracking from `~/tracking`;
document.getElementById('my_button').addEventListener('click', () => {
Tracking.event('dashboard:projects:index', 'click_button', {
label: 'create_from_template',
property: 'template_preview',
value: 'rails',
});
})
```
## Toggling tracking on or off
Snowplow can be enabled by navigating to:
- **Admin area > Settings > Integrations** in the UI.
- `admin/application_settings/integrations` in your browser.
The following configuration is required:
| Name | Value |
| ------------- | ------------------------- |
| Collector | `snowplow.trx.gitlab.net` |
| Site ID | `gitlab` |
| Cookie domain | `.gitlab.com` |
Now the implemented tracking events can be inspected locally by looking at the network panel of the browser's development tools.
...@@ -69,10 +69,6 @@ How we use SVG for our Icons and Illustrations. ...@@ -69,10 +69,6 @@ How we use SVG for our Icons and Illustrations.
How we use UI components. How we use UI components.
## [Event Tracking](event_tracking.md)
How we use Snowplow to track custom events.
## Frontend FAQ ## Frontend FAQ
Read the [frontend's FAQ](frontend_faq.md) for common small pieces of helpful information. Read the [frontend's FAQ](frontend_faq.md) for common small pieces of helpful information.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment