Undertow — Privacy Policy
Effective 5 September 2026. Version 1.0.
Undertow is operated by Flapp Bilişim Anonim Şirketi ("we"), and this policy covers the Undertow iOS app and the service behind it. Questions: undertow@flapp.ist.
This policy describes what the software actually does. Where a claim below is specific, it is specific because it was read out of the code that implements it, and the file is named so you can check.
The short version
- Undertow connects to your mailbox read-only and looks only for newsletters. Mail that is not a newsletter is identified from a handful of headers and then left alone — its body is never downloaded and never stored.
- The text of your newsletters is stored so decks can be built from it, and excerpts of the issues shortlisted on a given night are sent to Anthropic's API, which writes the cards.
- Your mail credential is encrypted before it is written to disk and is never sent to your phone.
- There is no advertising, no tracking, no analytics SDK, and nothing is sold or shared with data brokers.
- Deleting your account in Settings purges your issues, decks, swipes, devices and stored credential.
1. Connecting your mailbox
In this release you connect Gmail with an app password — a mailbox-specific password you generate in your Google Account and can revoke there at any time, without changing your Google password. We are moving to Google OAuth with the read-only gmail.readonly scope (PRD §4.5); when that ships, this section will be updated and the app password path retired.
The connection is IMAP over TLS to imap.gmail.com, and the mailbox is opened read-only (imaplib.IMAP4_SSL(...), imap.select("INBOX", readonly=True) — ingest.py). Undertow cannot and does not archive, delete, move, label, reply to, send, or mark messages as read. Message bodies are fetched with BODY.PEEK, which does not set the \Seen flag: reading a newsletter here does not make it look read in Gmail.
Each nightly run searches the last 60 days of your inbox (LOOKBACK_DAYS = 60, ingest.py).
2. How newsletters are told apart from your personal mail
This is the part that matters most, so here is the exact mechanism.
Every run does two passes. The first pass asks the mail server for six header fields only —
SUBJECT,FROM,DATE,LIST-UNSUBSCRIBE,REPLY-TO,RETURN-PATH
— for the messages in the window (ingest.py, the BODY.PEEK[HEADER.FIELDS …] fetch). A message is treated as a newsletter only if it carries a List-Unsubscribe header, or if its From, Reply-To or Return-Path names a bulk-mail platform (Substack, beehiiv, Mailchimp, ConvertKit, Buttondown and similar — the list is ESP_SENDER_MARKERS in ingest.py, and is_newsletter() is the whole test).
The second pass downloads message bodies, and it runs only for messages that passed that test and that we have not already stored. A message from a colleague, a bank, a family member or a doctor never reaches the second pass. Its subject and sender are seen in memory during the first pass and discarded; nothing about it is written down.
This is a heuristic, not a promise about every message that will ever exist: if a person or a company sends you mail through a newsletter platform, or adds an unsubscribe header to a personal message, it will look like a newsletter to Undertow. You can drop any sender in the app, and a dropped sender is excluded from everything afterwards.
3. What we store about your newsletters
For each newsletter issue that passes the test:
- the subject line, the sender's display name, and the sender's address in lowercase (used as a stable id for that sender),
- the date it was sent and the date we read it,
- the issue's link and up to eight story links found inside it,
- the extracted reading text of the issue — the article body, with navigation, unsubscribe lines and footers stripped (
trafilaturaextraction iningest.py). Raw email source, images, attachments and tracking pixels are not kept, - a local embedding of the first 1,500 characters: a 384-number vector used to find related issues. It is computed on our own server by a downloaded model (
all-MiniLM-L6-v2,embed.py). No third party sees anything at this step.
Issues shorter than 20 words are dropped rather than stored.
4. How decks are written, and what leaves our server
Each night a ranking step picks a shortlist of candidate issues from your own corpus. The shortlist — issue titles, sender names, publication dates, and the extracted text of each, capped at 5,000 characters per issue — is sent to the Anthropic API (claude-sonnet-5, pipeline.py) together with your taste profile, the headlines of your recent decks, and any "deepen" notes you wrote. Anthropic's model writes the cards; we validate them, force every source link back to a URL that actually appeared in the issue, and store the deck.
Not sent to Anthropic: your email address, your name, your mail credential, your device token, or any message that failed the newsletter test.
Anthropic acts as our processor under its commercial API terms, which do not use API inputs or outputs to train models. Requests are transmitted over HTTPS.
The one other place card text travels is Apple's push service: your daily notification carries the editor's one-sentence note about that night's deck (worker.py), so that sentence passes through APNs on its way to your phone.
5. Account and usage data
| What | Why | Where it lives |
|---|---|---|
| Email address | Identifies the account; it is also the mailbox we read | Server database |
| Mail app password | Needed every night to fetch new issues | Server database, Fernet-encrypted with a key held only in the server environment (server/crypto.py); never returned by the API, never stored on your phone |
| Session token | Keeps you signed in | Only the SHA-256 hash is stored (server/auth.py); the token itself lives in your iPhone's Keychain |
| Keep / Skip / Deepen verdicts, and any note you attach | Teaches the editor what to pick tomorrow, and mutes senders you never keep | Server database |
| Sender decisions (kept / dropped) | Excludes senders from every future deck | Server database |
| Deck opened / not opened, and whether you arrived from the push | Tells us whether the product works, and stops us generating decks for someone who has stopped reading | Server database |
| Delivery hour and timezone | When your deck is built and pushed | Server database |
| APNs device token | Sends that one notification | Server database |
| Operational logs | Debugging the nightly run | Server disk; they record account email addresses, the senders and issue titles considered, and token counts |
On your phone, the app stores today's and yesterday's deck, a queue of swipes waiting to sync, your server address, delivery hour and timezone, and the session token in the Keychain. Nothing else.
6. What we do not do
- No advertising, and no advertising identifiers. The app never requests App Tracking Transparency permission because it has nothing to track you with.
- No third-party analytics or attribution SDKs. The app has no third-party dependencies at all; the only network destination it contacts is the Undertow server (
ios/Undertow/API/UndertowAPI.swiftholds every request the app can make). - No tracking across other companies' apps or websites, and no data brokers.
- No sale or sharing of personal information as those terms are defined by the California Consumer Privacy Act.
- No profile-building for anyone but you. Your taste profile exists to pick your cards and is never pooled with anyone else's.
7. Who else touches your data
| Recipient | What they get | Why |
|---|---|---|
| Anthropic | Newsletter excerpts and your taste profile, as in §4 | Writes the cards |
| Apple (APNs) | Device token and the editor's note | Delivers your daily notification |
| Apple (App Store) | Your purchase; we never see your payment details | Billing for the subscription |
| Our hosting provider | Operates the server the database sits on | Infrastructure |
That is the complete list. There is no fifth party.
8. How long we keep things
Your issues, decks and swipes are kept for as long as your account exists, because the archive is what makes a "resurface" card possible months later. We do not currently expire old issues automatically — the 365-day rolling window described in our product plan is not yet implemented, and we would rather say so than describe a deletion job that does not exist. Deleting your account removes everything immediately (§9), and we will publish a retention window here before shipping one.
9. Deleting your account
Settings → Delete account, and the app calls DELETE /v1/account. That request purges, immediately and not on a queue: every stored issue, every deck, every swipe, your registered devices, your sender decisions, your encrypted mail credential and your session token (server/app.py).
One record survives: a tombstone row holding your account id, your email address and the deletion time. It exists so a session token that is replayed after deletion is rejected instead of silently opening a new account. Signing up again with the same address reopens the account with an empty corpus.
Full detail, including how to revoke the app password on Google's side and why one tombstone row survives, is on our support page.
10. Your rights
Wherever you live, you can delete everything from inside the app. On request to undertow@flapp.ist we will also give you a copy of what we hold, correct it, or confirm what has been deleted.
If you are in the EEA or the UK: our legal basis for processing your mailbox content is performance of the contract you entered into when you subscribed — it is the service. Usage data is processed on the basis of our legitimate interest in making the product work, and you may object at any time by writing to us. We do not make automated decisions with legal effects. Our processors are listed in §7.
If you are in California: we do not sell or share personal information and have not done so in the past twelve months.
If you are in Türkiye: the data controller (veri sorumlusu) is Flapp Bilişim Anonim Şirketi. Under KVKK art. 11 you may ask whether your data is processed, ask what is held and why, ask for it to be corrected or erased, and object to a result produced solely by automated analysis. Write to undertow@flapp.ist; we answer within thirty days. Our lawful basis is KVKK art. 5/2(c) — processing necessary for a contract you are party to. Mailbox content is not special-category data, and none is sought.
11. Google user data
While the app connects with an app password, Undertow uses no Google API and holds no Google OAuth token; the credential is one you can revoke from your Google Account at any time, which immediately stops all access. When OAuth (gmail.readonly) ships, Undertow's use of information received from Google APIs will adhere to the Google API Services User Data Policy, including the Limited Use requirements, and this section will be updated with the scopes we hold.
12. Children
Undertow is not directed to children and is rated 13+. We do not knowingly collect information from anyone under 13.
13. Changes
If we change how any of this works, the version and effective date at the top change, and a material change is announced in the app before it takes effect.
Contact: undertow@flapp.ist · [REGISTERED OFFICE ADDRESS — required for a Turkish seller under Law 6563 and the Distance Sales Regulation]