Privacy
The short version
- We collect what's necessary to run a leaderboard and not much else.
- Sign-in is OAuth via RideWithGPS or Google — we never see a password.
- Your GPS tracks are stored so the verifier can match them to civic routes. You choose whether heart-rate and power get included.
- The public leaderboards show your display name plus ride stats. Your email, IP, OAuth tokens, and underlying files are never displayed.
- You can edit, unlink, or delete everything at your profile. "Disconnect account" wipes your row, every activity, every attempt, every stored file.
- We don't sell anything, run ads, run analytics, or share your data with third parties beyond the OAuth providers you chose.
What we collect
From OAuth sign-in
- Your provider's account ID (Google subject or RideWithGPS user ID) — so we can recognize you on return visits.
- Your email address, when the provider shares it. RideWithGPS doesn't
always share an email — when it doesn't, we generate a placeholder
(
rwgps-{id}@users.civicfkt.invalid) that can never deliver mail. You can supply a real email yourself on /me. - Your name from the provider, used as the default display name. You can change it any time on /me — that's the string shown on public leaderboards, not your provider's account name.
- An OAuth bearer token, stored encrypted-at-rest by the database. Used only to fetch trips you've authorized us to import. Wiped when you unlink the provider or disconnect your account.
From rides you upload or auto-import
- The GPS track itself: latitude, longitude, elevation, timestamps.
- If you upload a
.fitfile directly: power, heart-rate, cadence, and any other channels the file contains. If you set the RideWithGPS import format to .gpx-equivalent, those sensor channels are stripped server-side before storage — they never reach disk and never reach the database. - The original file (or, for RideWithGPS auto-imports, a synthesized GPX we generate from the API response). Stored under a SHA-256-derived path so identical re-uploads de-duplicate to a single file.
- Summary stats (start, duration, distance, average and normalized power if applicable) computed from the track points.
RideWithGPS sync defaults
- When you link RideWithGPS, auto-import is turned on and the .fit format is selected — meaning we'll pull heart-rate and power from each ride if your device captured them.
- The RideWithGPS API exposes both your public and private trips to a linked app, so auto-import will fetch private rides too. That's how the API works — there's no "public only" filter on their side. Most rides won't match a civic route anyway, but the ones that do land on the public leaderboard with your display name.
- You can uncheck auto-import on /me and instead upload each activity you want ranked, either by pasting its RideWithGPS URL on the upload page or by exporting the file from RideWithGPS yourself.
- You can delete any individual ride from your /me page — the row is removed, the file is removed from disk, and any leaderboard standings the ride produced go with it.
From the contact form
- Whatever you typed — name, optional email, message body.
- Your IP address, used briefly to throttle obvious spam (3 messages per hour per IP). Stored on the message row for admin context but never displayed publicly.
Operational data
- Server access logs — standard HTTP method, path, response code, request duration, client IP. Useful for debugging and security; no analytics or fingerprinting.
Cookies
CivicFKT sets a small set of strictly-necessary cookies — all
first-party, all on the civicfkt.com domain, all
Secure (HTTPS only) and SameSite=Lax. There are
no analytics cookies, no advertising cookies, no third-party trackers,
and no fingerprinting. The site doesn't load any third-party JavaScript
that could set its own cookies in your browser.
| Name | Set when | Purpose | HttpOnly? | Lifetime |
|---|---|---|---|---|
fkt_csrf |
First visit (anonymous or signed in) — every page load sets it if it isn't already present | Cross-site-request-forgery protection — every form embeds the cookie's value as a hidden field, and the server rejects POSTs whose embedded value doesn't match the cookie | No (the form template needs to read the value) | 30 days |
fkt_oauth_state |
Click "Sign in with Google" or "Sign in with RideWithGPS" | Random nonce that prevents CSRF on the OAuth callback. Discarded immediately after the callback succeeds or fails | Yes | 10 minutes |
fkt_return_to |
Click sign-in from a non-home page (e.g. /upload when not logged in) | Remembers where you were so the sign-in flow can land you back there | Yes | 10 minutes |
fkt_oauth_link |
Click "Link RideWithGPS account" from /me | Carries the signed-in user id through the RideWithGPS OAuth round-trip so the link attaches to the right account | Yes | 10 minutes |
fkt_session |
After successful sign-in | Identifies you on subsequent requests. Signed with a server-side secret; tampering invalidates it. Cleared by sign-out or by the disconnect button on /me | Yes | 30 days, refreshed on use |
Under EU ePrivacy/GDPR and California CCPA/CPRA, all of these qualify as strictly necessary cookies — required for security (CSRF, OAuth state) or for the requested service (session, return-to). Sites that only set strictly-necessary cookies don't need a consent banner, and we don't show one.
If you want a cookie-free experience, your browser's site-data controls let you wipe CivicFKT's cookies anytime — the only consequence is that you'll need to sign in again, and any form you submit will need a fresh CSRF cookie issued first (handled automatically on the next page load).
Where the data goes
Public leaderboards
When your ride matches a civic FKT route, the leaderboard shows your display name, your time and distance, and the date you rode it. That's everything. Your email, IP, OAuth identifiers, the underlying GPS track, and any sensor data are never shown to other riders. Power and heart-rate, when they exist, drive your position on power-leaderboard panels but are summarized as totals only — the per-second values aren't exposed.
Third parties
- Google (when you sign in with Google) and RideWithGPS (when you sign in or link your account) — they tell us your account identifier and email. We tell them nothing about you. Their privacy policies are their own.
- OpenStreetMap serves the map tiles that render in your browser on map pages. Your IP reaches their servers when those tiles load. We have no relationship with them beyond using their public tile service.
- Nothing else. No analytics, no ads, no CRM, no marketing email.
How long we keep it
Until you ask us not to. There's no automatic expiry — your account, your rides, your standings persist as long as you want them.
If you disconnect your account on /me (the red button at the bottom), the system runs a single transaction that:
- Deletes your
usersrow. - Cascades to delete every activity you uploaded, every leaderboard attempt those activities produced, and every stored OAuth token.
- Best-effort removes the underlying ride files from disk.
- Clears your session cookie.
Disconnect is final. There's no recovery — by design.
What you can change without disconnecting
- Display name and email on /me.
- RideWithGPS auto-import on/off, and the format choice
(
.fit-equivalent vs.gpx-equivalent). - Unlink one OAuth provider while keeping the other (the system refuses to unlink your only sign-in path).
- Flag a specific ride for admin review if you think a route should have matched but didn't (button on the upload-done page).
Security
Data lives on a single server in a US data center, behind HTTPS only. The database isn't reachable from the public internet. OAuth tokens are stored in a separate table that cascades on user delete. Webhook deliveries from RideWithGPS are HMAC-verified against a secret only we and RideWithGPS know — forged webhooks are rejected.
Your rights
You can:
- Access — sign in and look at /me; everything we have on you is shown there or one click away.
- Correct — edit display name and email directly.
- Delete — disconnect on /me wipes everything.
- Restrict — turn off auto-import, unlink a provider,
or pick the
.gpx-equivalent format to keep sensor data out. - Ask — anything else, send a message via the contact form.
Changes to this policy
Material changes will move the "Last updated" date at the top and, where they affect data we already hold, get announced on the front page. This policy lives in the same source tree as the rest of the site so its change history is preserved.
Contact
Use the contact form. One human reads it. You'll get a reply only if you supplied an email address on the form — we don't have any other way to reach you.