Last active
February 18, 2026 00:13
-
-
Save abraxas86/ad72ba46b6cdd86dc63058bba0c629c2 to your computer and use it in GitHub Desktop.
Export collecitons on itch.io as csv files
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name Itch Collection CSV Exporter | |
| // @namespace https://github.com/abraxas86/tampermonkey-scripts/blob/main/itch.io/ | |
| // @version 4.6 | |
| // @description Scroll down to the bottom of your collection, click the button, get CSV of your collection! | |
| // @author Abraxas86 | |
| // @match https://itch.io/c/* | |
| // @match https://itch.io/my-purchases | |
| // @match https://itch.io/b/* | |
| // @match https://itch.io/bundle/* | |
| // @match https://itch.io/s/* | |
| // @require https://gist.github.com/raw/2625891/waitForKeyElements.js | |
| // @require https://raw.githubusercontent.com/eligrey/FileSaver.js/master/src/FileSaver.js | |
| // @grant none | |
| // @icon https://itch.io//static/images/itchio-square-144.png | |
| // ==/UserScript== | |
| /* globals jQuery, $, waitForKeyElements, saveAs */ | |
| // Thank you to LeeThompson for the duplicate title fix, and KindaArtsy for the category scrape! | |
| (function() { | |
| 'use strict'; | |
| const games = []; | |
| let mode = "null"; | |
| let gameID = ""; | |
| let imagePath = ""; | |
| let Title = ""; | |
| let Synopsis = ""; | |
| let Author = ""; | |
| let Genre = ""; | |
| let Category = ""; | |
| let URL = ""; | |
| let Blurb = ""; | |
| let output = "gameid,category,title,author,synopsis,imagepath,url,blurb\n"; | |
| let filename = $('.grid_header > h2:nth-child(1)').text(); | |
| if(!filename) { | |
| filename = $('.stat_header_widget .text_container h2 .object_title').text(); | |
| } | |
| waitForKeyElements(".game_link", makeRed); | |
| if (document.querySelector('[class*=bundle_download_page]')) { | |
| mode = "bundle"; | |
| } else if (document.querySelector('[class*=game_list]')) { | |
| mode = "list"; | |
| } else if (document.querySelector('[id^=game_grid]') || document.querySelector('[class*=bundle]')) { | |
| mode = "grid"; | |
| } else { | |
| mode = "Error"; | |
| } | |
| //alert(mode); | |
| $('.footer').prepend('<span class="csvButton">Export to CSV</span> <input type="text" id="fileName" class="csvText" value=""> <span class="extension">.csv</span><p></p>'); | |
| $('#fileName').attr("value", filename); | |
| $('.csvButton').css({'color':'white','background-color':'grey','border-radius':'10px','padding':'15px','cursor':'pointer'}); | |
| $('.extension').css({'font-size':'14pt'}); | |
| $('.csvText').css({'padding':'5px','border':'none','border-radius':'10px','font-size':'13pt','background-color':'#555555','color':'#BCBCBC','text-align':'right'}); | |
| function makeRed() { | |
| $('.game_link').css("color", "red"); | |
| } | |
| $('.csvButton').click(function() { | |
| // These elements will mess up our data for the CSV. | |
| $('.price_value').remove(); | |
| $('.gif_label').remove(); | |
| console.log("======= Game Package Data ======="); | |
| // GRID MODE | |
| if (mode == 'grid') { | |
| $('.game_cell').each(function() { | |
| const cell = $(this); | |
| // Itch Game ID | |
| gameID = cell.attr('data-game_id'); | |
| console.log("gameID: " + gameID); | |
| // Path to thumbnail | |
| imagePath = cell.find('.lazy_loaded').attr('src'); | |
| console.log("imagePath: " + imagePath); | |
| // Game Title Note: .title is for bundle compatibility | |
| Title = cell.find('.game_link, .title').text().replace(/"/g, '""'); | |
| console.log("Title: " + Title); | |
| // Game URL Note: .title is for bundle compatibility | |
| URL = cell.find('.game_title a, .title').attr('href'); | |
| console.log("URL: " + URL); | |
| // Game Synopsis Note: .short_text is for bundle compatibility | |
| Synopsis = cell.find('.game_text, .short_text').text().replace(/"/g, '""'); | |
| console.log("Synopsis: " + Synopsis); | |
| // Game Author | |
| Author = cell.find('.game_author, .user_link').text().replace(/"/g, '""'); | |
| console.log("Author: " + Author); | |
| // Game Category (from tag link) | |
| Category = cell.find('.cell_tags a').attr('href'); | |
| if(Category == undefined){ | |
| Category = "games"; | |
| } else { | |
| Category = Category.replace(/\//g, ""); | |
| } | |
| console.log("Category: " + Category); | |
| // Game Blurb (user-created comment about library item) | |
| Blurb = cell.find('.blurb_drop').text().trim().replace(/"/g, '""'); | |
| console.log("Blurb: " + Blurb); | |
| // Build Array to push to CSV File, sanitizing data to prevent commas in scraped data from screwing things up | |
| games.push(`"${gameID}","${Category}","${Title}","${Author}","${Synopsis}","${imagePath}","${URL}","${Blurb}"`); | |
| }); | |
| } | |
| // LIST MODE | |
| else if (mode == 'list') { | |
| $('.game_row').each(function() { | |
| const row = $(this); | |
| // Game Title | |
| Title = row.find('.game_link, .title').text().replace(/"/g, '""'); | |
| console.log("Title: " + Title); | |
| // Itch Game ID | |
| gameID = row.find('.game_cell').attr('data-game_id'); | |
| console.log("gameID: " + gameID); | |
| // Path to thumbnail | |
| imagePath = row.find('.game_thumb').attr('src'); | |
| console.log("imagePath: " + imagePath); | |
| // Game URL | |
| URL = row.find('.game_title').attr('href'); | |
| console.log("URL: " + URL); | |
| // Game Synopsis (not avaiable in list mode) | |
| Synopsis = ""; | |
| console.log("Synopsis: " + Synopsis); | |
| // Game Author | |
| Author = row.find('.author_link').text().replace(/"/g, '""'); | |
| console.log("Author: " + Author); | |
| // Game Category (from tag link) | |
| Category = row.find('.cell_tags a').attr('href'); | |
| if(Category === undefined){ | |
| Category = "games"; | |
| } else { | |
| Category = Category.replace(/\//g, ""); | |
| } | |
| console.log("Category: " + Category); | |
| // Game Blurb | |
| Blurb = row.find('.blurb_drop').text().trim().replace(/"/g, '""'); | |
| console.log("Blurb: " + Blurb); | |
| // Build Array to push to CSV File, sanitizing data to prevent commas in scraped data from screwing things up | |
| games.push(`"${gameID}","${Category}","${Title}","${Author}","${Synopsis}","${imagePath}","${URL}","${Blurb}"`); | |
| }); | |
| } | |
| // BUNDLE MODE | |
| else if (mode == 'bundle') { | |
| $('.game_row').each(function() { | |
| const row = $(this); | |
| // Path to thumbnail | |
| imagePath = row.find('.game_thumb').attr('data-background_image'); | |
| console.log("imagePath: " + imagePath); | |
| // Game URL | |
| URL = row.find('.game_title a').attr('href'); | |
| console.log("URL: " + URL); | |
| // Game Title | |
| Title = row.find('.game_title a').text().replace(/"/g, '""'); | |
| console.log("Title: " + Title); | |
| // Game Synopsis | |
| Synopsis = row.find('.game_short_text').text().trim().replace(/"/g, '""'); | |
| console.log("Synopsis: " + Synopsis); | |
| // Game Author | |
| Author = row.find('.game_author a').text().replace(/"/g, '""'); | |
| console.log("Author: " + Author); | |
| // GameID (not available in bundle lists) | |
| gameID = ""; | |
| console.log("gameID: " + gameID); | |
| // Game Category (from tag link) | |
| Category = row.find('.cell_tags a').attr('href'); | |
| if(Category === undefined){ | |
| Category = "games"; | |
| } else { | |
| Category = Category.replace(/\//g, ""); | |
| } | |
| console.log("Category: " + Category); | |
| // Game Blurb (not available in bundle lists) | |
| Blurb = ""; | |
| console.log("Blurb: " + Blurb); | |
| // Build Array to push to CSV File | |
| games.push(`"${gameID}","${Category}","${Title}","${Author}","${Synopsis}","${imagePath}","${URL}","${Blurb}"`); | |
| }); | |
| } | |
| else { | |
| alert("Error: Unable to correctly identify code."); | |
| } | |
| // Format array for CSV output, sanitizing for titles with commas, | |
| // and adding a newline at the end of each title | |
| for (let i = 0; i < games.length; i++) { | |
| output += games[i] + "\n"; | |
| } | |
| filename = document.getElementById("fileName").value; | |
| if (filename === "") { | |
| filename = "collection"; | |
| } | |
| filename = filename + ".csv"; | |
| const blob = new Blob([output], { | |
| type: "text/plain;charset=utf-8" | |
| }); | |
| saveAs(blob, filename); | |
| }); | |
| })(); |
4.5
IntuitiveThinker on Itch had asked if there was a way to differentiate different types of content (games, books, physical games, soundtracks, etc). I couldn't find any way to do this, so I was thinking that adding it to the Blurb is probably the best way to manage it. If Itch ever expands to allow this type of info to be added, I will update the script to reflect the change.
hey i figured out a way to do this, at least in grid mode while on a bundle page (
https://itch.io/b/*)Category = cell.find('.cell_tags a').attr('href'); if(Category == undefined){ Category = "games"; } else { Category = Category.replace(/\//g, ""); }a bit ugly but it works
if(Category === undefined){ may be safer but I'm not a JS expert.
Author
Ahh, sorry for ghosting here... life got lifey. I just updated the script to 4.6 - one day I'll learn how to do proper versioning haha
4.6 adds:
- Bugfix, title scrape hopefully works better now (thanks to @LeeThompson)
- Category scrape - will give you an idea if it's a game, asset, physical game, ect. (thanks @KindaArtsy)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
4.5
hey i figured out a way to do this, at least in grid mode while on a bundle page (
https://itch.io/b/*)a bit ugly but it works