Guide
How to track billable hours automatically (and stop reconstructing your week)
There are two ways to fill in a timesheet. You can record hours as they happen, or you can sit down on Friday and remember them. Almost everyone says they do the first and actually does the second.
This is a guide to the first one, done without a timer.
Why reconstructed timesheets are always short
When you rebuild a week from a calendar and a git log, you recover the blocks that left a trace: meetings, commits, sent emails. You do not recover the twenty minutes reading a spec before the commit, the three context switches back into a thread, or the half hour spent reproducing a bug that turned out to be environmental.
Those fragments are individually too small to write down and collectively the difference between a good month and a thin one. Reconstruction has a systematic bias in one direction, and it is not in your favour.
Manual timers fix the accuracy problem only when you use them perfectly, which is a strategy that depends on you never being interrupted — the exact condition freelance work does not offer.
What an automatic tracker actually records
An automatic tracker samples the state of your machine on a short interval. In Tracker that means the frontmost window and, when that window is a browser, the current URL, every few seconds.
Two things follow from that.
The record is a sequence of short observations rather than a set of declared intervals. Nothing depends on you remembering anything, because nothing asked you.
And the raw material is specific enough to classify. Figma — Northwind Rebrand and github.com/acme/api/pull/812 are not ambiguous about who they belong to. That specificity is what makes rules possible.
Setting up client rules
A rule is a pattern plus a client. You write one or two per client, once, and then stop thinking about it.
Useful patterns tend to fall into three groups.
- Repository and project URLs.
github.com/acmecovers every issue, pull request and file view for that client.linear.app/acmeornotion.so/northwindwork the same way. - Window titles containing the client or project name. Design files, documents and spreadsheets usually carry the project name in the title: a title containing
Northwind Rebrandfiles that Figma session correctly without you touching anything. - Client-specific domains. Their staging environment, their admin panel, their documentation site.
The rule to resist is the broad one. A pattern for figma.com assigned to your biggest client will be right most of the time and silently wrong the rest, and you will never notice, because wrong classifications do not announce themselves. Match on the thing that identifies the client, not on the tool you happen to use for them.
Let ambiguous work stay ambiguous
Some of your day genuinely belongs to nobody in particular. Your inbox, general reading, your own admin. Tracker leaves anything that matches no rule unassigned rather than guessing, and unassigned time is visible time — you can look at it, decide, and add a rule if a pattern emerges.
A tracker that always produces an answer is not more accurate. It is just less honest about the parts it does not know.
Idle time
Automatic tracking has one obvious failure mode: you walk away and the Mac keeps counting the last window you looked at. Lunch becomes ninety minutes of “client work” that never happened.
The handling is to detect the absence of input and remove the gap from the day rather than attribute it. What survives in the report is time you were actually at the keyboard. This matters less for your own curiosity and a great deal for the invoice, because an inflated line item that a client questions costs more than the hour was worth.
Getting it onto an invoice
Pick a client and a date range and export. Tracker writes a CSV with totals per day and per source, which is the shape you need for two separate jobs:
- The invoice line. Total hours for the period, and per-day rows if your client expects a breakdown.
- The evidence. The per-source column answers “what was this?” months later, when a client queries an entry and you have no memory of that week at all.
CSV is deliberately boring. It opens in a spreadsheet, imports into accounting tools, and does not require the app that produced it to still exist in three years.
The privacy part is not optional
A tool that reads window titles and URLs is reading client names, document titles, ticket subjects and confidential project codenames. That is unavoidable — it is the raw material that makes the classification work.
What is avoidable is where it goes. Tracker keeps it in a SQLite file on your disk with no account and no server, which means the answer to “who else can see my clients’ project names” is nobody, by construction rather than by policy. If you have signed an NDA, that distinction is worth understanding properly: why your time tracker should be local-only.
A routine that survives contact with a real week
Automatic tracking removes the daily discipline, not all of it. Ten minutes on Friday is still worth spending:
- Open the unassigned bucket and see whether a repeated pattern deserves a rule.
- Scan the per-client totals for anything obviously wrong — a rule matching too broadly usually shows up as one client having an implausibly good week.
- Export the range you are billing.
That is the whole loop. Compare it to the version where you open a blank timesheet and try to remember Tuesday.
For the wider question of what belongs on the invoice in the first place, see time tracking for freelancers.
Summarize withChatGPTClaudePerplexity