diff --git a/kwc-tracking.html b/kwc-tracking.html index 9d22244..b639208 100644 --- a/kwc-tracking.html +++ b/kwc-tracking.html @@ -48,6 +48,14 @@ * @type {String} */ path, + /** + * If the session hasn't started, then we won't have all the + * data available for the event. We can cache them in the + * `preInitEvents` queue, and then process once the session + * has started. + * @type {Array} + */ + preInitEvents = [], /** * The user's device mode (Kano 2 app only) * @type {Boolean} @@ -175,12 +183,33 @@ }); } /** - * Trigger the `_clearQueueDispatch` and remove the listener - * properly when unloading the page. + * Send what's left of the queue using a synchronous XMLHttpRequest + * to block transitions until the data has been sent. + * TODO: A blocking XMLHttpRequest could be very poor for user + * experience and should be carefully evaluated + * `navigator.sendBeacon` would be a good alternative, but sending + * JSON is currently blocked in Chrome due to CORS considerations + * (see here: https://bugs.chromium.org/p/chromium/issues/detail?id=490015). + * `sendBeacon` also does not allow custom headers such as + * Authorization, so we could not send through tokens to identify + * the user. */ function _handleUnload () { - _clearQueueDispatch(); window.removeEventListener('unload', _handleUnload); + try { + let client = new XMLHttpRequest(), + url = `${config.API_URL}/track/${schema}`, + body = JSON.stringify({events: queue}); + client.open('POST', url, false); + client.setRequestHeader('Content-type', 'application/json'); + if (token) { + client.setRequestHeader('Authorization', token); + } + client.send(body); + } catch (e) { + _log(e); + } + queue = []; } /** * Ensure that all the relevent information is set (including the @@ -207,11 +236,11 @@ _getLocation().then(response => { location = response; localStorage.setItem(LOCATION_KEY, response); - _startSession(); + _startSession(preInitEvents); }); } else { location = storedLocation; - _startSession(); + _startSession(preInitEvents); } } /** @@ -221,7 +250,7 @@ function _queueEvent (payload) { let sessionExpired = _sessionExpired(lastUpdate); if (sessionExpired && sessionStarted) { - return _restartSession(payload); + return _restartSession([payload]); } let body = { app_id: config.APP_ID, @@ -255,14 +284,14 @@ * @param {Object} restartEvent An event to add to the queue after * restarting the session */ - function _restartSession (restartEvent) { + function _restartSession (restartEvents) { let idString = window.navigator.userAgent + Date.now().toString(), hashedId = md5(idString); sessionId = hashedId; sessionStorage.setItem(SESSION_KEY, hashedId); sessionStarted = false; previousSession = false; - _startSession(restartEvent); + _startSession(restartEvents); } /** Set an interval to dispatch the event queue */ function _scheduleQueueDispatch () { @@ -357,7 +386,7 @@ * restarted it (if provided) and schedule the queue processing * @param {Object} startEvent */ - function _startSession (startEvent) { + function _startSession (startEvents) { if (!previousSession) { _queueEvent({ name: 'started_session', @@ -365,8 +394,10 @@ user_location: location } }); - if (startEvent) { - _queueEvent(startEvent); + if (startEvents && startEvents.length) { + startEvents.forEach(startEvent => { + _queueEvent(startEvent); + }); } } sessionStarted = true; @@ -403,6 +434,15 @@ if (e.detail.token) { payload.token = e.detail.token; } + /** + * If the session hasn't started, then we won't have all the + * data available for the event. We can cache it in the + * `preInitEvents` queue, and then process once the session + * has started. + */ + if (!sessionStarted) { + return preInitEvents.push(payload); + } _queueEvent(payload); } /** @@ -427,6 +467,15 @@ previous_page_path: previous } } + /** + * If the session hasn't started, then we won't have all the + * data available for the event. We can cache it in the + * `preInitEvents` queue, and then process once the session + * has started. + */ + if (!sessionStarted) { + return preInitEvents.push(payload); + } _queueEvent(payload); } /** @@ -502,7 +551,7 @@ _clearQueueDispatch(); }, _handleUnload () { - _clearQueueDispatch(); + _handleUnload(); window.removeEventListener('beforeunload', this._handleUnload); } };