Skip to content
AF
Integration Guides

How to Integrate the Strava API (2026)

Last verified October 17, 2026 · 10 min read

Sources checked (8) · October 17, 2026
The Strava API gives your app an athlete's activities, routes, gear and profile through OAuth 2.0: you send the athlete to Strava's consent screen, exchange the returned code for a six-hour access token and a refresh token that can change on every refresh, and call the v3 REST API with a Bearer token. Access is gated before any code runs: Strava says a subscription is a prerequisite for creating an app, every new app starts in single-player mode where only your own account can connect, a self-service upgrade raises that to 10 athletes, and more than 10 requires Strava's review. Use the single webhook subscription each app is allowed instead of polling, and read the overall and non-upload rate-limit headers on every response.

Covered here:StravaGarmin

Strava is the natural integration for a social running or cycling app, where athletes already record activities and expect them to sync. If you are building that kind of product, this pairs well with the wider wearable data APIs layer and the app-shape decisions in how to build a running app. Strava's access requirements, and every page on this site that covers it, are collected in the Strava API overview.

Checked against Strava's own pages on October 17, 2026. Every limit, scope and date below comes from developers.strava.com or Strava's legal pages as fetched that day. Strava changed its access model, rate limits and terms in 2026, so treat older tutorials (and older versions of this page) as out of date.

Access and approval: single-player mode first#

Strava's getting-started guide says a Strava subscription is a prerequisite for creating an app, and that "All new applications start in single-player mode", the default state in which only your own Strava account can authenticate with the app. That is enough to build and test against your own data, not to serve anyone else.

From there access grows in two steps:

StageWho can connectRate limits Strava documentsHow you get there
Single-player modeOnly you (athlete capacity 1)Overall 200 requests / 15 min and 2,000 / day; non-upload 100 / 15 min and 1,000 / dayCreate an app at https://www.strava.com/settings/api
Self-service upgradeUp to 10 athletesOverall 400 / 15 min and 4,000 / day; read 200 / 15 min and 2,000 / dayUpgrade from the API Settings Dashboard once the app is configured
Reviewed appMore than 10 athletesRaised case by caseSubmit the Developer Program form for review

The review form asks for screenshots of every place Strava data appears and of the "Connect with Strava" button, and Strava says plainly that increased access is not a guarantee. Its API Policy, effective June 1, 2026, adds that admission to the Developer Program is at Strava's discretion with no fixed review-time commitment.

The same policy sorts apps into access tiers. The Standard Tier covers apps limited to 10 registered users and apps limited to 9,999, and is subject to subscription requirements, "including a requirement that the developer or specified end users maintain an active Strava subscription". The Extended Access Tier, generally for apps serving 10,000 users or more, is admitted case by case and is not subject to those subscription requirements unless Strava publishes otherwise. What the subscription costs is covered on Strava API pricing.

What you'll need#

  • A Strava account with a subscription, and an app registered at https://www.strava.com/settings/api, which gives you a Client ID and Client Secret.
  • An Authorization Callback Domain on the app. Strava requires your redirect_uri to be within that domain, and white-lists localhost and 127.0.0.1 for development.
  • A backend to hold the Client Secret and each athlete's refresh token. The token exchange, refresh, revoke and webhook-subscription calls all need the secret, so it never belongs in a mobile or browser client.
  • For webhooks: a public HTTPS callback that can answer Strava's validation request within two seconds.

Auth and scopes#

Strava uses OAuth 2.0 authorization code. Web apps send the athlete to GET https://www.strava.com/oauth/authorize; Android and iOS apps use https://www.strava.com/oauth/mobile/authorize, which opens the Strava app when it is installed (version 75.0 or later) and falls back to mobile web otherwise.

Request only the scopes you need. Strava documents seven:

ScopeWhat it grants, per Strava
readPublic segments, public routes, public profile data, public posts, public events, club feeds and leaderboards
read_allPrivate routes, private segments and private events
profile:read_allAll profile information, even if visibility is Followers or Only You
profile:writeUpdate weight and FTP, star or unstar segments
activity:readActivities visible to Everyone and Followers, excluding privacy zone data
activity:read_allThe same as activity:read, plus privacy zone data and Only You activities
activity:writeCreate manual activities and uploads, and edit activities visible to the app

Scopes go in the scope parameter "as a comma- or URL-safe space-delimited string", and activity:read is required for activity webhooks. The athlete can untick any scope on the consent screen, so read what comes back:

https://www.strava.com/oauth/authorize
  ?client_id=CLIENT_ID
  &redirect_uri=https://yourapp.example.com/exchange_token
  &response_type=code
  &approval_prompt=auto
  &scope=read,activity:read_all

approval_prompt is auto by default; force always shows the prompt. A denial comes back as error=access_denied; an approval as code plus the accepted scope. The code is short-lived and single-use, so exchange it straight away from your server:

curl -X POST "https://www.strava.com/oauth/token" \
  -d "client_id=CLIENT_ID" \
  -d "client_secret=CLIENT_SECRET" \
  -d "code=AUTH_CODE" \
  -d "grant_type=authorization_code"

The response carries access_token, refresh_token, expires_at, expires_in and an athlete summary. Since April 23, 2026 it also returns a scope field: a space-delimited list of what was granted, which can be narrower than what you asked for.

Refresh, and why the refresh token changes#

Strava's access tokens expire six hours after they are created. Refresh with grant_type=refresh_token against the same token endpoint:

curl -X POST "https://www.strava.com/oauth/token" \
  -d "client_id=CLIENT_ID" \
  -d "client_secret=CLIENT_SECRET" \
  -d "grant_type=refresh_token" \
  -d "refresh_token=REFRESH_TOKEN"

If the athlete's current access token still has more than an hour to live, Strava returns that same token; within the last hour, it issues a new one. Every successful call can return a different refresh token, and Strava says that once a new refresh token is returned, the older one is invalidated immediately. Persist the newest refresh token per athlete, and serialize refreshes so a background job and a user action cannot race and strand the athlete.

Data: the activities endpoint#

The v3 REST API covers athletes, activities, routes and gear. To list the authenticated athlete's activities:

curl -X GET "https://www.strava.com/api/v3/athlete/activities?per_page=30&page=1" \
  -H "Authorization: Bearer ACCESS_TOKEN"

Strava's Swagger spec documents before and after (epoch timestamps) to window the results, and its docs say lists are paginated to 30 items by default with per_page up to 200. A page can hold fewer items than requested even when it is not the last, so iterate until an empty page comes back. The endpoint requires activity:read, and Only You activities are filtered out unless the token carries activity:read_all. Strava publishes the full spec at https://developers.strava.com/swagger/swagger.json, which you can feed to Swagger Codegen 2.x to generate a client.

Webhooks: one subscription, pointer events#

Strava encourages every app to use its webhook events API, and its getting-started guide says that, per the API terms, you need webhooks to know when an athlete has deauthorized your app. Each application may have only one subscription, which receives events for every athlete who authorized it. Create it with your client credentials:

curl -X POST "https://www.strava.com/api/v3/push_subscriptions" \
  -F client_id=CLIENT_ID \
  -F client_secret=CLIENT_SECRET \
  -F callback_url=https://yourapp.example.com/webhook \
  -F verify_token=YOUR_VERIFY_TOKEN

Strava then sends a GET to the callback with hub.mode=subscribe, hub.verify_token and hub.challenge. Within two seconds, respond with HTTP 200 and the challenge echoed back as JSON:

{"hub.challenge":"15f7d1a91c1f40f8a748fd134752feb3"}

Once live, Strava POSTs an event when an activity is created or deleted, when its title, type or privacy changes (privacy needs activity:read_all), and when an athlete revokes access, which arrives with "authorized": "false" in updates. The event is a pointer: object_type, object_id, aspect_type, owner_id, subscription_id, event_time and updates. Fetch the activity yourself with that athlete's token. Acknowledge every POST with 200 within two seconds; Strava retries a failed push up to three attempts in total, so process asynchronously and expect duplicates, because one save can produce several events.

Apps with activity:read but not activity:read_all get a delete event when an activity becomes Only You, and a create event when it becomes visible again. Treat those as the privacy changes they are, not as data loss.

Deauthorization: move to the revoke endpoint#

The original endpoint, POST https://www.strava.com/oauth/deauthorize, invalidates all of the athlete's tokens for your app. Strava's authentication docs say that from June 1, 2026 apps can use POST https://www.strava.com/oauth/revoke instead, that it is the recommended method, and that it "will be the only endpoint supported for deauthorization effective June 1, 2027". It authenticates with HTTP Basic using your client ID and secret, takes the token to revoke (with an optional token_type_hint), and returns 200 whether or not the token was found:

curl -X POST "https://www.strava.com/oauth/revoke" \
  -H "Authorization: Basic BASE64_CLIENT_ID_COLON_SECRET" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "token=ACCESS_OR_REFRESH_TOKEN"

Rate limits and headers#

Limits are per application, over a 15-minute window that resets at 0, 15, 30 and 45 minutes past the hour and a daily window that resets at midnight UTC. Strava runs an overall limit and a separate one for "non-upload" endpoints, which is every endpoint except creating activities, uploads and media uploads. Requests that break the short-term limit still count toward the daily one, and an over-limit request returns 429 with a JSON error.

Every response reports usage in X-RateLimit-Limit and X-RateLimit-Usage (overall), plus X-ReadRateLimit-Limit and X-ReadRateLimit-Usage (non-upload), each a "15-minute, daily" pair. Read them and back off; the cookbook's rate-limit-aware fetch wrapper is one tested way to do that, with a list where you add a provider's own header names. Strava's own advice for apps under 100 users that hit limits is to implement webhooks instead of polling activities, and to throttle backfills using the headers.

The rules that shape the product#

Strava's API Policy (2026) is short on ambiguity. The parts most likely to change a design:

  • Display back to the same athlete only. Strava Data from a user may be shown only to that user, even data that is public on Strava.
  • No AI use. The policy forbids using Strava API materials or data "in connection with the development, training, evaluation, or operation of any AI Application", including embeddings, retrieval-augmented generation and context windows.
  • Short cache. Strava Data may not sit in a cache for more than seven days, and data an athlete deletes must disappear from your app within 48 hours.
  • No re-exposure. Pass-through proxies, aggregators that re-expose the API, and MCP servers that expose Strava data are prohibited; Strava's own MCP is the only authorized agent interface.
  • Garmin attribution. If you display data that came from a Garmin device, you must attribute Garmin the way Garmin's brand guidelines require.

If your current integration predates these terms, adapting to Strava's API changes covers the practical steps.

What changed recently#

Date (Strava's changelog and docs)Change
April 23, 2026Token responses include a space-delimited scope field
May 21, 2026FIT set messages ingested for strength training; JSON uploads for weight training
June 1, 2026New API Agreement and API Policy; revoke endpoint introduced; application tier shown in the dashboard; self-service expanded access for single-player developers
September 1, 2026Club Activities, Club Members and Club Admins endpoints removed; Explore Segments restricted to approved Extended Access Tier developers
January 4, 2027New base URL https://api-v3.strava.com becomes available, replacing https://www.strava.com/api/v3
June 1, 2027oauth/revoke becomes the only supported deauthorization endpoint

Plan the base-URL move now: make the host a configuration value rather than a literal in every call.

Gotchas and production notes#

  • The subscription and the 10-athlete gate come before code. A new app connects only you until you upgrade, and only 10 athletes until Strava reviews it. Put the review in the launch plan.
  • Rotating refresh tokens are the number-one integration bug. Persist the newest one on every refresh and never run two refreshes for one athlete at once.
  • Private activities need activity:read_all. Both the REST listings and webhook events hide Only You activities without it; if athletes report "missing" runs, this scope is usually why.
  • Webhooks are pointers, and one per app. Fan events out to athletes on your side using owner_id, and fetch the record before acting on it.
  • Two limits, two headers. The non-upload limit is the tighter one for read-heavy apps; watch X-ReadRateLimit-Usage, not only X-RateLimit-Usage.

For where Strava fits among device and aggregator options, see wearable data APIs, and for apps that need sleep or recovery data Strava does not model, the Strava API alternatives.

Frequently asked questions

Does the Strava API require approval to use?
Not to start, but it does to scale. Strava's getting-started guide says a Strava subscription is a prerequisite for creating an app and that every new app starts in single-player mode, where only your own account can authenticate. A self-service upgrade in the API Settings Dashboard raises the athlete capacity to 10; beyond 10 you submit the Developer Program form for review, and Strava says increased access is not guaranteed.
What are the Strava API rate limits in 2026?
As Strava documented on October 17, 2026, a new app gets an overall limit of 200 requests per 15 minutes and 2,000 per day, and a non-upload limit of 100 per 15 minutes and 1,000 per day. The self-service upgrade raises them to 400 and 4,000 overall and 200 and 2,000 for reads. The 15-minute window resets on the quarter hour, the daily one at midnight UTC, and an over-limit request returns 429.
How long do Strava access tokens last?
Strava's access tokens expire six hours after they are created. Refreshing returns the existing token if it has more than an hour left, and a new one if it expires within the hour. The refresh token can also change on any refresh, and Strava says the older refresh token is invalidated as soon as a new one is returned, so always store the newest one.
How do I get private Strava activities?
Request the activity:read_all scope. Plain activity:read covers activities visible to Everyone and Followers and excludes privacy zone data, while activity:read_all adds privacy zone data and activities set to Only You. The same split applies to webhooks: an app with only activity:read receives a delete event when an activity becomes Only You and a create event when it becomes visible again.
Does the Strava webhook include the activity data?
No. Strava's events carry object_type, object_id, aspect_type, owner_id, subscription_id, event_time and an updates hash, not the activity itself, so you fetch the record with that athlete's token. Respond with HTTP 200 within two seconds, because Strava retries a failed push for up to three attempts in total, and remember that each application gets only one subscription.

All 113 questions in Integration Guides →

Keep reading

Elsewhere on the site

Pages that share this one’s concepts and sources, from other sections.

Next steps

Was this page useful?

Independent comparison, last reviewed October 17, 2026. Pricing, rate limits, and feature availability change often — confirm current details in each provider’s official documentation before you commit. Product and company names are trademarks of their respective owners; AIFitnessAPI is not affiliated with, endorsed by, or sponsored by any product listed here.

← All integration guides · by AIFitnessAPI