Tweaking Spotify For Podcasters Feature Flags

Fiddling with Fiddler to enable hidden features in the podcaster dashboard.

By Den Delimarsky in Hackery

December 30, 2021

Spotify’s foray into podcasting may be fairly recent, but I’m already discovering some interesting APIs that I can play with. The podcaster dashboard is tremendously useful and offers way more data than Apple and Google combined (with better reliability too), so the more I use it, the more I started thinking that it would be helpful for me to build some kind of automation mechanism to ingest the data into my own storage and then process it outside the default dashboard boundaries. In the process, I also spotted a little thing that I wanted to share with readers, and that is the ability to enable experimental features inside your podcast private view.

The dashboard in question is available at:

1
https://podcasters.spotify.com/catalog

Spotify podcaster dashboard screenshot

In on itself, this seems pretty typical - a view that is powered by some backend API, that is populated dynamically whenever the page loads. However, what attracted my curiosity was a specific API call that is executed when the page is first loaded - a GET request to the following endpoint:

1
https://generic.wg.spotify.com/podcasters/v0/user/me

This response is authenticated (it uses a bearer token), and returns an interesting response:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
    "authorizations": {
        "spotify:show:<SHOW_ID>": [
            "viewer",
            "editor",
            "admin"
        ]
    },
    "avatarUrl": "https://i.scdn.co/image/<AVATAR_ID>",
    "dataRange": {
        "from": "2015-05-01",
        "until": "2021-12-28"
    },
    "displayName": "<USER_NAME>",
    "emailAddress": "<USER_EMAIL>",
    "employee": false,
    "features": {
        "s4pod-home-card-playlists": "Release",
        "s4pod-home-view-for-all": "Release",
        "s4pod-show-episode-v2-button": "Control",
        "s4pod-show-localized-content": "Release",
        "s4pod-show-site-alert": "Control",
        "s4pod-show-wrapped-banners": "Release"
    },
    "needsToAcceptTerms": false,
    "uri": "spotify:user:<USER_NAME>",
    "username": "<USER_NAME>"
}

On the surface, this also seems like a standard API response for a user information request. What’s interesting about it, though, is the features block. Spotify uses it to determine what features to enable for podcast managers in the dashboard based on values in this list. Now, it seems that for most features I am in the Release group, which means that they are enabled by default. For others, it appears I am in the Control one. I’d very much like to be in the treatment group to see what those features are about, but that also meant that I needed to intercept and alter the request on the fly before it gets to Spotify. Luckily, I’ve been using a pattern similar to this when I was exploring the Twitter verification API.

The problem with the approach I used earlier is that Spotify chains requests, and I would need to be in stop-and-go traffic to get it to work properly - that’s not really optimal. Fortunately, Fiddler has this amazing capability called AutoResponder. The gist of this feature is that it enables one to automatically respond with pre-baked content to any requests matching a given rule. Because I want to only intercept one request and the JSON body is static, I can use AutoResponder to only send modified JSON data when a match for the URL comes up.

In my case, it looked like this:

Fiddler AutoResponder rule

The 200_SpotifyJSON.dat file that I use as a returned value is a response template that is stored in Fiddler’s installation folder (e.g., C:\Users\<YOUR_NAME>\AppData\Local\Programs\Fiddler\ResponseTemplates) and looks like this snippet:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
HTTP/1.1 200 OK
content-type: application/json; charset=UTF8
cache-control: private, max-age=0
access-control-allow-origin: *
access-control-allow-headers: Accept, Authorization, Origin, Content-Type, Spotify-App, Spotify-App-Version, App-Platform, Retry-After, X-Spotify-Connection-Id, SPA-Preferred-Publisher, SPA-Current-Team, X-Cloud-Trace-Context, X-Client-Id, x-twitch-jwt, X-SamsungDaily-Version, X-ClientAttribute-Version, client-token, content-access-token
access-control-allow-methods: GET, POST, OPTIONS, PUT, DELETE, PATCH
access-control-allow-credentials: true
access-control-max-age: 604800
strict-transport-security: max-age=31536000
x-content-type-options: nosniff
date: Thu, 30 Dec 2021 03:24:25 GMT
server: envoy
Via: HTTP/2 edgeproxy, 1.1 google
Alt-Svc: clear
Content-Length: <CONTENT_LENGTH>

<JSON_BODY>

When you first create a response template, make sure to restart Fiddler for it to appear in the list of existing templates.

With this functionality in tow, I was now able to modify one particular response to my liking, and I started by enabling the s4pod-show-episode-v2-button and s4pod-show-site-alert features (flagging them as Release rather than Control). This resulted in immediate changes to the dashboard:

Spotify for Podcasters dashboard alert

Clearly, s4pod-show-site-alert is a note that is being added to the dashboard to alert of data delays. Not that interesting.

What about s4pod-show-episode-v2-button? From the name, this seems like something that needs to be associated with a podcast episode - that’s our hint as to where to look. I now got a V2 switch available for the Episode Performance metric:

Enabling a V2 flag in podcast episodes for Spotify Podcasters

When flipped, it appears that the data is reloaded by exectuting an API call to:

1
https://generic.wg.spotify.com/podcasters/v0/episodes/<EPISODE_ID>/performance

With the V2 toggle enabled, the request is issued to:

1
https://generic.wg.spotify.com/podcasters/v0/episodes/<EPISODE_ID>/performance?v2=true

Running these requests through Postman and Fiddler doesn’t show any surface-level differences, but looks like Spotify is experimenting with a potential alternative view over the metric.

The feature flags seem to be interesting from a curiosity perspective, but there was also another one that I overlooked:

1
"employee": false

What if I set this to true? Well, it looks like the UI changes a bit to open another view into the world - that of networks:

Showing a podcast with a network entry in the image

Notice that in the image above, upon reload with "employee": true, I now see an extra “from” label that says Spotify Direct Submission. That is a moniker for “submitted the podcast via their own RSS feed” - it’s the Licensor/Hosting Provider from the podcaster dashboard, and it links off to another page:

1
https://podcasters.spotify.com/network/<NETWORK_ID>

At that point, API calls start failing with a 403 Forbidden because, naturally, my bearer token does not have the right permissions. However, it does seem like there are APIs to query episode data on a per-network basis, such as:

1
2
https://generic.wg.spotify.com/podcasters/v0/networks/<NETWORK_ID>/topEpisodes?start=2021-12-22&end=2021-12-28
https://generic.wg.spotify.com/podcasters/v0/user/networks

The latter returned an empty array, and my catalog became quite empty without network visibility. This concluded my explorations with the podcaster dashboard - there are APIs that I am interested in using, and others that are interesting to learn about just for curiosity’s sake. I genuinely hope that Spotify formalizes a podcasting API surface that will enable developers to do more with their podcast data, especially considering how ahead they are in terms of experience compared to other services.

Want to get more notes like the above? Subscribe to The Den!

A monthly newsletter about product management, engineering, and tinkering with code.

Feedback

Have any thoughts? Let me know on Twitter!