Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save tadwohlrapp/73864c03734a14a9d27cc15e4fa142ba to your computer and use it in GitHub Desktop.
Save tadwohlrapp/73864c03734a14a9d27cc15e4fa142ba to your computer and use it in GitHub Desktop.
How to Export Google Podcasts listening history

How to Export your Google Podcasts listening history

Since Google doesn't provide any method to export or download your listening history, I wanted to find a way to preserve that data for later reference when setting up a new podcast app. I came up with the following script that can be run in your browser console to retrieve and export your Google Podcasts listening history as a CSV file.

NEVER RUN CODE YOU DON'T UNDERSTAND.

Running untrusted code in your browser console can potentially be harmful, so it's important to understand what the code does before executing it. I've included comments in the code to explain its functionality.

Instructions:

  1. Open Google Podcasts (https://podcasts.google.com) in your browser and make sure you're logged in to your account.
  2. Right-click anywhere on the page and select "Inspect" or "Inspect Element" to open the browser's developer tools.
  3. Navigate to the "Console" tab.
  4. Copy and paste the code below into the console and press Enter.
  5. The code will fetch your listening history and generate a CSV file named google_podcasts_listening_history.csv. Your browser will prompt you to download the file.

The generated CSV File has the following format:

podcast date episode played
Some Podcast 2022-07-04 #3 Our last episode
Some Podcast 2022-06-01 #2 JavaScript is weird
Some Podcast 2022-05-02 #1 Welcome
The Best Podcast 2023-09-16 3. Episode three 56%
The Best Podcast 2023-08-29 2. Electric Boogaloo
The Best Podcast 2023-08-13 1. First Episode

Columns explained:

  • podcast: Podcast Name (sorted ascending)
  • date: Episode Date (sorted descending for each podcast)
  • episode: Episode Name
  • played: Your listening progress. Either a percentage or if it's anything over 95% then the episode is marked as played fully with a "✅"

Resources:

If you're having trouble understanding or running the code, you can refer to these resources:

// Get necessary data from the WIZ_global_data window object
const sid = window.WIZ_global_data.FdrFJe
const bl = window.WIZ_global_data.cfb2h
const at = encodeURIComponent(window.WIZ_global_data.SNlM0e)
// Get document language and generate random request ID
const hl = document.documentElement.lang
const reqid = Math.round((Math.random() * 100000) + 300000)
// Define the RPC IDs for subscriptions and feed (endpoints for batchexecute calls)
const rpcids = {
"subscriptions": "Saeaed",
"feed": "ncqJEe",
}
// Define the options for the fetch requests
const fetchOptions = body => {
return {
"headers": {
"accept": "*/*",
"cache-control": "no-cache",
"content-type": "application/x-www-form-urlencoded;charset=UTF-8",
"pragma": "no-cache",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"sec-gpc": "1",
"x-same-domain": "1"
},
"referrer": "https://podcasts.google.com/",
"referrerPolicy": "origin",
"body": body,
"method": "POST",
"mode": "cors",
"credentials": "include"
}
}
// Array to store all played episodes
const allPlayedEpisodes = []
// Function to get all podcast IDs from the subscriptions
async function getAllPodcastIds() {
try {
// Fetch data from the "subscriptions" endpoint
const response = await fetch(`https://podcasts.google.com/_/PodcastsUi/data/batchexecute?rpcids=${rpcids.subscriptions}&source-path=%2Fsubscriptions&f.sid=${sid}&bl=${bl}&hl=${hl}&_reqid=${reqid}`, fetchOptions(`f.req=%5B%5B%5B%22${rpcids.subscriptions}%22%2C%22%5B%5D%22%2Cnull%2C%223%22%5D%5D%5D&at=${at}&`));
const data = await response.text();
// Parse the response data to get the individual podcast IDs
const subscriptionsRaw = JSON.parse(JSON.parse(data.replace(")]}'", "").trim())[0][2])[0]
const allPodcastIds = []
subscriptionsRaw.forEach((subscription) => {
const podcastId = subscription[10]
allPodcastIds.push(podcastId)
});
// Return the array of podcast IDs
return allPodcastIds
} catch (err) {
console.log(err);
}
}
// Function to get played episodes for a given podcast ID
async function getEpisodesPlayed(podcastId) {
try {
// Fetch data from the "feed" endpoint
const response = await fetch(`https://podcasts.google.com/_/PodcastsUi/data/batchexecute?rpcids=${rpcids.feed}&source-path=%2Ffeed%2F${podcastId}&f.sid=${sid}&bl=${bl}&hl=${hl}&_reqid=${reqid + 1000}`, fetchOptions(`f.req=%5B%5B%5B%22${rpcids.feed}%22%2C%22%5B%5C%22${podcastId}%5C%22%5D%22%2Cnull%2C%221%22%5D%5D%5D&at=${at}&`));
const data = await response.text();
// Parse the response data to get the individual episodes
const episodesRaw = JSON.parse(JSON.parse(data.replace(")]}'", "").trim())[0][2])[1][0];
const episodesPlayed = [];
episodesRaw.forEach((episode) => {
// Ignore unplayed episodes
if (null != episode[3]) {
const podcastName = episode[1];
const episodeName = episode[8];
// Generate row of data containing podcast name, date, episode name and progress
const episodeData = [
podcastName.includes(',') ? `"${podcastName}"` : podcastName,
new Date(episode[11] * 1000).toISOString().split('T')[0],
episodeName.includes(',') ? `"${episodeName}"` : episodeName,
episode[3] > 0.95 ? "✅" : Math.round(episode[3] * 100).toString() + "%"
];
episodesPlayed.push(episodeData);
}
});
// Return the array of played episodes for the podcast
return episodesPlayed;
} catch (err) {
console.log(err);
}
}
// Function to log all played episodes and generate the CSV file
async function logAllPlayedEpisodes() {
// Get all podcast IDs
const allMyIds = await getAllPodcastIds();
// Get played episodes for each podcast ID
const allPlayedEpisodes = (await Promise.all(allMyIds.map(async podcastId => {
const playedEpisodesInThisPodcast = await getEpisodesPlayed(podcastId);
return playedEpisodesInThisPodcast;
}))).flatMap(episodes => episodes);
// Sort the played episodes: first ASC by podcast name and then DESC by date
allPlayedEpisodes.sort((a, b) => {
const podcastComparison = a[0].toLowerCase().localeCompare(b[0].toLowerCase());
if (podcastComparison !== 0) {
return podcastComparison;
}
return b[1].localeCompare(a[1]);
});
// Generate the CSV content
let csvContent = "podcast,date,episode,played\n"
+ allPlayedEpisodes.map(episode => episode.join(",")).join("\n");
// Download the CSV file
const csvBlob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
const csvUrl = URL.createObjectURL(csvBlob);
const link = document.createElement('a');
link.setAttribute('href', csvUrl);
link.setAttribute('download', 'google_podcasts_listening_history.csv');
link.click();
}
// Call the function to log all played episodes and generate the CSV file
logAllPlayedEpisodes()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment