Amethyst counts how long you actively spend on each website. Time only counts while the tab is visible and a Chrome window has focus. Switch to Slack and the clock on that site should stop.
The event that doesn't always arrive
Chrome reports focus changes through chrome.windows.onFocusChanged. When focus leaves every Chrome window, it fires with chrome.windows.WINDOW_ID_NONE, which is -1. Amethyst pauses the session when it sees that.
On macOS, that event doesn't always come. Switch apps with Cmd+Tab or the Dock, and Chrome can lose focus without telling extensions. The session stays active, and the site you left keeps getting a minute added, every minute, until something else happens in Chrome.
Ask Chrome before every save
Amethyst saves time once a minute, on a chrome.alarms alarm. Before that save writes anything, it asks Chrome which window has focus instead of trusting the last event:
const lastFocusedWindow = await windows.getLastFocused();
const focusedWindowId =
lastFocusedWindow?.focused && typeof lastFocusedWindow.id === 'number'
? lastFocusedWindow.id
: windows.WINDOW_ID_NONE;
getLastFocused() returns a window even when Chrome is in the background. Its focused flag says whether Chrome has focus right now. If it's false, Amethyst treats that like a focus-lost event and pauses the session. The save then finds a paused session and writes nothing.
The same check runs on tab switches, closed tabs, and worker start-up. The onFocusChanged handler itself ignores the window ID it receives and asks again. The event only tells Amethyst that something may have changed.
Which way to be wrong
When the check finds focus gone, it can't know when you left. It might have been two seconds ago or fifty. So Amethyst ends the session at the last moment it heard from it, its lastEventAt, and drops the time after that.
A missed event now costs a little real time. Before, it added time you never spent. I'd rather a time tracker undercount by a few seconds than tell you that you spent the afternoon on a site you weren't looking at.
If you're tracking focus in an extension, treat onFocusChanged as a hint. Before you record anything that depends on focus, ask chrome.windows.getLastFocused() again.
A tiny vote of confidence
Was this note worth your time?