Privacy

Knowmarks marketing site privacy.

This public site uses self-hosted Umami analytics so we can see whether the marketing page is being visited and which pages are useful. Umami is running on the operator’s NAS.

The tracker does not set cookies, does not record session replay, and does not collect saved links, notes, search queries, alpha account data, or anything inside the hosted Knowmarks app.

This page is the published privacy policy for the hosted Knowmarks alpha and its browser extension — covering app data, AI calls, error reporting, feedback, and deletion/export requests. The essentials are laid out here, with the extension's specifics in the Browser extension section below, since anything the extension sends ends up governed by the same hosted-alpha handling. Questions? Email m@h3r3.com.

Browser extension.

Nothing reaches the Knowmarks server carrying page or conversation content until you pick a capture mode (Article, Selection, Images, Conversation) or click Save in the extension's popup — or the Catch-up page re-processes a queued item. What's sent at that point is the page's URL and title, plus — depending on the mode — the full page text, your text selection, chosen images, or a recognized AI chat's raw conversation payload (see below for exactly what that contains), along with the access token that authenticates the request — when you've set one; local single-user mode has none configured by default, and those requests carry no Authorization header at all. One save path is worth calling out on its own: if you highlight text on a page and click Save without explicitly picking a mode, that highlighted text is sent as your selection — same as if you'd clicked the Selection chip yourself. Exactly which of a note, Space assignment, and page metadata (content type, site name, a preview image, an author, a publish date, when the page provides them) rides along varies by save path — a note and Space assignment go with every popup-triggered save but not with Catch-up; page metadata goes with Link, Selection, Article, and Catch-up but not with Images or Conversation, whose payload shapes don't carry that page-declared metadata object (Conversation does send its own, much smaller metadata object — just the capture method and extension version, no page-declared fields; Images sends no metadata object of any kind). Nothing here is inferred beyond what the page's own markup says or what you explicitly selected/typed. That data is uploaded only to the Knowmarks server you've configured in the extension's options — your own local instance, or the hosted alpha — with three exceptions where the extension itself talks to a destination other than Knowmarks, all described below the table: Conversation mode's transcript read, Images mode's picker-grid preview loads from each image's own source site, and Catch-up navigating your browser to the source page before it captures anything. A code-derived breakdown of the primary save modes and their main data flows:

Save path URL / title / canonical Note Spaces Page metadata Selection text Article text Screenshot Conversation payload Usage/diagnostic metadata (capture method, char counts, ext. version)
Link (default) YesIf typedIf chosen Yes — whichever of type/site/image/author/date the page declares NoNoNoNo Yes — capture method, a content-length counter (0 for Link), a selection-length counter (present if you happen to have text highlighted, even though Link doesn't send that text), and the extension version
Selection, explicit, text actually highlighted YesIf typedIf chosenYes Yes — the highlighted textNoNoNo Yes — capture method, both length counters (equal to the highlighted text's length), extension version
Selection, explicit, no text highlighted — the popup's own guard for this mode requires a live selection; without one the payload falls through to the same empty-content shape Link uses YesIf typedIf chosenYes No — indistinguishable on the wire from a Link save NoNoNo Yes — capture method reported as link (not selection), both length counters at 0, extension version
Selection, auto-promoted — you highlighted text and clicked Save without picking a mode YesIf typedIf chosenYes Yes — identical to explicit Selection; the extension silently treats an un-chosen mode with a live highlight as Selection NoNoNo Same as explicit Selection above
Article, extraction non-empty (any length, thin or not) YesIf typedIf chosenYes No — only a character count, never the text Yes — the extracted readable text is sent as imported_content in every case, and a non-empty capture is never downgraded to a server-side source fetch. But when it's thin (see the row below), what gets sent isn't necessarily what ends up stored — a screenshot OCR result can still replace itNo (unless also thin — see the row below)No Yes — capture method, a content-length counter (the article's length), a selection-length counter (a separate diagnostic signal, present even though Article mode doesn't send the selection text itself), extension version
Article, extraction non-empty AND thin (< 200 characters) — a screenshot rung can replace the row above's text with an OCR result YesIf typedIf chosenYes SameYes — the thin, non-empty extraction is sent as imported_content; still no server-side source fetch. But it is not necessarily what ends up stored — see the Screenshot column Yes — because the sent text is under 200 characters, a screenshot of the visible tab is attached and the server runs it through OCR. A successful (non-empty) OCR result replaces the thin article text as the stored/indexed content — it may include incidental on-screen content the OCR picked up, not just the article. The original thin text is discarded, not merged with it. Only if OCR produces nothing does the originally-sent thin text stand, still with no source fetchNo Same as the Article row above
Article, extraction empty — no readable text found at all YesIf typedIf chosenYes No No — payload is empty, same shape as Link Yes — a screenshot is attached (0 chars is still under the 200-char thin threshold); the server OCRs it first, and a successful OCR becomes the saved content with no source fetch. Only if OCR also produces nothing does the save fall back to Link's server-side fetch of the source.No Yes — capture method reported as link (not article), content-length 0, selection-length counter, extension version
Images — a different endpoint from every other row; loads preview images from their source sites before Save (see below the table) Partial — page URL/title only, no canonical URL field exists If typedIf chosen No — this payload has no metadata object at all NoNoNoNo No — none of these fields exist in this payload shape at all
Conversation — auto-selected on a recognized chat page, or chosen explicitly Partial — URL only, no title or canonical URL field exists If typedIf chosen No — no type/site/image/author/date fields at all NoNoNo Yes — the AI platform's entire raw API response, unparsed by the extension Partial — capture method and extension version only; no char-count fields in this branch's metadata object
Catch-up — re-processing a queued item; a different code path from every popup save above Yes No — this flow has no note field No — this flow can't route to Spaces YesNot transmitted — the shared page-lift helper does evaluate the page's selection as a side effect, but Catch-up's own save logic discards it and never uploads it If the rendered page yielded article text; empty otherwise Same thin-extraction rule as Article, only if the worker tab is still active No Yes — capture method, a content-length counter, a selection-length counter fixed at 0 (the value isn't transmitted here, not because it isn't read — Catch-up's save logic just discards whatever the shared page-lift helper evaluated), extension version

This table describes the primary save modes and their main data flows — it's read directly from the extension's payload-construction code, not summarized from memory. It isn't a claim that every possible edge case in that code is enumerated above; the recipient categories listed on this page (who data can reach) are the complete, disclosed set — this table is the behavioral detail for the modes people actually use.

Two things happen as soon as you open the popup, before you've picked a mode or clicked Save: the current tab's URL and title are read locally (to display them and to detect a recognized AI chat page) — that read stays in your browser, nothing is transmitted by it — and, separately, the extension does make one small authenticated request to your configured server, to check how many of your saves are queued for a browser revisit so it can show a count if any are waiting. That server check carries no page content, URL, or title — it sends only the request needed to ask "how many are queued," and the server responds with a number and nothing else. Neither of these two things is the same as reading the page's actual content (article text, a selection, images), which doesn't happen until you pick a capture mode or click Save.

Conversation mode, precisely: on a recognized Claude or ChatGPT conversation page, the popup automatically shows Conversation as the selected mode — visibly, labeled "Conversation mode," the same kind of switchable chip as Link, Article, Selection, or Images. Detecting the page is just a URL check; the transcript itself still isn't read until you click Save. If you switch to a different mode first, that's a hard override — the extension makes zero requests to the chat site, and Save sends exactly what the mode you're looking at says. If you leave Conversation selected and reading the transcript fails, the save doesn't quietly fall back to saving a bare link: it stops before contacting the Knowmarks server, tells you inline that it couldn't read the conversation, and leaves your note and mode choice in place so you can retry or switch modes yourself. What gets uploaded, precisely: the AI platform's entire raw private-API response, unparsed — the extension doesn't filter or trim it, so it can include internal identifiers and model/timing metadata alongside the visible messages. The Knowmarks server is what extracts and stores the readable conversation from that raw payload.

Images mode, precisely: switching to Images mode renders a picker grid of the candidate images found on the page, and building that grid loads each one from its own source site or CDN directly into the popup (a live <img src> per tile) so you can see what you're choosing from — the same kind of request your browser already made once to display the page itself, just made again by the popup. That's a real network request to a destination other than Knowmarks, distinct from the Conversation-mode call above, and it happens as soon as you open Images mode, before you select anything or click Save. What actually gets uploaded to your Knowmarks server on Save is narrower than what got loaded for preview: only the URLs of the images you selected, not the image bytes themselves — Knowmarks' own server fetches each image's bytes separately, after the save arrives. Separately again, on the server side: the page you were viewing when you picked images is saved as its own item, and if you hadn't already saved that page, the server extracts it the same way a Link save would — by fetching the page URL itself, since Images mode never sends page content. If you'd already saved that page, this fetch is skipped.

Catch-up, precisely: processing a queued item points a reusable worker tab at that item's URL and navigates it there, in your own logged-in browser — before any capture or upload happens. That's an ordinary, cookie-bearing page visit exactly like clicking the link yourself, and the source site (plus any redirect it sends you through, including a sign-in/SSO page if the site requires one) receives it, whether or not the item ends up captured successfully. This is the behavior the extension's broad, opt-in *://*/* host permission exists to authorize, and it happens for every item Catch-up processes. If the resulting page turns out to be a sign-in wall rather than the article, Catch-up detects that and skips uploading it — but the visit itself already happened. Once the worker tab has loaded, Catch-up reads the rendered page the same way Article mode does: any non-empty text it finds — thin or not — is what gets sent, and for the save's own content-extraction step, the server trusts it and doesn't separately fetch the URL. When the page yields no readable text at all, a screenshot is attached and the server tries OCR first, same as an empty Article capture — but here the parallel with Article ends: a Catch-up item is always a re-process of a row that already exists (there's no such thing as a Catch-up item for a URL that was never saved), so even when OCR also fails, this extraction step never falls through to a source fetch the way a brand-new empty save would. Instead, a failed Catch-up OCR exhausts the item: it's marked failed and dropped from the awaiting-capture queue outright — it is not left queued for a future attempt; there is no automatic retry. Catch-up's extraction behavior is therefore stronger than Article's: the save's content-fetch decision never contacts the source, full stop — its own client-side worker-tab visit above still reaches the source site regardless, and (like every save) it isn't exempt from the favicon and share-link behaviors described below, which run independent of capture mode.

What happens to a save after it arrives, if you're on the hosted alpha: it's stored in your own per-user database on a server the operator runs at Fly.io (a US hosting provider), on an encrypted disk volume — that's the primary store, and it's encrypted at rest. It's also backed up daily, over an encrypted connection, to the operator's private home server (a NAS behind a private tunnel, not exposed publicly) so a hosting-provider failure can't lose your data — and that off-provider backup copy is encrypted at rest with its own encryption layer (using age), independent of the operator's network access controls. The unencrypted data is held only in memory during the transfer and is encrypted before anything is written to the home server's disk — so no unencrypted copy is ever stored there, even briefly — and the private key that decrypts a backup is held separately (in a password manager), never stored next to the backups. If no encryption key is configured, the pull refuses to run, producing no off-provider copy at all, rather than writing an unencrypted one. Beyond storage: the operator has technical access to the server and its backups, but won't view your saved content — the actual text of your saves, notes, or searches — without your explicit consent first. If support requires looking at your specific content (e.g. investigating a bug you reported), the operator will ask, and waits for your go-ahead before viewing it — not just a heads-up after the fact. The narrow exceptions where content can be viewed without asking first are the same ones named in the Limited Use disclosure below: a security incident, a legal requirement, or in aggregated/de-identified form for internal operations — never as a routine matter of course. Separately: in the course of saving, enriching, and later displaying an item, Knowmarks (client and server) may contact the site you saved, its redirects, and related third-party services — to extract page content, resolve a share link, load a favicon, or query a platform's extraction API. This is not an exhaustive list, and whether a given save contacts the source depends on the mode and the site — there is no mode that guarantees the source is never contacted by anything. The useful, primary distinction below is about the save's own content-extraction decision — which modes send captured content the server can use directly, versus which cause the server to fetch the page itself — described as primary behavior, not an absolute guarantee. A plain Link save or a Selection save with nothing actually highlighted sends only the URL — the server then fetches that URL itself to extract it. An Article attempt that found no readable text at all is not an automatic source fetch, though: a screenshot is attached whenever the capture is this thin, and the server OCRs it first — a successful OCR becomes the saved content and this extraction step skips the source fetch. Only when OCR also comes back empty, on a brand-new (not-previously-saved) URL, does the save fall through to the same source fetch a Link save triggers. Catch-up is different here, not just a variant of Article: its extraction step never triggers this fetch at all — a Catch-up item is always a re-process of a row that already exists, so even a failed OCR there never falls through to a source fetch. It also doesn't stay queued for another try: a failed Catch-up OCR exhausts the item (marked failed, dropped from the awaiting-capture queue) rather than retrying later (more below — though Catch-up's own client-side worker-tab visit, and every save's favicon/share-link behavior, are separate and unaffected by this). When the Link/Article fetch does happen, the server follows any redirect it hits, and — for a growing, non-exhaustive set of platforms — may query that platform's own extraction service or API instead of a plain page fetch (examples: Reddit, Hacker News via the Algolia HN API, X/Twitter via an fxtwitter proxy, YouTube, Medium, Substack). This is a disclosed category, not a closed list — any URL you save may cause the server to contact that URL's host, its redirects, and an associated extraction endpoint we haven't named here. Selection saves with text actually highlighted, and Article/Catch-up captures that found any readable text — however short — send that captured content directly, and this extraction step trusts it as-is without re-fetching, even when it's thin enough to also trigger a screenshot (see above). (Images mode causes two fetches, described above: the server fetches the *page* itself the same way a Link save would when that page hasn't been saved before (since Images mode never sends page content), plus — always — each selected image's own bytes from its source URL/CDN, separately from the page fetch. Conversation mode's extraction step causes no source-URL fetch — the transcript comes from the AI platform's own API via your session, described above. And separately from any server-side extraction fetch, Catch-up already navigated your browser to the source page before any of this, described above.) Two more, independent of capture mode: a Reddit share URL (/r/{sub}/s/{id}) is resolved to its canonical form via a HEAD request before dedup, on essentially every save of such a URL — including saves that also supplied captured content — so captured content is not a guarantee the source is otherwise untouched; and displaying any saved item requests its domain's favicon, which the server fetches directly from that domain the first time (cached afterward, with a secondary icon CDN fallback for some domains) — regardless of which mode saved it. Also separately, the Knowmarks service processes every save to build its search index — sending the extracted text to a hosted embedding model is a mandatory part of ordinary saving and searching, not an optional AI feature — and to generate the summary, classification, and connections you see in the app. That processing sends the saved content to Knowmarks' LLM provider, OpenRouter (and the underlying model provider OpenRouter routes the request to), solely to produce those features. This is enforced, not just intended, for nearly every hosted call: content is processed by OpenRouter and routed only to providers whose data policy prohibits training on or using it to improve their models — set at the request level on every hosted chat, vision, and embedding call except the Brief feature's, not a dashboard toggle we're merely trusting for those calls. Brief is the one lane where this can't be a per-request setting: it routes through an OpenRouter preset (@preset/knowmarks-pulse), and OpenRouter's preset mechanics mean a request-level restriction would silently override the preset's own routing configuration rather than compose with it — so for Brief specifically, the no-training restriction has to be configured inside the preset itself, on the OpenRouter dashboard, and verifying that's actually set is a pre-submission operator step, not something this page can attest to sight-unseen (the app's own diagnostics, km doctor, flag the lane until it's confirmed there). Logging and retention are still governed by each provider's own policy, though — this is not a zero-retention guarantee; OpenRouter's separate, stricter zero-data-retention control isn't enabled today. Hosted AI requests for an ordinary save — including the background enrichment (summary, connections, embedding) that runs right after you save — also carry a pseudonymous per-user label to OpenRouter: a one-way hash of your account id, not your email or name, so the operator can see per-user cost in the OpenRouter dashboard. The operator's own systems still know which account a label belongs to (that's the point of the label), but OpenRouter itself never receives your email or account name directly. This doesn't yet cover every hosted AI call in the product — bulk-import enrichment and the automatic content-type classifier still run unattributed, a known gap tracked for a future fix — but it does cover the path an ordinary save and its enrichment take, which is what matters for the extension. All hosted-alpha traffic, including the extension's requests, transits Cloudflare (our edge/tunnel provider) in the ordinary course of reaching the server. Neither OpenRouter nor Cloudflare is paid, permitted, or used to sell your data, serve you ads, or build an advertising profile — they're processing steps in delivering the feature you asked for, not a third-party share of your data for their own purposes. Server-side error tracking (Sentry) is also on for the hosted alpha: a scrubbing pass strips request bodies, headers, and known-sensitive fields before an error report leaves the server, but it's a filter, not a guarantee — user-derived text can occasionally survive in an error message. If you run your own local Knowmarks instance instead (pointed at http://localhost:3749), the same processing happens against whatever LLM endpoint you've configured for your own instance, not ours, and there's no Fly.io storage, NAS backup, or hosted Sentry involved at all.

A word on sensitive-seeming content: the extension doesn't target names, health details, financial information, or the like — but whatever you choose to save can contain them, directly. An Article, Selection, or Conversation capture sends the actual content of the page or chat you picked, so if that page or chat happens to be about a health topic, contains a payment amount, or quotes someone's name, that's what gets sent — the same way it would if you copy-pasted it yourself. That's inherent to saving a page, not a side effect to apologize for. Separately, screenshots add an incidental path on top of that: if the page-text extraction comes back too thin to be useful (a client-rendered or paywalled page, in Article mode or on the Catch-up page), the extension takes a screenshot of the visible tab and sends it along with the save. The server runs that screenshot through OCR, and if the OCR read comes back non-empty, it replaces the thin extracted text as what's actually stored and indexed — the original thin capture is discarded, not merged with it. Because it's a screenshot of whatever's on screen, it can incidentally include filled-in form fields, account details, or payment information visible at that moment, whether or not the page was otherwise about that content — and for a thin capture, that incidental content can end up as the saved content instead of the article text you thought you were saving. This only happens for thin Article-mode or Catch-up saves, never for Link, Selection, Images, or Conversation saves.

Outside of an explicit capture-mode selection or Save (and the local URL/title read and content-free queue check above), the extension does not read or send anything from a page. It doesn't watch your background browsing, and it has no separate analytics or telemetry channel of its own — no independent event stream, no third-party analytics SDK. It does, though, send a small set of usage/diagnostic fields alongside most saves (which capture method you used, two character-count fields, the extension's version number — see the table above) as part of the save payload itself, not as a standalone telemetry system. Your access token, when you've set one, is stored on your device only (chrome.storage.local) — it does not sync to other Chrome profiles, and it's added only to requests to your configured Knowmarks server; requests to a third party (the AI-platform ferry, image-preview loads) never carry it.

One more recipient, user-initiated only: GitHub. The in-app "Send feedback" button (in the web dashboard, not the extension popup) posts a private, maintainer-visible GitHub Issue to the operator's repository. This is the complete disclosed payload — everything that can go into that issue body:

  • Your typed description.
  • Your browser's user agent string and viewport size (window width × height) — captured automatically alongside every submission, labeled Browser and Screen in the issue.
  • Your browser's own recent console errors from the current session (client-submitted, capped in length and count — never read from any server-side log).
  • Seven fixed diagnostic fields, an allowlist enforced in code: app version, Python version, OS name/version, the embedding provider and model name (never a key), the LLM provider and whether it's configured (again, never a key), and — scoped to your own tenant only, omitted entirely when that can't be resolved, never substituting another tenant's or the operator's aggregate figures — your own collection's item count and database size. No filesystem path of any kind is ever included in these.
  • Your display name and email address, in multi-user mode only.
  • Only when the feedback is sent from the in-app reader (a "report a display issue" flow launched from an item's own reader page): the item's id, its content type, its reader kind, and its render format — sent regardless of whether you also opt in to the page snapshot below. These are low-sensitivity identifiers/labels (which item, which renderer), not page content.
  • Only if you additionally opt in to including the page snapshot: the reader page's rendered HTML and its source URL. The URL rides the same opt-in as the HTML snapshot — declining the snapshot omits both, and the server enforces that even against a client that didn't.

No application or service log of any kind is ever attached, in either single-user or multi-user mode. This only happens when you click Send; there's no automatic or background submission, and the extension itself never talks to GitHub.

Chrome Web Store Limited Use disclosure. This is a pre-submission draft: the extension is not yet listed on the Chrome Web Store, and full Limited Use certification is affirmed at submission time, once the remaining gate is met (named below) — this section states what's true today and what's still pending, rather than asserting unconditional present-tense compliance. What the product does follow now: data the extension reads is used only to provide the save/search/organize features described on this page — never for advertising, and never sold, transferred to data brokers, or used for creditworthiness or lending decisions. No one reads your saved content by hand except with your explicit consent, in aggregated/de-identified form for internal operations, when needed for security purposes, or when required by law. Data is transferred only as needed to provide the feature, to this disclosed (not closed or exhaustive) set of recipients: the Knowmarks server you configured; the website you saved (and any redirect target, plus — for a non-exhaustive, growing set of platforms — a platform-specific extraction service or API, e.g. Reddit, Hacker News via the Algolia HN API, X/Twitter via an fxtwitter proxy, YouTube, Medium, Substack; any URL you save may involve a service not named here) — reached by the Knowmarks server's content-extraction step for a Link save, an Images-mode save of a not-yet-saved page, a Selection save with nothing highlighted, or a brand-new (not previously saved) Article attempt that found no readable text and whose screenshot OCR also came back empty (a Selection with text highlighted, and any Article capture that found text — thin or OCR-healed — send the page content directly instead, so this extraction step doesn't make that particular request; Catch-up's extraction step never makes this request, since a Catch-up item is always a re-process of a row that already exists, and a failed OCR there exhausts the item (marked failed, dropped from the queue) rather than triggering a fetch or staying queued for another try) — plus, independent of mode or captured content: a HEAD request that may resolve a Reddit share URL to its canonical form before dedup (fires on essentially every save of such a URL, whether or not content was also captured), and a favicon fetch to https://<domain>/favicon.ico (with a secondary icon-CDN fallback) the first time the dashboard needs to display that domain's icon, for any saved item regardless of how it was captured; and reached separately by your own browser for every Catch-up item, which navigates a worker tab to the source URL before any capture happens — an unrelated, client-side-only visit, independent of whether the server's extraction step ever fetches anything; its LLM provider, OpenRouter (and, in turn, the underlying model provider OpenRouter routes a given request to, per OpenRouter's own routing and each provider's own data policy), for search indexing and AI features; its transit/edge provider, Cloudflare; server-side error tracking, Sentry — scrubbed before an event leaves the server, though the scrub is a filter, not a guarantee, so user-derived text can occasionally survive in an error report (see above); the AI platform's own API (claude.ai, chatgpt.com, or its legacy alias chat.openai.com), reached only in Conversation mode, using your existing session there; and each saved image's own source site or CDN, reached both by your browser (Images mode's picker-grid preview) and, separately, by the Knowmarks server (fetching each selected image's bytes after the save); and, only when you click the in-app "Send feedback" button, GitHub — never automatic, and never from the extension itself — all described above — or for those same narrow legal/security/consent exceptions. This is the disclosed set of recipients data is transferred to for these purposes, not a promise that no service in this chain ever has its own further processors — each recipient's own privacy policy governs what happens on their side. The LLM-provider transfer described above is restricted at the request level to providers whose data policy prohibits training on submitted content, per the enforcement described above — for every hosted call except the Brief feature's, which relies instead on the same restriction being set inside its OpenRouter preset on the dashboard, not per request. That request-level restriction is affirmable today without resting on an unverified account setting; the Brief lane is not yet, until that preset-level setting is confirmed on the OpenRouter dashboard.

Full Limited Use certification is not yet affirmed — one gate remains open, tracked on the submission runbook and not claimed here on faith: the Brief-preset no-training setting above, still needing confirmation on the OpenRouter dashboard. The other two gates are now closed: the off-provider backup copy described above is encrypted at rest with its own age layer, independent of network access controls (GH #770), and the extension now shows an in-product, in-extension first-run disclosure with an affirmative-consent step before it captures anything (GH #774). Submission and certification wait until that remaining gate is closed.

Ask a privacy question