Privacy Policy
Contents
1. Who we are
OvertimeLog is a local-only desktop application that monitors a Slack
user's own message history to detect after-hours work and generate
billing evidence. This policy covers the OvertimeLog desktop software
and the website at overtimelog.com.
For GDPR purposes, you are the data controller when you run OvertimeLog on your own device. The developer does not receive or process your Slack data at any point. The developer acts as the controller only for the small amount of data associated with this website (see ยง5) and, if you purchase a Pro licence, for the payment metadata processed by our payment provider.
2. What data is stored
OvertimeLog stores the following on your device when you use it:
| Category | Example | Source |
|---|---|---|
| Slack messages you receive or send | Message text, timestamps, channel IDs, permalinks | Slack API (your user token) |
| User & channel metadata | Display name, user ID, channel name, DM / group-DM type | Slack API |
| OAuth tokens |
Your Slack user token (xoxp-โฆ) and bot
token. Encrypted at rest with a
per-install Fernet key stored at
<DATA_DIR>/encryption.key (mode
0600). A leaked overtime.db on its own
doesn't expose the tokens โ both files are needed.
|
Slack OAuth flow |
| Settings & preferences | Work-hours, timezone, watched channels, invoice template | You, via the app UI |
| Billing adjustments | Manually-entered durations, notes, multipliers | You |
| Manual time entries | User-attested billable sessions for off-Slack work (incident debugs, calls, pairing) โ title, description, start & end timestamps, optional multiplier and ticket reference. Stored locally in the same SQLite database as your Slack data and treated identically for privacy purposes. Manual entries carry no SHA-256 evidence hash because there is no captured external event to verify against; exports mark them explicitly as user-attested. | You, via the dashboard |
| Ticket references (Jira / Linear / GitHub / Custom) |
A free-text ticket reference (e.g.
ENG-1234) and a provider name attached
to interactions or manual entries. URL templates
for each provider are stored alongside in the
application settings table. Today OvertimeLog
does not call any tracker's API โ
refs are typed locally and rendered as links via
your template. Nothing about your tickets leaves
your machine until you choose to export the PDF or
Excel and share it with the recipient yourself. A
future Pro feature will add optional Jira / Linear /
GitHub API integrations; that work is gated behind
your explicit opt-in and a separate disclosure
here when it lands.
|
You, via the dashboard chip + Settings panel |
| Licence key (Pro users) | A single text file in your app data folder | Issued on purchase |
| Password hash (if enabled) | PBKDF2 / scrypt hash of your web-UI password | You, in Settings โ Security |
We do not collect: analytics, telemetry, crash reports, usage metrics, IP addresses, or anything that leaves your device. There is no "phone home" check. There is no A/B testing.
3. Where it's stored
Everything above lives in a single application-data folder on your computer:
| OS | Path |
|---|---|
| Windows | %APPDATA%\OvertimeLog\ |
| macOS | ~/Library/Application Support/OvertimeLog/ |
| Linux | ~/.local/share/OvertimeLog/ |
Inside that folder you'll find overtime.db (SQLite),
license.key (if Pro), and an exports/
subfolder for PDFs and spreadsheets you generate. Deleting the folder
deletes everything.
4. GDPR lawful basis
Where GDPR applies, the lawful basis for processing your personal data through OvertimeLog is legitimate interest (Article 6(1)(f) GDPR) โ specifically, your interest in documenting overtime that you are legally entitled to be compensated for.
The European Court of Justice ruling in CCOO v Deutsche Bank (Case C-55/18, 14 May 2019) obliges employers to maintain "an objective, reliable and accessible system" for measuring working time. OvertimeLog is an employee-side mirror of that obligation: when the employer-side system is missing or unreliable, the worker needs their own record. Recital 47 GDPR recognises balancing a data subject's legitimate interests against those of others as a valid basis; documenting one's own unpaid working time is a textbook example.
You process message content authored by third parties (coworkers, managers) incidentally, because it is attached to timestamps that prove when you were contacted. Minimising that exposure is why Privacy Mode exists โ see ยง6.
If you would like to inform your employer of the record in advance, a short notice template (Word + PDF) is available: Privacy notice for employers (template).
5. Third parties
OvertimeLog touches three categories of third-party service, and only under the circumstances listed:
5.1 Slack
When you authorise OvertimeLog, the app uses the Slack Web API with your own user token to read your own conversation history. This is the same data Slack already shows you inside the Slack client. Slack's own data practices are governed by Slack's privacy policy.
5.2 Optional AI summaries
If you enable AI summaries in Settings, message content is sent to an
endpoint you configure (e.g. a local Ollama or LM Studio
instance, or an OpenAI-compatible cloud API). OvertimeLog does not
host any AI service. If you point it at a cloud provider, that
provider's privacy policy applies to the content you send. Feature
is off by default. The API key you provide is
encrypted at rest in the local database with the
same per-install Fernet key that protects your Slack OAuth
tokens โ a leaked overtime.db alone doesn't expose
the key.
5.3 Website hosting & payments
The website at overtimelog.com is served by Cloudflare
Pages. Cloudflare processes standard HTTP request logs for security
and abuse prevention. Payments for Pro licences are processed by a
third-party payment provider (LemonSqueezy or Stripe โ see your
receipt). The payment provider handles card data directly; we never
see your card number. Their privacy policy applies to the purchase
transaction.
5.4 Optional Jira API integration (Pro)
Pro users can connect a Jira Cloud instance so OvertimeLog auto-fills ticket titles, status, and assignee on linked dashboard rows. This is opt-in, off by default, and lives entirely outside the Free tier.
You provide three things in
Settings → Jira API integration: your
Atlassian site URL (https://your-org.atlassian.net),
the email of your Atlassian account, and an API token
generated at
id.atlassian.com. The
credentials are encrypted at rest in
app_settings.ticket_provider_jira_credentials
using the same per-install Fernet key that protects your
Slack OAuth tokens and AI key (Track F #65/#66) and are
never sent anywhere except the Jira host you typed.
While the integration is enabled, the desktop app calls Jira Cloud's REST API on three occasions:
- You click Test connection in Settings โ
GET /rest/api/3/myselfandGET /rest/api/3/serverInfoconfirm the credentials work and tell you which Atlassian site you're connected to. - You link an interaction to a Jira ref โ one
GET /rest/api/3/issue/<ref>fetches the ticket's summary, status, and assignee and caches them locally. If the fetch fails (auth, network, 404), the link is still saved without metadata. - Once a week, in the background, the dashboard refreshes
any cached Jira ticket older than seven days โ same one
/rest/api/3/issue/<ref>call per stale ticket. The refresh is best-effort: errors are logged but don't surface in the UI. You can also force a fresh fetch by clicking the โณ button on a row's chip.
What leaves your machine: the issue keys you've linked, plus
the Atlassian authentication headers. What comes back:
ticket title, status, assignee display name, and an
Atlassian-generated self URL we don't store.
Slack message text, billable durations, employee names,
invoice totals โ none of this is sent to Jira. The fetched
title and status are stored locally in
interaction_tickets alongside the rest of the
row.
Atlassian's own privacy policy applies to the data they already hold about you (the issues, your account, etc.) โ see atlassian.com/legal/privacy-policy.
Disconnect at any time by clicking Disconnect in the Settings panel. That clears the encrypted credentials immediately; existing links keep their cached title until they're cleared or re-linked.
5.5 Optional Linear API integration (Pro)
Pro users can connect Linear so OvertimeLog auto-fills issue titles, status, and assignee on linked dashboard rows โ the same shape as the Jira integration above, just talking to a different tracker. Opt-in, off by default, lives entirely outside the Free tier.
You provide one thing in
Settings → Linear API integration: a
personal API key generated at
linear.app/settings/api
(keys start with lin_api_). The key is encrypted
at rest in
app_settings.ticket_provider_linear_credentials
using the same per-install Fernet key that protects your
Slack OAuth tokens, AI key, and Jira credentials
(Track F #65/#66) and is never sent anywhere except
api.linear.app.
While the integration is enabled, the desktop app calls Linear's GraphQL API on three occasions:
- You click Test connection in Settings โ
a single GraphQL query for
viewerandorganizationconfirms the key works and tells you which Linear workspace you're connected to. - You link an interaction to a Linear ref โ one GraphQL
issue(id: โฆ)query fetches the ticket's title, state, assignee, and canonical URL and caches them locally. If the fetch fails (auth, network, missing issue), the link is still saved without metadata. - Once a week, in the background, the dashboard refreshes
any cached Linear ticket older than seven days โ same
issue(id: โฆ)call per stale ticket. The refresh is best-effort: errors are logged but don't surface in the UI. You can also force a fresh fetch by clicking the โณ button on a row's chip.
What leaves your machine: the issue identifiers you've linked
plus the API key in the Authorization header.
What comes back: issue identifier, title, workflow state
name, assignee display name, and the canonical
linear.app/… URL. Slack message text,
billable durations, employee names, invoice totals โ none of
this is sent to Linear. The fetched title and state are
stored locally in interaction_tickets alongside
the rest of the row.
Linear's own privacy policy applies to the data they already hold about you (the issues, your account, etc.) โ see linear.app/privacy.
Disconnect at any time by clicking Disconnect in the Settings panel. That clears the encrypted key immediately; existing links keep their cached title until they're cleared or re-linked.
5.6 Optional GitHub API integration (Pro)
Pro users can connect a GitHub repository so OvertimeLog auto-fills issue titles, state, and assignee on linked dashboard rows โ same shape as the Jira and Linear integrations above, just talking to GitHub instead. Opt-in, off by default, lives entirely outside the Free tier. v1 supports one repository per OvertimeLog instance; multi-repo lands in a follow-up slice.
You provide three things in
Settings → GitHub API integration:
the repository owner (your GitHub user or organisation
name), the repository name, and a Personal Access Token
generated at
github.com/settings/tokens.
Only repo:read (classic) or
"Read access to issues" (fine-grained) is needed โ
OvertimeLog never writes to GitHub. The credentials are
encrypted at rest in
app_settings.ticket_provider_github_credentials
using the same per-install Fernet key that protects your
Slack OAuth tokens, AI key, Jira credentials, and Linear
API key (Track F #65/#66) and are never sent anywhere
except api.github.com.
While the integration is enabled, the desktop app calls GitHub's REST API on three occasions:
- You click Test connection in Settings โ
GET /userandGET /repos/<owner>/<repo>confirm the token works and the repo exists. - You link an interaction to an issue number โ one
GET /repos/<owner>/<repo>/issues/<n>fetches the issue's title, state (open / closed), assignee, and html_url and caches them locally. If the fetch fails (auth, network, 404), the link is still saved without metadata. - Once a week, in the background, the dashboard refreshes any cached GitHub issue older than seven days โ same single-issue call per stale row. The refresh is best-effort: errors are logged but don't surface in the UI. You can also force a fresh fetch by clicking the โณ button on a row's chip.
What leaves your machine: the issue numbers you've linked,
plus the Authorization: Bearer โฆ header. What
comes back: issue title, state, first assignee login, and
the canonical github.com/… URL. Slack
message text, billable durations, employee names, invoice
totals โ none of this is sent to GitHub.
GitHub's own privacy policy applies to the data they already hold about you (the repository, your account, etc.) โ see GitHub's privacy statement.
Disconnect at any time by clicking Disconnect in the Settings panel. That clears the encrypted credentials immediately; existing links keep their cached title until they're cleared or re-linked.
5.7 Optional Asana API integration (Pro)
Pro users can connect Asana so OvertimeLog auto-fills task names, completion state, and assignee on linked dashboard rows โ same shape as the Jira / Linear / GitHub integrations above, talking to Asana's REST API instead. Opt-in, off by default, lives entirely outside the Free tier.
You provide one thing in
Settings → Asana API integration:
a Personal Access Token generated at
app.asana.com/0/my-apps.
The PAT is encrypted at rest in
app_settings.ticket_provider_asana_credentials
using the same per-install Fernet key that protects your
Slack OAuth tokens, AI key, and the Jira / Linear / GitHub
credentials (Track F #65/#66) and is never sent anywhere
except app.asana.com.
While the integration is enabled, the desktop app calls Asana's REST API on three occasions:
- You click Test connection in Settings โ
a single
GET /users/meconfirms the PAT works and tells you which Asana workspace you're connected to. - You link an interaction to an Asana task GID โ one
GET /tasks/<gid>fetches the task's name, completed flag, assignee, and permalink_url and caches them locally. If the fetch fails (auth, network, 404), the link is still saved without metadata. - Once a week, in the background, the dashboard refreshes any cached Asana task older than seven days โ same single-task call per stale row. The refresh is best-effort: errors are logged but don't surface in the UI. You can also force a fresh fetch by clicking the โณ button on a row's chip.
What leaves your machine: the task GIDs you've linked,
plus the Authorization: Bearer โฆ header. What
comes back: task name, completion state (open / completed),
assignee name, and the canonical
app.asana.com/… permalink. Slack message
text, billable durations, employee names, invoice totals โ
none of this is sent to Asana.
Asana's own privacy policy applies to the data they already hold about you (the tasks, your account, etc.) โ see asana.com/terms#privacy-policy.
Disconnect at any time by clicking Disconnect in the Settings panel. That clears the encrypted PAT immediately; existing links keep their cached title until they're cleared or re-linked.
5.8 Update checks
With your permission (Settings โ Updates, on by default), the
desktop app makes a plain HTTPS GET to
overtimelog.com/releases.json at most once a week to
learn about new versions. The request carries no install ID, no
UUID, no usage data, no cookies โ just the URL and the default
python-requests User-Agent. Your IP is briefly visible
to Cloudflare for DDoS protection (the same as for any HTTPS
request to any site). The app caches the result locally for seven
days; turning the toggle off stops all such requests immediately
and the manual Check now button is the only
remaining trigger.
6. Your rights under GDPR
Because your data never leaves your device, most GDPR rights are exercised directly inside the app rather than by asking us for a copy:
- Art. 15 โ Right of access: all data is visible in the Dashboard, Timesheet, Billing, and Settings views.
- Art. 16 โ Right to rectification: edit any billing adjustment or setting through the UI. Message content is immutable by design (it's evidence), but you can hide it via Privacy Mode or delete the event entirely.
- Art. 17 โ Right to erasure: delete individual events from the Dashboard, or wipe everything by deleting the app-data folder.
- Art. 20 โ Right to data portability: Settings โ "๐ก๏ธ Privacy & GDPR" โ Download all data (JSON). Exports every table in the local database as structured JSON. OAuth tokens, password hashes, and AI API keys are redacted in the export.
- Art. 21 โ Right to object: stop running the app. It has no remote kill switch and no ability to keep processing after you quit.
-
Privacy Mode: toggle in Billing โ Invoice
Template. When on, PDF and Excel exports replace message text
with
[redacted]โ useful before sharing exports with your employer, lawyer, or works council.
7. Data retention
Data stays on your device until you delete it. OvertimeLog does not prune, archive, or rotate your records automatically. Uninstalling the app does not delete the app-data folder โ that's a separate step so that licence keys and evidence are not accidentally lost when you reinstall. To wipe, delete the folder listed in ยง3.
8. Children's data
OvertimeLog is an occupational tool aimed at adults in professional environments. It is not directed at children under 16, and we do not knowingly process data relating to them.
9. Changes to this policy
If this policy changes materially, the "Last updated" date above will change and a notice will appear on the website homepage for at least 30 days. Because we do not have your email, we cannot notify you directly; please check this page before each new major release if the contents matter to you.
10. Contact
Privacy questions, data-subject requests relating to the website, or anything else: support@overtimelog.com. See /contact for other routes and expected response time.
This document is a plain-English policy rather than formal legal counsel. If your organisation or jurisdiction requires a lawyer-reviewed version, please let us know and we'll coordinate.