Skip to content

Instantly share code, notes, and snippets.

@petersvp
Created February 3, 2021 20:30
Show Gist options
  • Select an option

  • Save petersvp/270f7d5d7d548448f4897586a0d389c0 to your computer and use it in GitHub Desktop.

Select an option

Save petersvp/270f7d5d7d548448f4897586a0d389c0 to your computer and use it in GitHub Desktop.
Batch Query Steam Keys for activation on SteamWorks
// 1. GO TO SteamWorks, into the Query CD Key page, here: https://partner.steamgames.com/querycdkey/
// 2. Fill in your keys below:
// 3. Go to DevTools, Console, and paste all of this here there!
// 4. Report will be printed to the console.
keys = `
0ZQR4-N0H7K-AEJ77
D05V5-P47AP-4ET3Q
GGJZ5-ZN0BR-F74C5
FWZP4-2IXHB-GYV3A
`
var keylist = keys.split("\n");
keylist.forEach(key => {
if(key.length<17) return;
function reqListener () {
let body = this.responseText;
let result = body.split('<h2>Activation Details</h2>')[1];
if (!result && !err) {
console.log('Error quering CD Key ' + key);
}
result = result.split('</table>')[0];
result = result.match(/<td>.*<\/td>/g);
result = result.map(function (line) {
return line.replace(/<[^>]*>/g, '');
});
let line = [key, (result[0] === 'Activated') ? '"' + result[1] + '"' : result[0]].join('\t');
console.log(line);
}
var oReq = new XMLHttpRequest();
oReq.addEventListener("load", reqListener);
oReq.open("GET", "https://partner.steamgames.com/querycdkey/cdkey?cdkey="+key+"&method=Query");
oReq.send();
});
@Jimbly

Jimbly commented Feb 4, 2021

Copy link
Copy Markdown

Nice idea! You might want to rate limit this or add a warning though - checking 1000 keys at once will look a lot like a DoS attack on partnern.steamgames.com and will get this kind of querying banned quickly =).

@Wikzo

Wikzo commented Feb 10, 2022

Copy link
Copy Markdown

@petersvp @Jimbly Did you make a version with a rate limiter? My JS skills are not good enough. I tried to look into Underscore via https://stackoverflow.com/questions/5031501/how-to-rate-limit-ajax-requests, but didn't manage to make a JS version I could plug into the DevTools browser console without an HTML file.

@petersvp

petersvp commented Feb 10, 2022 via email

Copy link
Copy Markdown
Author

@Wikzo

Wikzo commented Feb 10, 2022

Copy link
Copy Markdown

Thanks for the quick reply! Do you have an idea of how many keys is "safe" to check in one chunk?

And what did you mean with wrapping the code in spiletter? (sorry, I don't know a lot about JS)

@Jimbly

Jimbly commented Feb 10, 2022

Copy link
Copy Markdown

If you've got a ton of keys to query, the Node.js version that does this is inherently rate limited (limits to one request in-flight at a time), though it takes a little more to set up https://gist.github.com/Jimbly/9f6c6a0d9414310347f2803902ac7bb7

I think it'd be pretty straightforward to change this one to do the same (and reduce a ton of code) now that await fetch() is something that works in modern browsers, instead of using XMLHttpRequest... but that sounds like work, so this is what you've got ;).

@Wikzo

Wikzo commented Feb 10, 2022

Copy link
Copy Markdown

@Jimbly Thank you. We've been using your Node.js tool for a few years to great success. I was recently put in charge of it and then I saw the comment from Peter and thought I'd look into the updated version. Guess we'll stick to Node.js for now :)

@petersvp

petersvp commented Feb 10, 2022 via email

Copy link
Copy Markdown
Author

@Jimbly

Jimbly commented Feb 10, 2022

Copy link
Copy Markdown

Yeah, a couple hundred keys should be fine in the browser, it's not that much traffic. Also, most browsers usually rate limit to 7 connections per host, although in modern days if Valve has switched to a load balancer/server that supports HTTP2 that goes out the window. If you're querying thousands of keys I might be a little careful =).

@petersvp

Copy link
Copy Markdown
Author

Chrome does rate-limit too, I managed to batch-check 500 keys with no issue. I want to keep this implementation as CLEAN as possible, so people can read what it do and not fear of self-xss attack towards them - after all, pasting untrusted code in the browser console is real concern nowadays, so i at least tried to make my implementation clear what it does :)

@tcurtis526

Copy link
Copy Markdown

Appreciate this.

@Goury

Goury commented Jul 22, 2024

Copy link
Copy Markdown

I was about to code a better snippet based on this, but decided that this one is good enough.
Thanks.

The only issue is that it won't find <h2>Activation Details</h2> if your language is set to anything other than English.

@petersvp

petersvp commented Oct 10, 2024

Copy link
Copy Markdown
Author

I was about to code a better snippet based on this, but decided that this one is good enough. Thanks.

The only issue is that it won't find <h2>Activation Details</h2> if your language is set to anything other than English.

Just change the text to whatever your language is, or add ?hl=en to the query string. This code is written in such a way that a human being should be able to quickly verify what the script is all about and you have to edit the script anyways to feed in your keys.

@AumCoin

AumCoin commented Jan 27, 2025

Copy link
Copy Markdown

Do I need to be signed up as a developer and have a paid developer account? Will this work with any key or just keys for my own games?

@petersvp

Copy link
Copy Markdown
Author

Yes, and the developer account must have access to the game you are querying too.

@hydrok

hydrok commented Mar 20, 2025

Copy link
Copy Markdown

If you need to add a delay for the purpose of rate limiting each request, try this code. I wrapped the original code in a setTimeout() and var interval is the amount of time (in ms) to delay. Thanks again for this solution!


keys = `
0ZQR4-N0H7K-AEJ77
D05V5-P47AP-4ET3Q
GGJZ5-ZN0BR-F74C5
FWZP4-2IXHB-GYV3A
`

    var keylist = keys.split("\n");
	var interval = 1000;

keylist.forEach((key, i) => {
	setTimeout(() => {	
		if (key.length < 17)
			return;
		function reqListener() {
			let body = this.responseText;
			let result = body.split('<h2>Activation Details</h2>')[1];
			if (!result && !err) {
				console.log('Error quering CD Key ' + key);
			}
			result = result.split('</table>')[0];
			result = result.match(/<td>.*<\/td>/g);
			result = result.map(function (line) {
				return line.replace(/<[^>]*>/g, '');
			});
			let line = [key, (result[0] === 'Activated') ? '"' + result[1] + '"' : result[0]].join('\t');
			console.log(line);
		}
		var oReq = new XMLHttpRequest();
		oReq.addEventListener("load", reqListener);
		oReq.open("GET", "https://partner.steamgames.com/querycdkey/cdkey?cdkey=" + key + "&method=Query");
		oReq.send();
	}, i * interval);
});

@petersvp

petersvp commented Mar 20, 2025 via email

Copy link
Copy Markdown
Author

@bfmmdev

bfmmdev commented Apr 7, 2025

Copy link
Copy Markdown

Getting errors expecting expecting semicolon before error.

What am I doing wrong?

EDIT: Clear console totally before running the script. Yes, this includes deleting the precurors "allow pasting" and all that.

@Goury

Goury commented Apr 7, 2025

Copy link
Copy Markdown

What am I doing wrong?

Not telling us the exact and whole error

@bfmmdev

bfmmdev commented Apr 7, 2025

Copy link
Copy Markdown

Doesn't matter what the issue is because I posted the solution for the issue I was running into. TLDR; ensure the console is completely empty before running the script.

@ThomazDiniz

Copy link
Copy Markdown

Just wanted to say thank you, I've used your code to make one that returns a list of not yet used keys.

@heintzer

Copy link
Copy Markdown

This is fantastic, thank you so much. Kinda insane Steamworks doesn't just spit out status of keys in the CSV when you download batches!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment