Posted On July 24, 2015 By In Developers With 53577 Views

Creating a Steam Trade Bot with Node.js/IO.js (Updated for Node-Steam v1.0)

Last year I wrote an article on creating a Steam trade bot which seemed to be pretty popular.  Since then, the core library has been updated to v1.0 and a majority of the API has been rewritten.  Variable names have changed, key functionality has been modularized, and a lot of the old code no longer works.  In this updated article I’m going to jump right into the code and libraries, but if you’re interested in core concepts, history, and setting up your environment for node, see the original article.  For IO.js you can follow similar installation steps.  Be aware that IO.js and Node.js have joined the Node.js foundation back in May and the split between the two frameworks will no longer exist after all merge conflicts are resolved.  Expect this to occur sometime in the later part of 2015 or early 2016.  When the merge occurs, IO.js will become Node.js once again.  Until then though, pick whichever framework you want since our code works on either platform.  IO.js is much faster if you care about that kind of thing.

At the time of writing this, the old tutorial still works perfectly fine.  There’s no reason to upgrade old projects to v1.0 yet, but eventually v0.6.8 will stop working and you will need to upgrade.  For new projects, I recommend starting with 1.0.

Also, a lot of you asked for examples with trade offers, so I’ve taken this opportunity to rewrite the old example bot using trade offers instead of live trades.  If you want to continue using regular trading, make sure to check out the documentation section for more information.

Library Changes

FirePowered’s own Dr. McKay has been publishing node libraries left and right since the last time we made a trade bot.  They have more features and require less coding to implement, so we’re going to use them in this example.  One is a wrapper around node-steam–the library we used in the last tutorial–and the other is a better implementation of trade offers.

The first library, Steam-User, uses the latest node-steam and steamid together for a complete approach to creating Steam bots.  In the last tutorial you’ll remember that we had to write our own implementation of dealing with Steam Guard codes, saving sentry files and so forth.  This library takes care of all that for you.  Right off the bat we can cut out about 50 lines of code and never have to worry about it again.  We also get access to a lot more information, such as account limitations.   As I write this article the library is actively being developed, so be sure to read the docs or you could miss some pretty neat features!

The second new library we’re using is Steam-Tradeoffer-Manager.  The trade offer library mentioned last time had some of its functionality cut out and moved elsewhere (automatically getting an API key for you was really the only feature it had) and wasn’t much more than the standard request library wrapper to begin with.  With Steam-Tradeoffer-Manager we can set up trades easier and it comes with lot more options.  Bonus points because it can take the previous Steam-User library as its client with no work involved from our end.

Oh, and if you decide you don’t want to use trade offers, you can use the node-steam-trade library.  Steam-User automatically includes SteamTrading for responding to requests, but you’ll need this to actually trade.


Before I paste a bunch of code at you, here are some links to documentation for some components of our trade bot.  They’ll have a lot more information than this article and will stay up to date as features are added/changed.

  • Steam-User: The core of the bot.  Expands upon the familiar node-steam library.
    • SteamTrading: Included by Steam-User from node-steam and can be accessed by the trading property.  Allows for responding to regular Steam trading requests, but does not have functionality to handle the trades themselves.
    • SteamFriends: Included by Steam-User from node-steam and can be accessed by the friends property.  Lets you send/receive messages, appear online, add/remove friends, etc.
  • Steam-TradeOffer-Manager: Handles all trade offer components.  You don’t need this if you’re not going to use trade offers.
  • SteamID: Used by many components to handle different types and formats of Steam IDs.  Allows you to check the validity of Steam IDs and easily convert between the types (64-bit int, Steam2 ID, and the new Steam3 ID).
  • SteamCommunity: Used by the main components to do basic Steam Community things.  We don’t include this ourselves and you probably don’t need this documentation directly, but it’s useful for projects outside of this article’s scope.

Code On;

Before you begin, make sure you turn off email confirmations or you’ll have to click a link in your email before each trade completes!  Also note that with Steam Guard enabled you’ll need to log into the account through the bot at least 15 days before you intend on actually trading.  If you ever need to run your bot as a different user and want to import the old auth code, refer to the Steam-User documentation for where the Steam Guard auth code lives.  You can copy/move the files around to make your bots work on completely different machines without the Steam trading cooldown.

Since the bot we’re building uses trade offers, it has to work differently than it did in the last post.  The way we’re going to set it up is to accept all one-sided trade offers where items are being donated (the bot isn’t losing anything) and any trade offers from the administrator.  If you want to retrieve items from the bot, you have to add it as a friend and request what you want through chat.  We’re only willing to hand out TF2 crates, so the format will be !trade <series> [amount].  We assume they want 1 crate if they don’t specify an amount.  This bot is not designed to take special crate series into account.  If an item doesn’t have exactly a pound symbol followed by a number, we can’t find the series.  That means we’re not allowing users to withdraw any of the new/special crates such as The Powerhouse Weapons Case in our example.

Please visit the git repo if you want to clone the project entirely or if you’d like to create an issue.  Pull requests welcome if you find a bug.  I’ll do my best to keep this blog post up to date with any changes.

We begin with some really basic setup.  Include required libraries, setup some helper variables, instanciate the libraries that need it, setup logging… all the boring stuff first.

The trade offer manager library has a cool option where you can take the previously downloaded data and import it.  If your bot crashes, or if it’s just offline for a bit, we can import the old data right off the bat and pick up where we left off.  We’ll deal with saving the data later, but for now we’ll try loading a file if it exists.

Everything that can be setup without actually logging in is ready to go now.  The only thing left is to sign into Steam and share the session data with the trade offer manager library.  It never hurts to log and print out things as we go, so we’ll do that too.  After all, what good is an example if we’re skipping most the features?

If you’re familiar with the old way of doing things, you can clearly see that this new library opens up a lot of possibilities.  One of the more useful events to subscribe to is accountLimitations.  If you’re running an army of trade bots, you can setup a way for them to report when something is going wrong.  For example, sometimes Valve will issue trade bans to bots that manage to get their hands on scammed items.  Bots are an easy way for scammers to dump their stolen goods in exchange for various site credits or clean items (A few CS:GO betting/trading websites have been affected by this).  Unfortunately for those of us who write bots, it means that we can lose our entire inventory at no fault of our own, since we have no way of checking if an item was scammed or not.  If you’re running 20 or even 1000 trade bots, it’s nice to have a record of the bots that are affected in one way or another (plus you can shut them off the save resources).

Now we can get on to handling friend requests and messages.

We’ll worry about making the sendCrates function later.  If you’re writing your own code while you follow along, just create a function that doesn’t do anything (or better yet, one that logs some debug output so you know it’s being called!).

Let’s step back for a moment to realize where all this functionality is coming from.  SteamFriends is included in node-steam, and steam-user includes a copy of node-steam within it.  However, with node-steam you have to create a new instance of SteamFriends before using any functionality (ex: new steamFriends = new Steam.SteamFriends(steamClient);).  Instead of having to declare this yourself, steam-user creates an instance of SteamFriends by default and provides it as the friends property.  In that way we can use SteamFriends through client.friends in our example.

In practical terms, this means that if you have issues with any SteamFriends component you should create an issue on node-steam’s github project, not steam-user’s.  It also means that all the documentation for this component is located within a subset of node-steam.  You can find more information in the documentation section near the top of this article.

Still with me?  Of course you are because you’re brilliant.

Trade Offers

Our bot loves free stuff.  It also loves its administrator.  Beyond that though, it’s going to decline every trade offer that other users initiate.

Note: The regular method of trading still needs to be included using node-steam-trade if you’re not using trade offers.  The initial functions (trade proposed and response) are available to us in the same way that SteamFriends is.  Again, this is a node-steam feature.  We’re going to ignore it for this tutorial, but it’s pretty straight-forward if you’ve understood everything thus far.

For informational purposes, we want to log incoming items from users.  If someone gives us something super awesome, we can look up who did it in the logs later and thank them personally.

We can also take note of the things we gave away.  Although since they’re just crates, we don’t care enough to record the specifics.

Remember how we tried to read a polldata.json file earlier?  We need save the poll data to that file or it will never succeed in loading.  While we’re at it, let’s log any issues we have with the trading API.

That’s all the logic!  Although we did reference a sendCrates function earlier and we haven’t made it yet.  We should probably do that before calling it a day.  Most of this is the same as the last tutorial, except we send the result out in a trade offer instead of a trade.  Oh, and with our trade offers library we don’t have to convert the items to a different trade-specific format, and we can push them all to the trade at once.  No more loops!

We’re done!  If you run all the above code it will JustWork™ provided you supply a valid config file.  Here’s a sample config.js:

Questions?  Comments?  Issues?

Leave a comment below with any questions related to this article.  I’d love to hear about your project and how you’re using NodeJS to automate Steam things!

Please post issues with the code on github so they can properly be tracked.

Need A Host?

If you’re just developing to learn, you can easily run this entire project on your PC.  But if you’re looking for stability and availability, you probably want a dedicated host.  Here are my three favorites in the categories of: PaaS (free), VPS (cheap), and Dedicated (expensive).

I’ve been running the old project on the OpenShift PaaS for about four months now and it’s still up and running with no intervention from me.  Red Hat maintains security updates and very good uptime of your application for you (yay cloud), so if you don’t want to deal with any systems administration things this is a really good option.  You can run up to three separate applications for free, and it only takes about a minute to have things up and running.  And this doesn’t just apply to Node.js or IO.js applications; you can one-click install a lot of popular things such as WordPress.  I use the IO.js cartridge for this because the pre-configured NodeJS cartridge was too old back when I was fiddling with it (I imagine they have a new version now).  You can find the IO.js cartridge I used here.  If you’re a paid customer, you can have your apps automatically scale up on demand too.   It does take a few minutes to get used to the PaaS concepts though.

If you’re the more DIY kind of person, Digital Ocean is an awesome VPS provider and can have an entire server up for you in a minute or two.  This isn’t a free service, but if you click the link I provided you’ll get $10 of free credit.  Using the smallest VPS package, that equates to two months of free hosting while you hack away at your project.  I’ve used their services to work on projects where I need a very specific environment and don’t want to bother setting up a local VM because it’s really that much easier.  They bill by the hour up to a monthly cap, so if you run your app for 24 hours then you only get charged about 17 cents.

And if you’re working on a large-scale project where you need more than just trade bots, I recommend PhoenixNAP as a dedicated host.  We use them for all FirePowered servers and services; they’ve protected us from hundreds of DDoS attacks.  A solid network, great support, amazing uptime, and good prices (ask a sales rep about discounts) are their major selling points.  We’ve tried a few dedicated hosts and PNAP stands out as a rare gem.  We’ve been with them for a year and a half now and I’ve never been happier.

Good luck fellow hackers!

Tags : , , , , ,


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.

81 Responses

  1. Hey, love the tutorials!

    I noticed that this doesnt have the sentryhash variable in the code. In the older bot I used a raw hash from an older project as a variable in the code to login(avoided the 7day trade ban with this).

    How would I do this with this code?

  2. You can’t, sadly. node-steam 0.6.8 saved only the hash, when it should have been saving the entire sentry from the start.

    That said, I believe that if you login and use the bot from the same IP as before, Steam shouldn’t impose the trading restriction.

  3. Hey guys, I keep getting this error when trying to “node server.js”.
    I know C#, JS, and PHP, but I’m completely new to node and steam bots. If you could just point me in the right direction that would be great! 🙂

    SteamUser.protoype.setSentry = function(sentry) {
    TypeError: Cannot set property ‘setSentry’ of undefined

  4. friendcount will also count blocked/ignored friends.

  5. Would anyone know how to change to trade offer acceptance to where it will only accept offers from admins or offers containing 10 or less items? i’ve tried using different comparison operators instead of the === in this area: offer.itemsToGive.length === 0, such as <= 10, but the bot continues to accept offers with 11 or more items.

    • itemsToGive is the number of items your not is giving away. Check the documentation to find the variable for the number of items it is recieving

  6. Can i give away items for some users with this boot? Where can i read something about it?
    And how i can get names of items that i get?

  7. Sorry for stupid question but what the difference between using SteamTrading and TradeOfferManager?

    • SteamTrading is a module that allows you to send and accept trade requests in Steam, nothing more. To use standard real-time trading, you’ll need to use SteamTrading to send/accept requests, then something like node-steam-trade to actually complete the trade.

      TradeOfferManager is a module that provides a simple interface for sending and receiving trade offers.

  8. Honestly, I’m new to node.js or any type of developing/programming. I want to get to the point of coding bots and all but this guy is speaking a whole different language than I am. Anywhere I could get started? Link me to any tutorials? All help is appriciated!

  9. I Just got to the point where I decided to update my existing code. God I hope they don’t have anymore major shake ups like this anytime soon. But thank you guys for the tutorial. Its really appreciated all the support and help you guys give both seasoned and noob developers is just wow. Thanks so much for this and the previous tut

  10. I’m having an issue,

    “Error reading polldata.json. If this is the first run, this is expected behavior:”

    which is fine because it was my first run, but it never creates one. So I tried creating a blank file and saving it as polldata.json, but that just crashes the script.

    Is there any advice for this? Not sure what I’m doing wrong here. Thanks!

    • I forgot to mention the bot immediately closes after this. I’ve been having this issue with both guides (0.6.8) as well as this one now apparently. When I attempt to run the logon function the client immediately closes. I thought it might have been an issue with the 0.6.8 library no longer being supported or something but it seems like an issue on my end.

      Any advice on what could be wrong? I have Python, OpenSSL, the 64 bit SDK, and everything else from the previous tutorial installed and added to my PATH (at least as far as I’m aware).

  11. You don’t need any of those dependencies from the old tutorial anymore.

    You’re almost definitely getting some kind of error right before it crashes. Are you running it through a batch file? Try adding “pause” to the end of the file so it won’t close right away (so you can see the error).

  12. Hello, nice tutorial, thanks! I have a question. How can i get other information about reserved items, like we get name of them.
    I find out this words in documentation at node-steam-tradeoffer-manager page.
    “Can be called on an accepted offer to retrieve item data about the items you received, including names, descriptions, and new assetids.”

    Buy i can only get name like you do it in your tutorial, but “return item.description;” or “return item.assetid;”
    Does not log anything. What i do wrong?

  13. It is possible to get price of item form steam-marketplace?

  14. I’m a bit confused about the whole internal_name thing in the sendCrates function. Would there be a way to filter via craft_class?

  15. My jackpot bot is givving me and error. Can someone help me with an ideea?
    When the bot receive a trade offer, this error pops up:

    if(offer.items_to_receive.length > row[0].value)
    Type error: cannot read property “0” of undefined
    ( the error can be seen here )

  16. Getting Windows script host error; 800a138F; Microsoft JScript runtime error when I try to run the code above.. please help.

  17. I keep on receiving a steam guard error? do I have to add my authentication code to the config file? would any Guru please guide me toward the right path, please?

    • I see that I have prompt the code in but after I receive and SyntaxError: Unexpected token ILLEGAL error? any ideas. Please any help would be amazing!

  18. I have an error Error polling for trade offers: No Api-Key set (yet), what i have to do to solve it?

  19. Hello, I love the tutorial. It is very helpful but I have a quick question. How may I go about running one server.js to start and control like 3 bots. Will the bots run in line, like one will wait for the other to finish before going to the next or will everything happen real time side by side with out waiting for each other. I would like it to be side by side. Would I have to run separate instances for each bot eg bot1,js, bot2,js, bot3.js.


    • To answer your first question: I’ve run multiple bots in the same file using objects of bots (ex: bot.username.client = new steamUser();) and then foreach bot in bots, define the logic. In a production situation though you’d want to modularize your bot. Then you could just: var bot.username = new MyBot();. This would give you greater flexibility and you could run as few or as many bots per file as you want without much effort.

      Your second question hits on one of the fundamentals of javascript. JS is asynchronous. This means that code runs top-down, but if something requires an out-of-script response, such as an HTTP request or a file-read, the code skips that part and continues to run until the response is returned. When the HTTP request returns a response, the code goes back to the callback, executes that, and then skips back down to where it left off. The nature of Javascript is to run as fast as it can until there’s nothing left to do. In the case of trade bots, almost everything is done with event listeners and HTTP requests. Since they’re all waiting on things to trigger, the bots act like they’re running in parallel even when that’s not truly what’s happening under-the-hood.

  20. I get the following error when updating the server.js using openshift.

    Application ‘tradebot’ failed to start (port 8080 not available)

    Any ideas?

    • It sounds like you’re trying to use a nodejs webserver on the default port. Are you using Express or anything like that? If so, you need to specify the port via: process.env.OPENSHIFT_NODEJS_PORT

      • I’m terribly new to all of this and it sounds like I will need to do a lot of google searching tonight.
        I don’t think I’m using express at the moment (unless its build into node.js) so I will need to look that up too.
        Do i specify the port in the server.js file or in the package.json file?

        • If you didn’t add express to your application then you’re not using it. But it does seem like you’re using a modified version of the tutorial posted above. If you have a listen server of any type (ex: http.createServer(app).listen(PORT…)), you need to specify the port number via the OpenShift env variable when starting it up. In this case, it’s probably in server.js somewhere.

  21. Hi guys!

    I am currently doing a bot that records items received in a MySQL database. But I’ve noticed that once accepted the trade objects ID (assetid) changes. So then it is impossible to identify you when you send these objects to another user.

    Would there be a way to get the actual object id received within the event ‘receivedOfferChanged’?

    Thanks in advance and very good tutorial, Rannmann!

  22. How do I access the ‘Options’ in steam-user. I want to set singleSentryfile: true but I can’t figure out how to pass it to my SteamUser object.

    • When you type ‘new SteamUser’, it takes two optional parameters: client and options. The client is for using this library with node-steam, and the options are just an object. For example, here are the defaults:

      var defaultOptions = {
      “dataDirectory”: process.env.OPENSHIFT_DATA_DIR ? process.env.OPENSHIFT_DATA_DIR + “/node-steamuser” : appdir.userData(),
      “autoRelogin”: true,
      “singleSentryfile”: false,
      “promptSteamGuardCode”: true,
      “createHandlers”: true,
      “machineIdType”: SteamUser.EMachineIDType.AccountNameGenerated,
      “debug”: false

      • Ok thanks! I didn’t realize there was a client parameter before the options. I just passed it null for the client and then my options. Love the tutorial it was very helpful!

  23. I can’t run it because ” ‘winston.logger’ is not a function” :/ Did I make something wrong? Code looks the same

  24. How to create a input? like if entered “stop” it stops

  25. My bot decline offer but add data in database.
    When I all decline methods rewrite on accept methods so offer will not accept or to reject

  26. What is element.internal_name for CSGO cases? i didnt find out

  27. Hello, how can i make bot (nodejs) still running on Openshift? Everything works fine with putty, but if i get putty quit, so connection will be lost and my bot stop working. Any ideas? Thanks a lot.

  28. how can i implement this into a site for skin betting?

  29. Im getting an error at,
    “client.friends.on(‘relationships’, function(){}”
    TypeError: Cannot read property ‘on’ of undefined

    im assuming this is because this is being called before the client is defined.
    any solutions for this?

    • client.friends was removed in node-steam-user v2.0.0. You’ll want the newest v1.x.x, which is 1.13.0.

      • Whats the option if we are using the v2? I got it running fine without it but i have a few implementations i was thinking to do with the friends. At least put the acc Online which i cant atm.

  30. I’m with the same problem on client.friends. I had to comment all use to that. Also the bot is not accepting any trade offer and i cant really understand why. seems like he doesnt even check for them.

  31. Hello,
    Thank you very much for this posts, is it possible to make a steam trade bot with the new escrow update to steam? I am sure many people will be looking forward to a new guide with 2FA verification.

  32. Hey,
    I get every das a lot of offers
    Can i use systems like this on my main account, to accept offers with free stuff?

    And can i get banned for systems like this)

  33. Hey!
    I just wanted to know if i can use this on a gambling website the i am currently developing.
    Is there anyway to use the bot for some features like depositing on the website, withdrawins, etc.

  34. Instead of trade offers, how would you go about doing normal trades?

  35. Can you point example of managing more than one bot. I`m wondering what is the best way to do that. Thanks

  36. Guys when i try to send trade offer from time to time i got HTTP error 401. I read that this is steam session issue and right think to do is to renew session: client.webLogOn(). But how to send again same offer after webLogOn. Now when i renew my session i have to send offer from front end again.

  37. Hello, can you say how to trade with new rules on Steam, now if I dont use Steam Mobile Guard the trade will pending for 1 day. Maybe you have something ideas, because i dont know how to avoid this.

  38. github Alright, I am attempting to setup the bot, but it is 3.3.1 Will this still work with the latest version of steam?

  39. Hello, how to confirm trades using new mobile token?
    Thanks for tutorial.

  40. Can you pass me the bot??

  41. Hi, nice tutorial 🙂 Thanks for all the amazing modules !
    Dunno if i’ll get an answer but still:

    The client (SteamUser) does seem to have its “friends” property as undefined.

    client.friends.on(‘relationships’, function() {

    TypeError: Cannot read property ‘on’ of undefined

    I see in your doc that there’s now a “myFriends” property in SteamUser, but I can’t get it to work either.
    Thanks again, havaniceday 🙂

  42. debug: Found previous trade offer poll data. Importing it to keep things running smoothly.
    Steam Guard App Code: ‘my code’
    info: Logged into Steam as ‘my steam id’
    info: Our email address is ‘my email’ and it’s validated
    debug: We have 24 friends.
    info: We do not have a Steam wallet.
    debug: Got web session
    debug: Trade offer cookies set. Got API Key: ‘my api key’

    TypeError: TradeOfferManager.getStateName is not a function

  43. can you send the complete code? for csgo bot that will accept trade offers

  44. What Version Of Node.js you should use !?
    Can u send me all file together !
    [email protected]

Leave a Reply