Syncing is one of the most requested features for ActivityWatch. It is currently being worked on and is in a testing phase.

You can read more about it, and how to try the early release, in the aw-sync README.

Here is a tweet announcing the early MVP:

Old syncing prototype


The below details the architecture of the old syncing prototype. It is kept here for reference.

There isn’t much written about syncing yet since it’s not yet implemented in a stable release. However, there does exist a working proof-of-concept prototype which should be easy to implement once details have been finalized. You can read what has been discussed in this issue:

Here’s a graph showing how data flows in the current syncing prototype:

digraph {
    rankdir = LR;
    node [shape=cylinder style=filled fillcolor=white fontsize=10 margin=0.05];

    subgraph cluster_sync {
        rankdir = LR;
        label="Sync folder \n(Syncthing, Dropbox, etc.)";
        d_a_window_sync[label="window from A" fillcolor=yellow];
        d_b_window_sync[label="window from B" fillcolor=yellow];
        d_c_window_sync[label="window from C" fillcolor=yellow];

    subgraph cluster_a {
        label="Device A";
        d_a_window[label="window" fillcolor=green];

    subgraph cluster_a_dest {
        label="Device A";
        d_b_window_at_a[label="window from B" fillcolor=gray];
        d_c_window_at_a[label="window from C" fillcolor=gray];

    subgraph cluster_b {
        label="Device B";
        d_b_window[label="window" fillcolor=green];

    subgraph cluster_b_dest {
        label="Device B";
        d_a_window_at_b[label="window from A" fillcolor=gray];
        d_c_window_at_b[label="window from C" fillcolor=gray];

    subgraph cluster_c {
        label="Device C";
        d_c_window[label="window" fillcolor=green];

    subgraph cluster_c_dest {
        label="Device C";
        d_a_window_at_c[label="window from A" fillcolor=gray];
        d_b_window_at_c[label="window from B" fillcolor=gray];

    d_a_window -> d_a_window_sync[color=green,penwidth=2];
    d_b_window -> d_b_window_sync[color=green, penwidth=2];
    d_c_window -> d_c_window_sync[color=green, penwidth=2];

    d_a_window_sync -> d_a_window_at_b[color=orange, penwidth=2];
    d_a_window_sync -> d_a_window_at_c[color=orange, penwidth=2];
    d_b_window_sync -> d_b_window_at_a[color=orange, penwidth=2];
    d_b_window_sync -> d_b_window_at_c[color=orange, penwidth=2];
    d_c_window_sync -> d_c_window_at_a[color=orange, penwidth=2];
    d_c_window_sync -> d_c_window_at_b[color=orange, penwidth=2];

    { rank=same; d_a_window; d_b_window; d_c_window; }
    { rank=same; d_a_window_sync; d_b_window_sync; d_c_window_sync; }

Green boxes are source buckets (only written to and read from by the owner). Yellow boxes are the synced version of buckets (written to by the owner, read by consumers). Gray boxes are local copies of remote buckets.

It can be briefly described as follows:

Device A takes its buckets to sync and puts the data in the synced copy, the synced copy gets distributed to device B, device B takes the synced copy and imports it to it’s local datastore.