This is a Rust server that downloads all Strava activities and the corresponding activity streams (tracks) for the authenticated user. The activities are stored in local a SQLite 3 database; the activity streams are written to GPX files.
The downloader respects the rate limits defined for your Strava API client. By default, the built-in scheduler issues a request every 10 seconds. The delay can be adapted in the server configuration. When the daily request limit is reached, the scheduler suspends. The downloading can be resumed later from point where it stopped. This also works after a server restart.
The server can be controlled by a React UI, which is also part of this project. It takes care of authenticating the application with Strava, lets you start and stop the downloading, and shows the download progress.
Optionally, if flag store_tiles in application.yaml is set to true,
the downloader computes the slippy map tiles
for zoom levels 14 and 17 of the downloaded activities and stores them in the same SQLite database.
The tiles are used by the tiles hunter project to show which tiles of
the world map you have already covered with your activities.
- Rust with
cargofor the server. - Node.js with
npmfor the UI. - Optionally sqlite3 for querying the local DB.
To connect to Strava, you need a Strava API client. If you don't have one already, you can register a new API client at https://www.strava.com/settings/api.
Make sure that the Authorization Callback Domain of your client is localhost:2525.
You will need values for Client ID and Client Secret of your API client for configuring the server (see below).
ce <project>/server
cargo buildCreate a server configuration from the template:
cp conf/application.yaml.example conf/application.yamlThen edit conf/application.yaml and set the Client ID and Client Secret of your Strava API client:
oauth:
client_id: "<your-strava-client-id>"
client_secret: "<your-strava-client-secret>"cd <project>/console
npm install
npm run build
cd ..Start the server:
RUST_LOG=info cargo run Then point your browser to http://localhost:2525 and start downloading your activities!
It is also possible to run the console UI in vite's preview mode.
The preview server runs at port 2020. To ensure that the Rust server redirects to the vite preview server
after authenticating with Strava, the target_url configured in conf/application.yaml should be
oauth:
target_url: "http://localhost:2020" # Redirect to after authenticationIn addition, the React app needs to fetch the data from an absolute address. In App.tsx change
const SERVER_URL = 'http://localhost:2525'Then start the dev server in another shell (tab):
cd <project>/console
npm run devPoint your browser to http://localhost:2020.
Build and deployment instructions for Docker Desktop and Google Cloud can be found in Deploy.md.
Instead of using the console UI, the server can be controlled via REST API.
For usability, all endpoints use GET.
A browser is only needed for the authorization,
where Strava redirects to its login and authorization pages.
GET /authorize
starts the authorization with Strava.
Under the hood, the server performs an OAuth 2.0 Authorization Code Grant flow
to obtain a Strava token. At the end of the process, the server redirects to
the URL configured at oauth.target_url in conf/application.yaml.
By default, this is the console UI exposed at the root path of the server.
GET /status
opens an SSE channel that receives
server-status updates as JSON objects in the SSE data field. An example object is
{
"authorized": true,
"download_state": "Inactive",
"activity_stats": {
"act_count": 1191,
"act_min_time": "2010-04-01T15:13:08Z",
"act_max_time": "2024-03-10T10:16:17Z",
"trk_count": 380,
"trk_max_time": "2016-10-03T14:00:56Z"
}
}
GET /toggle
starts the download process or stops it, depending on the previous state.
The request returns the name of the new state (e.g. "Inactive").
The server stores the GPX files in the data folder, grouped by year and month.
The file names refer to the activity ids provided by Strava. An example path is
./data/2024/03/7654321123.gpx
To read the GPX files from oldes to newest, you can either sort the files by name (as Strava uses increasing activity ids), or by file data (because the server downloads the files in chronological order).
If you have sqlite3 installed, you can also query the activity database (activity.db).
This example query selects all activities of 2024:
sqlite3 activity.db "select * from activity where substr(start_date, 1, 4) = '2024'"
The id column is the primary key and holds the activity id.
Column gpx_fetched shows the GPX download status:
0 means: "not yet downloaded",
1 means "GPX downloaded" (there is a corresponding file in folder data), and
2 means "the activity does not have a track".
Note that you can reveal the column names and format the results like so:
sqlite3 activity.db -header -column "select * from activity"
