Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mobile device info #176

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
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
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,18 @@ const client = new KeenTracking({

---

### Vibration

If your device supports [Vibration API](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/vibrate) you can turn on vibration once an event is recorded
```javascript
const client = new KeenTracking({
projectId: 'PROJECT_ID',
writeKey: 'WRITE_KEY',
vibration: true
});
```
---

### Contributing

This is an open source project and we love involvement from the community! Hit us up with pull requests and issues.
Expand Down
2 changes: 1 addition & 1 deletion docs/helpers.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ const windowProfile = KeenTracking.helpers.getWindowProfile();

### Browser profile

`KeenTracking.helpers.getBrowserProfile()` returns a set of properties describing the current browser, like "useragent", "online" status, and "language", plus [screen](#screen-profile) and [window](#window-profile) profiles.
`KeenTracking.helpers.getBrowserProfile()` returns a set of properties describing the current browser, like "useragent", "online" status, and "language", plus [screen](#screen-profile) and [window](#window-profile) profiles. We've added some new properties like [`battery`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/getBattery) and [`mediaDevice`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/mediaDevices) so if the browser supports these features you'll get a Promise instead of a plain object.

```javascript
import KeenTracking from 'keen-tracking';
Expand Down
30 changes: 20 additions & 10 deletions lib/browser-auto-tracking.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,7 @@ export function initAutoTrackingCore(lib) {
output : 'geo'
});

client.extendEvents(function() {
const browserProfile = helpers.getBrowserProfile();
const getExtendedObject = (browserProfile) => {
return {
tracked_by: pkg.name + '-' + pkg.version,
local_time_full: new Date().toISOString(),
Expand All @@ -161,41 +160,52 @@ export function initAutoTrackingCore(lib) {
time_on_page: allTimeOnSiteS > 0 ? allTimeOnSiteS : getSecondsSinceDate(now),
time_on_page_ms: allTimeOnSiteMS > 0 ? allTimeOnSiteMS : getMiliSecondsSinceDate(now)
},

ip_address,
geo: { /* Enriched */ },

user_agent: '${keen.user_agent}',
tech: {
profile: browserProfile
/* Enriched */
},

url: {
full: window ? window.location.href : '',
info: { /* Enriched */ }
},

referrer: {
initial: initialReferrer,
full: document ? document.referrer : '',
info: { /* Enriched */ }
},

time: {
local: { /* Enriched */ },
utc: { /* Enriched */ }
},

keen: {
timestamp: new Date().toISOString(),
addons,
}
};
}

client.extendEvents(function() {
const browserProfile = helpers.getBrowserProfile();

if (browserProfile instanceof Promise) {
return browserProfile
.then(data => getExtendedObject(data));
apryka marked this conversation as resolved.
Show resolved Hide resolved
}
return getExtendedObject(browserProfile);

});

if (options.recordClicks === true) {
utils.listener('a, a *').on('click', function(e) {
utils.listener('a, a *, button').on('click', function(e) {
const el = e.target;
let event = {
element: helpers.getDomNodeProfile(el),
Expand Down Expand Up @@ -339,4 +349,4 @@ function getSecondsSinceDate(date) {

function getMiliSecondsSinceDate(date) {
return new Date().getTime() - date.getTime();
}
}
4 changes: 2 additions & 2 deletions lib/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ if (localStorage && localStorage.getItem('optout')) {
KeenCore.optedOut = true;
}

if (getBrowserProfile().doNotTrack === '1'
|| getBrowserProfile().doNotTrack === 'yes') {
if (navigator.doNotTrack === '1'
|| navigator.doNotTrack === 'yes') {
KeenCore.doNotTrack = true;
}

Expand Down
14 changes: 14 additions & 0 deletions lib/helpers/getBattery.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export function getBattery() {
let batteryPromise;

if ('getBattery' in navigator) {
batteryPromise = navigator.getBattery();
} else {
batteryPromise = Promise.resolve(navigator.battery);
}

return batteryPromise
.then(battery => battery)
.catch(err => console.error(err));

}
71 changes: 62 additions & 9 deletions lib/helpers/getBrowserProfile.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,80 @@
import { getBattery } from './getBattery';
import { getMediaDevices } from './getMediaDevices';
import { getScreenProfile } from './getScreenProfile';
import { getWindowProfile } from './getWindowProfile';

export function getBrowserProfile() {
// MediaDevices and BatteryManager supported
if ((navigator.mediaDevices && navigator.mediaDevices.enumerateDevices)
&& ('getBattery' in navigator || ('battery' in navigator && 'Promise' in window))) {
return Promise.all([getBattery(), getMediaDevices()])
.then((data) => {
const [ battery, mediaDevices ] = data;
const browserProfile = getBrowserData();

browserProfile.battery = battery;
browserProfile.mediaDevices = mediaDevices;
return browserProfile;
});
}

// MediaDevices supported
if (navigator.mediaDevices && navigator.mediaDevices.enumerateDevices) {
return getMediaDevices()
.then((data) => {
const browserProfile = getBrowserData();

browserProfile.mediaDevices = data;
return browserProfile;
});
}

// BatteryManager supported
if ('getBattery' in navigator || ('battery' in navigator && 'Promise' in window)) {
return getBattery()
.then((data) => {
const browserProfile = getBrowserData();

browserProfile.battery = data;
return browserProfile;
});
}

// none of the above supported
return getBrowserData();
}

function getDocumentDescription() {
var el;
if (document && typeof document.querySelector === 'function') {
el = document.querySelector('meta[name="description"]');
}
return el ? el.content : '';
}

function getConnection() {
return navigator.connection || navigator.mozConnection ||
navigator.webkitConnection || navigator.msConnection;
}

function getBrowserData() {
return {
'activeVRDisplays' : navigator.activeVRDisplays,
'connection' : getConnection(),
'cookies' : ('undefined' !== typeof navigator.cookieEnabled) ? navigator.cookieEnabled : false,
'codeName' : navigator.appCodeName,
'description': getDocumentDescription(),
'deviceMemory' : navigator.deviceMemory,
'doNotTrack' : navigator.doNotTrack,
'hardwareConcurrency' : navigator.hardwareConcurrency,
'language' : navigator.language,
'maxTouchPoints': navigator.maxTouchPoints,
'name' : navigator.appName,
'online' : navigator.onLine,
'platform' : navigator.platform,
'useragent' : navigator.userAgent,
'version' : navigator.appVersion,
'doNotTrack' : navigator.doNotTrack,
'screen' : getScreenProfile(),
'window' : getWindowProfile()
}
}

function getDocumentDescription() {
var el;
if (document && typeof document.querySelector === 'function') {
el = document.querySelector('meta[name="description"]');
}
return el ? el.content : '';
}
5 changes: 5 additions & 0 deletions lib/helpers/getMediaDevices.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export function getMediaDevices() {
return navigator.mediaDevices.enumerateDevices()
.then(devices => devices)
.catch(err => console.error(err))
}
4 changes: 4 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ KeenCore.on('client', function(client){
this.optedOut = client.config.optOut;
}

if (client.config.vibration) {
this.vibration = client.config.vibration
}

client.queue = queue(client.config.queue);
client.queue.on('flush', function(){
client.recordDeferredEvents();
Expand Down
8 changes: 8 additions & 0 deletions lib/record-events-browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ export function recordEvent(eventCollectionOrConfigObject, eventBody, callback){
message: 'Keen.doNotTrack is set to true.'
})
}

if (Keen.vibration && navigator && navigator.vibrate) {
navigator.vibrate(200);
}

return send.call(this, { url, extendedEventsHash, callback, configObject, eventCollection });
}
Expand Down Expand Up @@ -157,6 +161,10 @@ export function recordEvents(eventsHash, callback){
})
}

if (Keen.vibration && navigator && navigator.vibrate) {
navigator.vibrate(200);
}

return send.call(this, { url, extendedEventsHash, callback });
}

Expand Down
6 changes: 5 additions & 1 deletion test/setupJest.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ global.IntersectionObserver.prototype.simulate = function(elements){
this.callback(elements);
};
global.navigator = {
sendBeacon: jest.mock()
sendBeacon: jest.mock(),
mediaDevices: {
enumerateDevices: jest.mock(),
},
getBattery: jest.mock(),
};
const mockStorage = {};
const localStorage = {
Expand Down