crate-robot

Posted On December 2, 2014 By In Developers With 68826 Views

Creating a Steam Trade Bot with Node.js

Update 2015-07-25: node-steam v1.0 recently was released.  A lot of the functionality of node-steam has drastically changed with this update.  Make sure to install version 0.6.8 when following this guide.  A new version of this article using node-steam 1.0 and trade offers can be found here: https://firepowered.org/developer/create-a-steam-trade-bot-with-nodejs-iojs-updated-for-node-steam-v1-0/

The first part of this article provides some background into Steam trade bots, what options are available, how to setup your system to use Node, and some of the packages you’ll need to get started.  Beyond the first section, I’ll stop talking in generalizations and focus on one specific example.  If you are new to the trade bot scene, please start from the beginning.  If you’re just trying to get a handle on how to write a trade bot but understand what libraries you’ll need, go ahead and skip down to “Writing your first bot”.

Background, environment, and required packages

Creating a Steam trade bot is easier today than it ever has been due to the amount of open source libraries out there.  There are two common libraries available for making a Steam trade bot: Jessecar’s C# version (which uses VoiDeD’s SteamKit library), and Seishun’s Node.js version (which requires his port of SteamKit).  There are some less-common ones floating around in Java and Python, but they’re mostly dead projects.  For this article though, we’ll be focusing on just the Node.js version since JavaScript is both more portable and easier to write than C#.

 Setting up your environment

Note: I’ve never really done development work on Windows, so any Windows-specific instructions may be a little rough.

Linux (CentOS 7)

Assuming a fresh install, you’ll need to setup some extra repos.

RPMForge is optional, but it’s a common thing to enable.  These versions may change over time, but as of Dec 2014 the links are up to date.  If you’re running CentOS 6, or just want some more information on what we’re doing, you can follow the instructions at my wife’s blog instead.

With EPEL repos setup, installing Node.js is the same as any other package.  We also need git to install repos that aren’t in the npm ecosystem.  Git is likely installed already, but just in case it’s not try to install it anyway.

Create a new directory wherever you want your trade bot to live, such as ~/steamtrade/ and you’re ready to start your project.

Windows 7

Grab a snack; this one could take a while.  I spent about four hours to finally get everything working, but hopefully with the notes below it will got a bit smoother for you.

Download the Node.js installer.  Install with default settings.

Edit 2015-05-22: You also need git to clone a node repo outisde of NPM: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git#Installing-on-Windows.  Make sure it’s in your PATH otherwise npm can’t use it.  If you install git and open a terminal (cmd/powershell), you can type “git” to see if it’s available.  If it’s not working, add it to the PATH in the same way that Python is added below in the paragraph below.

Some of the dependencies require special packages on Windows to compile.  First we need to grab an old version of Python, which is pretty quick and painless.  Python 2.7.6 is the newest supported version, but anything in the v2 range will do.  Version beyond 3.0 will cause builds to fail.  If you already have 3+ installed, update your path with the older version.  Sometimes the install will fail to update your path, so you’ll need to add it.  If you used the default install options, just append the following to your path:

There’s some conflicting information about this next part.  According to the author, you need Visual Studio 2010 for the ursa dependency (2012 for Win8).  The express version is supposed to work, but I had no luck.  After some trial and error, I eventually installed the full version of Visual Studio 2013 (Warning: this is a few gigs).

If you’re running 64-bit Node.js, you may also need the Windows 7 64-bit SDK (~60MB).

You also need the normal version (not Light) of OpenSSL should be installed to either C:\OpenSSL-Win32 or C:\OpenSSL-Win64.

If you run into errors installing Steam through npm later, you may need a compiler update for the Windows SDK 7.1, but I don’t think you actually need this with Visual Studio 2013.

Open the command prompt (cmd.exe) and navigate to your project directory.  In my case, I’m working from C:\Users\rannmann\git\CrateDump.

Installing dependencies

Run the following from the command line.  It can take a while for protobuf to install and you’ll see a lot of warnings, but this is normal.

Tip: If this is a project box where you’re going to be experimenting with lots of trade bots, you can add the “-g” option to install these packages globally (sudo required on Linux) so you won’t have to install them for each project individually.

WINDOWS: If your build is failing with something like error MSB6006: "CL.exe" exited with code -1073741515, visual studio not found errors, or fatal error LNK1181: cannot open input file 'kernel32.lib', then you either did not install the SDK or npm is trying to build with the wrong version of Visual Studio.  Yellow warnings are normal, red errors are not.  I ran into an issue where npm was trying to use the wrong version of Visual Studio or completely unable to find any version.  This can be fixed by manually specifying what version we want.  Since I’m using Visual Studio 2013, here’s the command I ran.

A breakdown of the packages we’re installing:

  • Steam – Seishun’s SteamKit port to Node.js.  It has fewer features than the C# version, but it does more than enough (and is soooo much lighter)
  • fs – Allows the use of filesystem operations.  Ex: read/write files.  We use this to save our Steam Guard information.  Edit: This no longer needs installed via NPM.
  • winston – A really nice logging tool, for both log files and the console.
  • readline – Allows for user interaction in the terminal.  We use this to enter Steam Guard codes when needed.  Edit: This no longer needs installed via NPM.

Now you get to choose whether you want to use Steam trade offers or directly interact with users through the old-fashioned trades.  It really comes down to what you want to do.  If the main interface is a website, trade offers may work better for you.  If you have no interface at all, regular trades are probably the best solution.  You can always build a text-based interface through Steam chat.  Take a moment and really plan  how you want users to interact with this bot; your decision will affect the entire development process.

There is nothing preventing you from using both, but keep in mind that you will need to write handlers for each method, even if they achieve the same goal.

Steam Trade Offers

Trade offers are often troublesome due to cryptic errors only displaying numbers, failures for seemingly no reason, or sometimes, very rarely, a trade will be marked as failed even though it succeeded (and vise versa).  This means you’ll need to do extra error checking after the trade has returned success/fail to make sure it really did what Steam is telling you.

Even with these flaws, lately I’ve been using trade offers over regular trades on a near exclusive basis.  There’s less chance for trickery by users and latency isn’t an issue.  Heck, the bot could even crash 20 times before accepting a trade offer and the user may not even notice.

The documentation and installation instructions for trade offers can be found in the github repo by Alexey Komarov.  If you just want to get started now though, you can type the following:

Alternatively, Steve Rabouin, better known as Backpack.tf’s Brad Pitt, has a fork of this repo with some slight changes.  It tends to receive updates quicker, but I don’t have a great reason why you should use it.

This article will not include examples for trade offers.

Steam Trading

Regular trading is a fairly straight-forward, but you need to lookout for users trying to exploit your bot.  There are ways to trick the bot into thinking an item was put up when it wasn’t, or thinking a worthless item is a more valuable item.  You can always add extra checks to decrease the likelihood of being stolen from, but bots can never be as smart as a human.  The more direct interaction users can have with it, the more opportunities for things to go wrong.  In general though, this Node library is pretty solid.  If used correctly you shouldn’t have any problems with thieves.

One interesting issue I’ve run into is with bot-on-bot interactions using live trading.  Events can fire off so quickly that one bot can put up its entire inventory before the other one even starts looking for items to go into the trade window.  One may see 70 items posted, the other may see 0.  In the past I’ve had to use a handful of setTimeout callbacks to achieve moderate success between bots.  Trade offers would be a better solution for exchanging between bots.

Nonetheless, most use cases work well with regular Steam trading.  If you’re not sure which to choose, this library is probably the easiest to learn from since you can interact with the bot while testing in stages.  Using trade offers means everything is submitted it one go and you have to parse all the responses from within Node.

The steam trading repo is maintained by the same person who built the Steam library for Node.js.  It is not published through the Node Package Manager (NPM), so you’ll need to specify the git URL to install it.

Steam API Key

One last thing before we start coding.  You might want a  Steam Web API key for loading anything off the official API, such as the TF2 item schema.  If you don’t already have one, you can get one assigned to your account here: http://steamcommunity.com/dev/apikey.  Most projects don’t actually need this (the project here won’t), but if you want to do complex item filtering then you should grab the schema first and cross-reference items via their defindex and quality values.

Writing your first bot

In this example we’ll be building a crate dump bot.  It seems like a silly thing to build, but I’ve had a huge number of requests to make another one since the original crate dump bot I wrote (in C#) stopped working over a year ago.  I promised I would write another, so consider this a promise fulfilled wrapped in a tutorial.

The idea is that everyone playing TF2 is swamped with crates, but occasionally someone wants to go on an unboxing spree and requires a bunch of a specific series.  They can trade the bot and ask it to put up 20 crates of series 54, for example, and it does so free of charge.  Think of the “Need a penny? Take a penny. Have a penny? Leave a penny,” trays at your local store.

Build the core

Pretty much every project starts off looking the same: define all your required libraries, login to Steam, deal with Steam guard codes if needed, connect to the web interface, and listen for various events to fire (ex: chat messages, trade requests).  This is boring, but it’s good to learn at least once.  Build your own quickstart repository and you’ll be set to launch future projects much quicker.

A lot of this stuff is pretty easy to understand and breaking it up in sections might make it more confusing.  Follow along with the comments for a bit.

*WHEW*!  Still with me?

It’s best to test things incrementally, so try running it with just the above.  Plus, this will allow you to generate a new Steam Guard hash immediately.  It takes 7 days before you can use Steam trading on a new device, so getting this out-of-the-way early means you can spend an entire week learning the trading library while the timer counts down.

Make it do something

The above snippet works just fine if you supply an real username/password.  Unfortunately, the bot doesn’t actually do anything.  We need to add a few more event listeners to make it useful.

The CrateDump bot will accept friend requests from everyone.  If you expect hundreds of users to use the bot, you’ll need to remove old friends when the account list is full, but that’s beyond the scope of this tutorial.  We just want to get something working for now, so accept all friend invites and trade requests, and explain to new users how to get started.

So far we have only added Steam client listeners.  Now we get to add some for our trading library.  Here’s where it starts to get fun!

The Steam client starts a new trade session when a trade is accepted, but it has no more functionality than that.  We start by listening for a new trade session and then actually open a “trade window” with the steam-trade library (note: not a real trade window, just a pretend one that uses the API).  Then we need to load our inventory after the trade starts so we know what we have available if they request a crate.

In order to avoid callback hell where we can, let’s make our own function called onTradeStart that is called every time a trade is successfully loaded.  We need to explain how to use the bot, so that’s a good place to start.  It’s sort of ironic that we’re avoiding callback hell with a great example of what callback hell looks like…

Tip: Using a library like async allows you to execute things in order without using a bunch of callbacks.  This can make your code more readable if you find yourself doing the following frequently.

Now we’ll assume the user has started the trade and hopefully read the little guide in their trade chat window.  Just to be sure they’re not requesting anything silly, let’s double-check any command they try to use for valid syntax before handing it off to a function.

If the user is just dumping their items onto the bot, the above event may never be emitted.  This is fine since all we really need to do is accept any proposed trade.  Standard practice is to let the other user click “ready” when they want to complete the trade and have the bot follow their lead.  This will be our cue too.

Since this is a demo, there’s a few extra common trade events that you may want to listen for.  We don’t need them for this particular project, but I always find examples more useful than just documentation.

Just two more pieces of the puzzle until everything comes together!  We’re on a roll with event listeners, so let’s finish those up.

Before we send our bot out into the world we should probably teach it how to handle terminated trades.  We don’t want it to hang forever thinking, “Are you still there?” (unless you’re into that kind of thing).

Oh, and don’t forget about the variables we set near the beginning of this project!

The possible result statuses are: complete, empty, cancelled, timeout, or failed.  You can log all the items exchanged if you want, but in our case we really don’t care who does what with the bot; it’s a free service.

All that’s left is defining our addCrates function, but before we do that we should take a moment to understand what sort of item information we actually have available.

TF2 item schema

The following is a single JSON object obtained from a trade, in this case for Crate #82.  We generally refer to this by the variable, ‘item’, so accessing the values such as the name is done via: ‘item.name’.

There are a few important values in here, and a lot that we couldn’t care less about.  This item object is actually a hybrid of information obtained from two different Steam APIs.  The first is user backpack information from GetPlayerItems, which contains very basic information such as an original item ID, current item ID (this changes with every trade or action taken on the item), defindex, and item quality.  The second is the definition of all TF2 item information from GetSchema, which includes item qualities, names, descriptions, attributes and images.  Each item from GetSchema is given an index number, “defindex”, which is mapped to an object defining the item.  Not all the information from either API is included in the items returned here, but most of the information we need is.

Tip: If you ever need any extra information about an item, grab the defindex and look up the item in the schema by that index.

With the data provided, we will assume that all crates have a tag where the internal_name is “Supply Crate”.  Any item can have any number of tags, and any inventory can have any amount of items (up to 2000 in TF2’s case).  It sounds like we need a loop within a loop filter out all our crates from our inventory!  Rather than brute forcing directly, we’ll use javascript’s “filter” and “some” functions since they’re more efficient.  Then we’ll try to grab the series number from the item name, and finally add the requested amount to the trade if we have them.

With this function, the entire project is complete.  If you were hacking away while reading along, run it with: node filename.js and see how you did!.

TL;DR

If you just want to jump right in with a working bot, this project is available on github.  It should just work out of the box, but remember that Steam Guard will not let you trade on a new device for 7 days, which means you have to wait a week to test any of this!

Caveats

In our example we built the entire project in a single file.  While this is good for learning, it is a horrible design.  Node.JS is designed to be modular and our code should be too.  The “core” code should probably be its own project which is included in all your other projects.

If you’re new to JavaScript, the asynchronous nature is probably very confusing.  Instead of reading code from top to bottom like in traditional blocking languages, JavaScript executes everything as fast as it can, even if it’s not in order.  The code will run top to bottom, but when there is a delay, such as waiting for a network action to complete or waiting for a file to read, code continues to execute beyond the current point.  This is why we use callbacks and listeners.  Callbacks, or functions handed to other functions to be executed at completion, allow us to wait until a task completes before moving on.  There are plenty of guides out there on how to start using Node.js and JavaScript, and if this is your first introduction to either of those I recommend doing some reading before starting a project like this.

Good luck, and happy hacking!

Update 2015-01-09: Steam has added captchas to trade offers in order to stop malware from stealing items through trade offers.  Numerous services and libraries exist for solving them (Death By Catpcha, for example), but you generally will pay a fraction of a penny per solve.  It’s still viable but not really recommended to use trade offer libraries anymore.

Update 2015-01-10: Steam has removed captchas from trade offers and implemented recaptcha after the most popular malware provider pushed an update with integrated Death By Catpcha.  This new version cannot be solved by the previous services and require an actual mouse click.  So while the API still exists for trade offers, it can no longer be utilized by trade bots.  Although there may be a way around it with headless browsers (ex: Phantom.js), consider trade offers dead in the water for the time being.

Update 2015-01-14: It seems anyone with 5000 or more trades on record does not have to enter captchas.  Super active traders with expensive backpacks may still be just as vulnerable.  If you are one of these and want to further protect your items, a secure alternate account may be beneficial.

Update 2015-01-21: Captchas have been removed and been replaced by email confirmation.  This can easily be automated via imap libraries such as: https://github.com/mscdex/node-imap.  Or you can just turn it off, but Steam refuses to return scammed/hacked items if you do.

About

Jake is a web developer who loves data and automation. He went to the University of Alaska Fairbanks and studied Computer Science and Information Technology. Most of his work is done in PHP, MySQL, and Javascript.

46 Responses

  1. I’ve found it helpful to use [steamID + ‘ (‘ client.users[steamID].playerName ‘)] so that you can actually see a name instead of just a steam ID. REmember not to use this in the ‘friend’ event or your bot will crash.

  2. Absolutely love this tutorial. It’s a pity that trade offers are not included in it…

    Still, great job!!!

  3. Hello, Can it work with offline trade offers without friending?

  4. How can i know context id for CS: GO?

    • Unfortunately, it’s not something Valve documents. But the context IDs for TF2, DOTA2, and CS:GO are all the same: 2.

  5. When i want to start the Bot it gave me an error in Line 7 where an Object is expected, its the Include but ive installed all the dependencies.. :/

    • Line 7 is where the ‘steam’ library is included. Maybe it failed to install? Try to ls (or dir on Windows) the contents of node_modules and see if the “steam” directory is in there. If not, npm install steam from your bot’s root directory.

      If you cloned my repo from github, you can just type npm install with no parameters and all the dependencies will be grabbed automatically. If you didn’t, you can just paste the contents of this file into package.json and then type npm install: https://raw.githubusercontent.com/rannmann/node-steam-trade-tutorial/master/package.json

  6. hi,
    I got the same prob than Paul Renger but my dir “steam” exists .. what can I do?

  7. If anyone needs help on windows, feel free to add me on steam. I do most of my development on windows, and have made quite a few bots.

    http://steamcommunity.com/id/dragonbanshee

  8. > npm install steam fs winston readline
    fs was built in module (https://nodejs.org/api/fs.html), you doesn’t need to install it (actually there is noting to install https://www.npmjs.com/package/fs – data not found -> package does not exist)

    Please remove fs from that line.
    Thanks

  9. I mate thanks for that really good tutorial but i have a problem i want to do a steam trading bot for my team and me but we want to make scrapbanking…
    can you help me with it ?

  10. Hi. I have a question. If i want to keep a record of the items I have in my bots backpack(which will be filled with items given to me) what feild should I use to uniquely identify an item. the instance id or the id or both ? and what is the class id

  11. Node-Steam seems to no longer depend on urea, so you could probably yes it that beginning part out about visual studio and ssl, since I don’t think you need it anymore.

  12. usgo trading code?

  13. is there any port to open on server ?

  14. where I have to write code Building a core? I looked at the source code :Jessecar’s C# version and Seishun’s Node.js version, but did not find such strings

  15. Can You Make a Tutoril for Windows 8 or does this work for Windows 8 too?

  16. Hi ! Great tutorial on NodeJS & Steam It’s rare 😀 I have some questions for you, It is possible to implement socket.io with node-steam-tradeoffers ? I’m currently having some issue with that … It’s working without socket.io but with It’s completly demolish x)
    If you can take a look at my code I would appreciate (because I really don’t know the reason why It’s not working …)
    Code : http://pastebin.com/AJpYjTPx (The whole connection and first console.log in socket working but not after)

    Thanks per advance!
    PokeRwOw

  17. could anyone help? I got an error on 73line:

    C:\Temp\server.js:73
    client.logOn({
    ^
    TypeError: undefined is not a function
    at Object. (C:\Temp\server.js:73:8)
    at Module._compile (module.js:460:26)
    at Object.Module._extensions..js (module.js:478:10)
    at Module.load (module.js:355:32)
    at Function.Module._load (module.js:310:12)
    at Function.Module.runMain (module.js:501:10)
    at startup (node.js:129:16)
    at node.js:814:3

    • You downloaded node-steam version 1.0.0 when you should have downloaded version 0.6.8. This guide will not work with 1.0.0. Type this in console:

      npm uninstall steam
      npm install [email protected]

  18. anyone have any idea how I could use the C# SteamBot sentryfile on this bot?

  19. P.S:- The link here is linked to the same thread.

    A new version of this article using node-steam 1.0 and trade offers can be found here: https://firepowered.org/developer/creating-a-steam-trade-bot-with-node-js/

    Please fix it.

    And thanks for the tutorial 🙂

  20. I need help what is that..

    logon fail: 65, sessionID: 1913043
    events.js:85
    throw er; // Unhandled ‘error’ event
    ^
    Error: Logon fail: 65
    at SteamClient.handlers.(anonymous function) (/root/node_modules/steam/lib/handlers/user.js:178:11)
    at SteamClient._netMsgReceived (/root/node_modules/steam/lib/steam_client.js:106:26)
    at SteamClient.handlers.(anonymous function) (/root/node_modules/steam/lib/steam_client.js:192:10)
    at SteamClient._netMsgReceived (/root/node_modules/steam/lib/steam_client.js:106:26)
    at Connection.emit (events.js:107:17)
    at Connection._readPacket (/root/node_modules/steam/lib/connection.js:50:8)
    at Connection.emit (events.js:104:17)
    at emitReadable_ (_stream_readable.js:424:10)
    at emitReadable (_stream_readable.js:418:7)
    at readableAddChunk (_stream_readable.js:174:11)

  21. Hi! Not sure if I will ever get a reply but worth trying..

    I’ve followed your guide through and I keep getting Steam Error 5, which if I’m correct is invalid password. I’ve tried at least 10 times and I’ve copy and pasted my password into my Steam application and it logs in fine! It’s driving me nuts! Can you help me? Thanks!

  22. Hello it work but when i trade with my bot i became this error 0.o

    ReferenceError: item is not defined
    at Query._callback (/root/tradebot.js:419:18)
    at Query.Sequence.end (/root/node_modules/mysql/lib/protocol/sequences/Sequence.js:96:24)
    at Query._handleFinalResultPacket (/root/node_modules/mysql/lib/protocol/sequences/Query.js:144:8)
    at Query.EofPacket (/root/node_modules/mysql/lib/protocol/sequences/Query.js:128:8)
    at Protocol._parsePacket (/root/node_modules/mysql/lib/protocol/Protocol.js:271:23)
    at Parser.write (/root/node_modules/mysql/lib/protocol/Parser.js:77:12)
    at Protocol.write (/root/node_modules/mysql/lib/protocol/Protocol.js:39:16)
    at Socket. (/root/node_modules/mysql/lib/Connection.js:96:28)
    at Socket.emit (events.js:107:17)
    at readableAddChunk (_stream_readable.js:163:16)
    [email protected]:~#

  23. Hey, is there any way to import a sentry from windows pc to linux server in order to avoid waiting 7 days to trade?

  24. Hi any idea’s with this error?
    30 error Windows_NT 6.3.9600
    31 error argv “C:\\Program Files\\nodejs\\node.exe” “C:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js” “install” “git://github.com/srabouin/node-steam-tradeoffers.git”
    32 error node v4.0.0
    33 error npm v2.14.2
    34 error code ENOGIT
    35 error not found: git
    36 error Failed using git.
    36 error This is most likely not a problem with npm itself.
    36 error Please check if you have git installed and in your PATH.
    37 verbose exit [ 1, true ]

  25. Done with that error)

  26. but still how do i start the bot on linux? What is the command?

  27. is there any way to start steam client while steam mobile authenticator is on?

  28. I’d like to instantly accept items which are gifted to me. Is it possible?

  29. Hey I keep getting this, http://i.imgur.com/Jooq2n0.png I would appreciate any help I can get! Thanks!

  30. Outdated, u have to rewrite, example missing: steam-totp – 2FA auth

Leave a Reply