Library / SDK
stravalib/stravalib avatar
stravalib/stravalib

stravalib wraps the Strava V3 API in a Client with units, dates and token refresh

Library to provide simple client interface to Strava's REST API (v3).

1,002 stars250 forksPythonApache-2.0

At a glance

What is it?
stravalib is a Python package for reading and writing Strava data through the V3 REST API, with a Client class that handles authentication, keeps the token current, returns typed models for activities, clubs and profiles, and expresses quantities and dates through Pint and arrow. It is Apache 2.0 licensed, supports Python 3.11 to 3.14, and its test suite runs against a mock so that no test hits the Strava API.
Who is it for?
stravalib fits a Python team that pulls athlete, activity or club data out of Strava on a schedule and wants objects with units and dates rather than raw dictionaries, especially for analysis work. It is the wrong choice for a script that only needs one endpoint once, where the dependency list is heavier than the request you would write.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 21, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One Client class over the V3 REST API

The stravalib package provides easy-to-use tools for accessing and downloading Strava data from the Strava V3 API, and almost everything you will use is in the stravalib.client.Client class.

The README lists what that class supports, and the list is worth reading as a specification of the integration surface. Authenticating with stravalib. Managing your authentication to ensure it is current, with the parenthetical caveat that this depends on your environment being set up. Accessing and downloading Strava activity, club and profile data. And making changes to account activities.

That last item matters more than it first appears. A read-only client for a fitness API is a reporting tool. A client that can write back to activities, for example to update a description or a workout, is a tool that can change data you may not be able to change through the site itself, and that is worth understanding before you point it at a real account.

The package supports date, time and temporal attributes as well as quantities, and it does that through the Python Pint library rather than with hand rolled unit handling. That is a real design decision for a fitness library, because a pace is not a number and a distance in kilometres is not a distance in miles, and Pint gives you the conversion rather than leaving the arithmetic to every caller.

The homepage is the documentation at stravalib.readthedocs.io, the last push was on 2026-10-05, and the project is not archived.

Token refresh is where integrations like this break

Authentication is the part of the README that gets the most tutorial coverage, and the order of the tutorials is itself a description of the difficulty.

The first is how to create a Strava app, the second is how to refresh and auto refresh your app token using stravalib, and then the tutorials move on to getting activities, to athlete data, and to unit conversion.

The second tutorial is where the library earns its place. Strava's API issues a token that expires, and a client that quietly returns empty results once the token has expired is a client that costs you an afternoon. The README frames the capability as managing your authentication to ensure it is current, and it is careful to add the condition that this depends on your environment being set up, which is the honest way of saying that the refresh needs somewhere to keep the refreshed token.

The repository contains an examples/strava-oauth/ directory, and that name is the clearest indication of what the flow requires. A Strava app has to be registered with a redirect URI, and the user has to authorise it in a browser, and the code has to receive the returned code and exchange it for a token. In a script that runs on a schedule with no browser, that exchange is a problem, and the example directory is where the project shows how it is handled.

For an evaluation, the practical question is not whether stravalib can do OAuth, it is whether you have somewhere to put the resulting token so that a job running at three in the morning can find it.

Typed models, and units that survive the round trip

The dependency list is short and each entry earns its place.

pint handles the quantities, so a distance or a pace is a value with a unit rather than a float with a name. arrow handles the date and time attributes, and Strava data is full of them, since an activity has a start time, a moving time, an elapsed time and a local time zone offset, and those do not agree with each other. pydantic 2.x does the modelling, which is what gives you typed objects and validated fields instead of dictionaries. requests does the HTTP work.

The project metadata confirms the shape. requires-python is 3.11 or newer, and the classifiers list 3.11, 3.12, 3.13 and 3.14, with a development status of 5, Production/Stable. The package is Apache 2.0 licensed, the author is Hans Lellelid, and the maintainer list includes Leah Wasser, Jonatan Samoocha, Yihong and Émile Nadeau.

There is a type marker too. The package data configuration ships a py.typed file, which is the marker that tells a type checker that the library ships inline annotations. For a package that models an external API, that is not a small thing, because the alternative is every caller writing their own TypedDict or dataclass layer over the same JSON.

The unit conversion helpers get their own tutorial page in the documentation, which is a clue about how the maintainers think the library is used. The audience is people doing analysis, where a distance in the wrong unit is a wrong answer rather than a cosmetic bug.

Installation is one line, and the tutorials carry the examples

The package is on PyPI and installs with pip.

bash
pip install stravalib

The README does not then walk through an API call. Instead it points at five tutorials, and they are the actual getting started material.

The list is a sensible progression. Create a Strava app, then refresh and auto refresh your app token using stravalib, then get activities using stravalib, then athlete data using stravalib, and then the unit conversion and stravalib page for the quantity helpers. The published Sphinx documentation is where the rest lives, and the README says as much, since the tutorials are described as material the maintainers welcome contributions to.

That arrangement is normal for a library that fronts a large external API. The library surface is the client class, and the interesting decisions are about Strava's own semantics, which change independently of the library, and the documentation is the right place for them.

The dependency list adds one requirement that is easy to miss. Alongside Python 3.11 and the runtime libraries, the build needs Setuptools, which is listed as a dependency for building stravalib rather than for using it.

There is also a DOI badge, pointing at a Zenodo record, which is the archiving and citation mechanism for research software. If you write a paper that used this library, the DOI is the reference to cite, and the version you used is the version that gets archived.

The test suite runs against a mock, not against Strava

The contribution guide is unusually specific about testing, and the reason is given in one sentence. The project developed a mock fixture that ensures that when tests are run, they are not hitting the Strava API.

That single design decision removes the two failure modes that make testing a client library painful. A test suite that hits the live API is slow, it needs credentials, and it depends on somebody else's uptime, and it can mutate real data. A mock fixture removes all three, and it is also what lets a contributor run the tests without creating a Strava app first.

The rest of the contributor path is conventional. You fork the repository and clone your fork locally, then read the development guide to learn how to run the test suite, build the docs, and lint and format the code. The clone command in the README is the SSH form, and the build from source is an editable install.

bash
git clone [email protected]:your_name_here/stravalib.git
cd stravalib/
bash
$ pip install -e .

The repository is set up for that workflow rather than for a bespoke one. There is a noxfile.py for the task automation, a .pre-commit-config.yaml for the hooks, a .coveragerc and a .codecov.yml for coverage, and a MANIFEST.in for the packaging. The contribution guide asks that tests be added for any change, and says that adding tests will greatly reduce the effort of reviewing and merging a pull request.

The documentation build is part of the same instruction set, which makes sense for a project whose tutorials are a deliverable rather than an afterthought.

The version number is written by setuptools_scm at build time

The version handling in pyproject.toml is a small thing that explains a lot about the release process.

The build system is setuptools with setuptools_scm, and the version is declared as dynamic. The configuration makes sure setuptools uses the version of the last created tag, with a post-release version scheme, and it deliberately does not use the local scheme version for a push to PyPI, so that the published version does not carry a local version marker. The generated version is written to src/stravalib/_version_generated.py from a template, and the template sets the string to v followed by the version.

In practice, the released version is whatever the last tag says, and the number in the package is not typed by hand. The comment in the configuration explains the reasoning, that using the last created tag lets a specific bump be specified, and that avoiding the local scheme keeps a plus sign out of the published version.

The release history is regular. The listed tags are v2.6.0 from 2026-08-27, v2.5.0 from 2026-06-01 and v2.4 from 2025-06-18, and the project is not archived. The changelog is a file in the repository, changelog.md, rather than a section of the README, which is the arrangement you would expect from a library that has been releasing for a long time and treats its changelog as a deliverable for users of a hosted API that changes under them.

The licence is Apache 2.0, with the text in LICENSE.txt at the repository root, and there is a CODE_OF_CONDUCT.md alongside a CONTRIBUTING.md and a CLAUDE.md for tooling.

Editorial conclusion

stravalib fits a Python team that pulls athlete, activity or club data out of Strava on a schedule and wants objects with units and dates rather than raw dictionaries, especially for analysis work. It is the wrong choice for a script that only needs one endpoint once, where the dependency list is heavier than the request you would write. Verify first that your Strava app and token setup matches the documented flow, since authentication and refresh are where integration usually breaks, and check the mock based test suite before you point your own credentials at it.

Frequently asked questions

What does stravalib do?

It provides easy-to-use tools for accessing and downloading Strava data from the Strava V3 API. Its Client class supports authenticating, managing your authentication so it stays current, accessing activity, club and profile data, and making changes to account activities.

How do I install stravalib?

The package is on PyPI and installs with pip install stravalib. It requires Python 3.11 or newer, and its runtime dependencies are requests, pint, arrow and pydantic 2.x.

How do I handle Strava authentication with stravalib?

The documentation has a tutorial on creating a Strava app and a separate one on refreshing and auto refreshing your app token using stravalib, and the repository includes an examples/strava-oauth/ directory. The README notes that keeping authentication current depends on your environment being set up.

Do the stravalib tests call the real Strava API?

No. The README says the project developed a mock fixture that ensures that when tests are run, they are not hitting the Strava API, and it asks contributors to add tests covering any change they make.

Which Python versions does stravalib support?

Python 3.11 and newer, with classifiers for 3.11, 3.12, 3.13 and 3.14, and a development status of Production/Stable. The licence is Apache 2.0 and the latest listed release is v2.6.0 from 2026-08-27.

Official sources

  1. License: Apache-2.0
  2. Project website
  3. README
  4. Releases
  5. stravalib/stravalib on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/stravalib-stravalib.svg)](https://hysenlabs.com/projects/stravalib-stravalib)

Was this useful?