Cookies and browser storage

What CCB stores in your browser, and why.

CCB is a Facility-run training platform for Coaches, Admins, and Athletes. The product runs on the storage below, and on nothing else. This page is the complete inventory.

Why CCB uses storage

CCB stores only what it needs to authenticate Users, authorize anonymous Athletes, keep Work-Phase submissions recoverable across a network drop, and remember a small set of interface choices. None of it is sold, shared with advertisers, or used to build a profile of you off the platform.

Strictly necessary

Required for sign-in, anonymous Athlete access, Session authorization, and Work-Phase submission recovery. Disabling these will sign you out, remove anonymous Athlete access, or drop in-flight submissions on a network drop.

CookieStrictly necessary

ccb.session (dev) | __Secure-ccb.session (prod)

Stored under ccb.session (dev) | __Secure-ccb.session (prod).

Keeps a signed-in User authenticated in the CCB platform. The cookie carries a signed JWT and is read-only by JavaScript.

Owner
Collective Cadence Burden
Retention
7 days from sign-in
Required for
  • Account access for Coaches and Admins
  • Facility and Coach authorization
  • Cross-Session Athlete history
CookieStrictly necessary

athlete_token_{sessionId}

Stored under athlete_token_{sessionId}.

Proves that this browser joined a specific Session as an anonymous Athlete. The token is HMAC-bound to the Session and is read-only by JavaScript.

Owner
Collective Cadence Burden
Retention
Up to the configured Athlete token lifetime
Required for
  • Athlete Session state
  • Private recap access
  • Anonymous Athlete realtime authorization
Local storageStrictly necessary

pendingReportFreeze

Holds a Work-Phase Checksum payload that the Athlete Node could not deliver to the server after three retry attempts. The queued payload is replayed on the next page load or connectivity event.

Owner
Collective Cadence Burden
Retention
Removed on the next successful POST; removed on station advance; cleared on a malformed entry
Required for
  • Work-Phase Checksum delivery across a transient network drop
  • Recovery of an explicit Athlete tap on a single Station
Local storageStrictly necessary

pendingRacePracticeResult

Holds a Race Practice station result that the Athlete Node could not deliver after three retry attempts. The queued value is scoped to a single station so it cannot replay against a different station.

Owner
Collective Cadence Burden
Retention
Removed on the next successful POST; removed when the Athlete advances to a new station
Required for
  • Race Practice result delivery across a transient network drop
  • Recovery of an explicit Athlete result entry on a single station
Session storageStrictly necessary

ccb.joinAttempt:{sessionId}

Stored under ccb.joinAttempt:{sessionId}.

Caches the Join-attempt token (a short-lived HMAC-signed bearer) so that retries during a single page render resolve to the same anonymous Athlete identity. The storage key is the server-provided Session identifier; the QR bearer token is never embedded in the key.

Owner
Collective Cadence Burden
Retention
Until the form tab is closed; cleared on cap-rejection and on a malformed entry
Required for
  • Retry idempotency — the same cached token resolves to the same `athleteId` across retries, which is what the atomic join's single-row guarantee depends on
  • Cap-rejection re-mint flow — the cache is cleared on cap-rejection so the next attempt mints a fresh token (and a fresh `athleteId`) for the retry

Functional preferences

Browser storage that remembers a UI choice the visitor made (theme, language). The product continues to work without them; the visitor just loses the preference and re-picks on the next load. CCB does not gate these on consent because the preference belongs to the visitor in the first place.

Local storageFunctional preference

ccb-theme

Holds the visitor's light / dark / system theme choice so it persists across page loads. Removing the value falls back to the system preference; the product continues to work.

Owner
Collective Cadence Burden
Retention
Until the visitor clears browser storage or switches theme
Affects
  • Remembered theme choice across page loads (preference, not a hard requirement)
Session storageFunctional preference

ccb-deck-lang

Holds the investor-deck language selection for the current tab. Removing the value falls back to English; the product continues to work.

Owner
Collective Cadence Burden
Retention
Until the browser tab is closed
Affects
  • Remembered deck language within the current tab (preference, not a hard requirement)

Error reporting

CCB reports unhandled browser errors to Sentry so the team can fix bugs quickly. The reporter does not write any cookies or browser storage in the current configuration, and every event passes through a PII-stripping filter before it leaves the browser. The filter covers four surfaces: the request cookie jar, the top-level extra object, the top-level user object, and the top-level data object on each breadcrumb. On those surfaces, it removes the identifiers that pin an error to an individual User, Athlete, Session, or Facility, redacts emails and magic-link URLs from string values, and deletes auth-shaped cookie keys. Other event surfaces (tags, contexts, exception values, request headers and URL, nested extra or breadcrumb objects, breadcrumb messages) are not touched by the filter and should not be relied on to remove sensitive material — CCB never sets those fields with personal data.

Errors onlySentry

Sentry receives unhandled browser errors and unhandled promise rejections. No session replay, no performance tracing, no product analytics, and no default PII.

PII filtering: CCB-owned beforeSend hook strips emails, magic-link URLs, auth-cookie values, and athleteId / sessionId / boxId / userId from the four surfaces it touches: top-level request.cookies, top-level event.extra, top-level event.user, and the top-level data object on each breadcrumb. Other event surfaces (tags, contexts, exception values, request headers / URL, nested objects, breadcrumb messages) are not covered — CCB never writes personal data there.

No advertising or tracking

CCB does not currently use advertising or marketing trackers, and does not run consent-based product analytics. A future change in that posture will require a consent boundary — see Changes to this page below.

First-party analytics (cookieless)

The public CCB pages send a single anonymous event per page view, CTA click, and outbound-link click to a first-party endpoint at POST /api/track. The endpoint is cookieless: no identifier, no persistent client ID, no session stitching, no fingerprint, no advertising profile is built from it. The wire shape accepts only name, path, slug, cluster, cta, href, and ts; any other field is dropped at the schema stage. Magic-link URLs, QR-join tokens, and email addresses that happen to appear in the wire fields or in the browser's Referer header are redacted to [redacted] before the line is written. The redactor is the same PII strip list used by the Sentry beforeSend filter.

The endpoint writes the redacted event to the application's standard log stream. It is not sent to a third-party analytics provider, and the Sentry error reporter is not invoked by the analytics path.

Because the endpoint carries no identifier, there is no per-Visitor opt-out link. The practical opt-out is to block the request in your browser's dev tools, in an extension such as uBlock Origin (custom rule: ||*/api/track$post), or at the network level.

The full story of what CCB collects, why, and the rights you have over it is on the Privacy Policy.

Removing browser storage

You can remove any of the above from your browser at any time. The trade-off: clearing the session cookie signs you out, clearing the anonymous Athlete cookie removes that browser's proof of join for any in-progress Session, and clearing the recovery queues drops any Work-Phase or Race Practice submission that the browser had not yet delivered to the server.

Changes to this page

This page is updated whenever CCB introduces a new cookie or storage key, expands a storage purpose, or integrates an analytics or marketing tool that requires consent. The current product has no such integration.

Contact

Questions about CCB's storage choices can be sent to the team via the Contact link in the site footer.