CragMate Privacy Policy
Effective: 2026-08-21 · Version: 1.4
Scope
This policy covers two things:
- This website, cragmate.com - live today. It sets no cookies, and its data processing is limited to three things: counting which of our own links people arrive through; the hosting and server logs that serving any website necessarily produces; and cookieless, aggregate analytics - which are described below but are not currently running. All three are described in This website.
- The CragMate iOS and watchOS app, version 1.0 - available today on the App Store, free. Everything after "This website" describes how that app - the build you can install right now - handles your data, apart from the later entries that mark themselves website-only.
Where a section applies to only one of the two, it says so.
The short version
CragMate has no backend server and no user accounts. Your climbing data lives on your devices - iPhone and Apple Watch - and nowhere else. The only data the app sends off your device is:
- Session summaries sent to your paired Apple Watch (and back) via Apple's WatchConnectivity protocol, device-to-device only.
- Workout data written to Apple Health, if you grant that permission.
- A fixed set of fourteen pseudonymous signals sent to TelemetryDeck: some tell us how the app is used, and some report that one of the app's own subsystems failed. None of them carries anything you typed.
- One small founding-member record - a date and a version number, nothing else - written to your own private iCloud database, so your founding-member access can outlive any one installation. See 4. Your private iCloud database.
- One of those fourteen signals is a short, fixed-shape summary of a crash or a freeze - sent to TelemetryDeck like the rest, but sourced from Apple's MetricKit. It says what kind of failure happened, not what you were doing - no stack traces, no addresses, no text of any kind. iOS's analytics settings do not stop it, which is the opposite of what most people expect; see 5. Crash and hang diagnostics.
Separately, the cragmate.com website sets no cookies, and its analytics are not currently running - no analytics script is served with any page. What the site does do is count which of our own links people arrive through, and produce the hosting and server logs any website produces - your IP address, the page you asked for, the time and your browser's user-agent, seen by our host - see This website.
If you are looking for the GDPR section, it is under Your rights.
This website
This section describes the data processing that happens on the cragmate.com marketing website. Everything after it describes the CragMate app, apart from the later entries that mark themselves website-only - see Scope.
Cookies and device storage
This website sets no cookies and stores no identifier of any kind on your device -
no cookies, no localStorage, no sessionStorage, no device fingerprinting, and no
advertising or tracking pixels. Nothing this site puts in front of you reads any
identifier back off your device. Where one of our links carries a campaign label - see
Campaign links and the App Store banner -
that label describes the link, not you, and passing it on is strictly necessary to the
navigation you asked for, which is one of the cases the law exempts from the consent
requirement. So the site shows no cookie-consent banner: there is nothing to consent to.
Website analytics
Website analytics are not currently running. No analytics script is served with any page on this site: the site is built without a TelemetryDeck app ID, so the analytics code is left out of the build entirely and your browser never receives it. Nothing on the page you are reading counts your visit. The rest of this section describes what would be sent if we switch website analytics on - and we will not switch them on without putting this section back into the present tense in the same deploy.
If we switch it on, the site will use TelemetryDeck (TelemetryDeck GmbH, Germany - see Third parties) to understand aggregate visitor activity, and a page load will send:
| Signal | Data sent |
|---|---|
web_page_view |
the page path you viewed (e.g. /privacy) and the host of the site that referred you (e.g. google.com), if any |
web_cta_click |
an identifier for the button or link you clicked (e.g. footer_privacy) |
The TelemetryDeck SDK would attach a per-page-load random session ID (not stored, not
reused on your next visit) and a single constant value, web-anonymous, that is identical
for every visitor. The site would not assign you a persistent identifier. As with any
request to any website, TelemetryDeck's server would receive the IP address inherent in
the network connection; per TelemetryDeck's policy that IP is used transiently and is not
stored in raw form.
What this means: switched off, as it is today, the site counts nothing. Switched on, it still could not identify you, follow you across visits, or build a profile of you - it would count page views and clicks in aggregate.
Legal basis (GDPR Art. 6(1)(f) - legitimate interests): if we switch this on, we will rely on our legitimate interest in understanding, at an aggregate level, how the site is used and which pages are useful. Because the analytics are cookieless and do not single you out, the impact on you is minimal. You will be able to object to this processing at any time - see Your rights.
Campaign links and the App Store banner
Some places we hand out CragMate links use a short address - cragmate.com/get, or one of
the form cragmate.com/r/… - printed on a card at a climbing gym, encoded in a QR code
we print, or pasted into a forum post. These links are the same wherever we hand them out,
printed or pasted. Visiting one sends your browser straight on to the CragMate listing on
the App Store. That is all they do: no page is rendered and no script runs.
The onward address carries two fixed labels, plus mt=8, a legacy marker that says only
"this is an iOS app". One label identifies our developer account - the same value wherever
it appears. The other says which of our own links you came through (ct=gym for a gym
card, and so on). That second label describes the card, not you: every single person who
scans that card sends exactly the same value. Neither label carries anything about you,
anything you typed, or any identifier of any kind - and any query string you had added to
the address yourself is discarded rather than forwarded, so you cannot pass anything on
through one of these links either.
The App Store buttons and the scan-to-install QR code on this site itself carry no labels at all - they point straight at the plain listing.
As with any link between two sites, Apple's servers see the request your browser makes. Whether your browser also tells Apple where you came from is up to your browser and the page you were on: a scanned QR code or a typed address usually sends nothing at all, and a link in a forum post sends that forum. The redirect itself adds nothing.
Separately, on iPhone, Safari may show a small CragMate banner at the top of this site
with an INSTALL button. That comes from one fixed line of text in this page's HTML - the
same line for every visitor. It reads nothing from your device and reports nothing back to
us. If you tap INSTALL, Safari opens the App Store carrying the same two kinds of label:
our developer account, and a fixed label meaning "came through the website" rather than
any particular card or post. The same line also carries the address of the page you are on
with that same website label appended - for this page,
app-argument=https://cragmate.com/privacy?ct=web. It is there for the case where you
already have CragMate installed and tap OPEN: iOS would hand it to the app on your own
device, and the app as shipped registers nothing to receive it, so iOS discards it. Either
way it goes neither to us nor to Apple.
What happens at Apple's end, stated plainly. Once you reach the App Store you are on Apple's site, under Apple's privacy policy (https://www.apple.com/legal/privacy/). Apple counts an install against a label when it happens within 24 hours of your using the link; how Apple does that is Apple's to describe - we do not set anything, cannot read anything, and have no control over it. What Apple gives back to us is a set of counts per label over whatever date range we ask for - impressions, product page views and first-time downloads, and later any purchases - never a per-person row. Apple withholds a label's numbers entirely while the count behind them is very small, so a label only a handful of people used reports nothing at all. There is no identifier, and no way for us to see any individual visitor or device. If you would rather not pass through one of these links, open the App Store listing directly - the app is the same either way.
What this means: we can tell that gym cards work better than forum posts. We cannot tell that you installed the app, and neither the label nor anything else here follows you anywhere.
Legal basis (GDPR Art. 6(1)(f) - legitimate interests): we rely on our legitimate interest in learning which of our own channels people actually find CragMate through, so we can stop spending effort on the ones that do not work. The label identifies a venue rather than a person, and what we receive is an aggregate count, so the impact on you is minimal. You can object to this processing at any time - see Your rights.
Hosting and server logs
This website is hosted on Cloudflare. As with every website, your request reaches Cloudflare's servers, which necessarily see the IP address your connection comes from, which page you asked for, the time, and your browser's user-agent string. This is unavoidable: without your IP address there is nowhere to send the page back to.
Cloudflare processes this on our behalf and on our instructions, as our processor under GDPR Art. 28, to deliver the site and protect it from attack and abuse. We do not use it to build a profile of you, we do not combine it with anything else, and we do not use it to identify you. Retention of Cloudflare's own operational logs is governed by Cloudflare's terms; we keep no separate copy - see Retention. Cloudflare is certified under the EU–US Data Privacy Framework and its data processing addendum additionally incorporates the 2021 Standard Contractual Clauses.
Legal basis (GDPR Art. 6(1)(f) - legitimate interests): our legitimate interest in serving the page you asked for, keeping the site available, and protecting it from abuse. You can object to this processing at any time - see Your rights - though there is no version of serving you this page that does not involve it, so the only complete way to avoid it is not to visit the site.
What we collect
The sections from here through Retention describe the CragMate app, apart from the entries under Third parties, Your rights and Retention that mark themselves website-only. The rest tell you how the app handles your data.
CragMate stores the following data locally on your device using Apple's SwiftData
framework. This data resides inside the iOS/watchOS shared App Group container
(group.com.climbr.shared), with one exception noted at the end of this section, and is
never uploaded to any server operated by CragMate.
Local profile (User record)
When you first launch the app, CragMate generates a random UUID as your local user ID. No sign-in, no account, no email address is required or collected. The profile record stored on-device includes:
- Local user ID (randomly-generated UUID, created on first launch)
- Display name (defaults to "Anonymous Climber"; you can change it)
- Grade scale preferences per climbing discipline (e.g., V-scale for bouldering, French sport for lead)
- Preferred measurement units (metric or imperial)
- Experience level (beginner / intermediate / advanced / expert)
- Primary climbing style preference
- Self-reported baseline climbing grades for bouldering and for routes. CragMate asks for these once, on first launch - you can skip the question - and you can set or change them later in Settings under "Climbing Baselines". They are used only on your device, to give the app a starting point for scoring your effort before you have logged enough climbs for it to work that out from your own history.
- Timestamps for record creation and last update
Fields that exist in the data model but are NOT collected or used in the current anonymous-only version: email address (stored as empty string), first name, last name, profile image URL, authentication provider, and a profile-visibility flag (stored, defaults to private; the app ships no reachable screen that changes it, and nothing reads it).
Climbing sessions
Each recorded session stores:
- Session start and end timestamps
- Location label (a text string you enter - not GPS coordinates)
- Session type (indoor bouldering, outdoor sport, trad, etc.)
- Optional goal and notes text (free-form, entered by you)
- Active calories burned (sourced from Apple Health if permission granted, otherwise 0)
- Average and peak heart rate (sourced from Apple Watch if connected)
- Heart rate timeline - a time-series of (timestamp, bpm) pairs for the session, stored as JSON in an external data file on your device
- Resting heart rate, heart rate variability (HRV) for the day, a 7-day average HRV, step count, and floors climbed - the session record has fields for these five, but this version never fills them in. CragMate reads the values from Apple Health (if granted) each time you open a session's details and holds them in memory for that screen only. See Apple Health (HealthKit).
- Recovery heart rate - not read from Apple Health. CragMate calculates it on your device, as the average of the last minute of that session's heart rate samples.
- Total distance - also not read from Apple Health. CragMate estimates it on your device from the number of attempts you logged and a default route height for the session type, and stores a flag marking the value as an estimate.
- HealthKit Workout UUID (a reference to the corresponding workout saved in Apple Health)
- Source device tag ("iPhone" or "Apple Watch")
- Creation and update timestamps
Individual climb attempts
Each attempt logged within a session stores:
- Optional route name (free-form text you enter)
- Grade (selected from your grade scale)
- Outcome (attempt, send, flash, onsight)
- Relative effort (easy, medium, hard)
- Tags (movement style labels you select, e.g., "crimpy", "overhang")
- Optional notes (free-form text)
- Start and end timestamps for the attempt
- Sort order within the session
Recovery analysis
For sessions with enough heart rate data, CragMate computes a recovery analysis on your device and stores the result alongside the session. It is derived entirely from data already listed above - that session's heart rate samples and its attempt timestamps - and no new measurement is read to produce it. The stored record holds the session it belongs to, when it was computed, a format version, and the derived numbers: per-attempt recovery times, average and fastest recovery time, how often you were recovered before your next attempt, the session's peak heart rate and aerobic load, fatigue and rest-ratio figures, send rates, and a session quality score with its breakdown. It stays on your device with everything else.
App preferences stored in UserDefaults / shared container
- Grade scale selections (persisted as strings)
- Feature flags. Their defaults are compiled into the app; each can be overridden by a
matching key in UserDefaults, but the app ships no screen that writes one.
analyticsOptInis one of these - see 3. TelemetryDeck analytics.
Founding-member record
If your first launch falls within the founding period, CragMate stores one further record: the date your founding membership was granted, and a version number for that record's own format. It is kept separately from everything above, and it is the one thing CragMate mirrors to your private iCloud database - see 4. Your private iCloud database.
What leaves your device
1. Apple Watch sync (WatchConnectivity)
If you have an Apple Watch with the CragMate watch app installed, the following data travels between your iPhone and Apple Watch using Apple's WatchConnectivity framework. This is a direct device-to-device channel - it does not pass through Apple's servers and it does not go to CragMate's servers (CragMate has no servers).
Data synced between iPhone and Apple Watch:
- Full session records (all fields listed in "Climbing sessions" above)
- Full attempt records (all fields listed in "Individual climb attempts" above)
- Grade scale preferences - which grading system you use for each climbing type, plus any custom scales you have defined - and your local user ID. Your display name, measurement units and the rest of the profile record stay on the iPhone.
- Sync control messages (acknowledgments, conflict signals)
For large payloads (typically sessions with dense heart rate timelines), the data is written to a temporary file in the app's own private temporary directory and transferred via WatchConnectivity's file transfer channel. The temporary file is read and then deleted on the receiving device; the sending device's copy is a short-lived temporary file that the system reclaims.
2. Apple Health (HealthKit)
CragMate requests HealthKit permission to read and write the following data types. Permission is optional; the app works without HealthKit, but heart rate metrics and calorie data will not be available.
Apple Health data CragMate requests permission to read:
| Category | Types |
|---|---|
| Characteristics | Date of birth, biological sex |
| Body measurements | Height, body mass |
| Heart & cardio | Heart rate (during workout), resting heart rate, heart rate variability (HRV/SDNN) |
| Activity | Active energy burned, step count, flights climbed |
| Workouts | Workout records |
That is the complete list - eleven types. CragMate asks for nothing it does not read.
An earlier version of the app requested seven further types - body mass index, walking heart rate average, VO₂ max, blood oxygen saturation, resting (basal) energy burned, walking + running distance and Apple Exercise Time - for features that were planned and never built. No value from them was ever read, stored, or sent anywhere. They have been removed from the permission request, so they no longer appear on the Apple Health permission sheet.
Each of the eleven is read by a feature, as described below.
Data CragMate writes to Apple Health:
| Type | What is written |
|---|---|
| Workout record | A climbing workout entry (start time, end time, activity type) |
| Active energy burned | Calories burned during the climbing session |
| Heart rate | Heart rate samples collected during the session |
This data is written to Apple Health on your device, where it lives in Apple's HealthKit store under your control. You can review and delete it at any time in the Health app.
CragMate never queries Apple Health for the workouts it has already saved there, with one exception: when you delete a session in CragMate, the app looks that session's workout up by the identifier it stored, so it can remove it - see Deletion. The session figures the app shows you - duration, calories, average and peak heart rate, the heart rate timeline - are held in its own local session record, listed under Climbing sessions, not fetched back out of Apple Health.
CragMate reads Health data only while you are using the app. Each time you open a session's details, CragMate queries Apple Health for your resting heart rate, your heart rate variability (today and a 7-day average), your step count and flights climbed over that session's time range, and your profile characteristics. Those values are shown on that screen and are held in memory only while it is open; this version does not write them back into the stored session record, so they are read from Apple Health again each time you open the session. If you export a session while its details are open, the exported file carries the values that were on screen. During a live workout, the app also reads back the heart rate and active energy the workout is accumulating, so it can show you current figures. Opening the Profile screen also makes a small read - your resting heart rate, or your recent step count if that is unavailable - purely to show whether CragMate is connected to Apple Health.
How CragMate uses the profile data it reads. Your date of birth is used to derive your age, and your age is used to calculate an estimated maximum heart rate (220 minus your age). That estimate is what lets the Session Details screen show your heart rate zones. Your height, body mass, and biological sex are read as part of the same profile lookup, but no feature in this version displays or acts on them. None of this profile data is stored in CragMate's own database - the app holds it in memory only while the screen that needs it is open.
3. TelemetryDeck analytics
CragMate uses TelemetryDeck (TelemetryDeck GmbH, Germany - see Third parties) to collect pseudonymous signals - no name, email or account is attached to any of them. They serve three purposes: understanding how the app is used, learning that one of the app's own subsystems failed on a real device, and receiving the crash and hang summaries described under 5. Crash and hang diagnostics. We call these signals pseudonymous rather than anonymous because a stable, hashed identifier is attached to each one; that identifier and its consequences are described below.
What TelemetryDeck receives. CragMate sends fourteen events, and fourteen only. The events are a fixed set compiled into the app, with no free-form or developer-defined event path, so CragMate cannot send an event outside this table. (The SDK itself originates one further signal - see below.)
Eight of the fourteen describe something that happened in the app. Five more, marked
(failure report) below, are sent only when one of the app's own subsystems failed; one
of those, diagnostic_reported, covers crashes and freezes and is described in full under
5. Crash and hang diagnostics. The
remaining one, healthkit_authorization, reports the outcome of the Apple Health
permission prompt - whether you granted it or declined.
| Event | Parameters sent |
|---|---|
app_launched |
platform - the fixed string "iOS". Sent once per app launch. |
user_created |
(none) - sent once, when the app first creates your local profile record |
workout_session_recorded |
duration_seconds (whole seconds - the app's own wall-clock timer for the session, minus the time you had it paused; it is not read back from Apple Health), attempt_count (a whole number), session_type (one of boulder_indoor, boulder_outdoor, sport_indoor, sport_outdoor, trad_outdoor) |
workout_session_details_opened |
session_id - the local UUID of the session you opened |
entitlement_resolved |
reason - one of founding, earlyAccess, subscription, none, developerOverride |
entitlement_transition |
from and to - two values from the same reason list above |
pro_feature_accessed |
feature - one of advancedAnalytics, unlimitedHistory, advancedHealthAnalytics, customGradeScales, dataExport; and reason, from the list above. Sent at most once per feature per app launch, and only when access was granted. advancedHealthAnalytics is the name of a feature - no health measurement is attached to it. |
monetization_mode_changed |
from and to - each either foundingMember or live |
cloudkit_sync_failed (failure report) |
phase (setup, import, export or unknown), plus error_domain, error_code, underlying_domain and underlying_code - Apple error-domain names and numeric codes only. The error's human-readable text is never included. Sent at most once per distinct failure signature per app launch. |
sync_operation_stuck (failure report) |
operation_type (create, update or delete), status (inProgress or awaitingAck) and reclaim_count (a whole number, never above 5). Sent when an item queued for transfer to your watch has not completed in time. It identifies the kind of item, never which session or climb it was. |
sync_transport_failed (failure report) |
tier (direct, compressed, file or realtime - which of the four ways of reaching your watch was attempted), plus error_domain and error_code. Error-domain names and numeric codes only; the error's human-readable text is never included. |
healthkit_authorization (permission outcome) |
status - one of unavailable, requestFailed, undetermined, shareDenied, shareGranted - and category_count, a number from 0 to 3. This records the outcome of the permission prompt and how many of the three things CragMate can write to Apple Health you have allowed it to write. It never carries a health measurement, and it says nothing about what CragMate is allowed to read: Apple does not let apps see whether a read request was granted. |
session_persist_failed (failure report) |
phase - one of create, endWorkout, update, delete, receiveCreate, receiveUpdate, receiveDelete, syncEnqueue, draftSave - plus error_domain and error_code. Sent when one of the app's session-writing steps fails: saving to your device's own database, queuing a change for your watch, or writing the crash-recovery draft. It tells us a save was lost. The session's contents are never included; only which step failed. |
diagnostic_reported (failure report) |
kind (crash or hang), exception_type and signal (each a number, or none), frame_origin (app, system or unknown) and duration_bucket (none, under250ms, under1s, under5s, under20s or over20s). Five values, all from fixed lists. See 5. Crash and hang diagnostics for what this is, what it deliberately leaves out, and why iOS's analytics settings do not stop it. |
Four things this table does not cover, stated here rather than left implied:
- The six failure and outcome reports are de-duplicated, so their counts are not failure counts. Each is sent at most once per distinct combination of the values above, per app launch, and no more than 16 distinct combinations per launch for each subsystem that reports (24 for stuck sync items; saving failures are reported by four separate subsystems, each with its own limit of 16). What we can see is roughly "this failure happened to this device during this launch" - never how many times it happened. Every occurrence is still written to your device's own system log, which stays on the device.
diagnostic_reporteddoes not originate from anything you did in the app. It comes from Apple's MetricKit and exists only on iPhone. It is also the one people most often assume iOS's analytics settings switch off - they do not; see 5. Crash and hang diagnostics.- The Apple Watch app sends nothing. It is built without a TelemetryDeck application
identifier, so every event it raises is discarded on the watch. The
platformparameter above therefore only ever arrives as"iOS". Eleven of the events above are compiled into the watch app, and about half of them do fire there, into that discard; three - the session-details event,cloudkit_sync_failedanddiagnostic_reported- do not exist on the watch at all. (MetricKit is not part of watchOS, so crash and hang reporting cannot happen there even in principle, and the iCloud mirroring described below is iPhone-only.) - The TelemetryDeck SDK originates one signal we did not write:
TelemetryDeck.Acquisition.newInstallDetected, sent once, on a device's first session.
Alongside the parameters above, the TelemetryDeck SDK attaches its own payload to every signal: your app version and build number, OS version, device model, CPU architecture, screen size and scale, orientation, colour scheme, layout direction, locale, language, region, time zone, calendar fields for the moment the signal was sent, whether the build came from the App Store, TestFlight or a simulator, the SDK's own name and version, a set of aggregate usage counters (first-use date, number of sessions, distinct days used, average session length), and your iOS accessibility accommodation settings such as Reduce Motion, Bold Text and your preferred text size - among other SDK-level fields. TelemetryDeck's own privacy policy (https://telemetrydeck.com/privacy/) documents the full list.
It also attaches a random session identifier - regenerated on each cold launch and
whenever the app returns from the background after five minutes - and a stable
pseudonymous user identifier: a SHA-256 hash. Once per launch, CragMate hands the SDK
the random UUID it generated for you locally, and the hash is computed from that. For
signals sent very early in a launch - before that UUID has been loaded - the hash is
computed from Apple's per-vendor device identifier (identifierForVendor) instead. The
hashing happens on your device before transmission, and neither underlying identifier is
ever sent in the clear. The hash is stable - it does not rotate. Because the identifier it
is derived from is stored in the iOS Keychain, which survives app deletion, the same hash
can return if you delete CragMate and install it again on the same device.
A note on session_id: the session_id sent in workout_session_details_opened
is a UUID generated locally on your device when the session is created. It is not
linked to your name, email, or any external account. However, it is a stable identifier
that, in combination with other signals, could theoretically be used to track usage
patterns over time. The same applies, more broadly, to the stable user identifier
described above: because it does not rotate, signals from one installation can be linked
to each other over time. Neither identifier is linked to your name, email, or any account.
Analytics are on by default, and the app has no in-app off switch.
Analytics are enabled by a setting compiled into the app. The app reads that setting once, at launch, when it decides whether to build a live TelemetryDeck client or a stand-in that discards every event on your device. There is no consent prompt, no privacy settings screen, and no analytics toggle anywhere in the app. Nothing you can tap inside CragMate switches analytics off.
Two controls people reasonably assume apply here do not:
- iOS's analytics sharing settings - Share iPhone Analytics (shown as Share iPhone & Watch Analytics if you have a paired Apple Watch) and, beneath it, Share With App Developers, both at Settings → Privacy & Security → Analytics & Improvements - govern what Apple shares with developers. They do not gate an analytics library embedded inside a third-party app, so they do not stop CragMate's signals. This includes the crash and hang reports, which people most often assume are covered: they reach us through Apple's MetricKit, which delivers to the app regardless of those settings. See 5. Crash and hang diagnostics, which explains the distinction and what those settings do affect.
- CragMate shows no App Tracking Transparency prompt, because it does no cross-app tracking and uses no advertising identifier. There is no permission for you to decline.
In practice, the only ways to stop CragMate sending analytics are to not install it, or to delete it. This describes the app as it is built today; it is not a commitment about a future opt-out. If you want to object to this processing, contact us at privacy@cragmate.com - see Your rights.
What TelemetryDeck explicitly does NOT receive:
- Your display name, route names, or any free-text notes
- Your HealthKit data (heart rate, weight, age, etc.). No health measurement of any kind
is ever sent. The one HealthKit-related thing that is sent is the outcome of the
permission prompt and a count of how many of the three writable types you allowed -
the
healthkit_authorizationevent above. Never a value, never a date, never which type. - Your climbing grades or individual attempt outcomes
- Any location data CragMate collects - the app never uses location services, and the location label on a session is text you typed, not GPS coordinates. (The SDK does attach your device's locale, region and time zone, and TelemetryDeck's server sees your IP address as noted above.)
- Any advertising identifier - CragMate uses none, and shares no identifier with any advertising network or data broker
- Any error message text. Six of the fourteen events above report a failure or a permission outcome. Three of them carry an error's domain name and numeric code; the crash report carries numeric exception and signal identifiers; the other two carry no error fields at all. The descriptive text of an error is never sent; it stays in your device's local system log
4. Your private iCloud database (founding-member record)
This is the single exception to everything else staying on your device, and it is small enough to describe completely.
The first time you open CragMate, if that is before the founding period closes, the app
writes one record intended for your own private iCloud database, in the CloudKit container
iCloud.com.climbr.founding. The record has two fields: the date your founding membership
was granted, and a version number for the record's own format. That is the entire record.
It contains no name, no email, no identifier of you or of your device, no notes, no
session or climb data, and nothing from Apple Health. It is not linked to your local user
ID. It is written once and never updated.
It exists so your founding-member access can outlive any one installation. Because the record sits in your Apple Account rather than only on the device, CragMate can find it again if you delete and reinstall the app, or set up a new iPhone under the same Apple Account, and recognise that you joined early.
The upload is best-effort. If it does not succeed, the record simply stays on your iPhone
and the app behaves exactly the same; the failure is what the cloudkit_sync_failed
analytics event above reports. If your device is not signed in to iCloud, nothing is
uploaded at all.
The record goes into the private database of that container, which belongs to your Apple Account. Apple only permits the owner of an account to read its private database. CragMate has no server and no means to query, browse, or export it, and we never see its contents.
Nothing else is ever mirrored to iCloud. Every other kind of data CragMate stores lives on the local, non-synced store described under What does NOT leave your device.
5. Crash and hang diagnostics (Apple MetricKit)
If CragMate crashes, or freezes long enough for iOS to notice, we may receive a short summary of what happened. It is described in full here because it is the newest and the least obvious thing the app sends, and because the control people assume covers it does not.
Where it comes from. CragMate does not use a crash-reporting service. It subscribes to
MetricKit, a framework built into iOS by Apple. Apple's operating system observes the
crash or freeze, prepares a report, and hands it to the app. A crash report necessarily
arrives on a later launch - an app cannot report its own crash while it is crashing; a
freeze report can arrive while the app is still running. CragMate then reduces that report
to five values and sends them as the diagnostic_reported event described above.
What we receive - the complete list. Five values, each drawn from a fixed set:
| Value | What it can be |
|---|---|
kind |
crash or hang. Nothing else. |
exception_type |
For a crash, the number iOS assigns to the category of failure (for example 1, meaning an invalid memory access), or none if iOS did not classify it. For a hang, always none. |
signal |
For a crash, the number of the POSIX signal that ended the process (for example 11), or none if iOS did not report one. For a hang, always none. |
frame_origin |
app, system, or unknown - whether the deepest frame CragMate could follow in the reported call stack was inside CragMate's own code or somewhere else. It answers "is this our bug", nothing more. system is not a claim that Apple's code is at fault. |
duration_bucket |
For a hang, which band its length fell into: under250ms, under1s, under5s, under20s or over20s - or none if iOS did not report a usable length. For a crash, always none. The length is deliberately reduced to a band rather than sent as a precise number. |
Those five values are everything CragMate adds. As with every other signal, the TelemetryDeck SDK attaches its own standard payload - device model, OS version, screen metrics, locale, time zone, accessibility settings, usage counters and the stable identifier described above. That is unchanged for crash reports; nothing extra is attached because the signal is a crash.
What is deliberately not sent. Apple's report contains a great deal more, and CragMate transmits none of it:
- The stack trace - every frame, every memory address, every function name, and the identifiers of the binaries involved.
- The offset into CragMate's own code, which together with a build's symbol table would point at an exact line of source.
- The exception code, which is frequently the memory address that caused the fault.
- The termination reason, the virtual-memory region dump, and the name and message of any Objective-C exception. This last one matters most: that message is prose assembled at the moment of failure and can quote whatever the app was handling - including a route name or a note you typed. It is never transmitted.
- App version, build number and OS version from the report itself. (TelemetryDeck's SDK attaches its own copy of those to every signal, as described above.)
The app also ignores the other kinds of report MetricKit offers - CPU exceptions, disk write exceptions, launch-time diagnostics - and never requests Apple's daily performance metrics or the backlog of past reports. It reads crashes and hangs, and nothing else.
There is no way to switch this off, and it is worth being precise about why. It would be reasonable to assume that iOS's Settings → Privacy & Security → Analytics & Improvements switches cover this. They do not, and we would rather say so than let you believe in a control that does nothing.
Share With App Developers governs what Apple shares with developers - Apple's own
crash reporting, described in the next paragraph. MetricKit is a different mechanism: iOS
hands the report directly to code running inside the app, and Apple's own engineers have
stated that MetricKit does not consult that setting when deciding to deliver a payload, and
have demonstrated diagnostics still arriving with both Share With App Developers and
Share iPhone Analytics turned off. Turning those switches off therefore does not stop
diagnostic_reported. Like the other thirteen events, it has no opt-out in this version of
CragMate. If you want to object to this processing, contact us at privacy@cragmate.com -
see Your rights.
A separate Apple channel exists, and this section does not cover it. Independently of MetricKit, Apple's own crash reporting can make a full crash report - including the stack trace - available to us through App Store Connect and Xcode. That is Apple's collection, governed by Apple's privacy policy, and the Share With App Developers switch does apply to it. One exception matters if you are a beta tester: Apple states that TestFlight testers automatically share crash reports with the developer regardless of their device's diagnostics-sharing settings. That exception is limited to TestFlight builds - if you installed CragMate from the App Store, the Share With App Developers switch governs. Everything else in this section describes only what CragMate's own code receives and transmits.
iPhone only. MetricKit is not part of watchOS, so the Apple Watch app performs no crash or hang reporting and sends us nothing of the kind.
A note on the local record. Alongside the five values it sends, CragMate writes a fuller record to your device's own system log, so a crash can be investigated on a device we have in front of us. That record adds the exception code, the termination reason, a memory-region description, the name and message of any Objective-C exception, and the name and offset of the single deepest code module in the failure. It is not Apple's complete crash report: the call stack itself, individual memory addresses and binary UUIDs are discarded and never recorded. Of what is recorded, the Objective-C exception message is the part worth knowing about - it is assembled at the moment of failure and can quote whatever the app was handling, including something you typed. That log stays on your iPhone under iOS's control, is not readable by us remotely, and is not uploaded anywhere by CragMate. It is retained and rotated by iOS, not by us. It can leave your device only if you choose to share it - for example by generating a sysdiagnose at Apple's request, or by sending us a log file yourself.
What the numbers mean, and do not mean. Because a crash report does not arrive until a subsequent launch, and because repeated identical reports are de-duplicated, what we see is a partial picture. It tells us that a kind of failure occurred on some devices. It cannot tell us how often you experienced it, and no absence of reports proves an absence of crashes.
What does NOT leave your device
The following data stays on your iPhone and Apple Watch and is never transmitted to CragMate or any third party (other than Apple Health writes, which Apple controls, and except as noted in the list itself). Separately, if the app crashes or freezes, a five-value summary of the failure may be sent - the full detail stays on the device; see 5. Crash and hang diagnostics:
- Your display name and climbing preferences
- Your session notes and route names
- Your individual climb attempts, grades, tags, and outcomes
- Your heart rate timeline (the per-second BPM log stored in the external data file)
- Your HealthKit profile data (date of birth, height, body mass, biological sex)
- Your recovery analysis for each session
- Your local user ID (the UUID that identifies you within the app). A SHA-256 hash of it is attached to analytics signals, as described above. The UUID itself is sent to your own Apple Watch, so the two devices agree on whose sessions are whose; it is never sent to CragMate or to any third party.
CragMate has no backend server. There is no CragMate cloud, no CragMate-operated remote database, and no sync service operated by CragMate.
Everything in the list above is stored on your device only. The database that holds your
profile, your sessions, your climb attempts, your grade scales, your tags, and your
recovery analysis is configured with cloudKitDatabase: .none - iCloud sync is off for
all of it. On Apple Watch, the app has no iCloud capability at all; the watch stores
everything locally.
There is exactly one exception: the founding-member record - a grant date and a version number, written to your own private iCloud database. It is described in full under 4. Your private iCloud database. Nothing else is ever mirrored to iCloud.
Third parties
Apple (HealthKit)
CragMate integrates with Apple HealthKit to read workout metrics and write workout records. Apple operates the HealthKit data store on your device under Apple's own privacy policy (https://www.apple.com/legal/privacy/). CragMate does not control how Apple handles your health data.
Apple (WatchConnectivity)
Session sync between iPhone and Apple Watch uses Apple's WatchConnectivity framework. This is a peer-to-peer channel between your devices. Apple's servers do not relay the payload content - the transmission goes directly between your iPhone and Watch when they are within Bluetooth or Wi-Fi range of each other, or through Apple's relay infrastructure when they are not (in which case the content is encrypted end-to-end).
Apple (iCloud / CloudKit)
The founding-member record is stored in your own private iCloud database, on Apple's servers, under Apple's privacy policy (https://www.apple.com/legal/privacy/). It is the only thing CragMate puts there, it holds a date and a version number, and we cannot read it - see 4. Your private iCloud database.
Apple (App Store)
This is a website entry: it describes links from this site to the App Store, not anything the installed app does.
The short cragmate.com/get and cragmate.com/r/… addresses we print and paste carry two
fixed labels: one identifying our developer account, and one saying which of our own links
you came through. The App Store banner iOS Safari may show on this site carries the same
pair, with a single fixed label meaning "came through the website" rather than any
particular card or post. The App Store buttons and the scan-to-install QR code on this site
itself carry no labels at all. Apple counts installs under those labels and reports totals
to us; we receive no information about any individual visitor or device. Once you reach the
App Store you are on Apple's site, under Apple's privacy policy
(https://www.apple.com/legal/privacy/), including any cookie Apple sets on its own domain.
See Campaign links and the App Store banner.
TelemetryDeck GmbH
TelemetryDeck is a privacy-focused analytics service headquartered in Germany and therefore subject to GDPR. Signals are sent over HTTPS. As with any network request, TelemetryDeck's server receives the IP address inherent in the connection; per TelemetryDeck's policy that IP is used transiently and is not stored in raw form, and raw signals are not retained - only aggregated counts. The user identifier attached to each app signal is a SHA-256 hash computed on your device before the signal is sent; as CragMate configures the SDK, that hash is stable rather than rotating - see "What TelemetryDeck receives" above. CragMate uses TelemetryDeck for three purposes: to understand aggregate usage patterns (how often sessions are recorded, which session types are used, etc.); to learn that one of the app's own subsystems failed on a real device; and to receive the crash and hang summaries described under 5. Crash and hang diagnostics.
TelemetryDeck is also the analytics provider we have chosen for the cragmate.com website, but website analytics are not currently running and no TelemetryDeck code is served with this site - see Website analytics.
TelemetryDeck's privacy policy: https://telemetrydeck.com/privacy/ TelemetryDeck's EU data processing: TelemetryDeck GmbH is established in the EU (Germany) and processes data within the EU.
Cloudflare, Inc. (website hosting)
The cragmate.com website is served by Cloudflare. Delivering the site necessarily exposes your IP address, the page you asked for, the time and your browser's user-agent string to Cloudflare's servers, which process them on our behalf and on our instructions as our processor under GDPR Art. 28. Nothing the app stores or syncs goes to Cloudflare, and the app sends it nothing of its own accord - with one exception: opening this policy from inside the app loads this website in an in-app browser, so that request reaches Cloudflare exactly as a request from your browser does. See Hosting and server logs.
No other third parties
CragMate does not integrate with advertising networks, social platforms, or crash reporting services (such as Firebase Crashlytics or Sentry). TelemetryDeck is the only third-party component in the app that transmits anything anywhere. The app does build on a few other open-source Swift packages, but they are developer tooling that runs entirely on your device - a dependency-injection container and a compile-time code generator - and they have no network access, collect nothing and send nothing.
Apple's own platform crash reporting is a separate matter and is described under 5. Crash and hang diagnostics. It is Apple's collection, carried out by iOS itself, not a third-party service integrated into CragMate.
Your rights
Access
All data CragMate holds about you is stored on your own device, apart from the founding-member record, which is stored in your own private iCloud database. You can view your sessions, attempts, and profile at any time within the app.
Export
You can export your session data from the Session Details screen. CragMate supports export in JSON and CSV formats. The exported file includes the full session record and all individual climb attempts. You control where you send the exported file - CragMate does not receive a copy.
Deletion
You can delete individual sessions from within the app. Deleting a session also deletes all climb attempts associated with it (cascade delete). Deleting the app from your device removes the SwiftData store and the on-device data listed under What we collect.
Two things are not removed by uninstalling:
- The founding-member record in your own private iCloud database - a grant date and a version number. That record outliving the installation is what preserves your founding access. See 4. Your private iCloud database.
- The local user ID - the randomly-generated UUID described above - which iOS keeps in the system Keychain rather than in the app's own storage.
If a climbing session was saved to Apple Health, deleting that session in CragMate also deletes the corresponding workout from Apple Health. CragMate looks the workout up by the identifier it stored, deletes it, and then deletes the local session record. That HealthKit deletion is best-effort: if it fails, or if the workout is no longer there, CragMate records the failure and still deletes the local session. What CragMate deletes is the workout entry itself; it does not separately delete the energy and heart rate samples written alongside it. You can review and delete anything CragMate wrote - the workout and those samples - in the Health app at any time.
GDPR rights (EU/EEA/UK users)
If you are located in the European Union, the European Economic Area, or the United Kingdom, you have the following rights under the General Data Protection Regulation (GDPR) or the UK GDPR:
Right of access (Article 15 GDPR): You have the right to obtain confirmation of whether CragMate processes personal data about you, and if so, access to that data. For the data on your device, you can exercise this right directly in the app at any time. The founding-member record in your private iCloud database consists only of the date your membership was granted and a version number; we cannot read it, and no screen in the app surfaces it, but we can confirm its contents in writing on request. If you want a formal confirmation in writing, contact us at privacy@cragmate.com.
Right to erasure (Article 17 GDPR, "right to be forgotten"): You have the right to request deletion of your personal data. You can exercise this right directly by deleting sessions within the app or uninstalling the app. Uninstalling does not remove the founding-member record from your private iCloud database - that record outliving the installation is what preserves your founding access. CragMate never deletes it, and it holds only a date and a version number. It sits in your own Apple Account, not on any server we operate. To request deletion of the pseudonymous analytics signals sent to TelemetryDeck, contact us at privacy@cragmate.com and we will forward the request to TelemetryDeck. Because TelemetryDeck hashes and aggregates signals, individual-level deletion may not be technically possible once aggregation has occurred.
Right to rectification (Article 16 GDPR): You can edit your profile and session data directly in the app.
Right to data portability (Article 20 GDPR): You can export your data in JSON or CSV format as described above.
Right to object (Article 21 GDPR): The website processing that relies on our legitimate interests - campaign attribution, hosting and server logs, and website analytics if they are ever switched on - is open to objection; contact us at privacy@cragmate.com. The app's analytics are on by default and the app offers no in-app opt-out - see "Analytics are on by default" above; to object to them, contact us at the same address. That route covers the crash and hang reports too: iOS's analytics settings do not stop them, so there is no self-help alternative - see 5. Crash and hang diagnostics.
Right to restrict processing (Article 18 GDPR): You have the right to request restriction of processing. Contact us at privacy@cragmate.com.
Supervisory authority: If you believe your rights have not been respected, you have the right to lodge a complaint with your local data protection authority.
Retention
Your data stays on your device for as long as you keep the app installed, with the exceptions noted below. For the app, CragMate does not operate a retention schedule because we do not hold your data - you do. On the website side we hold nothing ourselves either; what our processors hold on our behalf is listed below.
- Session and attempt data: retained until you delete individual sessions or uninstall the app.
- User profile: retained until you uninstall the app.
- The Apple Health workout written by CragMate: retained in Apple Health until you delete it there, or until you delete the corresponding session in CragMate - see Deletion. CragMate does not separately delete the energy and heart rate samples written alongside that workout; you can delete those in the Health app.
- Founding-member record in your private iCloud database: CragMate writes it once and never updates or deletes it. It lives in your own Apple Account, not on any server we operate.
- TelemetryDeck analytics (the app's; the website's if they are ever switched on): TelemetryDeck's documented retention period applies; refer to TelemetryDeck's privacy policy (https://telemetrydeck.com/privacy/) for details. This covers the crash and hang summaries too - they are ordinary TelemetryDeck signals, and we hold no separate copy.
- The crash and hang detail written to your device's system log: retained on your device by iOS, under iOS's own log rotation. CragMate does not set a period for it, does not read it remotely, and does not upload it - see 5. Crash and hang diagnostics.
- Cloudflare hosting and server logs (the website, including when the app opens it in an in-app browser): Cloudflare's own operational logs are retained under Cloudflare's terms, as our processor. We keep no separate copy and set no period of our own - see Hosting and server logs.
Changes to this policy
If we update this privacy policy, we will update the "Effective" date at the top of this document; the current version is always the one published at cragmate.com/privacy. Because the website has no accounts and collects no contact details, we cannot notify website visitors individually - please check this page for the latest version. The app opens this same page when you tap Privacy Policy, so what you see in the app is always the current version.
Contact
For privacy inquiries, data access requests, or erasure requests:
Email: privacy@cragmate.com
Alexander answers personally. For general questions, you can also reach us at hello@cragmate.com.
Who we are (Data Controller)
Under GDPR Article 13/14, the "data controller" is the party responsible for deciding how your data is processed. For CragMate, the controller is:
- Name: Alexander Batalov
- Legal status: Natural person (individual developer)
- Country of establishment: Luxembourg
- Governing law: Luxembourg - the General Data Protection Regulation (GDPR) as supplemented by the Luxembourg Law of 1 August 2018 on the organisation of the National Commission for Data Protection and the implementation of the GDPR.
- Contact: privacy@cragmate.com
- Supervisory authority: Commission nationale pour la protection des données (CNPD), Luxembourg - https://cnpd.public.lu/. If you believe your rights have not been respected, you may lodge a complaint with the CNPD or with the data protection authority of your own EU/EEA country of residence.
CragMate is developed by Alexander Batalov. This policy covers the cragmate.com website and the CragMate iOS and watchOS apps.