# Privacy. Dimmy.

> What Dimmy collects, why, where it goes, how long we keep it, and your rights. Mirrors PRIVACY.md in the app repo. In English and Italian.

Source: https://dimmy.app/privacy/

## Short version

* Dimmy can run fully offline when you choose local models. If you choose a cloud speech or AI provider, your audio or text goes to that provider, with your own key, under that provider's terms.
* Dictation audio is not kept unless you turn on audio in history. Meeting recordings (audio.wav) are always saved on your computer.
* Usage statistics and crash reports are off until you say yes. Two separate switches. They never contain your audio, your text or your prompts. They are linked to a random installation ID, which is pseudonymous, not anonymous.
* API keys are stored in a local file encrypted with AES-256-CTR and HMAC-SHA256, under a key derived from your user name and computer name.
* The licence service stores a hash of your e-mail, your licence and the devices you activate. Payment is handled by Stripe.

## Who is responsible

The controller is Konrad Dalla, Via La Piera 67, Bologna, Italy, who develops and sells Dimmy. Contact: hi@dimmy.app. Security issues: security@dimmy.app.

There is no data protection officer; the law does not require one at this size. Write to the address above for any request on this page.

## What stays on your computer

Dimmy keeps its data in one folder: %APPDATA%\\dimmy\\ on Windows, \~/Library/Application Support/dimmy/ on macOS, \~/.config/dimmy/ on Linux. Nothing in this folder is sent to us.

config.json Your settings.

keys.enc API keys and tokens, encrypted (AES-256-CTR + HMAC-SHA256). The key is derived from your user name and computer name, so the file cannot be read on another computer. It does not protect against malware that runs under your own account.

history.db Dictation history: the raw and the cleaned text, time, the name of the app you dictated into, style and language.

history\_audio/ Dictation audio, only if you turn on audio in history. Off by default. When on, files older than 30 days or beyond 5 GB are deleted (both limits can be changed).

meetings/ One folder per meeting: audio.wav and the separate microphone and system tracks, transcripts.txt, recap.md, meta.json, your notes. You can choose another folder in Settings.

consent.jsonl A local log of the recording-consent steps (shown, accepted, announced, …).

models/ Speech and language models you downloaded.

dimmy.log The app log: technical messages, not your transcripts.

analytics\_id The random installation ID (see telemetry).

license.json Your signed licence token, if you activated one.

Telegram session If you connect Telegram: the session, sealed with the machine key.

To delete it, quit Dimmy and delete the folder (and your meetings folder, if you moved it). Uninstalling the app does not delete it. You can also delete single history items and meetings inside the app.

## What leaves your computer, and when

Each provider you choose acts on your own account and under its own terms. Which providers can use API data for training is on the data and AI page.

Only if you choose them

Cloud speech and AI providers

Groq · OpenAI · Anthropic · Gemini · Deepgram · OpenRouter · Together · Fireworks

Audio for transcription, text for cleanup, command mode and recaps, with your own key.

Only if you choose a subscription backend

Claude Code · Codex · Gemini CLI

the CLI on your computer

The prompt is passed to the CLI, which sends it to its vendor under your account. Dimmy never reads the CLI's credential files.

Only if you connect them

Notion · Confluence · Telegram

your own account

Recaps or messages you send, or that you set to be sent automatically.

Downloads and updates

Hugging Face · GitHub

huggingface.co · github.com · api.github.com

Model and engine downloads you start, and update checks. A normal download request.

Trial and licence

Dimmy licence service

https://license.dimmy.app

Trial, activation, licence refresh, "I'd buy this". See the licence service section.

Only if you said yes

PostHog EU · Sentry EU

https://eu.i.posthog.com · https://o\*.ingest.de.sentry.io

Usage statistics and crash reports. The endpoints are fixed in the binary.

[Your data and AI](https://dimmy.app/data-and-ai/)

`#data`

## Usage statistics and crash reports

At first launch Dimmy asks whether it may send usage statistics and crash reports. The two answers are equal, and until you answer nothing is sent. Versions up to 0.7.13 started with both switches on; the consent question arrived with 0.7.14\. Values are categories (a provider name, a bucket such as 30\_120 seconds), counts, durations or true/false. Free text is never sent.

### Installation ID and context

A random UUIDv4 created on first launch and stored in analytics\_id. It is not derived from your name, e-mail, account or hardware, but it lets us recognise the same installation across events, so it is pseudonymous. Reset it in Settings → Privacy → Reset anonymous ID. A second random ID is created at each launch and never stored. Every event also carries the app version, OS family (windows / macos / linux) and CPU architecture (x86\_64 / aarch64).

### App and onboarding

* `app.started`The app launched; cold-start time.
* `app.session_ended`The app closed; session length, number of transcriptions.
* `app.update_check`An update check ran; current and available version.
* `app.update_applied`An update was installed; from and to version.
* `onboarding.*`started, step\_completed, completed, abandoned: progress through the first-run setup; step name, path, duration.

### Settings changes

* `config.stt_mode_changed`Local or cloud speech.
* `config.cloud_provider_changed`Which cloud provider (category).
* `config.llm_enabled_changed`AI cleanup on or off.
* `config.llm_style_changed`Which style.
* `config.shortcut_changed`A shortcut changed (not which keys).
* `config.preprocessing_changed`Audio preprocessing on or off.
* `config.input_gain_changed`The input gain value.
* `config.autostart_changed`Launch at login on or off.
* `config.recap_model_changed`The recap model, as a bucket.

### Dictation and transcription

* `transcription.completed`Local or cloud, provider and engine (category), source (hotkey, file, meeting, pill), audio length, processing time, word count (the number only), language code, whether filler removal and AI cleanup ran, which pipeline (batch or streaming).
* `transcription.failed`Provider and error category (for example 401, timeout).
* `transcription.cancelled`Audio length up to the cancel.
* `dictation.capture_ratio`How much of the recording time was captured (bucket) and the capture source.
* `llm.applied`AI cleanup ran; provider, style, tone, processing time, success.
* `llm.failed`Provider and error category.
* `feature.hotkey_triggered`The global hotkey started a recording.
* `feature.api_key_set`An API key was saved; scope (stt / llm) and provider. Never the key.

### Meetings and files

* `meeting.started / stopped`Stopped carries a length bucket, a word-count bucket and whether a recap ran. Also meeting.paused, meeting.resumed.
* `meeting.stop_timeout`Stopping a meeting took too long.
* `meeting.capture_ratio`Recorded audio against real time (bucket).
* `meeting.transcription_behind`Transcription could not keep up; engine, and how far into the meeting (bucket).
* `audio.loopback_rate_mismatch`System audio arrived at a different sample rate than announced (two rate labels).
* `meeting.recap_completed`A recap finished; provider, model family, length bucket, success, error category.
* `meeting.imported_from_file`A file was turned into a meeting.
* `feature.meeting_shortcut`A meeting was started from the shortcut or a menu (which one).
* `consent.logged`A recording-consent step (shown / accepted / cancelled / announced / declined / …).
* `file_load.started / completed`A file was transcribed; drop or picker, length, time and word buckets, success.

### Errors and performance

* `error.cloud_stt / cloud_llm`A cloud call failed; provider, HTTP status, error category.
* `error.local_stt / local_llm`A local model failed; model name, error category.
* `error.gpu_crash`After a GPU crash: backend and call site (paths scrubbed).
* `error.audio_health`An audio-device error code.
* `perf.startup_ms`Start-up time.
* `perf.gpu_status`Which GPU backend, whether it fell back to the CPU.
* `perf.transcribe_overhead_pct`Processing overhead as a percentage.

### Licence

* `license.activated`Plan.
* `license.activation_failed`Error category.
* `license.refreshed / refresh_failed`A licence refresh worked or failed.
* `license.scope_denied`Which feature was locked.
* `license.device_deactivated`This device or another.
* `license.interest_registered`Which plan. Never the e-mail.

### Other features

* `user_dict.*`word\_added (where from), word\_removed, size\_snapshot (size bucket). Never the words.
* `notion.*`connected, disconnected, recap\_sent (automatic or manual, success).
* `app_rules.*`evaluated (whether a rule matched, rule-count bucket), added, removed, reordered. Never the rule or the app name.
* `pill.*`visibility\_toggled, style\_scrolled, language\_scrolled, context\_menu\_opened.
* `update.*`channel\_changed (stable / prerelease), apply\_deferred.
* `permission.granted / denied`macOS permissions (microphone, accessibility, input monitoring).
* `claude_code.* · codex.* · gemini_cli.*`status\_probed, login\_spawned, login\_completed, invocation: ready / not logged in / not installed, login outcome, call site, time bucket, error category. Never the prompt, the answer, the CLI path or its output.

### Counters and profile properties

PostHog also keeps running totals for the installation ID (total\_transcriptions, total\_transcription\_failures, total\_transcriptions\_cancelled, total\_llm\_uses, total\_llm\_failures, total\_sessions) and properties: first and latest seen time, app version, OS and architecture, latest speech mode and provider, latest LLM provider.

### Crash reports (Sentry)

If you said yes to crash reports, an error or a crash sends: the error message (cut to 4 KB, with secret-shaped strings replaced by <redacted>), a stack trace, OS, architecture, app version and build, and the installation ID.

Environment variables, server name, host name and user name are removed. Some error messages name a file; your account name is removed from the path before sending (C:\\Users\\<USER>\\...).

telemetry

## Never in telemetry

There is no telemetry path in the code that sends any of the following. Every send is written to the local log with \[telemetry\], so you can check.

* Your audio.
* The text of any transcription.
* Any prompt, and any LLM output.
* File names, contacts, the names of apps you dictate into.
* Microphone device names.
* API keys or tokens.
* Your e-mail, user name or computer name.
* Calendar attendees, licence or device identifiers.
* IP addresses: PostHog events carry $ip: null, and Sentry EU drops them at intake.

## Inspect what's being sent

Every telemetry call is written to the local log. Open the log file and look for lines starting with \[telemetry\].

Windows`%APPDATA%\dimmy\dimmy.log`

macOS`~/Library/Application Support/dimmy/dimmy.log`

Linux`~/.config/dimmy/dimmy.log`

Example of what you'll see in the log:

[2026-05-11 09:47:06] [telemetry] track event=transcription.completed
[2026-05-11 09:47:06] [telemetry] spawn send for event=transcription.completed (payload 275 bytes)
[2026-05-11 09:47:06] [telemetry] send: HTTP 200 OK (sent=4)

The log also prints the start of the PostHog and Sentry project keys embedded in the build: search for key-diag. That way you can check where events go.

## Turn telemetry on or off

1. 1 Open Settings (the gear on the pill, or right-click the menu-bar / tray icon).
2. 2 Go to Privacy.
3. 3 Send anonymous usage data: usage events to PostHog EU.
4. 4 Send crash reports: errors and crashes to Sentry EU.
5. 5 A change takes effect immediately. Events already sent cannot be recalled; write to us to have them deleted.

Want to start fresh? Settings → Privacy → Reset anonymous ID makes a new installation ID. Feedback (Settings → Send feedback) sends the text you type, and your e-mail only if you type it, over the crash-report channel; if that is off, the form offers to turn it on and send.

## The licence service (license.dimmy.app)

The licence service runs on Cloudflare Workers with a Cloudflare D1 database. It stores:

Licences A SHA-256 hash of your e-mail (not the e-mail itself), the plan, start and end dates, the device limit, status, and the Stripe customer, session and subscription IDs.

Devices For each activated device: a random device ID, the device name (by default your computer name; you can change it before activating), first and last seen time, the app version and the User-Agent of the last licence refresh.

Activation codes One-time codes for the e-mail link, valid 10 minutes.

Audit log What happened to a licence (created, activated, refunded, deleted, …), with the e-mail hash and, for activations, the device ID and name.

Leads When you start a purchase or sign up for news: a hash of the e-mail, the plan and the language. When you ask to be written to ("I'd buy this" while sales are closed, or the Linux / mobile waitlist) and tick the consent box, also the clear e-mail and the time of your consent, only to write to you about that.

Rate limits A counter keyed by your IP address, to stop abuse.

To send you activation links and receipts, your e-mail address passes through Resend (e-mail delivery) and Stripe. Cloudflare, as the host, also processes your IP address to deliver each request.

## Payment and the website

Purchases are processed by Stripe, through Stripe Managed Payments: Stripe is the merchant of record. It collects the card or other payment data, your billing address and e-mail, calculates and collects taxes, and issues receipts and invoices. We never see your card number. Stripe may offer Link, its saved-payment service; using it is between you and Stripe.

dimmy.app is hosted on Cloudflare. It sets no cookies and runs no analytics. To show the page it loads code and images from unpkg.com, cdn.simpleicons.org, api.github.com and Product Hunt, which receive your IP address like any web request. The forms (buy, waitlist, newsletter, withdrawal) send what you type to license.dimmy.app.

## Why we process data (GDPR art. 6)

Licence, trial, activation, devices, payment, receipts, withdrawal requests Performance of the contract (art. 6(1)(b)). Keeping an ended licence for the card-dispute window, and an expired trial's e-mail hash: our legitimate interest in defending payment disputes and preventing repeated free trials (art. 6(1)(f)).

Usage statistics and crash reports Your consent (art. 6(1)(a); ePrivacy art. 5(3), Codice privacy art. 122).

"I'd buy this", waitlist and newsletter e-mails Your consent (art. 6(1)(a)).

Feedback you send Your consent, given by sending it.

Rate limits, abuse prevention, the audit log, security Our legitimate interest in keeping the service safe and in proving what we did (art. 6(1)(f)).

You can withdraw consent at any time. This does not affect what was done before.

## Who processes data for us

Stripe Payment, tax, receipts, as merchant of record (Stripe Managed Payments).

Cloudflare Hosting of the website and the licence service (Workers, D1).

Resend Delivery of activation and confirmation e-mails.

PostHog (EU cloud) Usage statistics, only with your consent.

Sentry (EU region) Crash reports and feedback, only with your consent.

Only Konrad Dalla has access to these accounts.

The speech and AI providers you pick, the subscription CLIs (Claude Code, Codex, Gemini CLI), Telegram, Notion and Confluence are not our processors: Dimmy connects to them on your own account, with your own key or login, and they act under their own terms with you.

Transfers outside the EU: some of these companies are based in the United States (for example Stripe, Cloudflare, Resend). Where data is transferred to the US, the transfer relies on the EU-US Data Privacy Framework where the company is certified, or on the European Commission's Standard Contractual Clauses.

## How long we keep it

Rate-limit rows (IP address) 48 hours.

Activation codes and account-deletion codes 24 hours after they expire.

Active licence and its devices As long as the licence is active.

Licence that ended (expired, refunded or revoked, withdrawn, deleted) and its devices 120 days after the end (the window for card disputes), then deleted.

Expired trial that never became a paid licence Only the hash of your e-mail, for 12 months after the trial ended, so that the same address cannot start a second free trial. Then deleted. Device names and User-Agents are removed when the trial ends.

Audit log 12 months.

Stripe event IDs (each payment event is processed once) 90 days.

Withdrawal declarations 12 months after we receive them.

Leads, "I'd buy this" and waitlist e-mails 12 months, or earlier when you ask or delete your account.

Usage statistics (PostHog) Up to 12 months.

Crash reports (Sentry) Up to 90 days.

Data on your computer Until you delete it.

Stripe (including Link) keeps your payment data as its own controller, under its own privacy policy. We keep Stripe's monthly self-billed invoices for 10 years, as Italian law requires for accounting records (art. 2220 of the Civil Code). These invoices do not contain your personal data.

## Your rights

Under the GDPR you can ask for access to your data, correction, deletion, restriction and portability, and you can object to processing based on legitimate interest. Write to hi@dimmy.app. We answer within one month.

You can also lodge a complaint with the Italian supervisory authority, the Garante per la protezione dei dati personali (garanteprivacy.it), or with the authority of the EU country where you live.

Delete your account: the licence service has a deletion request at POST /api/account/delete. You send your e-mail, we send you a one-time code, and you confirm with it. On confirmation the licence is marked deleted, the e-mail hash on the licence is replaced by a random placeholder, any subscription is cancelled, and your lead and waitlist rows are removed. The audit log, which holds the e-mail hash, stays, to prove the request was honoured. Records that tax law makes us keep are kept for that period. If you prefer, write to us and we do it for you.

Telemetry is linked only to the installation ID. To have it deleted, send us that ID (in the analytics\_id file), then reset it.

## AI transparency

Dimmy uses AI models: speech-to-text, text cleanup, command mode and meeting recaps. Their output can be wrong. Under the EU AI Act (Regulation 2024/1689) these are neither prohibited practices nor high-risk uses under Annex III; the obligation that applies is transparency, under Article 50.

* Every recap saved to recap.md carries a machine-readable marker (<!-- dimmy-ai-generated: true; by: Dimmy; model: … -->), and the app shows "AI-generated summary. Review it before sharing." above it.
* Some things happen without a review step, because you set them up that way: dictated text is pasted into the app in front of you, history is saved, a recap runs when a meeting stops, and a recap can be sent to Notion automatically if you turn that on. Review AI output before you share it.
* We do not train models on your data. Dimmy integrates third-party models without modifying them.
* Dimmy does not identify people from their voiceprint, infer emotions or do biometric categorisation. Speaker labels in meeting transcripts ("Speaker 1", "Speaker 2") only separate voices inside one recording.

This is our own assessment, not a certification, and it is not legal advice. Which cloud providers can train on your words if you bring your own key is on the data and AI page. [Your data and AI](https://dimmy.app/data-and-ai/)

## Changes to this policy

Material changes are announced in the release notes and the date at the top changes. The ground truth is PRIVACY.md in the app repository; git log PRIVACY.md shows every change.
