Skip to main content

HSL Kaupunkipyörä Exporter

en fi sv

Parse your HSL City Bike ride history and export each ride as a Strava-compatible TCX or GPX file.

Installation

Requires Python 3.13+. The easiest way to run the tool is via uvx:

uvx hsl-kaupunkipyora-exporter rides.txt

Or install with pip:

pip install hsl-kaupunkipyora-exporter
hsl-kaupunkipyora-exporter rides.txt

Web App

A browser-based version is available at the GitHub Pages site. Upload your ride history HTML file or paste the text, pick your options, and download the resulting files — no installation required. The web app runs entirely in your browser using Pyodide.

The browser build reuses the same Python modules as the CLI — it installs the project wheel into Pyodide and calls the shared RideHistoryParser and writers from a thin adapter. Run it locally with:

just serve-web  # builds the wheel and serves http://localhost:8000/

AI Agent Skill

This repo ships a skill that lets AI Agents like Claude Code run the exporter from natural language, mapping requests like "export my HSL rides to GPX" to the right CLI flags, and offering to fetch the ride-history page itself via a connected browser tool (e.g. Claude in Chrome) when you agree to it. The instructions reference Claude Code's own tools (ToolSearch, Bash, Write), so treat it as Claude-Code-specific for now even though it's installed via skills, which also supports other agents. skills/ in this repo is the source of truth; installing copies it into .claude/skills/ in your own project. Install it into your project with for example:

npx skills add nikosavola/hsl-kaupunkipyora-exporter

Usage

  1. Open your ride history at https://www.hsl.fi/en/my-information/citybikes/ride-history.
  2. Save the page as HTML (Ctrl+S) or copy-paste the visible text into a .txt file.
  3. Run the exporter:
uvx hsl-kaupunkipyora-exporter rides.html

Path Modes

The exporter supports three distinct modes for handling geographic data:

  1. Summary Only (Default): Exports a TCX file containing the exact distance and duration reported by HSL, but no GPS trackpoints. This is the most accurate way to record kilometers in Strava without guessing the path.
  2. Linear Path (--linear): Includes a simple two-point straight line between the departure and return stations. Useful if you want a basic map visualization.
  3. Routed Path (--use-route): Fetches the suggested cycling route from the Digitransit API. This provides a realistic path on the map and preserves HSL distance data (when using TCX). Requires a free API key.

Options

Flag Description
--output-dir DIR Directory to write files into (default: ./tcx_output)
--format FMT Export format: tcx (default) or gpx.
--linear Include a straight-line path between stations
--use-route Use suggested HSL cycling route instead of a straight line
--api-key KEY Digitransit API key (alternative to DIGITRANSIT_API_KEY env var)
--refresh-stations Force re-download of the bike station coordinate list
--cache-ttl-days DAYS Refresh station cache after this many days (default: 30, env var below)
-n, --dry-run Preview which files would be written or skipped without writing
--zip Bundle all exported files into a single rides.zip archive
--merge Write one file with all rides (multi-track GPX / multi-activity TCX)
-v, --verbose Enable verbose/debug logging

The station cache TTL can also be set via the HSL_KAUPUNKIPYORA_CACHE_TTL_DAYS environment variable.

TCX vs GPX

While GPX is the most common format, it does not support an explicit "total distance" override. Strava calculates distance based on the GPS points provided.

TCX is the default and recommended format because it allows the tool to tell Strava exactly how many kilometers the ride was, regardless of the GPS path.

# Export as TCX with a straight line between stations
uvx hsl-kaupunkipyora-exporter rides.txt --linear

Routed Path Setup

To use the actual cycling route suggested by HSL, you need a Digitransit API key:

  1. Register for a free key at Digitransit Developer Portal.
  2. Provide the key via the --api-key flag or the DIGITRANSIT_API_KEY environment variable.
uvx hsl-kaupunkipyora-exporter rides.txt --use-route --api-key your_key_here

Kilometrikisa

This is a convenient way to add your Alepa Fillari kilometers to Kilometrikisa by importing your rides into Strava first.

How it Works

graph TD
    classDef input fill:#4A90D9,stroke:#2171B5,color:#fff
    classDef parser fill:#E67E22,stroke:#CA6F1E,color:#fff
    classDef lookup fill:#8E44AD,stroke:#7D3C98,color:#fff
    classDef decision fill:#FDEBD0,stroke:#E67E22,color:#000
    classDef skip fill:#E74C3C,stroke:#CB4335,color:#fff
    classDef pathNode fill:#A9DFBF,stroke:#27AE60,color:#000
    classDef api fill:#76D7C4,stroke:#16A085,color:#000
    classDef writer fill:#5DADE2,stroke:#2980B9,color:#fff
    classDef output fill:#2ECC71,stroke:#27AE60,color:#000

    A[HSL Ride History<br/>HTML or Text]:::input --> B(RideHistoryParser<br/>Parses HTML & plain-text<br/>ride history files):::parser
    B --> C{StationLookup<br/>Resolves station names<br/>to GPS coordinates}:::lookup
    C -- Coordinates Found --> D{Path Mode?}:::decision
    C -- Not Found --> E[Skip Ride]:::skip

    D -- Default --> F[Summary Only<br/>Exact HSL distance &<br/>duration, no GPS points]:::pathNode
    D -- "--linear" --> G[Linear Path<br/>Straight line between<br/>departure & return stations]:::pathNode
    D -- "--use-route" --> H[fetch_route<br/>Fetches cycling route<br/>via Digitransit GraphQL API]:::api

    F --> I(TCX/GPX Writer<br/>Serialises rides into<br/>Strava-compatible files):::writer
    G --> I
    H --> I

    I --> J[Strava-compatible<br/>TCX or GPX files]:::output

Development

Use just to run tasks.

git clone https://github.com/nikosavola/hsl-kaupunkipyora-exporter.git
cd hsl-kaupunkipyora-exporter
just install
just test

Metadata

Release files for hsl-kaupunkipyora-exporter 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for hsl-kaupunkipyora-exporter 0.1.2
File Size Uploaded
hsl_kaupunkipyora_exporter-0.1.2.tar.gz 29.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for hsl-kaupunkipyora-exporter 0.1.2
File Interpreter ABI Platform
hsl_kaupunkipyora_exporter-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 64.6 kB

Release files / hsl_kaupunkipyora_exporter-0.1.2.tar.gz

Download URL hsl_kaupunkipyora_exporter-0.1.2.tar.gz
Size 29.5 kB
Tags Source
SHA-256 checksum
How to use checksums
5ce26ee793f299cf49e8df3ed5f911861b8783597778043e1a99dfff17c0e36d
BLAKE2b-256 checksum
How to use checksums
f63490b2270af415ed3a097b31582aca327489dcd7c8de4b4d92a723b3feacd6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 12, 2026.

Transparency log

Release files / hsl_kaupunkipyora_exporter-0.1.2-py3-none-any.whl

Download URL hsl_kaupunkipyora_exporter-0.1.2-py3-none-any.whl
Size 35.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fe778b8e791b56e68a6e2d332d7433578381bfd5d6b34c669fafe1684ce4a219
BLAKE2b-256 checksum
How to use checksums
c20ad80dbf83f861534d8540d148d614468d35d4b9a45bfdb449a4570503397e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 12, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.2 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page