New way to upload custom screenshots to Steam

The process of uploading a (custom) screenshot is similar to what it used to be.

First find the relevant folder for the game you want to upload screenshots for. This is usually something like C:\Program Files (x86)\Steam\userdata\<user id>\<some number>\remote\<game id>\screenshots\. Refer to this guide (also linked in the question) if you still need help finding the game id. Put your screenshots in that folder. Open steam, right-click the game and click "Show screenshots". Let it load all the thumbnails. Exit the dialog, then exit steam completely (by right-clicking the notification icon and clicking "Exit").

Go to C:\Program Files (x86)\Steam\userdata\<user id>\<some number>\ (that is a few folders above the folder you put your screenshots in, and open screenshots.vdf in an editor that respects both windows and unix line endings, such as VIM or Notepad++. Now find the entry for each of your screenshots. In my case I was searching for the screenshot 20160809224314_2.jpg.

Editing screenshots.vdf in vim

The problem you encountered is because Steam now fills in the vrfilename entry with a non-existing file. Remove that filename so that it says "vrfilename" "". You might need to set imported to "0" depending on if you tried to upload it before.

Removed vrfilename and set imported to 0 for my screenshot

Save the file, then start steam again. Right-click the game again, then click "show screenshots". It now should allow you to upload your image.


Well, I promised to come back here with my own solution to this problem, and here I am with a cross-platform open-source utility to simplify the whole process.

At first I thought I'd do it as a Windows batch file, but doesn't provide a good way to work with regular expressions. Then I thought maybe Python script will do it, but hey, nobody wants to install an interpreter and mess with command-line tools. At last I thought I should give Qt a try, and I didn't regret that choice!

Meet SteaScree, Steam Cloud screenshot uploader: https://steascree.download

Here is what it is like: enter image description here

It works in Windows, Linux and macOS.

It's a bit ugly, but Qt has messy UI builder, and this is my first software project in recent times, so please don't judge by the looks.

The sources are shared via GitHub, so if you'd like to report a bug or improve this tool, welcome. This is my first project with Qt, so there may be some issues. Please report them on the GitHub as well.


Steam doesn't care about filename nor creation date. After you upload screenshot there is only "upload date" displayed. Real date is only used in Screenshots window so you see them ordered properly before upload.

While Sumurai8's answer is complete, some people may have problem with locating proper directory. That's why I wrote script to automate it a bit. It requires Python (you need to install it if you have Windows, other systems should already have it) and VDF Python module.

#!/usr/bin/env python
from __future__ import print_function
from time import sleep
import vdf, platform, os, glob, codecs, subprocess, shutil, time, sys
try:
    import winreg
except ImportError:
    import _winreg as winreg
try:
    input = raw_input
except NameError:
    pass
def find_default_steam_path():
    return {
        "Windows": lambda: winreg.QueryValueEx(
            winreg.CreateKey(winreg.HKEY_CURRENT_USER,r"Software\Valve\Steam"),
            "SteamPath"
        )[0],
        "Linux": lambda: os.path.expanduser("~/.local/share/Steam"),
        "Darwin": lambda: os.path.expanduser("~/Library/Application Support/Steam")
    }[platform.system()]()
def get_libraries(path):
    libraries = [path]
    ignored = ["TimeNextStatsReport", "ContentStatsID"]
    for k, v in vdf.parse(open(os.path.join(path, "steamapps", "libraryfolders.vdf")))["LibraryFolders"].items():
        if k not in ignored:
            libraries.append(os.path.normpath(v))
    return libraries
def get_games_vdfs(libs):
    vdfs = []
    for lib in libs:
        vdfs += glob.glob(os.path.join(lib, "steamapps", "*.acf"))
    return vdfs
def get_users(path):
    users = []
    for k, v in vdf.parse(open(os.path.join(path, "config", "loginusers.vdf")))["users"].items():
        users.append([v["PersonaName"], str(int(k)-0x110000100000000)])
    return sorted(users, key=lambda x: x[0].lower())
def get_user_data(path, user_id):
    return vdf.parse(codecs.open(os.path.join(path, "userdata", user_id, "config", "localconfig.vdf"), 'r', 'utf8'))["UserLocalConfigStore"]
def get_games(vdfs):
    games = []
    for v in vdfs:
        game = vdf.parse(open(v))["AppState"]
        if all(g[1] != game["appid"] for g in games):
            games.append([game["name"], game["appid"]])
    return sorted(games, key=lambda x: x[0].lower())
def filter_user_games(games, user_data):
    user_games = list(user_data["Licenses"].keys()) + list(user_data["apptickets"].keys())
    for game in games:
        if game[1] not in user_games:
            games.remove(game)
def get_last_game_index(games, user_data):
    last_played = ["", 0]
    for game, v in user_data["Software"]["Valve"]["Steam"]["Apps"].items():
        lp = int(v["LastPlayed"])
        if lp > last_played[1]:
            last_played = [game, lp]
    for i, game in enumerate(games):
        if game[1] == last_played[0]:
            return i
steam_path = os.path.normpath(find_default_steam_path())
steam_binary = os.path.join(steam_path, "steam" + (".exe" if platform.system() == "Windows" else ""))
if not os.path.exists(steam_path):
    steam_path = input("Enter main Steam directory location: ")
users = get_users(steam_path)
libraries = get_libraries(steam_path)
if len(users) == 1:
    user = users[0]
else:
    for i, u in enumerate(users):
        print(i, u[0], sep = ". ")
    user = users[int(input("Choose user: "))]
user_data = get_user_data(steam_path, user[1])
games_vdfs = get_games_vdfs(libraries)
games = get_games(games_vdfs)
filter_user_games(games, user_data)
last_played_index = get_last_game_index(games, user_data)
print()
for i, g in enumerate(games):
    print(i, g[0], sep = ". ")
game_choice = input("Choose game or leave empty for last played game (" + games[last_played_index][0] + "): ")
if game_choice == "":
    game_choice = last_played_index
game = games[int(game_choice)]
print()
screenshot_info_path = os.path.join(steam_path, "userdata", user[1], "760")
dst_path = os.path.join(screenshot_info_path, "remote", game[1], "screenshots")
screenshot_info_path = os.path.join(screenshot_info_path, "screenshots.vdf")
try:
    os.makedirs(dst_path)
except OSError:
    pass
src_path = input("Enter source directory: ")
if len(src_path) > 1 and src_path[0] in ('"\'') and src_path[-1] == src_path[0]:
    src_path = src_path[1:-1]
files_to_move = glob.glob(os.path.join(src_path, "*.[jJ][pP][gG]"))
if len(files_to_move) == 0:
    input("No files to move. Press Enter to exit.")
    sys.exit(1)
for file in files_to_move:
    shutil.move(file, dst_path)
if os.path.exists(screenshot_info_path):
    size_old = os.stat(screenshot_info_path)[-4]
else:
    size_old = 0
mod_old = -1
subprocess.Popen([steam_binary, "steam://open/screenshots"])
while True:
    size_new, _, mod_new = os.stat(screenshot_info_path)[-4:-1]
    if size_old != size_new:
        size_old = size_new
        mod_old = mod_new
    elif mod_old > -1 and time.time() - mod_old > 3:
        break
    sleep(1)
subprocess.call([steam_binary, "-shutdown"])
screenshot_info = vdf.parse(codecs.open(screenshot_info_path, 'r', 'utf8'))
for k, v in screenshot_info["Screenshots"].items():
    for k2, v2 in v.items():
        screenshot_info["Screenshots"][k][k2]["vrfilename"] = ""
vdf.dump(screenshot_info, codecs.open(screenshot_info_path, 'w', 'utf8'))
input("All done! Wait until Steam client closes and press Enter to start it again.")
subprocess.Popen([steam_binary, "steam://open/screenshots"])

How to use?

  1. Save it for example as steam_custom_screenshots.py
  2. On Linux and Mac make it executable
  3. Close Steam
  4. Run script

    • If script can't find Steam installation dir, it will ask you for one
    • If more than one user logged in to Steam on this computer, script will ask you to choose your account
    • You will be asked to choose a game
    • You will be asked to choose a path to your screenshots
    • Script will now move all *.jpg files from path you entered in previous step to correct directory, start Steam so it imports screenshots, close Steam, edit screenshots.vdf file and wait for you to press Enter to run Steam again.

If you still have any problem uploading screenshots, delete Steam/userdata/<your ID>/760/screenshots.vdf file and try again. I just uploaded 283 files this way.

Sidenote: There are several default locations of Steam on Linux machines depending on how you install it. I don't know them, so if you want to share one or you know how to find it with Python, let me know in comment.