Code Monkey home page Code Monkey logo

timeme.js's Introduction

What is TimeMe.js?

TimeMe.js is a JavaScript library that accurately tracks how long users interact with a web page. It disregards time spent on a web page if the user minimizes the browser or switches to a different tab. TimeMe.js also disregards 'idle' time: if the user goes idle (no mouse movement, no keyboard input) for a customizable period of time, TimeMe.js will stop tracking. Together, these attributes create a much more accurate representation of how long users are actually using a web page.

Live Demo

You can see a live demo of TimeMe.js here.

How do I use TimeMe.js?

First, obtain a copy of timeme.js. A minified version is bundled in this repository as timeme.min.js. Alternatively, you can get a copy by installing TimeMe.js via npm:

npm install timeme.js --save

Once downloaded, simply include the following lines of code in your page:

<script src="timeme.min.js"></script>
<script type="text/javascript">
    // Initialize library and start tracking time
    TimeMe.initialize({
	    currentPageName: "my-home-page", // current page
	    idleTimeoutInSeconds: 30 // seconds
    });

    // ... Some time later ...

    // Retrieve time spent on current page
    let timeSpentOnPage = TimeMe.getTimeOnCurrentPageInSeconds();
</script>

Notice that the code sample sets the idle duration to 30 seconds, which means 30 seconds of user inactivity (no mouse or keyboard usage on the page) will stop the timer. Also, we define a page name (my-home-page) to associate with the current timer.

Note: You can use TimeMe.js to time any activity that you want, not just page time. Simply call the following code around the activity of interest. TimeMe.js will automatically discount any idle time or time when viewing another tab or application.

TimeMe.startTimer("my-activity");
// ... some time later
TimeMe.stopTimer("my-activity");
let timeOnActivity = TimeMe.getTimeOnPageInSeconds("my-activity")

TimeMe gives you a hook to execute a function after a user has been interacting with your page for a set period of time. Simply call TimeMe.callAfterTimeElapsedInSeconds():

TimeMe.callAfterTimeElapsedInSeconds(15, function(){
	console.log("The user has been actively using the page for 15 seconds! Let's prompt them with something.");
});

TimeMe also lets you execute code when a user leaves the page (due to switching tabs, inactivity, etc.) and executes it when he or she returns:

// Executes the first 5 times a user leaves the page
TimeMe.callWhenUserLeaves(function(){
	console.log("The user is not currently viewing the page!");
}, 5);

// Executes every time a user returns
TimeMe.callWhenUserReturns(function(){
	console.log("The user has come back!");
});

TimeMe also lets you track how long users are interacting with specific elements. If the user moves their mouse over, clicks, or types on an element (or its children), TimeMe will begin tracking that interaction. Multiple timers can run concurrently, so this does not impact other times that you've already set up.

// Start tracking activity on element with id 'area-of-interest-1'
TimeMe.trackTimeOnElement('area-of-interest-1');
// some time later...
let timeSpentOnElement = TimeMe.getTimeOnElementInSeconds('area-of-interest-1');

What do I do with the time I've tracked?

In most cases you will want to store the time spent on a page for analytic purposes. You will likely need to send the time spent on a page to a back-end server.

Using WebSockets to send times

TimeMe.js has websocket reporting built into it. Your page will establish a websocket connection with your websocket server. TimeMe will end the connection and report the user's time when the user leaves. Simply provide a few arguments to the initialize() method to enable it:

TimeMe.initialize({
	currentPageName: "my-home-page", // current page
	idleTimeoutInSeconds: 30, // seconds 
	websocketOptions: { // optional
	    websocketHost: "ws://your_host:your_port",
		appId: "insert-your-made-up-app-id"
	}
});

Using standard http requests to send time

Alternatively you can issue an HTTP request to your back end server to report time. Note: the following example sends an HTTP request during the the window.onbeforeunload event. This approach may not work in all browsers as there is no guarantee that the request will complete before the browser terminates it.

window.onbeforeunload = function (event) {
	xmlhttp=new XMLHttpRequest();
	xmlhttp.open("POST","ENTER_URL_HERE", true);
    xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
	let timeSpentOnPage = TimeMe.getTimeOnCurrentPageInSeconds();
	xmlhttp.send(timeSpentOnPage);
};

Using onbeforeunload is by no means a requirement. You can hook into any other event or logical point in your application to send the time spent information to the server.

If using a Single Page Application (SPA) design, TimeMe.js can have its timer stopped, page name switched, and the timer resumed (for the new page) with the following calls:

TimeMe.stopTimer();
// ... Now might be a good time to upload the time spent on the page to your server!
// ... load up new page
TimeMe.setCurrentPageName("new-page-name");
TimeMe.startTimer();

All page times are tracked in TimeMe.js, so you can review total aggregate time spent on each page for a particular user's session:

let timeSpentReport = TimeMe.getTimeOnAllPagesInSeconds();

This call will return an array of objects of page names and the corresponding aggregate time spent on that page.

What browsers are supported?

All major desktop and mobile browsers.

How do I run the unit tests?

You'll need to install QUnit, which should be packaged with TimeMe.js if you performed a Bower install of TimeMe.js. Once you have installed QUnit, you can simply open the test HTML files in a browser to execute the tests.

API

TimeMe.initialize(options);

// options.currentPageName // - Optional. Name of the page (home, about, etc.).
// options.idleTimeoutInSeconds // - Optional. How long before user is considered idle. Default is 30s.
// options.initialStartTime // - Optional. Indicates start time for timer manually. Must be of type Date(). Default is *now*.
// options.trackWhenUserLeavesPage // Optional. Must be type boolean. Default is true.
// options.trackWhenUserGoesIdle // Optional. Must be type boolean. Default is true.
// options.websocketOptions: { // Optional. Turn on websocket reporting.
// 	 websocketHost: "ws://your_host:your_port",
// 	 appId: "insert-your-made-up-app-id"
// }

Initializes and starts first timer. Should only be called when first importing the library and beginning to time page usage. All config items are optional.

TimeMe.getTimeOnCurrentPageInSeconds();

Retrieves the time spent (in seconds) on the current page.

TimeMe.getTimeOnPageInSeconds(pageName);

Retrieves the time spent (in seconds) on the indicated page.

TimeMe.callAfterTimeElapsedInSeconds(timeInSeconds, callback);

Sets up a handler that executes after the user has spent the specified time interacting with the page.

TimeMe.callWhenUserLeaves(callback, [[numberOfInvocations]]);

Sets up a handler that executes when the user is no longer interacting with the page due to inactivity, switching tabs, or switching apps. You can optionally provide numberOfInvocations to limit how many times this executes.

TimeMe.callWhenUserReturns(callback, [[numberOfInvocations]]);

Sets up a handler that executes when the user returns to the page after inactivity, switching tabs, or switching apps. You can optionally provide numberOfInvocations to limit how many times this executes.

TimeMe.trackTimeOnElement(elementId);

Start timing all user activity on a certain element. A timer will be created that tracks how long the user typed, clicked, moused over, or otherwised focused on this element. Must pass in the ID of the HTML element.

TimeMe.getTimeOnElementInSeconds(elementId);

Retrieve the time spent by a user on a specific element. Must pass in the ID of the HTML element.

TimeMe.setCurrentPageName(newPageName);

Sets the page name to be associated with any future calls to timer.

TimeMe.setIdleDurationInSeconds(durationInSeconds);

Sets the time (in seconds) that a user is idle before the timer is turned off. Set this value to -1 to disable idle time outs.

TimeMe.getTimeOnAllPagesInSeconds();

Retrieves the time spent on all pages that have been recorded using TimeMe.js. Notice this only works for Single Page Applications (SPAs) where TimeMe.js is only initialized once.

TimeMe.startTimer();

Manually starts the timer for the current page. Notice this only works if the timer is currently stopped.

TimeMe.stopTimer();

Manually stops the timer. Notice this only works if the timer is currently running.

TimeMe.resetRecordedPageTime(pageName);

Clears the recorded time for the indicated page name.

TimeMe.resetAllRecordedPageTimes();

Clears all recorded times for all pages.

Build Tools

To minify the code, run the following:

# install babel-minify if not already available
npm install babel-minify -g

# Minify the code    
minify timeme.js --out-file timeme.min.js

timeme.js's People

Contributors

ammsa avatar elin3t avatar fridzema avatar jasonzissman avatar neil-ni avatar wheeyls avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

timeme.js's Issues

Dependencies with RequireJS

I'm building and embeddable JS widget which has a requirement not to inject any new global variable to the page. I'm using requireJS to do this and importing TimeMe as a module. The import works, but because TimeMe expects ifvisible to be available in the global scope, and it's isn't via RequireJS, it can't initialize properly.

I've made a couple of changes that I'd like to get your opinion on as I'm not that familiar with AMD modules and requireJS.

I've added ifvisible as a dependent module in define and set it as a property (which I don't think I like):

if (typeof define === "function" && define.amd) {
    define(['ifvisible'], function(ifvisible) {
      TimeMe.ifvisible = ifvisible;
      return TimeMe;
    });
} else {
    window.TimeMe = TimeMe;
}

and then detected this.ifvisible in getIfVisibleHandle to set the handle correctly.

getIfVisibleHandle: function(){
    if (typeof ifvisible === 'object') {
        return ifvisible;
    else if (typeof this.ifvisible === 'object') {
        return this.ifvisible;
    } else {
        if (typeof console !== "undefined") {
            console.log("Required dependency (ifvisible.js) not found.  Make sure it has been included.");
        }
        throw {
            name: "MissingDependencyException",
            message: "Required dependency (ifvisible.js) not found.  Make sure it has been included."
        };
    }
},

I think ideally i'd rewrite the class to have a constructor function and pass in the dependency but it's a lot of changes. Interested to hear your thoughts on this!

Add bower support & more

  • Please add bower support to your repository and register the project
  • Please add " ifvisible.js" as dependency, never put third party libs into your repository.
  • Please create a tag
  • Please correct the typo in TImeMe.js to TimeMe.js
  • Update the API from clear_ to reset_ inside the README.md

Thanks

Huge times

Some times the time that outputs the module is incredibly high.

I'm using this module on a tracking system and some times the time that i received from the module is really high.

Any ideas on what can be causing this?. I think it might be a browser incompatibility. But sadly i haven't been able to track the bug down

How to get total time spent on multiple pages?

Hi,

Thanks for this great plugin. as I can see when page is reloaded, time counter is set to '0'. I have below query

  1. lets say if user spent 2 min on home page and then goto about page, is there a way on about page counter should continue i..e start from 2 min and go ahead

i.e. instead of tracking time spent on page I would like to see total time spent on website when user visited different pages

Thanks
Pravin

idleTimeoutInSeconds -1

I have the 'idleTimeoutInSeconds' set to -1, however this doesn't seem to have an effect.

TimeMe.initialize({
    currentPageName: "live.php", // current page
    idleTimeoutInSeconds: -1 // seconds
});

setInterval(function(){
    var timeSpentOnPage = TimeMe.getTimeOnCurrentPageInSeconds();
    console.log(timeSpentOnPage);
    $.post( "record.php", { uuid: "<?php echo $uuid; ?>", time: timeSpentOnPage, page: 'live.php' } );
}, 1000);

Otherwise, script runs fine.

How to deal with embedded videos playing?

I have a page with embedded videos (not iframes). Short of writing a function to monitor the video embed pause/start times, can TimeMe be adjusted to factor in these elements?

Thanks

Auto save data to database

Hello,

Is there any way to auto save time spent on the page to database table (because i need to add some other data like usename) ?

Good job by the way !

Inittialize after reset causes failure

Try this:

TimeMe.setCurrentPageName('test');
TimeMe.initialize();
TimeMe.resetRecordedPageTime('test');

TimeMe.setCurrentPageName('test');
TimeMe.initialize();

is causing a type error:

TypeError: arrayOfTimes[(arrayOfTimes.length - 1)] is undefined

How do you measure how long the person has been on the page?

First of all, fantastic work on the library. I am looking to measure 2 things

  1. How long the person has been on the page regardless of whether they interacted or not?
  2. How long the person has interacted on the page?
  3. Going through your issues I found that mentioned if you idleTimeout to -1 it will stop tracking immediately the moment person goes idle
  4. How do I not have an idle timeout at all meaning even if the person is just reading the page and not doing anything indefinitely, the timer should keep running

Suggestions are super appreciated

Reset time

Hi.

first of all, really nice job!

I have a situation where i need to save the time in database, then reset the value to 0

this is my code
` setInterval(function () {

        var currentTime = TimeMe.getTimeOnCurrentPageInSeconds().toFixed(2);
            $.post("/admin/user_times", {time: currentTime, user_id: user_id}, function(data, status){
                TimeMe.resetRecordedPageTime('home-page');
                console.log('aici:' + currentTime);
            });

        }, 5);

    }, 5000);`

But after saving the time, i get undefined and "Uncaught TypeError: Cannot read property 'toFixed' of undefined"

What i'm doing wrong?

Thanks!

Release version 2.1

On version 2, Argument should be called websocketOptions instead of websocktOptions
2.1 would break the API but fix this, along with other 23 commits pending.

Not working correctly when user watches a video on a page

When a user is watching a video e.g. YouTube embedded on the page, he fastly goes idle with your script (not accounting the view time of a video).

It would be good, if you could implement a beacon function which could be triggered manually in order to let the script continue measuring time.

bower folder was pushed

You accidently pushed the bower_components folder, I suggest to remove it and add .gitignore...

Bug in your implementation Incorrect time tracked

Firefox version 68.0.2 (64-bit)
Platform OSX High Sierra 0.13.6

How to reproduce

  1. Set idletimeout to -1 so that it immediately stops the moment the user stops
  2. Move around the page, timer is running
  3. Go to a different tab
  4. Come back to our tab but dont move the mouse into the address bar or anywhere below the address bar
  5. Timer still running

bug

Timer stops counting when leaving page even though trackWhenUserLeavesPage = false

I want to just know the time a user completely spends on the site even if the user is afk or not...
i found this and tried configuring it so i could get the time a user has my site up for.
When i ran it with the trackWhenUserGoesIdle and trackWhenUserLeavesPage set to false, it continued to stop the timer...
Pls tell me if theres a way i can fix it in my code or if this is a problem from the developers...
heres the code:

<script src="../timeme.min.js"></script>
	<script type="text/javascript">
		TimeMe.initialize({
      trackWhenUserGoesIdle: false,
      trackWhenUserLeavesPage: false,
		});

Window event handlers

At several points the library adds focus and blur handlers to the window. However, there is no explicit unloading of these events.

Even after calling stopTimer or stopAllTimers events handlers are still registered and continued to fire. Because the event handlers are anonymous functions there is no explicit way to removing those specific handlers. Removing all handlers from the window could have unintended side effects on the client application.

userHasLeftPage on click on Iframe

Hello, when the user click on an iframe on a page TimeMe.js considers that the user has left the page because a click on an iframe triggers 'blur' on the window.

Do you have an idea to solve this issue ?

Stop timer when page is not visible

I run startTimer from a setInterval(); This is not detected, so it still starts counting while the page is not visible.
I think it would be best to immediately stop the timer when a startTimer() is triggered while being invisible. This will create an duration of '0', as would probably be sensible:

startTimer: function () {
    var pageName = TimeMe.currentPageName;
    if (TimeMe.startStopTimes[pageName] === undefined) {
        TimeMe.startStopTimes[pageName] = [];
    } else {
        var arrayOfTimes = TimeMe.startStopTimes[pageName];
        var latestStartStopEntry = arrayOfTimes[arrayOfTimes.length - 1];
        if (latestStartStopEntry !== undefined && latestStartStopEntry.stopTime === undefined) {
            // Can't start new timer until previous finishes.
            return;
        }
    }
    TimeMe.startStopTimes[pageName].push({
        "startTime": new Date(),
        "stopTime": undefined
    });

    // immediately stop timer, if start is requested while page is out of focus:
    if(TimeMe.getIfVisibleHandle().now() == false)
    {
        TimeMe.stopTimer();
    }
},

License Confusion

Bit confused about the license you've chosen to publish this under.

Is it Apache License, as the attached license file, or is it MIT as the bower.json file claims?

onbeforeunload not supported in iOS

Hello,

I have tested to send a time to database with AJAX script with the event onbeforeunload and it seems to not working.
Someone has the same issue ?

I tried with onunload and it seems to work, any problem to use this function instead onbeforeunload ?

Regards

Use of Pusher as the websocket receiver?

This package looks like it will definitely fit my needs! Quick question, though. Can anyone suggest some approaches for utilizing Pusher as the websocket receiver for the timing data? I'd rather not have to roll something just for this, since we already use Pusher on our pages.

Thanks for any guidance or suggestions!

ifvisible is not defined

Please confirm that ifvisible.js was loaded before you using it. Maby you pass it via the closure:

(function (ifvisible) {

if (typeof ifvisible === 'object') {
}

})(this.ifvisible);

How to get appid?

very nice work, it helped me too much.
I'm trying to send the time spent to the server through the web socket protocol but I don't know what is the app id that I must provide it with the websocketOptions
how to get it ?

What does the user see?

What are the implications of this for the user? What will they see?

  • What does the network traffic look like? How often is it sent? How large are the payloads? What urls will be hit?

Provide the element to tack, not the ID

Is it posible to tack an element by passing the element it self instead of it's ID ?

This would be specially useful for Apps developed in Polymer/WebComponents

getTimeOnCurrentPageInSeconds returns huge value

TimeMe works beautifully and we're using as directed to measure the amount of time people are using our site. We set a timer on page load and on various page events we post this back to the server and record it in a database.

Very occasionally, we see enormous times in these logs, like on the order of 7 million seconds, which is about 2 months. Since the activity timeout is 5 seconds, I don't think there's any way that this could be a true time spent on the page. Even if you left the page up and never timed out, it's hard to imagine a page staying alive for that amount of time.

And sometimes we'll see a time like 700,000 seconds, and then subsequent activity a minute later of 700,060 seconds, so it seems like TimeMe is somehow being initialized to this extreme value, and working correctly thereafter.

It's always probable that this is a bug in my code, but so far I don't see it.

Disable Timeout

I've been playing around with TimeMe.js today, however it seems there is no way to disable a timeout. By default, the timeout appears to be 60 seconds, and any other numbers (0, -1, infinity) all seem to change the timeout to 0. I've also tried 2678400 seconds as well, although it seems to default to the 0 timeout.

Timer needs to be reinitialized after being reset. How can I just set the timer to zero?

I save time the user spends working on a project on my page. Because saving to my database isn't that reliable just on unload, I also save the time spent every time the user saves their project.

So, after a user saves their project, I send that time to be saved to my database, and want to reset the timer to zero.

I thought that's what ResetRecordedPageTime(my page name) would do. What it actually seemed to do is remove the timer altogether - if I reset the page time, then wait, then try to retrieve time spent, I get NaN.

What I'm doing is calling ResetRecordedPageTime(mypage), then re-initializing the timer (same page name every time). This seems to work and have the behavior I want.

Should ResetRecordedPageTime destroy the timer? The docs should indicate this, if so. And it would be nice to have a function that lets you set a timer value to whatever you want so you can zero it out after saving the time saved.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.