I have a Chrome extension that I am using to run some batch jobs on a site in the early hours of the morning. I already have a content script in place to run when this URL is called in Chrome and complete all the necessary jobs. I'm having a problem now figuring out the best way to string this to a scheduler so this URL gets opened automatically in a Chrome tab at 3:00 am. I am running all this code in a dedicated Azure Virtual Machine so there won't be any user logged in when the script is set to run. When the new tab has finished it's work it will close automatically, this I have already handled.
So far I have experimented with using the Windows Task Scheduler to open Chrome with the URL passed in as an argument. This method however is proving to be somewhat unreliable!
If I leave Chrome open on the Virtual Machine, is there any native Chrome API I can use to open a tab at a specific time with a URL? I've also used the following javascript function in a separate page to trigger the URL to open, however I have no mechanism to test if it's already running in another tab so this code would result in endless new tabs being opened, unless it could be adapted to check if the URL is already open, and I think this will be outside the scope of Javascript on it's own.
var myUrlToCall = "http://www.myspecialurl.com/runme.html";
//IS 3 AM YET?
function runTimer() {
setTimeout(function () {
var dtNow = new Date();
var hoursNow = dtNow.getHours() * 1;
if (hoursNow >= 3) {
//Open new window here (but how can I know if it's already open?)
window.open(myUrlToCall);
} else {
runTimer();
}
}, 3000);
}
Any thoughts on this would be much appreciated.
The chrome.alarms API is a perfect fit for your use case, to be used at an event page.
function createAlarm() {
var now = new Date();
var day = now.getDate();
if (now.getHours() >= 3) {
// 3 AM already passed
day += 1;
}
// '+' casts the date to a number, like [object Date].getTime();
var timestamp = +new Date(now.getFullYear(), now.getMonth(), day, 3, 0, 0, 0);
// YYYY MM DD HH MM SS MS
// Create
chrome.alarms.create('3AMyet', {
when: timestamp
});
}
// Listen
chrome.alarms.onAlarm.addListener(function(alarm) {
if (alarm.name === '3AMyet') {
// Whatever you want
}
});
createAlarm();
About creating the tab: The chrome.tabs.query method can be used to check for the existence of a tab, and open a new one if necessary. I assume that you want to focus an existing tab if needed:
var url = '...';
chrome.tabs.query({
url: url
}, function(tabs) {
if (tabs.length === 0) {
chrome.tabs.create({ url:url, active: true });
} else {
// Focus first match
chrome.tabs.update(tabs[0].id, { active: true });
}
});
Related
I have a URL that is being invoked by a cron job, but I am not getting it to work.
I am planning to do the same using Javascript: how can I reload the page this way on particular hour of the day (8:00 PM)?
I wanted to reload a controller from the index page. I will write this script and place the URL in here – Hasif
Since the use of Javascript in your situation is restricted to the front-end, the user would need to keep the page open (index as you mentioned) the whole time. This means that:
the URL call will only be made if the user keeps the browser open (if this task really needs to run everyday, you should not rely on the client side to make it happen);
the cron-job you mentioned is the better alternative, but you have no way to force the user's browser to open up at 8:00 PM everyday;
the user's local time will not be useful to trigger this event if the URL is supposed to be loaded for all users at the same time, so trigger it at a certain time in the UTC timezone (for example).
Solution
Create a cookie that stores the date and time when the index page was last loaded by the user and each time the page loads, compare it to the current date and load the URL only once (MDN example). You might want to set the cookie in the backend, but a simple example to store and load it in JS:
var td =new Date(), date2store = `${td.getUTCFullYear()}-${td.getUTCMonth().toString().padStart(2,0)}-${td.getUTCDate().toString().padStart(2,0)} ${td.getUTCHours().toString().padStart(2,0)}:${td.getUTCMinutes().toString().padStart(2,0)}`;
alert('Cookie to store: last_date=' + date2store + ' --> Is it after 8 PM UTC? ' + (new Date(date2store).getUTCHours() >= 19 ? 'YES!' : 'NO!' ));
If the user keeps the browser open until the next day use a simple script loaded into the page to check the current UTC hour and update:
// place the code below in a setInterval(function() {...}, 1000*60*60);
// the if below should also the test the current cookie's datetime as the first condition
// 0 index hour exists (therefore compare with 19 instead of 20)
if(new Date().getUTCHours() >= 19) {
alert('Past 8 PM');
// save the current date and time in the cookie HERE
// reload the index page
// window.location.reload(true); // true for not using cache
// OR redirect to a new location
// window.location.href = 'https://...';
} else alert('Not 8 PM yet');
The following JavaScript snippet will allow you to refresh at a given time:
function refreshAt(hours, minutes, seconds) {
var now = new Date();
var then = new Date();
if(now.getHours() > hours ||
(now.getHours() == hours && now.getMinutes() > minutes) ||
now.getHours() == hours && now.getMinutes() == minutes && now.getSeconds() >= seconds) {
then.setDate(now.getDate() + 1);
}
then.setHours(hours);
then.setMinutes(minutes);
then.setSeconds(seconds);
var timeout = (then.getTime() - now.getTime());
setTimeout(function() { window.location.reload(true); }, timeout);
}
Then you can add a script tag to call the refreshAt() function.
refreshAt(15,35,0); //Will refresh the page at 3:35pm
I am in process of building an extension, the extension displays a value in seconds to the user as for the amount of time user has spent on a particular website. I have got everything working but every time chrome is quitted or the computer is restarted the time variable starts counting again from 0. I figured using chrome storage API should do the job. After going through the API documentation I managed to store and retrieve a number from the local storage. What I can't do is how to save the data to the local storage when user quits chrome. Is there a way to detect such an event?
First of all, you don't need to use the chrome.storage API to make this work. By the way, unfortunately, what you're looking for does not exist. You are looking for some event (like onBrowserClosed) that isn't implemented in the Chrome APIs. A bug report has been made HERE (although it actually isn't a bug), if you want to stay updated you can star it.
Although, you can still approach the problem with a setInterval(), that will execute your function to update the time a user has spent on a site every certain interval (in milliseconds), and will stop when the browser is closed. Something like this:
var currentActiveTab, chromeHasFocus = false;
localStorage.timeSpentOnSites = localStorage.timeSpentOnSites || "{}";
// get the first tab at startup
chrome.tabs.query({active: true, highlighted: true}, function(tabs) {
currentActiveTab = tabs[0];
console.log('New active tab:', tabs[0]);
});
// this will keep currentActiveTab updated to always be the active tab (the one that the user is watching)
chrome.tabs.onUpdated.addListener(function(tabID, info, tab) {
if (tab.active && tab.highlighted) currentActiveTab = tab;
console.log('New active tab:', tab);
});
// this also
chrome.tabs.onActivated.addListener(function(info) {
chrome.tabs.query({active: true, highlighted: true}, function(tabs) {
currentActiveTab = tabs[0];
console.log('New active tab:', tabs[0]);
});
});
// this will check if chrome is active or not
chrome.windows.onFocusChanged.addListener(function(windowID) {
if (windowID === chrome.windows.WINDOW_ID_NONE) {
chromeHasFocus = false;
console.log('Chrome lost focus.');
} else if (!chromeHasFocus) {
chromeHasFocus = true;
console.log('Chrome has focus.');
}
});
function addTimeSpentOnSite(site) {
var T = JSON.parse(localStorage.timeSpentOnSites);
// if site already exists increment the time spent on it
if (T[site]) T[site]++;
// otherwise set the time spent on it as 1 (second)
else T[site] = 1;
localStorage.timeSpentOnSites = JSON.stringify(T);
}
setInterval(function() {
if (!chromeHasFocus) return;
// if the chrome window isn't active the user is not watching the site
var site = currentActiveTab.url.split('/')[2];
// get the site name, something like www.site.com
addTimeSpentOnSite(site);
// increase the amount of time spent on the site
}, 1000);
I want to ask that, is to run a jquery/javascript function such that, A PopUp that will run once on browser of every new user who visit a webpage.
Here is the code which i want to run.
$(window).load(function() {
$('#index9').fadeIn("slow");
});
You can use cookie with expiry of 1 day to create this example.
function showOnceInADay(){
var user=getCookie("user");
if (user != "") {
} else {
$("#index9").fadeIn('slow');
setCookie("user", 1, 1);
}
}
Working fiddle
Say I've a browser extension which runs JS pages the user visits.
Is there an "outLoad" event or something of the like to start counting and see how long the user has spent on a page?
I am assuming that your user opens a tab, browses some webpage, then goes to another webpage, comes back to the first tab etc. You want to calculate exact time spent by the user. Also note that a user might open a webpage and keep it running but just go away. Come back an hour later and then once again access the page. You would not want to count the time that he is away from computer as time spent on the webpage. For this, following code does a docus check every 5 minutes. Thus, your actual time might be off by 5 minutes granularity but you can adjust the interval to check focus as per your needs. Also note that a user might just stare at a video for more than 5 minutes in which case the following code will not count that. You would have to run intelligent code that checks if there is a flash running or something.
Here is what I do in the content script (using jQuery):
$(window).on('unload', window_unfocused);
$(window).on("focus", window_focused);
$(window).on("blur", window_unfocused);
setInterval(focus_check, 300 * 1000);
var start_focus_time = undefined;
var last_user_interaction = undefined;
function focus_check() {
if (start_focus_time != undefined) {
var curr_time = new Date();
//Lets just put it for 4.5 minutes
if((curr_time.getTime() - last_user_interaction.getTime()) > (270 * 1000)) {
//No interaction in this tab for last 5 minutes. Probably idle.
window_unfocused();
}
}
}
function window_focused(eo) {
last_user_interaction = new Date();
if (start_focus_time == undefined) {
start_focus_time = new Date();
}
}
function window_unfocused(eo) {
if (start_focus_time != undefined) {
var stop_focus_time = new Date();
var total_focus_time = stop_focus_time.getTime() - start_focus_time.getTime();
start_focus_time = undefined;
var message = {};
message.type = "time_spent";
message.domain = document.domain;
message.time_spent = total_focus_time;
chrome.extension.sendMessage("", message);
}
}
onbeforeunload should fit your request. It fires right before page resources are being unloaded (page closed).
<script type="text/javascript">
function send_data(){
$.ajax({
url:'something.php',
type:'POST',
data:{data to send},
success:function(data){
//get your time in response here
}
});
}
//insert this data in your data base and notice your timestamp
window.onload=function(){ send_data(); }
window.onbeforeunload=function(){ send_data(); }
</script>
Now calculate the difference in your time.you will get the time spent by user on a page.
For those interested, I've put some work into a small JavaScript library that times how long a user interacts with a web page. It has the added benefit of more accurately (not perfectly, though) tracking how long a user is actually interacting with the page. It ignore times that a user switches to different tabs, goes idle, minimizes the browser, etc.
Edit: I have updated the example to include the current API usage.
http://timemejs.com
An example of its usage:
Include in your page:
<script src="http://timemejs.com/timeme.min.js"></script>
<script type="text/javascript">
TimeMe.initialize({
currentPageName: "home-page", // page name
idleTimeoutInSeconds: 15 // time before user considered idle
});
</script>
If you want to report the times yourself to your backend:
xmlhttp=new XMLHttpRequest();
xmlhttp.open("POST","ENTER_URL_HERE",true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
var timeSpentOnPage = TimeMe.getTimeOnCurrentPageInSeconds();
xmlhttp.send(timeSpentOnPage);
TimeMe.js also supports sending timing data via websockets, so you don't have to try to force a full http request into the document.onbeforeunload event.
The start_time is when the user first request the page and you get the end_time by firing an ajax notification to the server just before the user quits the page :
window.onbeforeunload = function () {
// Ajax request to record the page leaving event.
$.ajax({
url: "im_leaving.aspx", cache: false
});
};
also you have to keep the user session alive for users who stays long time on the same page (keep_alive.aspxcan be an empty page) :
var iconn = self.setInterval(
function () {
$.ajax({
url: "keep_alive.aspx", cache: false });
}
,300000
);
then, you can additionally get the time spent on the site, by checking (each time the user leaves a page) if he's navigating to an external page/domain.
Revisiting this question, I know this wouldn't be much help in a Chrome Ext env, but you could just open a websock that does nothing but ping every 1 second and then when the user quits, you know to a precision of 1 second how long they've spent on the site as the connection will die which you can escape however you want.
Try out active-timeout.js. It uses the Visibility API to check when the user has switched to another tab or has minimized the browser window.
With it, you can set up a counter that runs until a predicate function returns a falsy value:
ActiveTimeout.count(function (time) {
// `time` holds the active time passed up to this point.
return true; // runs indefinitely
});
I would like to measure a time (in seconds in integers or minutes in floats) a user spends on a page. I know there is an unload event which I can trigger when they leave the page. But how to get a time they have already spent there?
The accepted answer is good, but (as an alternative) I've put some work into a small JavaScript library that times how long a user is on a web page. It has the added benefit of more accurately (not perfectly, though) tracking how long a user is actually interacting with the page. It ignore times that a user switches to different tabs, goes idle, minimizes the browser, etc. The Google Analytics method suggested in the accepted answer has the shortcoming (as I understand it) that it only checks when a new request is handled by your domain. It compares the previous request time against the new request time, and calls that the 'time spent on your web page'. It doesn't actually know if someone is viewing your page, has minimized the browser, has switched tabs to 3 different web pages since last loading your page, etc.
Edit: I have updated the example to include the current API usage.
Edit 2: Updating domain where project is hosted
https://github.com/jasonzissman/TimeMe.js/
An example of its usage:
Include in your page:
<!-- Download library from https://github.com/jasonzissman/TimeMe.js/ -->
<script src="timeme.js"></script>
<script type="text/javascript">
TimeMe.initialize({
currentPageName: "home-page", // page name
idleTimeoutInSeconds: 15 // time before user considered idle
});
</script>
If you want to report the times yourself to your backend:
xmlhttp=new XMLHttpRequest();
xmlhttp.open("POST","ENTER_URL_HERE",true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
var timeSpentOnPage = TimeMe.getTimeOnCurrentPageInSeconds();
xmlhttp.send(timeSpentOnPage);
TimeMe.js also supports sending timing data via websockets, so you don't have to try to force a full http request into the document.onbeforeunload event.
If you use Google Analytics, they provide this statistic, though I am unsure exactly how they get it.
If you want to roll your own, you'll need to have some AJAX request that gets sent to your server for logging.
jQuery has a .unload(...) method you can use like:
$(document).ready(function() {
var start = new Date();
$(window).unload(function() {
var end = new Date();
$.ajax({
url: "log.php",
data: {'timeSpent': end - start},
async: false
})
});
});
See more here: http://api.jquery.com/unload/
The only caveat here is that it uses javascript's beforeunload event, which doesn't always fire with enough time to make an AJAX request like this, so reasonably you will lose alot of data.
Another method would be to periodically poll the server with some type of "STILL HERE" message that can be processed more consistently, but obviously way more costly.
In addition to Jason's answer, here's a small piece of code that should do the trick if you prefer to not use a library, it considers when the user switch tabs or focus another window.
let startDate = new Date();
let elapsedTime = 0;
const focus = function() {
startDate = new Date();
};
const blur = function() {
const endDate = new Date();
const spentTime = endDate.getTime() - startDate.getTime();
elapsedTime += spentTime;
};
const beforeunload = function() {
const endDate = new Date();
const spentTime = endDate.getTime() - startDate.getTime();
elapsedTime += spentTime;
// elapsedTime contains the time spent on page in milliseconds
};
window.addEventListener('focus', focus);
window.addEventListener('blur', blur);
window.addEventListener('beforeunload', beforeunload);
𝗨𝘀𝗲 𝗽𝗲𝗿𝗳𝗼𝗿𝗺𝗮𝗻𝗰𝗲.𝗻𝗼𝘄()
Running inline code to get the time that the user got to the page blocks the loading of the page. Instead, use performance.now() which shows how many milliseconds have elapsed since the user first navigated to the page. Date.now, however, measures clock-time which can differ from navigation-time by a second or more due to factors such as Time resynchonization and leap seconds. performance.now() is supported in IE10+ and all evergreen browsers (evergreen=made for fun, not for profit). The earliest version of internet explorer still around today is Internet Explorer 11 (the last version) since Microsoft discontinued Windows XP in 2014.
(function(){"use strict";
var secondsSpentElement = document.getElementById("seconds-spent");
var millisecondsSpentElement = document.getElementById("milliseconds-spent");
requestAnimationFrame(function updateTimeSpent(){
var timeNow = performance.now();
secondsSpentElement.value = round(timeNow/1000);
millisecondsSpentElement.value = round(timeNow);
requestAnimationFrame(updateTimeSpent);
});
var performance = window.performance, round = Math.round;
})();
Seconds spent on page: <input id="seconds-spent" size="6" readonly="" /><br />
Milliseconds spent here: <input id="milliseconds-spent" size="6" readonly="" />
I'd say your best bet is to keep track of the timing of requests per session ID at your server. The time the user spent on the last page is the difference between the time of the current request, and the time of the prior request.
This won't catch the very last page the user visits (i.e. when there isn't going to be another request), but I'd still go with this approach, as you'd otherwise have to submit a request at onunload, which would be extremely error prone.
i think the best way is to store time in onload and unload event handlers in cookies e.g. and then analyze them in server-side scripts
According to the right answer I think thats is not the best solution. Because according to the jQuery docs:
The exact handling of the unload event has varied from version to
version of browsers. For example, some versions of Firefox trigger the
event when a link is followed, but not when the window is closed. In
practical usage, behavior should be tested on all supported browsers
and contrasted with the similar beforeunload event.
Another thing is that you shouldn't use it after documents load because the result of substraction of time can be fake.
So the better solution is to add it to the onbeforeunload event in the end of the <head> section like this:
<script>
var startTime = (new Date()).getTime();
window.onbeforeunload = function (event) {
var timeSpent = (new Date()).getTime() - startTime,
xmlhttp= new XMLHttpRequest();
xmlhttp.open("POST", "your_url");
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
var timeSpentOnPage = TimeMe.getTimeOnCurrentPageInSeconds();
xmlhttp.send(timeSpent);
};
</script>
Of course if you want to count the time using Idle detector you can use:
https://github.com/serkanyersen/ifvisible.js/
TimeMe is a wrapper for the package that I paste above.
<body onLoad="myFunction()">
<script src="jquery.min.js"></script>
<script>
var arr = [];
window.onbeforeunload = function(){
var d = new Date();
var n = d.getTime();
arr.push(n);
var diff= n-arr[0];
var sec = diff/1000;
var r = Math.round(sec);
return "Time spent on page: "+r+" seconds";
};
function myFunction() {
var d = new Date();
var n = d.getTime();
arr.push(n);
}
</script>
I've found using beforeunload event to be unreliable, actually failing more often than not. Usually the page has been destroyed before the request gets sent, and you get a "network failure" error.
As others have stated, there is no sure-fire way to tell how long a user has been on a page. You can send up some clues however.
Clicking and scrolling are pretty fair indicators that someone is actively viewing the page. I would suggest listening for click and scroll events, and sending a request whenever one is fired, though not more often than say, every 30 or 60 seconds.
One can use a little intelligence in the calculations, eg, if there were events fired every 30 seconds or so for 5 minutes, then no events for 30 minutes, then a couple more events fired, chances are, the user was getting coffee during the 30 minute lapse.
let sessionid;
function utilize(action) {
// This just gets the data on the server, all the calculation is done server-side.
let href = window.location.href;
let timestamp = Date.now();
sessionid = sessionid || timestamp;
let formData = new FormData();
formData.append('sessionid', sessionid);
formData.append('timestamp', timestamp);
formData.append('href', href);
formData.append('action', action || "");
let url = "/php/track.php";
let response = fetch(url, {
method: "POST",
body: formData
});
}
let inhibitCall = false;
function onEvent() {
// Don't allow an update any more often than every 30 seconds.
if (!inhibitCall) {
inhibitCall = true;
utilize('update');
setTimeout(() => {
inhibitCall = false;
}, 30000);
}
}
window.addEventListener("scroll", onEvent);
window.addEventListener("click", onEvent);
utilize("open");