graycat.app

Website Privacy

Last updated: August 19, 2026 · Applies only to the GrayCat website and does not change how any app handles data

Short version

The GrayCat website uses first-party statistics to record home-page visits and three app-action events: product-page views (product_view), direct-download starts (download_start), and outbound App Store clicks (app_store_outbound). Full visit, download, action, and home-page geography aggregates are visible only to the site owner; the home page does not publicly display visit totals or any geography data. For directly downloadable apps, a public milestone such as 100+ appears after 100 counted starts. The site sets no analytics cookie, loads no third-party analytics script, and does not store raw IP addresses.

How one visit is counted

When the home page opens in a browser, it sends one request to a same-origin Cloudflare Worker. As with an ordinary website request, the Worker briefly receives the source IP while handling that request. It immediately combines the UTC date and IP with a key stored only as a Cloudflare Secret, calculates a keyed HMAC-SHA-256 daily digest, and discards the raw IP. Without that secret, the digest cannot be directly matched to the original address; this is pseudonymous deduplication, not complete anonymization.

The same public IP is counted at most once per UTC day. This is a network-and-day deduplicated visit count, not an exact person count: households, institutions, VPNs, and mobile networks may share one public IP.

For each first counted visit of the UTC day, the Worker reads the country code, first-level region, and city that Cloudflare estimates from the source public IP, then increments only the corresponding daily aggregate. This is not GPS, street, or residential-address data. VPNs, Tor, mobile networks, corporate gateways, and privacy proxies can make the result describe a network exit rather than the visitor's actual location; missing fields are grouped as “Unknown.” The geography table uses the UTC date as its smallest time unit and stores neither a visit timestamp nor a per-request log; at low traffic, a particular “date + city” aggregate can still have a count of one.

How the three app actions are counted

Each event type gets a separate keyed digest from the event type, UTC date, app ID, and public IP. The same public IP can count at most once per app, event, and UTC day. Different HMAC input domains are used for different events, so the records cannot reliably connect one visitor's product view to a later action as a personal funnel. HEAD requests, prefetches, prerenders, and known automated link-preview agents are excluded. If the statistics database is unavailable, direct-download and App Store redirects still work.

Campaign source codes

A link may carry a first-party campaign parameter. Metrics accept only producthunt, reddit, v2ex, sspai, bilibili, youtube, xiaohongshu, alternativeto, macupdate, hackernews, email, press, in_app, and unattributed; missing or invalid values become unattributed. A valid code is retained across ordinary same-origin page navigation and passed to this site's direct-download and App Store outbound routes. It is not added to privacy notices, restricted administration pages, APIs, static assets, or off-site links, and is not written to cookies, localStorage, or sessionStorage. For the same public IP, app, event, and UTC day, the campaign on the first counted request is retained and later duplicates do not rewrite attribution. Metrics do not read or store a raw referrer or full visited path.

What is stored

Visit and app-action deduplication records are retained for about 8 days. Home-page geography daily aggregates are retained for up to about 90 days. Both are cleared by an hourly scheduled task; the geography rows are used only to show recent country, state/province, and city distribution. App-action daily aggregates are retained long term to compare sources and action rates.

The first-party metrics database does not store raw IP addresses, street or residential addresses, postal codes, latitude or longitude, precise visit times, per-request location logs, full visited paths, page-view history, raw referrers, cookies, localStorage, sessionStorage, browser fingerprints, advertising identifiers, or user-submitted content. Visit and geography aggregates are not displayed on public pages.

Purpose and public display

The home page does not publicly display visit totals or country, region, or city distribution. Full visit, geography, download, and app-action aggregates are visible only to the site owner. Once an app reaches 100 direct-download starts, public pages show only tiered milestones such as 100+, 500+, or 1K+; nothing is shown below 100. Public endpoints provide neither exact totals, geography aggregates, nor individual event records. Campaign-level daily aggregates are used only to understand which publishing sources lead to product interest, direct-download starts, or outbound App Store clicks.

These data support aggregate action rates, not an exact person-level conversion funnel. Shared public IPs, JavaScript or content blocking, network failures, and daily deduplication all create differences between product-page views and later actions.

Cloudflare

The GrayCat website is served through Cloudflare Workers, Static Assets, and R2, so network requests are processed by Cloudflare. Country, first-level region, and city are Cloudflare IP-geolocation estimates. The counter uses Cloudflare D1 for storage; its digest key is stored as a Cloudflare Secret and is not written to site code or the database.

Apps are unaffected

These statistics run only on the GrayCat website and are not added to GrayCat Markdown, GrayCat Text, GraycatTunes, GrayCat PDF, or KneeDaily. Automatic app updates are not counted as direct website downloads, and this does not change any app's published privacy policy.

Contact

For website privacy questions, email support@graycat.app.