# strava

Published articles for strava.

This is one page of public article previews, not the complete archive. Follow Next page to continue. Summaries are not the original full articles.

## Porting a Discord Bot to Microsoft Teams with GitHub Copilot CLI

DevFeed: [Porting a Discord Bot to Microsoft Teams with GitHub Copilot CLI](<https://devfeed.tech/articles/porting-a-discord-bot-to-microsoft-teams-entirely-with-ai-31471.md>)

Original publisher: [Read original article](<https://code.dblock.org/2026/09/16/porting-strata-to-microsoft-teams-entirely-with-ai.html>)

Author: Daniel Doubrovkine (dblock@dblock.org)

Published: 2026-09-16T00:00:00Z

Content type: article

Language: en

Sources: [Daniel Doubrovkine](<https://devfeed.tech/sources/daniel-doubrovkine.md>)

Topics: [GitHub Copilot CLI](<https://devfeed.tech/topics/github-copilot-cli.md>), [Microsoft Teams](<https://devfeed.tech/topics/microsoft-teams.md>), [Artificial Intelligence](<https://devfeed.tech/topics/ai.md>), [Discord](<https://devfeed.tech/topics/discord.md>), [AdventureX 2025](<https://devfeed.tech/topics/adventurex2025.md>)

Tags: [ai](<https://devfeed.tech/tags/ai.md>), [discord](<https://devfeed.tech/tags/discord.md>), [github-copilot-cli](<https://devfeed.tech/tags/github-copilot-cli.md>), [hackathon](<https://devfeed.tech/tags/hackathon.md>), [microsoft-teams](<https://devfeed.tech/tags/microsoft-teams.md>), [porting](<https://devfeed.tech/tags/porting.md>), [ruby](<https://devfeed.tech/tags/ruby.md>), [strava](<https://devfeed.tech/tags/strava.md>)

### AI overview

The article compares a manual 2023 port of a Strava chat bot from Slack to Discord with a 2026 port to Microsoft Teams completed with GitHub Copilot CLI. The Teams port took three days and involved authentication, app-manifest, tenant distribution, and Azure setup work.

### Source excerpt

Slava (slack-strava) connects a Strava account to a chat and posts a card for every activity, complete with map, pace, and elevation, plus commands like connect, disconnect, stats, and leaderboard. In 2023 I ported Slava to Discord by hand, evening by evening over about three weeks, and it took most of that stretch to get a working bot called Strada (discord-strava). This week I ported the same app to Microsoft Teams as Strata (teams-strava) in 3 days instead of the 3 weeks the Discord port took, using time carved out during the Microsoft Global Hackathon. By "I", I mean GitHub Copilot CLI and I. The 2023 Baseline discord-strava's git history is a fair record of how long a manual port takes. The first commit, "Initial fork from slack-strava," landed July 30, 2023. "Most interactions working" was three days later. Getting install/help/error-handling polish took through August 20: 2023-07-30 23:56 Initial fork from slack-strava. 2023-08-02 23:46 Most interactions working. 2023-08-03 06:18 Remove PNG retrieval, Discord displays redirects correctly. 2023-08-03 06:26 Removed clubs. 2023-08-03 08:28 Fixed model specs. 2023-08-03 18:20 Fix API specs. 2023-08-04 19:44 Fix command specs. ... 2023-08-08 10:34 Countinously poll with 1 minute intervals. 2023-08-20 22:59 Improved install button and text. 20 commits spread across 9 evenings over roughly three weeks (there's a real job and a life in between those timestamps). All hand-typed, with GitHub Copilot's inline autocomplete helping the way it helped everyone in 2023, but no agent driving the actual porting work. The 2026 Port teams-strava's git history is a single continuous Copilot CLI session, 107 conversational turns over three calendar days, and the timestamps compress dramatically: 2026-09-14 11:05 Initial port of discord-strava to Microsoft Teams 2026-09-14 16:39 Fix local dev setup and personal-scope install handling 2026-09-14 16:43 Fix 400 error replying to personal-scope install notice 2026-09-15 08:29 Document

## Building a Data Pipeline to Track Strava's Bad Events

DevFeed: [Building a Data Pipeline to Track Strava's Bad Events](<https://devfeed.tech/articles/an-eventful-summer-at-strava-26571.md>)

Original publisher: [Read original article](<https://medium.com/strava-engineering/an-eventful-summer-at-strava-5692882e5f4f?source=rss----89d4108ce2a3---4>)

Author: Bisman Sodhi

Published: 2024-01-08T20:19:46Z

Content type: opinion

Language: en

Sources: [Strava Engineering](<https://devfeed.tech/sources/strava-engineering.md>)

Topics: [data](<https://devfeed.tech/topics/data.md>), [airflow](<https://devfeed.tech/topics/airflow.md>), [Amazon S3](<https://devfeed.tech/topics/amazon-s3.md>), [Python](<https://devfeed.tech/topics/python.md>), [Amazon Web Services](<https://devfeed.tech/topics/aws.md>), [JSON](<https://devfeed.tech/topics/json.md>), [dashboards](<https://devfeed.tech/topics/dashboards.md>), [Computer science](<https://devfeed.tech/topics/computer-science.md>)

Tags: [airflow](<https://devfeed.tech/tags/airflow.md>), [apache-airflow](<https://devfeed.tech/tags/apache-airflow.md>), [aws](<https://devfeed.tech/tags/aws.md>), [data](<https://devfeed.tech/tags/data.md>), [data-engineering](<https://devfeed.tech/tags/data-engineering.md>), [data-pipeline](<https://devfeed.tech/tags/data-pipeline.md>), [data-platforms](<https://devfeed.tech/tags/data-platforms.md>), [integrity](<https://devfeed.tech/tags/integrity.md>), [json](<https://devfeed.tech/tags/json.md>), [python](<https://devfeed.tech/tags/python.md>), [s3](<https://devfeed.tech/tags/s3.md>), [software-engineering](<https://devfeed.tech/tags/software-engineering.md>), [strava](<https://devfeed.tech/tags/strava.md>), [tableau](<https://devfeed.tech/tags/tableau.md>), [warehouse](<https://devfeed.tech/tags/warehouse.md>)

### AI overview

A software engineering intern describes building a daily Apache Airflow pipeline that extracts schema-invalid user behavior events from S3, decompresses them into JSON, and loads them into Snowflake. Staging tables protect production data from partial loads, while materialized SQL views and a Tableau dashboard improve querying and monitoring.

### Source excerpt

Hi my name is Bisman and I studied Computer Science at University of California, Santa Barbara. During summer of 2022, I had the most amazing experience working as a Software Engineer Intern on Strava's Data Platform Team. In the first fews weeks, I learned the tools my team uses and then spent the rest of the time working on my project. TRACKING BAD EVENTS For my major summer project, I created a data pipeline that pulls user behavior data out of external storage and persists it in our data warehouse. Strava uses a service called Snowplow to collect this user behavior data, like loading a club page or uploading a profile photo. Sometimes, this data fails to match the schema that we've set, and a piece of data that fails this schema validation is called a bad event. Previously, these bad events were temporarily stored in an Elastic Search. Persisting this data in Snowflake, our data warehouse, makes it accessible to a wider audience. It also makes it easier to incorporate the bad events data with other services used at Strava. To start my project, I created a directed acyclic graph in Apache Airflow, a scheduling framework, using python that extracts bad events data from the S3, AWS's storage service, buckets on a daily cadence. This data was stored as gzip files on S3 which I decompressed and stored the data as JSON blobs. As I was working with billions of rows of data, it was important to maintain data integrity and take measures in case data failed to load from S3. Therefore, I loaded data into a staging table in Snowflake. The staging table ensured that if loading from S3 failed, the production table would remain untouched. This data was then loaded into the production table free of any partial data. After all the data was loaded into the production table, I created six view tables because there were six different types of bad events stored in the production table. I collaborated with our stakeholders -- data analysts -- throughout this process to craft tables bas

## Counting Authorized Athletes for Strava API Applications at Scale

DevFeed: [Counting Authorized Athletes for Strava API Applications at Scale](<https://devfeed.tech/articles/ac-count-ing-for-scale-26569.md>)

Original publisher: [Read original article](<https://medium.com/strava-engineering/ac-count-ing-for-scale-becf9c27b104?source=rss----89d4108ce2a3---4>)

Author: jana

Published: 2023-04-26T18:23:14Z

Content type: article

Language: en

Sources: [Strava Engineering](<https://devfeed.tech/sources/strava-engineering.md>)

Topics: [API](<https://devfeed.tech/topics/api.md>), [OAuth](<https://devfeed.tech/topics/oauth.md>), [Authorization](<https://devfeed.tech/topics/authorization.md>), [data](<https://devfeed.tech/topics/data.md>)

Tags: [api](<https://devfeed.tech/tags/api.md>), [applications](<https://devfeed.tech/tags/applications.md>), [authorization](<https://devfeed.tech/tags/authorization.md>), [data](<https://devfeed.tech/tags/data.md>), [oauth](<https://devfeed.tech/tags/oauth.md>), [open-source](<https://devfeed.tech/tags/open-source.md>), [scale](<https://devfeed.tech/tags/scale.md>), [strava](<https://devfeed.tech/tags/strava.md>)

### AI overview

Strava's API & Platform team needed to enforce per-application limits on the number of athletes authorized to connect. The article describes using OAuth2.0 refresh tokens and unique athlete IDs as a proxy for counting connected athletes, while noting the scalability challenge of counting rows in a SQL database.

### Source excerpt

Tens of thousands of API applications interact with Strava's publicly available API, from small projects whose only users are the developers who created them to larger partners like Garmin, Zwift, Wahoo, or Peloton, who upload thousands of activities to Strava daily on our athletes' behalf. Recently the API & Platform team undertook a project to redefine the way that Strava supports API applications and allows them to interact with Strava data (read more about the updated Developer program here). As part of the effort to redefine the management of API applications, a main requirement of the project asked that we be able to assign and enforce a limit to the number of athletes who are allowed to authorize an application on their behalf, what we called an application's athleteCapacity. On creation of a new application, the default athleteCapacity is a single athlete -- the application owner. Developers can subsequently apply to have their limits increased. In order to enforce the assigned athleteCapacity we needed to know how many athletes had authorized any given API application to read and write data to their Strava account, what we termed as an application's connectedAthletesCount. When a new athlete attempts to authorize an application on their behalf (as pictured below), we wanted to be able to ascertain whether the authorization would cause the connectedAthletesCount to exceed its athleteCapacity. The prompt shown to an athlete to request their permission to authorize an external application to connect to Strava on their behalf. We planned to perform the check of an application's `connectedAthletesCount` against its `athleteCapacity` on click of "Authorize". If authorization would cause the application to exceed its athleteCapacity, we would prevent the athlete from authorizing. Otherwise we would allow authorization to proceed. Our use of the OAuth2.0 standard for external access to our API gave us an easy proxy for determining the connectedAthletesCount. As part

## Personal Heatmaps

DevFeed: [Personal Heatmaps](<https://devfeed.tech/articles/personal-heatmaps-26574.md>)

Original publisher: [Read original article](<https://medium.com/strava-engineering/personal-heatmaps-f51d15a0db2b?source=rss----89d4108ce2a3---4>)

Author: J Evans

Published: 2022-10-28T21:15:46Z

Content type: tutorial

Language: en

Sources: [Strava Engineering](<https://devfeed.tech/sources/strava-engineering.md>)

Topics: [data](<https://devfeed.tech/topics/data.md>), [Algorithm](<https://devfeed.tech/topics/algorithm.md>), [navigation](<https://devfeed.tech/topics/navigation.md>), [pixel](<https://devfeed.tech/topics/pixel.md>), [real-time](<https://devfeed.tech/topics/real-time.md>), [Google Maps](<https://devfeed.tech/topics/google-maps.md>), [Website](<https://devfeed.tech/topics/website.md>)

Tags: [algorithm](<https://devfeed.tech/tags/algorithm.md>), [cycling](<https://devfeed.tech/tags/cycling.md>), [data](<https://devfeed.tech/tags/data.md>), [engineering](<https://devfeed.tech/tags/engineering.md>), [gis](<https://devfeed.tech/tags/gis.md>), [google-maps](<https://devfeed.tech/tags/google-maps.md>), [gps](<https://devfeed.tech/tags/gps.md>), [heat](<https://devfeed.tech/tags/heat.md>), [map](<https://devfeed.tech/tags/map.md>), [mapping](<https://devfeed.tech/tags/mapping.md>), [navigation](<https://devfeed.tech/tags/navigation.md>), [pixel](<https://devfeed.tech/tags/pixel.md>), [real-time](<https://devfeed.tech/tags/real-time.md>), [recursion](<https://devfeed.tech/tags/recursion.md>), [running](<https://devfeed.tech/tags/running.md>), [strava](<https://devfeed.tech/tags/strava.md>), [zoom](<https://devfeed.tech/tags/zoom.md>)

### AI overview

This article explains the algorithm behind Strava's Personal Heatmap, which renders an athlete's GPS activity as a frequency-based heatmap on an interactive world map. It focuses on Mercator projection and recursive map tiling, where 256x256 pixel tiles are served at different zoom levels for real-time navigation.

### Source excerpt

This post discusses the algorithm behind Personal Heatmap, one of Strava's most acclaimed subscriber features. Product Overview The Personal Heatmap feature has been around in some form since 2015, but we gave it a major overhaul in 2020. For those unfamiliar, the heatmap is an aggregated view of an athlete's GPS-enabled activities on Strava. Activity data is rendered onto a map according to path traversal frequency; the more an athlete runs on a road, the brighter -- i.e. "hotter" -- that road shows up on the map. The result is a beautiful color gradient displaying the intricate web of past activities, unique to each athlete. The Personal Heatmap is displayed on an interactive world map, also known as a slippy map. Athletes can seamlessly zoom in and out or pan around to arbitrary views of the map, and their activity heat stays displayed the entire time. To enable this, we must provide a scheme for rendering and serving subsections of the world map on the fly. Enter map tiling. Mercator Projection & Map Tiling Map tiling is the practice of subdividing a map into many discrete images that can be stitched together and rendered as a single image in real-time during map navigation. The first step in choosing a tiling scheme is picking what world map to use. Enter, the Mercator Projection, the most commonly used projection of Earth as a flat, rectangular surface. We use this projection in all of our mapping products, including heatmaps. https://medium.com/media/d9e120d13950dd0f1bb4ee14108aa9a9/href Now, imagine a grid overlaying the Mercator projection. Each grid section is known as a tile, a pixel image with resolution 256x256. Every tile has an associated zoom level, and tiles are defined recursively according to this zoom level. A tile at a given zoom level can be subdivided into four equal sized tiles at a next zoom level. For example, Zoom level 0 displays the entire planet in a single 256x256 pixel image. Zoom level 1 displays the world in four 256x256 pixel images.

## An Intern's Experience Refactoring Strava's Saved Routes Android Feature

DevFeed: [An Intern's Experience Refactoring Strava's Saved Routes Android Feature](<https://devfeed.tech/articles/opportunity-arises-from-the-most-unexpected-26573.md>)

Original publisher: [Read original article](<https://medium.com/strava-engineering/opportunity-arises-from-the-most-unexpected-614e9e13dcb9?source=rss----89d4108ce2a3---4>)

Author: Ryan Paragas

Published: 2022-10-25T16:01:27Z

Content type: opinion

Language: en

Sources: [Strava Engineering](<https://devfeed.tech/sources/strava-engineering.md>)

Topics: [Development](<https://devfeed.tech/topics/development.md>), [Refactoring](<https://devfeed.tech/topics/refactoring.md>), [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [Android](<https://devfeed.tech/topics/android.md>), [Bootcamp](<https://devfeed.tech/topics/bootcamp.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [development](<https://devfeed.tech/tags/development.md>), [engineering](<https://devfeed.tech/tags/engineering.md>), [experience](<https://devfeed.tech/tags/experience.md>), [intern](<https://devfeed.tech/tags/intern.md>), [internships](<https://devfeed.tech/tags/internships.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [refactoring](<https://devfeed.tech/tags/refactoring.md>), [route](<https://devfeed.tech/tags/route.md>), [strava](<https://devfeed.tech/tags/strava.md>)

### AI overview

Ryan Paragas describes his 2022 internship at Strava, including his team's work on filters for Saved Routes. He explains how the Android team began refactoring a large routes presenter into separate presenters, view delegates, and filter factories, while he learned Kotlin and project-scale development.

### Source excerpt

About Me: Hey there! My name is Ryan, and I come from an unconventional background. I am not like most interns from the group in 2022. I've dropped out of college 3 times, worked in different fields for about 10 years, then transitioned into a bootcamp. Now working with Strava, they have set the expectation of what it should be like working in a professional environment. My Experience at Strava: Strava has been nothing but a wonderful experience. The weekly events they hosted to really engage the interns are motivational. The weekly AMAs were definitely my favorite of all the intern events. We got to meet the leaders of Strava and get to know them personally. The person I was most inspired by was Claude Jones. Claude also came from an unconventional background. He is a self taught programmer and worked his was up to VP of Engineering, leads motivational talks, and writes his own children books. From him I've learned that even if I don't come from a university, then I'll be able to make it in this field. So long as I continue to develop myself. https://medium.com/media/adf714e44d6915dfd4229f36178d2c49/href Aside from all the events we got to participate in, the support from my team, mentors, and managers provided for me was a whole new experience. I was given the chance to learn so much, and that definitely did not go to waste. The Project: I am on the Athlete Services Team, and my team's project was to create filters for the Saved Routes. The designs wanted us to be able to filter by sport, key word, distance, elevation, whether the route is starred or not, and who it is created by. Development: Creating this feature sounds easy right? Get the state of the filters, save it to the sheet, and apply it to the query. Yes, but there is more to it. The routes presenter and all of its associated classes are huge. So the android team wants to start refactoring that class into separate presenters, view delegates, and filter factories. Which I had the pleasure to start. In al