Add Komoot activity import with guided browser-based batch flow #25

Open
McPringle wants to merge 23 commits from McPringle/komoot-import into main
McPringle commented 2026-04-28 16:04:24 +02:00 (Migrated from github.com)

Goal

This PR adds a Komoot import flow to FitPub.

The goal of this feature is:

  • let a signed-in FitPub user connect to Komoot with temporary credentials
  • load recorded Komoot activities for a given Komoot user ID
  • show which activities are already imported and which are still new
  • import new activities into FitPub through the existing GPX import pipeline
  • preserve stable matching via komootActivityId so imported activities can be recognized later

This PR focuses on the import foundation and the end-user workflow. It does not introduce a background job system or a permanent Komoot connection.

What is implemented

Komoot import view

A new Komoot import page is available from the upload/import navigation.

The page provides:

  • Komoot email
  • Komoot password
  • Komoot user ID
  • optional start and end date filter

The credentials are only used for the current request and are not stored in FitPub.

Loading Komoot activities

The page can load Komoot activities for the given account and optional date range.

The loaded list shows:

  • activity name
  • date
  • mapped FitPub activity type
  • distance
  • duration
  • elevation
  • import status

The type shown in the list is the mapped FitPub type, not the raw Komoot sport value. This allows the user to see how each activity would be imported.

Import status in the list

Each activity shows whether it is already imported or still new.

The UI distinguishes between:

  • already imported
  • new / not yet imported
  • queued for import
  • currently importing
  • failed import

Matching and deduplication

Imported activities are linked to Komoot through komootActivityId stored on the FitPub activity.

This is used to:

  • skip already imported Komoot activities
  • keep the mapping stable even if the FitPub activity is edited later
  • show import status in the list

Import execution

The import runs as a browser-driven batch flow:

  • only activities currently listed in the UI are considered
  • already imported activities are skipped
  • new activities are imported from oldest to newest
  • the table updates row-by-row while import is running

Each activity is imported by:

  1. loading Komoot activity details
  2. downloading the Komoot GPX
  3. importing through the existing GPX activity pipeline
  4. overriding imported metadata with Komoot values:
    • komootActivityId
    • title
    • description
    • visibility
    • activityType

Throttling and rate-limit protection

To reduce the risk of Komoot rate limiting, delays are applied intentionally.

Configurable delays are available for:

  • paginated activity list requests
  • pause between activity detail request and GPX request
  • pause between imported activities

Cancellation

A running import can be stopped from the UI.

Behavior:

  • stop is requested from the browser
  • the currently running activity finishes
  • queued activities are reset back to their normal “new” state
  • remaining activities are not imported automatically afterward

Constraints and behavior made explicit in the UI

The page explains important limitations:

  • credentials are not stored
  • the import runs in the current browser tab
  • leaving or reloading the page stops the remaining batch
  • import starts with the oldest new activities
  • short delays are intentional
  • the integration depends on Komoot web endpoints, not a stable public API

Import flow

1. Fill in the form

The user enters:

  • Komoot email
  • Komoot password
  • Komoot user ID
  • optional start and end date

Screenshot:

Bildschirmfoto vom 2026-04-28 15-31-21

2. Load Komoot activities

The user loads Komoot activities.

The list shows:

  • mapped FitPub type
  • whether each activity is already imported
  • which activities are still new and importable

Screenshot:

Bildschirmfoto vom 2026-04-28 15-41-31

3. Start the import

The import button becomes available after activities are loaded.

When started:

  • all new listed activities are queued
  • import begins at the bottom of the list because the oldest new activities are imported first
  • status updates are shown directly in the table

Screenshot:

Bildschirmfoto vom 2026-04-28 15-42-01

4. Import completion or stop

After completion:

  • imported rows are marked accordingly
  • failed rows keep an error state
  • if the user stops the import, queued rows return to the “new” state

Screenshot:

Bildschirmfoto vom 2026-04-28 15-42-34

Technical notes

  • Komoot integration uses the web endpoints currently used by the Komoot website
  • GPX remains the effective sourceFileFormat
  • Komoot origin is tracked separately through komootActivityId
  • date filtering is passed through to Komoot using server-side request parameters
  • import is currently browser-driven, not job-based

Out of scope

This PR does not include:

  • a persistent server-side import job
  • automatic resume after page reload
  • permanent Komoot account linking
  • post-import editing workflow changes
  • a dedicated retry system for failed Komoot imports

Summary

This PR introduces a complete first Komoot import experience in FitPub:

  • discover activities from Komoot
  • see what is already imported
  • import new activities safely through the existing GPX pipeline
  • preserve Komoot linkage for future deduplication and follow-up features
## Goal This PR adds a Komoot import flow to FitPub. The goal of this feature is: - let a signed-in FitPub user connect to Komoot with temporary credentials - load recorded Komoot activities for a given Komoot user ID - show which activities are already imported and which are still new - import new activities into FitPub through the existing GPX import pipeline - preserve stable matching via `komootActivityId` so imported activities can be recognized later This PR focuses on the import foundation and the end-user workflow. It does **not** introduce a background job system or a permanent Komoot connection. ## What is implemented ### Komoot import view A new Komoot import page is available from the upload/import navigation. The page provides: - Komoot email - Komoot password - Komoot user ID - optional start and end date filter The credentials are only used for the current request and are not stored in FitPub. ### Loading Komoot activities The page can load Komoot activities for the given account and optional date range. The loaded list shows: - activity name - date - mapped FitPub activity type - distance - duration - elevation - import status The type shown in the list is the **mapped FitPub type**, not the raw Komoot sport value. This allows the user to see how each activity would be imported. ### Import status in the list Each activity shows whether it is already imported or still new. The UI distinguishes between: - already imported - new / not yet imported - queued for import - currently importing - failed import ### Matching and deduplication Imported activities are linked to Komoot through `komootActivityId` stored on the FitPub activity. This is used to: - skip already imported Komoot activities - keep the mapping stable even if the FitPub activity is edited later - show import status in the list ### Import execution The import runs as a browser-driven batch flow: - only activities currently listed in the UI are considered - already imported activities are skipped - new activities are imported from **oldest to newest** - the table updates row-by-row while import is running Each activity is imported by: 1. loading Komoot activity details 2. downloading the Komoot GPX 3. importing through the existing GPX activity pipeline 4. overriding imported metadata with Komoot values: - `komootActivityId` - `title` - `description` - `visibility` - `activityType` ### Throttling and rate-limit protection To reduce the risk of Komoot rate limiting, delays are applied intentionally. Configurable delays are available for: - paginated activity list requests - pause between activity detail request and GPX request - pause between imported activities ### Cancellation A running import can be stopped from the UI. Behavior: - stop is requested from the browser - the currently running activity finishes - queued activities are reset back to their normal “new” state - remaining activities are not imported automatically afterward ### Constraints and behavior made explicit in the UI The page explains important limitations: - credentials are not stored - the import runs in the current browser tab - leaving or reloading the page stops the remaining batch - import starts with the oldest new activities - short delays are intentional - the integration depends on Komoot web endpoints, not a stable public API ## Import flow ### 1. Fill in the form The user enters: - Komoot email - Komoot password - Komoot user ID - optional start and end date Screenshot: <img width="1102" height="601" alt="Bildschirmfoto vom 2026-04-28 15-31-21" src="https://github.com/user-attachments/assets/fed37e05-48e8-4e84-b81a-8ea7520a4c77" /> ### 2. Load Komoot activities The user loads Komoot activities. The list shows: - mapped FitPub type - whether each activity is already imported - which activities are still new and importable Screenshot: <img width="1117" height="874" alt="Bildschirmfoto vom 2026-04-28 15-41-31" src="https://github.com/user-attachments/assets/0075a87f-a51c-4a68-b678-e394dfed4a74" /> ### 3. Start the import The import button becomes available after activities are loaded. When started: - all new listed activities are queued - import begins at the bottom of the list because the oldest new activities are imported first - status updates are shown directly in the table Screenshot: <img width="1103" height="862" alt="Bildschirmfoto vom 2026-04-28 15-42-01" src="https://github.com/user-attachments/assets/4b1158be-ab9f-4ab3-845c-4ebf649a69a4" /> ### 4. Import completion or stop After completion: - imported rows are marked accordingly - failed rows keep an error state - if the user stops the import, queued rows return to the “new” state Screenshot: <img width="1105" height="931" alt="Bildschirmfoto vom 2026-04-28 15-42-34" src="https://github.com/user-attachments/assets/d257dabb-827f-47a5-8e5f-b86eba37e996" /> ## Technical notes - Komoot integration uses the web endpoints currently used by the Komoot website - GPX remains the effective `sourceFileFormat` - Komoot origin is tracked separately through `komootActivityId` - date filtering is passed through to Komoot using server-side request parameters - import is currently browser-driven, not job-based ## Out of scope This PR does not include: - a persistent server-side import job - automatic resume after page reload - permanent Komoot account linking - post-import editing workflow changes - a dedicated retry system for failed Komoot imports ## Summary This PR introduces a complete first Komoot import experience in FitPub: - discover activities from Komoot - see what is already imported - import new activities safely through the existing GPX pipeline - preserve Komoot linkage for future deduplication and follow-up features
javahippie (Migrated from github.com) reviewed 2026-04-29 10:04:10 +02:00
javahippie (Migrated from github.com) left a comment

Thanks for the request, this seems to have been a lot of work.

I'm not sure that this feature matches the software, though. It seems to violate Komoots Terms of Service and uses an internal API with a spoofed Browser agent. Aside from the legal considerations, this seems error prone and prone to break.

I'm currently in the middle of enabling a full fledged OIDC flow to enable third party clients. This importer could be a standalone software using this API instead.

Until then, you can export many activities from Komoot, and upload them via batch import as a ZIP. I did this with ~800 activities from Strava, this uses a stateful batch approach and works well.

Thanks for the request, this seems to have been a lot of work. I'm not sure that this feature matches the software, though. It seems to violate Komoots Terms of Service and uses an internal API with a spoofed Browser agent. Aside from the legal considerations, this seems error prone and prone to break. I'm currently in the middle of enabling a full fledged OIDC flow to enable third party clients. This importer could be a standalone software using this API instead. Until then, you can export many activities from Komoot, and upload them via batch import as a ZIP. I did this with ~800 activities from Strava, this uses a stateful batch approach and works well.
@ -0,0 +1,22 @@
package net.javahippie.fitpub.model.dto;
javahippie (Migrated from github.com) commented 2026-04-29 09:49:49 +02:00

DTOs in this PR are all records. While I generally like them, I'd prefer the DTO to mimic the existing ones, classes with Lomboks @Data annotation. If the DTOs switch to records, it should be done for all, not fragmented

DTOs in this PR are all records. While I generally like them, I'd prefer the DTO to mimic the existing ones, classes with Lomboks `@Data` annotation. If the DTOs switch to records, it should be done for all, not fragmented
javahippie (Migrated from github.com) commented 2026-04-29 09:50:59 +02:00

I don't think that this belongs into the activity table. I'd prefer a separate table to track the Komoot import status – there it could also be properly non-nullable

I don't think that this belongs into the activity table. I'd prefer a separate table to track the Komoot import status – there it could also be properly non-nullable
@ -0,0 +1,478 @@
package net.javahippie.fitpub.service;
javahippie (Migrated from github.com) commented 2026-04-29 09:54:23 +02:00

This seems to use an inofficial, internal API of Komoot which is prone to be changed or break. Also, from my understanding this breaks the Komoot Terms of Service. The fact, that the User Agent needs to spoofed in order for this to works shows, that this code does something that Komoot explicitly does not want. I fear that this change will be a) hard to maintain in the future and b) might open this project to a lawsuit by Komoot.

This seems to use an inofficial, internal API of Komoot which is prone to be changed or break. Also, from my understanding this breaks the Komoot Terms of Service. The fact, that the User Agent needs to spoofed in order for this to works shows, that this code does something that Komoot explicitly does not want. I fear that this change will be a) hard to maintain in the future and b) might open this project to a lawsuit by Komoot.
javahippie (Migrated from github.com) commented 2026-04-29 09:55:18 +02:00

See above, should be a seperate table

See above, should be a seperate table
McPringle commented 2026-04-29 10:24:01 +02:00 (Migrated from github.com)

Thanks for the review, I'll have a look at it soon.

Thanks for the review, I'll have a look at it soon.
McPringle (Migrated from github.com) reviewed 2026-04-29 10:57:30 +02:00
@ -0,0 +1,22 @@
package net.javahippie.fitpub.model.dto;
McPringle (Migrated from github.com) commented 2026-04-29 10:57:30 +02:00

Okay, I'll switch the implementation to classes to mimic the esisting ones.

Okay, I'll switch the implementation to classes to mimic the esisting ones.
McPringle (Migrated from github.com) reviewed 2026-04-29 11:08:43 +02:00
McPringle (Migrated from github.com) commented 2026-04-29 11:08:42 +02:00

I thought about it yesterday, too. I'll change it accordingly.

I thought about it yesterday, too. I'll change it accordingly.
McPringle commented 2026-04-29 11:49:33 +02:00 (Migrated from github.com)

You’re right that this relies on an undocumented, internal Komoot API. That comes with risks, especially around long-term stability, and I don’t want to downplay that.

A few clarifications:

  • The user agent does not need to spoof a browser. Komoot does not appear to depend on the user agent for these requests. I updated it to use a dedicated identifier: "FitPub Komoot Import".
  • The approach is similar to what other tools, for example Wanderer, have been using for years. While that does not guarantee anything, the endpoints used here have historically been relatively stable with only occasional changes.

Regarding the concerns about scope and risk: this is already implemented as a best-effort integration with clear boundaries.

  • The feature is explicitly user-initiated and not enabled by default
  • The UI contains a warning that this relies on an unofficial interface and may break at any time
  • The implementation is isolated so it can be removed or replaced easily if needed

FitPub already supports file-based imports (GPX/FIT). However, when importing activities that were exported from other platforms such as Komoot, these files are inherently lossy. In practice, important metadata is often missing: the activity name is frequently not preserved and the description is not included at all. The Komoot import addresses this gap by providing a more complete data set.

In addition, a direct integration enables access to further data in the future, for example metadata or media such as photos associated with an activity. This is not possible with a pure GPX export/import workflow.

Looking ahead, once OIDC support in FitPub is available, the authorization mechanism could be adapted accordingly. Based on my current understanding, this would mainly affect the authentication flow, while the underlying endpoints remain the same. In that case, the interaction would effectively use the same backend interfaces but via an officially supported authentication mechanism, rather than relying on a session-based login.

From a legal perspective, my understanding is that this mirrors what a user can already do via the web interface (accessing their own data). However, I agree that this area is not clearly defined, so being transparent about the nature of the integration is important.

If these trade-offs are not acceptable for the project, I’m also fine with keeping Komoot support out of scope.

You’re right that this relies on an undocumented, internal Komoot API. That comes with risks, especially around long-term stability, and I don’t want to downplay that. A few clarifications: - The user agent does not need to spoof a browser. Komoot does not appear to depend on the user agent for these requests. I updated it to use a dedicated identifier: "FitPub Komoot Import". - The approach is similar to what other tools, for example Wanderer, have been using for years. While that does not guarantee anything, the endpoints used here have historically been relatively stable with only occasional changes. Regarding the concerns about scope and risk: this is already implemented as a best-effort integration with clear boundaries. - The feature is explicitly user-initiated and not enabled by default - The UI contains a warning that this relies on an unofficial interface and may break at any time - The implementation is isolated so it can be removed or replaced easily if needed FitPub already supports file-based imports (GPX/FIT). However, when importing activities that were exported from other platforms such as Komoot, these files are inherently lossy. In practice, important metadata is often missing: the activity name is frequently not preserved and the description is not included at all. The Komoot import addresses this gap by providing a more complete data set. In addition, a direct integration enables access to further data in the future, for example metadata or media such as photos associated with an activity. This is not possible with a pure GPX export/import workflow. Looking ahead, once OIDC support in FitPub is available, the authorization mechanism could be adapted accordingly. Based on my current understanding, this would mainly affect the authentication flow, while the underlying endpoints remain the same. In that case, the interaction would effectively use the same backend interfaces but via an officially supported authentication mechanism, rather than relying on a session-based login. From a legal perspective, my understanding is that this mirrors what a user can already do via the web interface (accessing their own data). However, I agree that this area is not clearly defined, so being transparent about the nature of the integration is important. If these trade-offs are not acceptable for the project, I’m also fine with keeping Komoot support out of scope.
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin McPringle/komoot-import:McPringle/komoot-import
git checkout McPringle/komoot-import

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git checkout main
git merge --no-ff McPringle/komoot-import
git checkout McPringle/komoot-import
git rebase main
git checkout main
git merge --ff-only McPringle/komoot-import
git checkout McPringle/komoot-import
git rebase main
git checkout main
git merge --no-ff McPringle/komoot-import
git checkout main
git merge --squash McPringle/komoot-import
git checkout main
git merge --ff-only McPringle/komoot-import
git checkout main
git merge McPringle/komoot-import
git push origin main
Sign in to join this conversation.
No description provided.