question

TkTech avatar image
0 Votes"
TkTech asked harsha111111-5189 commented

Get actual time spent browsing websites by user C#.NET

I have written a C#.NET app to fetch browser's history of websites visited by a user on his machine. But, want his actual time while visiting sites. For example,

  1. If user just visits a website for 3 minutes.

  2. Next, he lets the website remain open in a tab for 2 hours

  3. Goes on to do some other task on his machine

So, the total time visiting the site should be 3 minutes only.


But, this is giving total time, i.e. 2 hours , which is incorrect. Please suggest

dotnet-csharp
· 4
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Browsers are not directly connected to a web server in a typical web application. The only timing information available is the last time the user's browser made an HTTP request to a URL on your site. Store URL and time in a table along with a userid. With this information, the time between requests can be calculated. This infers how long the user might have left the page open in the browser.

I recommend learning HTTP basic. This will help you come up with an acceptable solution within the bounds of a web application and your requirements.

1 Vote 1 ·

Thanks @AgaveJoe for response. .
Checked with customer. They want to develop an application similar to https://desktime.com/ .
Can you give some pointers now?

Regards,

0 Votes 0 ·

You would need to write a browser extension usually done for each browser eg. Chrome, FireFox etc.

For instance for Chrome https://developer.chrome.com/docs/extensions/mv3/getstarted/

1 Vote 1 ·

Thanks @karenpayneoregon for response. .
Checked with customer. They want to develop an application similar to https://desktime.com/ .
Can you give some pointers, how this app would be doing ?

Regards,


0 Votes 0 ·
cooldadtx avatar image
1 Vote"
cooldadtx answered AgaveJoe edited

There is no such information available that I'm aware of. How exactly do you know that a user is interacting with a site vs just leaving it open? The most you might have is when the site was opened (from history).

You said you used the given link to get the time but the original link was just getting browser history. How do you know that the user even sat on a site for 2 hours? Hopefully you're not relying on time differencing between history links as that won't work at all. Please provide some sample code.

Also please provide what problem you're actually trying to solve because honestly it sounds like you're trying to create a "big brother" app to monitor people and it probably isn't going to work.

· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi @cooldadtx ,
Checked with the customer. Their application needs to track URLs /websites visited by employees.

My source code uses history file of Chrome and Edge browsers, and gets time from visit_duration and last_visit_time columns. But as explained in my question, they need active visit time i.e. 2 minutes and not 3 hours .

They want to develop similar to https://desktime.com/
Can you give some pointers, how this app would be doing ?

Regards,


0 Votes 0 ·

That information is not available. There is no way to know how long someone is actually browsing a site. SPAs don't need to change the URL (take Azure DevOps) for example. You can use heuristics as mentioned earlier but you will not get accurate timing short of perhaps a browser extension for each browser. That is simply information that is not tracked anywhere.

The list of sites browsed is available as mentioned however an incognito browser would break that as would opening and closing the browser window faster than the timer runs. If you want true URL tracking then you have to go the firewall or network level.

I don't think the app you linked works the way you think it does. It either uses an extension or it is literally just tracking how much time a page is open, not necessarily how long they are on it. Hence someone could bring up youtube and leave it open all day and the timing is wrong.

Personally I'd start simple with URL tracking and total time length.

0 Votes 0 ·

Educate yourself and your customer on the limitations of HTTP. Once you understand these limitation, then you should be able to build a solution where everyone understands the limitations. For example, you can assume a user is not staring at the page for 3 hours. You can also assume a user is no longer visiting the site if the last access time is greater than 20 minutes or whatever time you and your customer come up with.

0 Votes 0 ·
TimonYang-MSFT avatar image
1 Vote"
TimonYang-MSFT answered harsha111111-5189 commented

I have a rough idea, we can use a service.

Tutorial: Create a Windows service app

Use Timer to detect whether the browser is open, record the currently active page, add it to a List<HistoryItem>, and then use another Timer to detect whether the currently active page has changed. If it changes, record the current time, which is the start time of the current page and the end time of the previous page.

At the same time, query whether the current page already exists in the list, if it already exists, modify the VisitedTime of that item.

Because the user may switch pages during the two polls of the Timer, the time obtained by this method is not completely accurate, just relatively close.

Moreover, as cooldadtx said, if a user opens a page for a long time without any action, we cannot tell whether the user is active or not, maybe he is reading a difficult paper. So in this way, as long as the page does not switch, we will treat it as active.

HistoryItem Class:

     public class HistoryItem
     {
         public string Title { get; set; }
         public DateTime VisitedTime { get; set; }
         public DateTime StartTime { get; set; }
         public DateTime EndTime { get; set; }
     }

Check if the browser is running:

        static bool CheckIfBrowserIsRunning()
         {
             Process[] Processes = Process.GetProcessesByName("chrome");
             if (Processes.Length <= 0)
                 return false;
             if (!Processes.Any(d => d.MainWindowHandle != IntPtr.Zero))
                 return false;
    
             return true;
         }

Get the title of the currently active window:

     class Program
     {
         public delegate bool Win32Callback(IntPtr hwnd, IntPtr lParam);
    
         [DllImport("user32.dll")]
         protected static extern bool EnumWindows(Win32Callback enumProc, IntPtr lParam);
    
         private static bool EnumWindow(IntPtr handle, IntPtr pointer)
         {
             List<IntPtr> pointers = GCHandle.FromIntPtr(pointer).Target as List<IntPtr>;
             pointers.Add(handle);
             return true;
         }
         [DllImport("User32", CharSet = CharSet.Auto, SetLastError = true)]
         public static extern int GetWindowText(IntPtr windowHandle, StringBuilder stringBuilder, int nMaxCount);
    
         [DllImport("user32.dll", EntryPoint = "GetWindowTextLength", SetLastError = true)]
         internal static extern int GetWindowTextLength(IntPtr hwnd);
         private static string GetTitle(IntPtr handle)
         {
             int length = GetWindowTextLength(handle);
             StringBuilder sb = new StringBuilder(length + 1);
             GetWindowText(handle, sb, sb.Capacity);
             return sb.ToString();
         }
         private static List<IntPtr> GetAllWindows()
         {
             Win32Callback enumCallback = new Win32Callback(EnumWindow);
             List<IntPtr> pointers = new List<IntPtr>();
             GCHandle listHandle = GCHandle.Alloc(pointers);
             try
             {
                 EnumWindows(enumCallback, GCHandle.ToIntPtr(listHandle));
             }
             finally
             {
                 if (listHandle.IsAllocated) listHandle.Free();
             }
             return pointers;
         }
     
         static void Main(string[] args)
         {
             foreach (var item in GetAllWindows())
             {
                 string title = GetTitle(item);
                 Console.WriteLine(title);
                 if (title.Contains("Google Chrome"))
                 {
                     Console.WriteLine(title);
                 }
             }
             Console.WriteLine("Press any key to continue......");
             Console.ReadLine();
         }
     }

The link I refer to:

Getting the current tab's URL from Google Chrome using C#

Update(6/25):

Method to get the URL of the active window:

         private static string GetUrlInternal()
         {
             string sURL = null;
             Process[] procsChrome = Process.GetProcessesByName("chrome");
             foreach (Process chrome in procsChrome)
             {
                 if (chrome.MainWindowHandle == IntPtr.Zero)
                 {
                     continue;
                 }
                 AutomationElement element = AutomationElement.FromHandle(chrome.MainWindowHandle);
                 AutomationElement elm1 = element.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "Google Chrome"));
                 AutomationElement elm2 = TreeWalker.RawViewWalker.GetLastChild(elm1);
                 AutomationElement elm3 = elm2.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, ""));
                 AutomationElement elm4 = elm3.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ToolBar));
                 AutomationElement elementx = elm1.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "Address and search bar"));
                 if (!(bool)elementx.GetCurrentPropertyValue(AutomationElement.HasKeyboardFocusProperty))
                 {
                     sURL = ((ValuePattern)elementx.GetCurrentPattern(ValuePattern.Pattern)).Current.Value as string;
                 }
             }
             return sURL;
         }

If the response is helpful, please click "Accept Answer" and upvote it.
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.


Thanks, @TimonYang-MSFT for elaborating it. But, will this code base return the following info?
1. URL - www.reddit.com
2. Total time spent on that website

In your code base, I only see title.


0 Votes 0 ·

I modified the answer and added some code to get the URL of the active window.
We can't get the time directly, we need to use Timer to get the URL continuously and record the time when there is a change. The time between two changes is the time spent on the previous website.

1 Vote 1 ·

Did You get time spent on website also?

0 Votes 0 ·