Skip to content
Open

V4 #37

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
d7c0798
updating readme
Psiale May 4, 2022
eb1f6b0
working on G4 updates
Psiale May 13, 2022
80be535
added sendEventG4
Psiale May 13, 2022
80e631f
created sendEventG4
Psiale May 13, 2022
2455598
changed README
Psiale May 13, 2022
9736ceb
fixed readme
Psiale May 13, 2022
4555ddb
workin on example
Psiale May 13, 2022
fdd2326
adding example
Psiale May 13, 2022
dbb2a98
handling error
Psiale May 13, 2022
4a0ffaf
handling error
Psiale May 14, 2022
3db9b49
handling error
Psiale May 14, 2022
b19b96a
error handling
Psiale May 16, 2022
5bec458
solved error
Psiale May 16, 2022
2d0c902
console log args"
Psiale May 16, 2022
81676a9
debugging
Psiale May 17, 2022
217b1be
debugging
Psiale May 17, 2022
571e30b
debugging
Psiale May 17, 2022
c784013
debugging
Psiale May 17, 2022
1ce074e
debugging
Psiale May 17, 2022
834364e
debugging
Psiale May 17, 2022
a43f8ab
adding client_id
Psiale May 17, 2022
cbcb6ea
using gtag method)
Psiale May 23, 2022
8944ea5
removing unnecesary check for GTAg
Psiale May 23, 2022
068c923
working
Psiale May 23, 2022
b35ebf9
working this out
Psiale May 23, 2022
a9ab204
working this out
Psiale May 23, 2022
4a8c240
changed sendEvent method to also use V4
Psiale May 23, 2022
76626e6
Update README.md
Psiale May 24, 2022
a982b21
done with requested changes
Psiale May 24, 2022
b0d92e0
Merge branch 'v4' of github.com:firstandthird/ga-track into v4
Psiale May 24, 2022
d4a6a37
working on GA using dataLayer
Psiale Jun 1, 2022
6a00989
working on GA using dataLayer
Psiale Jun 1, 2022
0186efd
working on GA using dataLayer
Psiale Jun 1, 2022
77c90dd
working on GA using dataLayer
Psiale Jun 1, 2022
1d8b387
working on GA using dataLayer
Psiale Jun 1, 2022
7496b1d
working on GA using dataLayer
Psiale Jun 1, 2022
87ea009
working on GA using dataLayer
Psiale Jun 1, 2022
af11a59
working on GA using dataLayer
Psiale Jun 2, 2022
2fe291f
working on GA using dataLayer
Psiale Jun 2, 2022
dfa7e73
working on GA using dataLayer
Psiale Jun 2, 2022
e6eb5b3
working on GA using dataLayer
Psiale Jun 2, 2022
097ca19
changing object structure
Psiale Jun 2, 2022
779cb9e
changed sendEvent and created new function
Psiale May 15, 2023
19744a5
adding ga-track
Psiale May 19, 2023
eac406e
solving conflicts
Psiale May 22, 2023
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
66 changes: 45 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,33 +29,68 @@ yarn add ga-track
import GATrack from 'ga-track';
```

Any element with `data-ga-track` as an attribute, will be tracked on click. Here's a quick reference:

| Attribute | Description | Default |
|------------------------|-----------------------|---|
| `data-ga-track` | Needed for autotracking. If a value is given it serves as the event's name. | `ga-track` |
| `data-ga-track-name` | Name of the event. This Field is required. | `click` |
| `data-ga-track-params` | Params of the event. This Field is required. | `{ name: `Element's textContent`, value: `Element's href` }` |
| `data-ga-track-label` | Label of the event. Optional Field. | not set |
| `data-ga-track-action` | Action of the event. Optional Field. | not set |
| `data-ga-track-category` | Category of the event. Optional Field. | not set |
| `data-ga-track-href` | Should this be `false` the link **won't** be navigated to. Otherwise `ga-track` will wait till the track happens and then navigates. | Element's `href` |

## Methods

### sendEvent(category, action, label)

Manually sends an event to Google Analytics. Returns a promise.
### sendEvent(name, event_params)

#### Parameters:

`category` - {string} - Event's category.
`name` - {string}

`event_params` - {Array of strings} - custom or [recommend](https://support.google.com/analytics/answer/9267735) event params ([25 max](https://support.google.com/analytics/answer/9267744?hl=en)).
V4

```
GATrack.sendEvent('read_article',[{name: 'author', value: 'David Mitchell'}, {name: 'title', value: 'Cloud Atlas'}]);
```


`action` - {string} - Event's action.
### sendEventOldGA(action, category, label)
if you want to create a custom event using the old GA events structure you can use this method

`label` - {string} - Event's label.
the event will be send using this structure:
```
events: {
name: action
params: {
event_category: category
event_label: label
}
}
```

#### Parameters:

`action` - {string}

### sendData()
`category` - {string}

Safely pass data to Google Analytics:
`label` - {string}

```javascript
GATrack.sendData('set', 'dimension2', 'member');
```
GATrack.sendEventOldGA('click', 'books', 'sci-fi' );
```


## Options


### Debug Mode

```js
```
import GATrack from 'ga-track';

GATrack.debug = true;
Expand All @@ -69,17 +104,6 @@ import GATrack from 'ga-track';
GATrack.trackerName = 'SomeTrackerName';
```

### Forcing a provider

Supported values: `''`, `'ga'`, `'gaq'`, `'gtag'`

This is useful if you have multiple tags on the same page but only want to use one of them.

```js
import GATrack from 'ga-track';

GATrack.force = 'ga';
```

### Category Prefix

Expand Down
224 changes: 185 additions & 39 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,170 @@
/* global window */

import { on, find, ready, closest, matches } from 'domassist';
import aug from 'aug';
class GATrack {
static prefix = null;
static debug = false;
static trackerName = '';
static force = null;

static async sendEvent(category, action, label) {
if (GATrack.prefix) {
category = `${GATrack.prefix}-${category}`;


static defaults = {
debug: (typeof window.localStorage === 'object' && window.localStorage.getItem('GATrackDebug')),
prefix: null,
trackerName: '',
force: null,
defaults: {
timeout: 1000
},
autotracking: false,
}


onTrackedClick(element, event, options) {
const data = GATrack.getData(element, options);
const target = element.getAttribute('target');
if (element.dataset.gaTrackHref === 'false') {
event.preventDefault();
} else if (data.href && !event.metaKey && event.which === 1 && target !== '_blank') {
event.preventDefault();
}
if (data.name && data.params) {
GATrack.sendEvent(data.name, data.params);
} else if (!data.name && !data.params) {
GATrack.sendEventOldGA(data.action, data.category, data.label);
}
}

track(element, options = {}) {
if (Array.isArray(element)) {
element.forEach(data => {
find(data.element).forEach(el => {
GATrack.track(el, data);
});
});

return;
}

if (typeof element.dataset.gaTrackInitialised !== 'undefined') {
return;
}

element.dataset.gaTrackInitialised = 'true';

options = aug({}, GATrack.defaults, options);

this.log('tracking', element, options);
on(element, 'click', event => {
GATrack.onTrackedClick(element, event, options);
});
}

// since we now use {name: string, params: []} instead of action, category, label
// I'm defaulting the values of name and params for the autotracking
getData(element, options = {}) {
const href = element.dataset.gaTrackHref || element.getAttribute('href');
const category = element.dataset.gaTrackName || options.category;
const label = element.dataset.gaTrackParams || options.label;
const action = element.dataset.gaTrackAction || options.action;
const params = element.dataset.gaTrackParams || options.params || { name: element.textContent.trim(), value: href };
const name = element.dataset.gaTrackName || options.name || element.dataset.gaTrack || 'click';


return { href, category, label, action, params, name };
}

autotrack() {
if (GATrack.autotracking === true) {
return;
}

GATrack.autotracking = true;
const selector = '[data-ga-track]';

on(document.body, 'click', event => {
let element = event.target;

if (!matches(element, selector)) {
element = closest(element, selector);
}

if (element) {
GATrack.onTrackedClick(element, event, GATrack.defaults);
}
});
}

static async sendEventOldGA(action, category, label) {
if (this.prefix) {
category = `${this.prefix}-${category}`;
}

return new Promise(resolve => {
GATrack.log(category, action, label);

if (!GATrack.isEnabled()) {
GATrack.log('sendEvent', 'ga-track disabled');
return resolve();
}

if (GATrack.isGAQ()) {
window._gaq.push(['_trackEvent', category, action, label, null, false]);
window._gaq.push(resolve);
} else if (GATrack.isGTag()) {
// Gtag check needs to go before since gtag creates a ga variable
const payload = {
event_category: category,
event_label: label,
event_callback: resolve
};

GATrack.sendData('event', action, payload);
} else if (GATrack.isGA()) {
const options = {
transport: 'beacon',
hitCallback: resolve
};

GATrack.sendData('send', 'event', category, action, label, options);
let payload = {}
if (typeof action !== 'string') {
console.error("action has to be of type string");
return;
}

if(action === '' || action === null) {
console.error("action is required");
return;
}
payload = {
events: {
name: action,
params: {
event_category: category || '',
event_label: label || ''
}
}
}
this.sendData(payload);
});
}

static async sendEvent(name, params) {

if (typeof event_name !== 'string') {
console.error("event_name has to be of type string");
return;
}

if(event_name === '' || event_name === null) {
console.error("event name is required");
return;
}

if (event_params.length > 25) {
console.error("can't send more than 25 event params")
return;
}

if (this.prefix) {
name = `${this.prefix}-${name}`;
}


return new Promise(resolve => {

if (!this.isEnabled()) {
this.log('sendEvent', 'ga-track disabled');
return resolve();
}

let payload = {}

payload = {
events: {
name,
params
}
}
this.sendData(payload);
});
}

Expand All @@ -48,7 +174,8 @@ class GATrack {
// with how we previously did it in leanin-web and optionb /web
static send(...args) {
console.log(args);
return GATrack.sendData(...args);

return this.sendData(...args);
}

static sendData(...args) {
Expand All @@ -57,17 +184,24 @@ class GATrack {
return;
}

if (GATrack.isGTag()) {
console.log('sendData', 'gtag', ...args); //eslint-disable-line no-console
window.gtag.apply(null, args);
} else if (GATrack.isGA()) {
if (GATrack.trackerName) {
args[0] = `${GATrack.trackerName}.${args[0]}`;
window.dataLayer = window.dataLayer || [];
if (usesOldGA) {
window.dataLayer.push({
'event': `${args[0].events.name}`,
'event_category': [args[0].events.params.event_category],
'event_label': [args[0].events.params.event_label],
});
} else {
window.dataLayer.push({
'event': `${args[0].events.name}`,
'event_params': [args[0].events.params]
});
}
console.log('sendData', 'ga', ...args); //eslint-disable-line no-console
window.ga.apply(null, args);
}
console.log('sendData', 'failed'); //eslint-disable-line no-console

}

static usesOldGA(...args) {
return args[0].events.params.event_category || args[0].events.params.event_label;
}

static isNullOrEnforced(provider) {
Expand Down Expand Up @@ -98,4 +232,16 @@ class GATrack {
}
}

ready(() => {
if (!window._GATrack_) {
window._GATrack_ = GATrack;

if (typeof window.gaTrackerName_ !== 'undefined') {
GATrack.trackerName = window.gaTrackerName_;
}

GATrack.autotrack();
}
});

export default GATrack;