Skip to content

Implement Gmail activity tracking with optional metadata extraction#218

Draft
RaoufGhrissi wants to merge 1 commit intoActivityWatch:masterfrom
RaoufGhrissi:feat/gmail-tracking
Draft

Implement Gmail activity tracking with optional metadata extraction#218
RaoufGhrissi wants to merge 1 commit intoActivityWatch:masterfrom
RaoufGhrissi:feat/gmail-tracking

Conversation

@RaoufGhrissi
Copy link
Copy Markdown

ActivityWatch is used in timesheet tracking, and knowing just "reading" or "composing" email info is not very useful on its own. Extracting involved email metadata (Sender, Recipients, Subject) helps determine the context of the activity relative to project models and workflows in the used software.

A new setting has been added to allow users to enable or disable Gmail tracking.

Also added a build.sh script to simplify the build and test process for Chrome and Firefox.

@RaoufGhrissi RaoufGhrissi force-pushed the feat/gmail-tracking branch from b06c12e to 2c15ffd Compare April 4, 2026 17:39
@BelKed
Copy link
Copy Markdown
Contributor

BelKed commented Apr 4, 2026

Hi! I might be wrong, but it seems to me that aw-watcher-web is meant to stay pretty focused on web watching. Because of that, I’d probably suggest implementing this as a separate extension instead :)

RaoufGhrissi added a commit to odoo/aw-webui that referenced this pull request Apr 4, 2026
@RaoufGhrissi RaoufGhrissi force-pushed the feat/gmail-tracking branch from 2c15ffd to d3f63b9 Compare April 4, 2026 17:47
@RaoufGhrissi RaoufGhrissi changed the title Implement Gmail activity tracking with optional metadata extraction (Sender, Subject, Composing state) Implement Gmail activity tracking with optional metadata extraction Apr 4, 2026
@RaoufGhrissi RaoufGhrissi marked this pull request as ready for review April 4, 2026 17:50
@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Apr 4, 2026

Greptile Summary

This PR implements Gmail activity tracking as an opt-in feature within the ActivityWatch web extension. When enabled via a new settings toggle, a content script injected into mail.google.com extracts contextual metadata (subject, sender, recipients including BCC) from the active view — distinguishing between composing an email, reading one, and browsing the inbox — and relays it as a custom heartbeat to the background script, which forwards it to ActivityWatch. The normal background heartbeat is suppressed for Gmail tabs while this mode is active to avoid duplicate events.

Key changes:

  • src/content/gmail.ts (new): Detects Gmail activity state and extracts email metadata using internal Gmail DOM selectors, polling on an interval.
  • src/background/heartbeat.ts: Adds setupMessageListener to receive AW_GMAIL_HEARTBEAT messages from the content script and skip the standard alarm-based heartbeat for Gmail tabs when the feature is on.
  • src/background/main.ts: Wires up the new listener. Also fixes a latent bug where autodetectHostname was silently relying on the outer-scope client variable — though the fixed parameter is typed as any.
  • src/storage.ts / src/settings/: Clean, consistent additions for the new gmailEnabled preference.
  • build.sh: Convenience build-and-unzip script, missing a shebang.

Main concerns:

  • The content script polls every 1 second, which is 30–60× more frequent than the normal heartbeat and will flood ActivityWatch with events.
  • gmailEnabled is read only once at load time, so toggling the setting won't take effect until the Gmail tab is reloaded.
  • Metadata extraction relies on internal Gmail CSS class names (span.gD, .gE, h2.hP) that can break silently on any Gmail deploy.

Confidence Score: 2/5

Not ready to merge — the 1-second polling interval and one-time settings check are production-quality blockers

The core architecture (content script → background message → AW heartbeat, with normal heartbeat suppressed for Gmail) is sound, but the 1-second interval will flood ActivityWatch with events at 60× normal frequency, and the setting toggle won't take effect dynamically. The fragile internal Gmail DOM selectors are an inherent risk that should at least be documented. The any typing in main.ts is a minor code quality issue.

src/content/gmail.ts has the most critical issues (interval frequency and dynamic settings handling); src/background/main.ts has a typing regression

Important Files Changed

Filename Overview
src/content/gmail.ts New Gmail content script with a 1-second polling interval, one-time setting check, and fragile internal Gmail CSS selectors — all three need attention
src/background/heartbeat.ts Adds message listener for Gmail heartbeats and skips normal heartbeat for Gmail tabs when tracking is enabled; hardcoded pulsetime of 10s
src/background/main.ts Wires up Gmail listener and fixes autodetectHostname to receive client as parameter, but types it as any instead of AWClient
src/storage.ts Adds gmailEnabled storage getter/setter, consistent with existing storage patterns
src/settings/main.ts Adds save/restore logic for gmailEnabled checkbox, consistent with existing settings patterns
src/settings/index.html Adds Gmail tracking checkbox to the settings UI
src/manifest.json Adds content_scripts entry for mail.google.com; .ts path is handled correctly by vite-plugin-web-extension
build.sh Convenience build-and-unzip script; missing shebang line

Sequence Diagram

sequenceDiagram
    participant GM as Gmail Tab (content/gmail.ts)
    participant BG as Background Script
    participant AW as ActivityWatch Server

    Note over GM: Content script loads on mail.google.com
    GM->>GM: browser.storage.local.get('gmailEnabled')
    alt gmailEnabled === true
        GM->>GM: setInterval(sendGmailHeartbeat, 1000ms)
    end

    loop Every 1 second
        GM->>GM: Extract activity state + metadata
        GM->>BG: runtime.sendMessage({type: AW_GMAIL_HEARTBEAT, data})
        BG->>BG: getEnabled() && getGmailEnabled()
        alt Both enabled
            BG->>AW: sendHeartbeat(bucketId, data, pulsetime=10s)
        else Disabled
            BG-->>GM: (message silently dropped)
        end
    end

    Note over BG: Alarm fires every ~30s
    BG->>BG: heartbeat(): check gmailEnabled
    alt gmailEnabled && url includes mail.google.com
        BG-->>BG: return (skip — Gmail content script handles it)
    else Normal tab or Gmail disabled
        BG->>AW: sendHeartbeat(bucketId, normalData)
    end
Loading

Reviews (1): Last reviewed commit: "Implement Gmail activity tracking with o..." | Re-trigger Greptile

@RaoufGhrissi
Copy link
Copy Markdown
Author

RaoufGhrissi commented Apr 4, 2026

Hi! I might be wrong, but it seems to me that aw-watcher-web is meant to stay pretty focused on web watching. Because of that, I’d probably suggest implementing this as a separate extension instead :)

Hi @BelKed thanks,
Correct me if i'm wrong but Gmail still happens in the browser, so it is web watching
I tried to do it in the same extension and bucket to avoid making it hard for users to manage their setup via 2 extensions.

@RaoufGhrissi RaoufGhrissi marked this pull request as draft April 4, 2026 18:11
@RaoufGhrissi RaoufGhrissi force-pushed the feat/gmail-tracking branch 7 times, most recently from ad12e9b to 2522a8a Compare April 4, 2026 21:09
ActivityWatch is used in timesheet tracking, and knowing just "reading" or "composing" email info is not very useful on its own. Extracting involved email metadata (Sender, Recipients, Subject) helps determine the context of the activity relative to project models and workflows in the used software.

A new setting has been added to allow users to enable or disable Gmail tracking.

Also added a build.sh script to simplify the build and test process for Chrome and Firefox.

ui related changes: ActivityWatch/aw-webui#796
@RaoufGhrissi RaoufGhrissi force-pushed the feat/gmail-tracking branch from 2522a8a to 5a79cb0 Compare April 5, 2026 01:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants