Watcher for Toggle Time Tracking for Activity Watch

Zach Strout · December 9, 2023

Activity Watch is an open source time tracker for your computer. It automatically tracks how you spend your time on your computer. It is a modular system. There are different modules to track different things so that you can correlate different activities. For example, some people have created different modules to track and import spotify usage into the tracker. Others have used it to track the height of a height-adjustable table. Each of these modules are called “watchers” since they “watch” something and report it to the Activity Watch server that runs locally and privately.

For work related things (particularly things that I do away from my computer) and to track other things like time spent reading, I use toggl track. It just works. It also has a pretty good browser extension so that tracking time is pretty easy. The API is fantastic; it provides a rich set of data and is easy to integrate with. In fact, other apps - like Timery are based around integrating with the API to improve the experience of using toggl.

So my problem was that I had these two data sources that could not be seamlessly compared: Activity Watch that tracked general computer usage and toggl that tracked specific things that were not necessarily tied to my computer. To better understand patterns, it would be nice to combine these two data sources. Since Activity Watch is designed to be a hub of data, it was natural to find a way to integrate my toggl data into Activity Watch. This meant that I needed to create a “watcher” for toggl. You can find the code for it here. There is not really anything too complicated about it, but it might be useful to talk about some design decisions that I made about it.

The primary way that watchers do their work is by doing live updates to the Activity Watch database. When you open a program, the watcher that watches for programs will initialize a new event. Through a “heartbeat” mechanism, it will determine if it should merge the opening of the program into one long event or if it should close out the event. While this is pretty helpful, it is kind of a shame that all of the great data in the toggl database is not used. It normally would only track new tracking events. To get around this, Activity Watch also has the ability to upload events if given start times, durations, and arbitrary data. Since I wanted to include at least a full month of data, I added the ability to have the watcher first fetch this month’s and last month’s events and add them to the activity watch database. After doing this bulk add, it will work in the normal live update way. Now, there is one big problem with this. If it does this for every time that the watcher is started, there is a good chance that there will be lots of duplicates will be added to the Activity Watch database. To get around this, I add the toggl event id to the arbitrary data that Activity Watch allows you to add, and only add toggl events to the Activity Watch database if they have not been added already. This method works pretty good, but maybe in the future, I should not depend on the id of the events. I should create individual hashes of the events in Activity Watch and check if the hash changes. This would be more useful if I edit the event on the toggl website like fixing an end date or a title. If I change those now, it will not update in Activity Watch since the id already exists. If I find that the id already exists and the hash has changed, then I can update the event. If the hash is the same, then I can leave it be.