ActivityWatch

Open source application that automatically tracks how you spend time on your devices.

· Website · Docs · GitHub ·

Data Model

Buckets

Each bucket contains a series of events and metadata for those events (such as their type and what collected them).
It is recommended to have one bucket per watcher and host. A bucket should always receive data from the same source.
bucket = {
  "id": "aw-watcher-test_myhostname",
  "created": "2017-05-16T13:37:00.000000",
  "name": "A short but descriptive human readable bucketname",
// Type of events in bucket
  "type": "com.example.test",       
  // Identifier of client software used to report data
  "client": "example-watcher-test",  
  // Hostname of device where data was collected
  "hostname": "myhostname",
}
BucketsEach bucket contains a series of events and metadata for those e...

Heartbeats

Heartbeats is a method that merges adjacent events with identical data (within a pulsetime window). This is useful to save on storage space and disk IO, and it is recommended that watchers use it when sending events to the server.

A merge of two events A and B is done if their data is identical and their timestamps are within the pulsetime window. The resulting event will have the earlier timestamp, and a duration to match the difference between the timestamps.
HeartbeatsHeartbeats is a method that merges...

Events

The event model used by ActivityWatch is pretty simple, here is the JSON representation:
event = {
/// ISO8601 formatted timestamp
"timestamp": "2016-04-27T15:23:55Z",
// Duration in seconds
"duration": 3.14,        
// A JSON object, the schema of this depends on the event type
"data": {"key": "value"},
}
All timestamps are stored as UTC. Timezone information (UTC offset) is currently discarded.
EventsThe event model used by ActivityWatch is pretty simple, here is the JSON represe...

Event types

To separate different types of data in ActivityWatch there is the event type. A buckets event type specified the schema of the vents in the bucket.

By creating standards for watchers to use we enable easier transformation and visualization.

Event typesTo separate different types of data in ActivityWatch there is the event type. A buckets event type spec...

web.tab.current

{
    url: string,
    title: string,
    audible: bool,
    incognito: bool,
}
web.tab.current...

app.editor.activity

{
    // full path to file, separated by forward slash
    file: string,
    // full path of cwd, separated by forward slash
    project: string,
    // name of language of the file
    language: string,
}
app.editor.activity...

currentwindow 

{
    app: string,
    title: string,
}
currentwindow...

afkstatus

{
// "afk" or "not-afk"
status: string
}
afkstatus...
Text is not SVG - cannot display

Querying data

Query by window title keywords

events = flood(query_bucket(find_bucket("aw-watcher-window_")));
not_afk = flood(query_bucket(find_bucket("aw-watcher-afk_")));
not_afk = filter_keyvals(not_afk, "status", ["not-afk"]);
events = filter_period_intersect(events, not_afk);
events = merge_events_by_keys(events, ["app", "title"]);
events = filter_keyvals_regex(events, "title", "(?i)strong.*heart");
events = merge_events_by_keys(events, ["title"]);
RETURN = sort_by_duration(events);