This post is a response to a recent
similar article . I will try to tell you how to automate the actions described in it.
The article looked at how the Strava Heatmap maps are useful for tourists and cyclists and how to connect a navigation application on a smartphone to them using the example of Osmand. The fact is that to download each piece of the card you need to specify the parameters with authorization data. Like that:
GET https://heatmap-external-{abc}.strava.com/tiles-auth/all/hot/{z}/{x}/{y}.png?px=256&Signature={CloudFront-Signature}&Key-Pair-Id={CloudFront-Key-Pair-Id}&Policy={CloudFront-Policy}
In order to obtain this data, it was suggested to log in to the Strava website from a desktop browser. As a result, cookie files should appear in the browser. You need to find the required lines in them and copy them to the request address. And then manually enter the request into Osmand so that he can download the map with his help.
However, this method is not very convenient, because the authorization data is quickly becoming obsolete and you have to repeat the above steps every few days. In this article I will explain how to automate the method described above.
')
Add an intermediate link
So that the user doesn’t have to replace the request URL in the smartphone each time the cookie data expires, you need to specify some unchanged URL. I have a link to my server application. This application will redirect the user to different addresses depending on the specified parameters.
https://anygis.herokuapp.com/Tracks_Strava_All/{x}/{y}/{z}
To get to the essence faster, I will not elaborate on the description of this server application. I will tell only about his main actions.
If a tile with a zoom of up to 12 is requested (such as Stava returns without authorization), the user is immediately redirected to the public URL.
https://heatmap-external-a.strava.com/tiles/all/hot/10/619/318.png
If not, the check is performed. For quick access, the application stores the latest working version of the cookie in its database. When it receives a request, it parses this file and creates a URL with all the parameters supplied.
It turns out something like this https://heatmap-external-a.strava.com/tiles-auth/all/hot/10/619/318.png?px=256<b>&Signature</b>=Q47FWl1RX-5tLNK9fGfa7hdoxqwwjCLfrxwb~L3eke8h~glz5IBHmkLmu8ofh6eNWUM3usHTz4Z3rypbQGByC2jRhdzL2iJndIOu2TY9ZU34YUJV9QgMEf0L5cDHGjEsksYSVdkCqNRvOMnnzUc96wR9sktK2a0pcsI~E5eNvqjfsGbSWi6KCdfc1-~2D8t9YjbKftokhvMY20pM~PD6Y-fGYmpoTO5LOyMfIYboXnKGm29VnA9kA8LIxD-LzpADWO81i4pOMBvkVkJuLBGtO96a79P5D4tRP05DpI7y457LuKcuqRZaVQRB1L2AXgKvQgnx6nqr9T2jRAZNoy06ng__ <b>&Key-Pair-Id</b>=APKAIDPUN4QMG7VUQPSA <b>&Policy</b>=eyJTdGF0ZW1lbnQiOiBbeyJSZXNvdXJjZSI6Imh0dHBzOi8vaGVhdG1hcC1leHRlcm5hbC0qLnN0cmF2YS5jb20vKiIsIkNvbmRpdGlvbiI6eyJEYXRlTGVzc1RoYW4iOnsiQVdTOkVwb2NoVGltZSI6MTU1ODUwODc2Mn0sIkRhdGVHcmVhdGVyVGhhbiI6eyJBV1M6RXBvY2hUaW1lIjoxNTU3Mjg0NzYyfX19XX0_
LzpADWO81i4pOMBvkVkJuLBGtO96a79P5D4tRP05DpI7y457LuKcuqRZaVQRB1L2AXgKvQgnx6nqr9T2jRAZNoy06ng__ https://heatmap-external-a.strava.com/tiles-auth/all/hot/10/619/318.png?px=256<b>&Signature</b>=Q47FWl1RX-5tLNK9fGfa7hdoxqwwjCLfrxwb~L3eke8h~glz5IBHmkLmu8ofh6eNWUM3usHTz4Z3rypbQGByC2jRhdzL2iJndIOu2TY9ZU34YUJV9QgMEf0L5cDHGjEsksYSVdkCqNRvOMnnzUc96wR9sktK2a0pcsI~E5eNvqjfsGbSWi6KCdfc1-~2D8t9YjbKftokhvMY20pM~PD6Y-fGYmpoTO5LOyMfIYboXnKGm29VnA9kA8LIxD-LzpADWO81i4pOMBvkVkJuLBGtO96a79P5D4tRP05DpI7y457LuKcuqRZaVQRB1L2AXgKvQgnx6nqr9T2jRAZNoy06ng__ <b>&Key-Pair-Id</b>=APKAIDPUN4QMG7VUQPSA <b>&Policy</b>=eyJTdGF0ZW1lbnQiOiBbeyJSZXNvdXJjZSI6Imh0dHBzOi8vaGVhdG1hcC1leHRlcm5hbC0qLnN0cmF2YS5jb20vKiIsIkNvbmRpdGlvbiI6eyJEYXRlTGVzc1RoYW4iOnsiQVdTOkVwb2NoVGltZSI6MTU1ODUwODc2Mn0sIkRhdGVHcmVhdGVyVGhhbiI6eyJBV1M6RXBvY2hUaW1lIjoxNTU3Mjg0NzYyfX19XX0_
After that, it sends the HEAD request to this address to check if it is available or not. If the status code “200 Success” comes back, then the cookie is still working. The application simply redirects the user to this address and his map is perfectly loaded.
But if the code “401 Unauthorized” arrives, then the cookie is outdated and you need to get them again. In this case, the application runs a script to get the authorization data.
Auto login
The first thought that comes to mind is to get authorized using the Strava API. Alas, but I did not manage to pull out the necessary parameters from there. So I decided to take a detour.
To do this, I used the browser with a remote control of Headless Chrome and wrote a script for it, so that it “physically” loaded the login page, entered the login and password, and then clicked on the button.
For this, there is the Puppeteer library, which is able to control the browser using Node.js scripts. The syntax is well described in
this article . I suggest to get acquainted with it yourself.
After reading it, the only question that remains is how to run our scripts. If you are an experienced Node.js developer, you can skip this section. For the rest I can offer to use the ready service from
Apify.com . This will save us from having to create and configure your server. A free account is enough for our tasks.
Apify account settings to run the scriptFirst you need to register on this service. After that, open the section with your account, go to the Actors section and create a new script.

In the Name field, specify the name that will be used when the script is run via Api. Click Save and go to the Source page.

To launch Headless Chrome, select the server image “Node.js 10 + Chrome on Debian” and click Save.

Now go to the Api section and copy the URL of the POST request, with which we will run our script.

In the body of this request, you can attach JSON with the data for our script. I will send there my login and password for authorization on Strava.
{ "email": "your_nick@gmail.com" , "password": "Your_Password" }
Script to automatically receive cookie data from StravaNow let's go back to the Source section and go to the window with the code editor. Our script will look like this:
const Apify = require('apify'); Apify.main(async () => {
Final stage
When the script runs, it will return a cookie with authorization data. The server application will save it to its database and will use Strava cards for all subsequent requests. Until the cookie expires and you do not have to repeat this procedure again. Fortunately, now everything happens automatically. Without unnecessary action by the user.
Alas, not everything is so smooth. This method has a weak point - this is the speed of work. The fact is that it takes some time to start the server, load a remote browser, load two web pages and authorize on each of them. According to my estimates, more than a minute is coming out.
During this time, the navigation application will simply terminate the download due to exceeding the timeout. Therefore, it is better to immediately return the user error code 401, so as not to land the battery once again.
To do this, the server application will set the flag when it realizes that the cookie data is out of date. After this, it will send a request to run the script, and users will immediately return an error code. In other words, the server will be unavailable for a minute.
And when the answer from our script comes with a new cookie, the application will save them to its database and remove the flag. After that, the server will start working again in normal mode and instantly redirect the user to the pages for downloading the map.
Result
The result of our works are immutable URLs with which users can connect their navigator to the maps of Strava.
https://anygis.herokuapp.com/Tracks_Strava_All_HD/{x}/{y}/{z} https://anygis.herokuapp.com/Tracks_Strava_Run_HD/{x}/{y}/{z} https://anygis.herokuapp.com/Tracks_Strava_Ride_HD/{x}/{y}/{z} https://anygis.herokuapp.com/Tracks_Strava_Water_HD/{x}/{y}/{z} https://anygis.herokuapp.com/Tracks_Strava_Winter_HD/{x}/{y}/{z}
Alternatively, you can make ready-made presets with these addresses for your navigator. For example,
on this village I posted such presets in formats for Osmand, Locus, GuruMaps and Orux. Links to download Strava maps are located in the “Complete Set” section in the “Overlay” or “Global - OSM - Ways” subsections.