Skip to main content

strava

CI codecov PyPI Python License

A modern, fully-typed Python SDK for the Strava API v3.

Features

  • Sync and async clients built on httpx
  • Full type annotations and py.typed support
  • 34 API endpoints across 9 resource groups
  • 50+ dataclass models with automatic serialization
  • OAuth2 authentication with automatic token refresh
  • Lazy pagination iterators
  • Custom exception hierarchy with rate limit details

Installation

pip install strava

Quick Start

from strava import Strava

with Strava(access_token="your_token") as client:
    # Get authenticated athlete
    athlete = client.athletes.retrieve_authenticated()
    print(f"{athlete.firstname} {athlete.lastname}")

    # List recent activities
    for activity in client.activities.list(per_page=10):
        print(f"{activity.name} - {activity.distance}m")

Async

from strava import AsyncStrava

async with AsyncStrava(access_token="your_token") as client:
    athlete = await client.athletes.retrieve_authenticated()
    activities = await client.activities.list(per_page=10).collect()

OAuth2 Authentication

Get an authorization URL

from strava import build_authorization_url

url = build_authorization_url(
    client_id="your_client_id",
    redirect_uri="http://localhost:8000/callback",
    scopes=["read", "activity:read_all"],
)
# Redirect the user to `url`

Exchange the code for tokens

from strava import exchange_token

tokens = exchange_token(
    client_id="your_client_id",
    client_secret="your_secret",
    code="code_from_callback",
)
print(tokens.access_token, tokens.refresh_token, tokens.expires_at)

Refresh a token manually

from strava import refresh_access_token

tokens = refresh_access_token(
    client_id="your_client_id",
    client_secret="your_secret",
    refresh_token="current_refresh_token",
)
print(tokens.access_token, tokens.refresh_token, tokens.expires_at)

Automatic token refresh

from strava import Strava

def save_tokens(access_token, refresh_token, expires_at):
    # Persist the new tokens to your database
    ...

client = Strava(
    access_token="...",
    client_id="your_client_id",
    client_secret="your_secret",
    refresh_token="...",
    expires_at=1700000000,
    on_token_refresh=save_tokens,
)

Revoke tokens

from strava import revoke_token

revoke_token(
    client_id="your_client_id",
    client_secret="your_secret",
    token="access_or_refresh_token",
    token_type_hint="access_token",
)

deauthorize(access_token=...) remains available for compatibility, but it is deprecated because Strava will retire oauth/deauthorize on June 1, 2027. Prefer revoke_token() for new code.

API Coverage

Resource Methods
Activities create, retrieve, update, list, list_comments, list_kudoers, list_laps, list_zones
Athletes retrieve_authenticated, update_authenticated, retrieve_zones, retrieve_stats
Clubs retrieve, list_activities, list_admins, list_members, list_authenticated
Gear retrieve
Routes retrieve, export_gpx, export_tcx, list_by_athlete
Segments retrieve, explore, list_starred, star
Segment Efforts retrieve, list
Streams get_activity_streams, get_route_streams, get_segment_effort_streams, get_segment_streams
Uploads create, retrieve

Strava API Changes

The default API host is https://www.api-v3.strava.com, matching Strava's June 1, 2027 migration from https://www.strava.com/api/v3.

Some methods remain in the SDK for compatibility but are affected by Strava's 2026 Developer Program changes:

  • clubs.list_activities(), clubs.list_admins(), and clubs.list_members() are deprecated by Strava effective September 1, 2026.
  • segments.explore() is restricted to approved Extended Access applications effective September 1, 2026.
  • deauthorize() is deprecated; use revoke_token() with your client credentials instead.

Pagination

List endpoints return lazy paginators:

# Iterate one item at a time (fetches pages on demand)
for activity in client.activities.list():
    print(activity.name)

# Collect all results eagerly
all_activities = client.activities.list().collect()

# Limit results
first_50 = client.activities.list().collect(max_items=50)

# Iterate page by page
for page in client.activities.list(per_page=50).pages():
    print(f"Got {len(page)} activities")

Error Handling

from strava import (
    StravaError,
    AuthenticationError,
    AuthorizationError,
    NotFoundError,
    RateLimitError,
    TokenExpiredError,
    ValidationError,
    ServerError,
)

try:
    activity = client.activities.retrieve(123)
except TokenExpiredError:
    print("Access token has expired — refresh it")
except AuthenticationError:
    print("Invalid or missing access token")
except AuthorizationError:
    print("Insufficient permissions")
except NotFoundError:
    print("Activity not found")
except ValidationError as e:
    print(f"Bad request: {e.message}")
except RateLimitError as e:
    print(f"Rate limited. 15-min usage: {e.usage_15min}/{e.limit_15min}")
except ServerError:
    print("Strava server error — try again later")
except StravaError as e:
    print(f"API error {e.status_code}: {e.message}")

Development

# Install dependencies
uv sync

# Run tests
make test

# Run tests with coverage
make coverage

# Lint and format
make lint
make format

Python Version

Supports Python 3.11 through 3.14.

Contributing

Contributions are welcome! Please read the Contributing Guide before opening a pull request.

Found a bug? Open an issue. Have an idea? Request a feature.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

strava-0.5.1.tar.gz (33.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

strava-0.5.1-py3-none-any.whl (44.3 kB view details)

Uploaded Python 3

File details

Details for the file strava-0.5.1.tar.gz.

File metadata

  • Download URL: strava-0.5.1.tar.gz
  • Upload date:
  • Size: 33.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for strava-0.5.1.tar.gz
Algorithm Hash digest
SHA256 b2237d3313492e5a5fb30a5bdb0aa6b3eff03c0d81b6ff132adc5914730f1174
MD5 1ca3d96a03c18b1342df51a5d4d521e8
BLAKE2b-256 fd89d211a1255928d9ccace6d06dfa7e24b9ef0447eb04efa80de8b6d52ebe20

See more details on using hashes here.

Provenance

The following attestation bundles were made for strava-0.5.1.tar.gz:

Publisher: publish.yml on ragnarok22/strava-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file strava-0.5.1-py3-none-any.whl.

File metadata

  • Download URL: strava-0.5.1-py3-none-any.whl
  • Upload date:
  • Size: 44.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for strava-0.5.1-py3-none-any.whl
Algorithm Hash digest
SHA256 41061bb522e031cff0160f810523de557ec7f7a37f83265bc07fbd88b3019662
MD5 4fed82f1fccbb4dbabf334006038fbf4
BLAKE2b-256 e65fee179e323b107a3daf852fd3132a428eaa2a9a3a669d9c14317cf7f3463f

See more details on using hashes here.

Provenance

The following attestation bundles were made for strava-0.5.1-py3-none-any.whl:

Publisher: publish.yml on ragnarok22/strava-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.5.1 This release

2 files

0.5.0

2 files

0.2.2

2 files

0.2.1

2 files

0.2.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page