Getting started

Purposes

A purpose is the reason your app gives, in one sentence, every time it reads a user's exact location. It is the main thing a user weighs when deciding whether to trust you with that access.

Why they matter

A scope says what your app can see. It cannot say why. location.lookup is the same scope whether you use it to put photos on a trip map or to check where someone was at 2 a.m. — and users know that.

So every call that returns coordinates names a purpose you registered and we reviewed, and the user reads that purpose's description, word for word:

  • on the consent screen, next to the scope it justifies, before they agree;
  • in their access log at contextkit.com/you, beside every request, where they can filter by purpose and report any entry that does not look right;
  • when they renew, with a count of what you used the access for over the last 90 days, by purpose.

That last one is the moment purposes pay off. The sensitive tier ends after at most 90 days (see Two expiries), and the user decides whether to renew by looking at what you actually did. "Put each photo you upload on the map at the place you took it — 212 times" is an easy yes. A vague description, or a count that does not fit it, is how you lose the access — and the user.

Write purposes for the person reading them, not for review.

What a purpose is

FieldRules
Key^[a-z][a-z0-9_]{2,39}$, unique within the app. What your code sends; never shown to users.
Description10–200 characters. Shown to users exactly as approved.
ScopesThe sensitive scopes this purpose may be used with.
Expected daily volume1–10,000. The most calls one connection should need for this purpose in a day.
StatusDraft, in review, approved or rejected, with the reviewer's note.

Purposes apply to the sensitive tier: location.latest.read, location.history.read and location.lookup. Standard-tier questions already say what they ask, in the access log, so they need none.

Registering one

In the developer portal, open your app and go to Purposes.

  1. Create a purpose: key, description, the scopes it covers and the expected daily volume. It starts as a draft.
  2. Use it in sandbox straight away. Sandbox apps may call with a draft purpose, so you can build before review.
  3. Submit it. It moves to in review, and we approve it or reject it with a note saying what to change.
  4. Production apps may only use approved purposes.

Editing an approved purpose sends it back to review. The approved version keeps working, with the approved wording, until we decide on the edit — so fixing a typo never takes your feature down.

A purpose you no longer use can be archived. Archive rather than repurpose: a key that meant one thing in a user's access log should not quietly mean another.

The same actions are available over the portal API: GET and POST /v1/developer/apps/:app_id/purposes, PATCH and DELETE /v1/developer/apps/:app_id/purposes/:purpose_id, and POST /v1/developer/apps/:app_id/purposes/:purpose_id/submit.

Using one

Send the key as the purpose query parameter on every sensitive call:

GET /v1/locations/lookup?at=2026-09-12T14:05:00Z&tolerance_s=300&purpose=photo_places
Authorization: Bearer cka_…

purpose is required on /v1/locations/latest, /lookup, /timerange and /days. A missing or unknown key, a draft key on a production app, or a key that does not cover the endpoint's scope answers 400 invalid_purpose — see Errors.

With the SDK it is a required field:

await ckUser.locations.at({ at: photo.takenAt, toleranceS: 300, purpose: "photo_places" });

One call, one purpose. If a single request serves two features, name the one that needed coordinates; if both did, register a purpose that honestly describes both.

Writing a good description

Say what the user gets, in their words, specifically enough that they could spot a request that does not fit.

GoodWhy it works
Put each photo you upload on the map at the place you took itNames the trigger (an upload) and the result (a map)
Show your friends where you are while you share your live locationNames who sees it and that it lasts only while sharing
Draw the route of a trip you asked us to recordBounded by something the user started
BadWhy it fails
Improve your experienceSays nothing; could justify anything
Location featuresNames the data, not the reason
Analytics and personalisationNot something the user gets; exporting coordinates to analytics also breaks the AUP
So the app works correctlyEvery app says this
Needed for photo_placesA key is not a reason

Some rules review applies:

  • One reason per purpose. Two features, two purposes. That is what lets the user's access log and your renewal summary say something useful.
  • Describe the use, not the mechanism. "Match photos to the places you were", not "reverse-geocode EXIF timestamps".
  • Match the scope. A purpose covering location.history.read should explain why a range of fixes is needed, not just one.
  • No promises you cannot keep. If the purpose says "only while sharing", your code has to stop when sharing stops.

Expected volume

The expected daily volume is how many calls one connection should make for this purpose on a busy day — not your app's total, and not an average.

Pick it from the feature. A photo app matching a day's uploads might need 300; a live-sharing session polling once a minute for an hour needs 60. Leave headroom for real busy days, not for bugs.

Every hour we count each connection's calls per purpose over the last day. A connection that goes past twice the expected volume is flagged for review with the purpose named. Calls are not refused and nothing is suspended automatically; a person looks at it. A volume that keeps being right at the edge is worth raising yourself, in the portal, by editing the purpose.

What purposes are, and are not

Purposes are declared and monitored, not cryptographically proven. We cannot see inside your servers, so we cannot prove that a call named photo_places was for a photo. What we can do, and do:

  • review every purpose before it reaches a production user;
  • show it to the user at every point they make a decision about you;
  • watch each purpose's volume against what you declared;
  • act on reports from users who read their access log and see something that does not match.

Misrepresenting a purpose, or using the coordinates a purpose returned for anything else, breaks section 5 of the Acceptable Use Policy and is grounds for suspending the app. Treat the description as a promise with your name on it, because to the user that is exactly what it is.

Previous
Scopes