Jump to content


Most Liked Content


#889 Identifying Steam Items

Posted by Dr. McKay on 20 May 2016 - 12:40 AM

Sometimes it can be a little confusing to identify a specific item in the Steam economy. There are several different types of IDs present in one particular item, and a lot of vague terminology. This guide aims to clear all that up for you.

For starters, the "official" term for a Steam item is an asset. When I say a "Steam item", I mean a particular copy of an item. I'm not referring to the item's definition, name, image, or anything. I'm referring to a specific, unique copy of the item.

In a general sense, every item on Steam must be owned by an app. An "app" is a game, software, or whatever on Steam. Every app has its own unique AppID. You can find a particular game's AppID by going to its store page or community hub and looking at the URL. For example, TF2's AppID is 440 so TF2's store page can be found at http://store.steampowered.com/app/440. CS:GO's is 730, Dota 2's is 570, and so on. Note that Steam Community items, Steam gifts, and other "Steam" items are owned by the "Steam" app, which has AppID 753. To identify an item, you'll need the AppID of the game which owns it.

Of course, the AppID alone isn't enough. You also need two other IDs. Have you ever noticed how some games have multiple inventories, which appear in a drop-down list? An example is the Steam inventory, which has sub-inventories for "Community", "Gifts", "Coupons", etc. These "sub-inventories" are called contexts, and each context has its own context ID. If a game doesn't have a drop-down menu to select a context, that doesn't mean that it's without contexts. That only means that it has one single visible context. That single context still has an ID. For all current Valve games, the context ID for the publicly-visible context is 2.

Context IDs can be a bit tricky. It's entirely up to the game's developer to determine how they work. For example, Valve games take the "single shared inventory" model in which there's one context ID which is shared by everyone. Under this model, an item belongs to one particular context and never leaves that context. Consequently, the item's context ID never changes. It is, however, possible for game developers to create contexts in any way they choose. For example, Spiral Knights uses the "per-character inventory" model in which everyone who plays the game has their own context IDs for their characters. Creating a new character creates a new context ID. This means that when an item is traded between users, its context ID will change as it moved out of a particular character's inventory.

Those are the two different types of "containers" in the Steam economy. Apps own contexts, and contexts own assets. Every asset on Steam has, in addition to its AppID and context ID, an asset ID which is guaranteed to be unique inside of a given AppID+ContextID combination. Notice that this means that asset IDs are not unique across all of Steam. They aren't even unique across a particular app. They are only unique inside of a given context. For example, there could be two items with asset ID 1 in the same game, as long as they have different context IDs. An item's asset ID may be referred to as "assetid" or just plain "id".

Context IDs and asset IDs are assigned by the game developer and can follow any pattern. They can change when traded or not. They may both be up to 64 bits in size. Consequently, Steam returns them (like all other 64-bit values) in JSON as strings.

Still following? All of what we've learned so far leads us to this conclusion: in order to uniquely identify an item, you need its AppID, its context ID, and its asset ID. Once you have these three things, only then can you uniquely identify it. In fact, this is how you link to a particular item in a user's inventory: steamcommunity.com/profiles/steamid/inventory#appid_contextid_assetid. Here's an example: https://steamcommuni...440_2_134161610

What on Earth are these "classid" and "instanceid" values though??
The observant reader may have noticed that there are two more IDs attached to a particular item which I haven't mentioned. These are the "classid" and "instanceid". These IDs are used to map an asset to its description.

What's a description? A description is what you need in order to actually display an item. An item's description contains its name, image, color, market_name, whether it's tradable or not, whether it's marketable or not, and more. There are many endpoints on Steam which return JSON objects representing assets that only contain the asset's AppID, context ID, asset ID, classid, instanceid, and amount. An item's amount is how big of a stack it is. Unstackable items always have an amount of 1. Stackable items (such as Steam gems) may have a larger amount. Stacked items always have the same asset ID.

What's the difference between a classid and an instanceid? Well in a nutshell, a classid "owns" an instanceid. The classid is all you need to get a general overview of an item. For example, items with the same classid will pretty much always have the same name and image. The instanceid allows you to get finer-tuned details such as how many kills are on a strange/StatTrak weapon, or custom names/descriptions.

You can turn a classid/instanceid pair into a description using the GetAssetClassInfo WebAPI method. Notice that the instanceid is actually optional: if you only have a classid that's fine, you just won't get finer details for the item.

Do note that it's possible for a game developer to flush Steam's asset cache entirely, which would change the classid/instanceid of every item. As of the time of this posting, I'm unaware of this ever having been done.

Name? Market Name? Market Hash Name? Halp?
Every asset on Steam has a name. Period. Without a name, there's nothing to show in your inventory. The item's name is the... (wait for it...) name property of its description (shocking, I know). The item's name may be localized if the game's developer has set it up to be.

Every marketable item also has a "market name". This name may be the same as, or different from the item's regular name. The item's market name is the market_name property of its description. This is the name that's displayed in the Steam Community Market when the item is up for sale. Why the distinction? There are some items which have value-affecting data that isn't in their name. For example, CS:GO skins have 5 different tiers of "wear", which isn't in their names. The wear tier is appended to each skin's market name however, so that the different tiers of wear are separated in the market. The market name may be localized or not, and may not exist at all if the item isn't marketable. It's up to the game's developer.

Finally, every marketable item also has a "market hash name", available under the market_hash_name property. This name is supposed to be the English version of the item's market name, but in practice it may vary. For example, Steam Community items prepend the AppID of the originating app to each item's market hash name, but not to the market name. The market hash name is never localized, and may not exist if the item isn't marketable. Again, it's up to the game's developer. You can view the Community Market listings for any marketable item using this URL formula: steamcommunity.com/market/listings/appid/market_hash_name. Here's an example: https://steamcommuni...upply Crate Key

Note that the Community Market has no concept of contexts. Consequently, market [hash] names are unique for a particular "class" of items per-app (and by extension per-context). This means that for marketable items, two items with identical market hash names will be worth roughly the same (with some exceptions, like unusual TF2 items).

Questions?
Ask below. I'm happy to help!


  • Mole, Andrew, trzyrazyzero and 2 others like this


#734 Trading and Escrow -- Mobile Trade Confirmations

Posted by Dr. McKay on 27 April 2016 - 03:19 PM

As of December 2015, all users who are losing items in a trade must have the Steam Guard Mobile Authenticator enabled, or else the trade will be held for three fifteen days. It's also no longer possible to opt-out of trade confirmations.

 

This means that effectively, all trading bots need a mobile authenticator and need to accept mobile trade confirmations. You don't need an actual physical phone to act as your mobile authenticator, however. Through the efforts of myself and others, you can emulate a mobile authenticator right from node.js, and also accept trade confirmations.

 

Enabling a Mobile Authenticator

 

The Steam Guard Mobile Authenticator provides two-factor authentication security (hereinafter "2FA") for your account, which is more secure than standard email-based Steam Guard. This is done using a "shared secret" which is known to both the Steam servers and to your authenticator. Both sides run this secret through an algorithm along with the current time, which produces a 5-character alphanumeric code. This code is only valid for 30 seconds, and can only be used once. Attempts to reuse a 2FA code (either through the Steam Client or by logging in on steamcommunity.com) will treat the code as incorrect and reject it. For this reason, you can't login more frequently than once in a 30-second period.

 

Enabling 2FA is a three-step process.

  1. Link and verify a phone number with your Steam account. You can do this manually from your account page, or programmatically using node-steamstore.
  2. Call enableTwoFactor using either node-steam-user or node-steamcommunity. If successful, this will return an object containing a bunch of properties. You should save this entire object. You can call JSON.stringify on it safely to turn it into a string. You'll need the revocation_code in the future if you ever want to disable 2FA. At this stage, 2FA isn't enabled yet. Steam will send you an SMS containing a code which you'll need in step 3.
  3. Call finalizeTwoFactor using either node-steam-user or node-steamcommunity. You will need the value of the shared_secret property from the object returned in step 2, and the numeric activation code from your SMS. If successful, your Steam account now has 2FA.

Logging in With a Mobile Authenticator

 

If you have 2FA enabled, then for every login you will need to provide a twoFactorCode (unless you're logging in with node-steam-user using a loginKey). You can generate this code using node-steam-totp and your shared_secret which you obtained (and should have saved) when you enabled 2FA.

 

Mobile-Confirming Trades

 

You are now required to confirm all trades in which you lose items. If you don't have 2FA enabled, then these confirmations will go to your email and the trades will be held for fifteen days. If you do have 2FA enabled, then the confirmations must be accepted through Steam's mobile confirmation interface. You can also accept mobile confirmations through node.js.

 

node-steam-tradeoffer-manager doesn't have anything built-in to accept mobile confirmations. This is because mobile confirmations encompass more than just trades -- market listings also require confirmation, and potentially other things in the future.

 

node-steamcommunity can accept your confirmations for you. In order to accept mobile confirmations, you will need the identity_secret (not the shared_secret used for login) from when you enabled 2FA. You have three options for confirming trades:

  1. Call getConfirmations periodically and act on the confirmations that are returned
  2. Use the automatic confirmation checker to check your confirmations automatically and emit events when a new one is received
  3. Provide your identity_secret to the automatic confirmation checker directly and it will just accept everything (there's no going back if you end up accepting something you actually didn't want to accept!)

  • Andreabum and AndrewRoni like this


#497 Error sending trade offer (15)

Posted by danek on 05 April 2016 - 01:53 PM

Hello.

What mean this error:

 

Error: There was an error sending your trade offer.  Please try again later. (15)

 


  • loyare74 and clisteri like this


#4199 Send/receive messages to/from non-friends

Posted by Dr. McKay on 23 August 2017 - 04:24 PM

You should be able to send messages to non-friends if you're in a group chat with them, but that's about it I think.


  • Kim and TheGoldenPotato like this


#3982 How do I get comments in a steam profile?

Posted by Vanish on 28 July 2017 - 05:26 AM

How to get a comment that is posted in a steam profile


  • LeighHyday and ReighHyday like this


#2838 Send items problem

Posted by Soska on 03 March 2017 - 10:56 AM

Hello. There was such problem: when the bot sends two DIFFERENT trades at the same time, for example where there are two or three of the same case. One trade is accepted, the other gets the status "Items unavailable for trade"
 
Items are sent by Market name (the classid and instanceid is always the same. they do not have sense). assetid in the offer and the inventory are different.
 
The task such: to send items that are not currently in other trades of the account.

  • ArlaSokindy and Penneyliz like this


#1537 Minimal code to stay logged in forever...

Posted by Dr. McKay on 06 August 2016 - 11:03 PM

That all looks fine to me. sessionExpired is only emitted when a request you make fails because you aren't logged in. It doesn't check automatically, it only checks whenever the library makes a request somewhere.

 

Starting a new confirmation checker without stopping the old one is just fine. It'll stop an old one if you call it while one is running.

 

I recommend updating to v3.23.1 if you're going to use webchat.


  • yellowish and klonaway like this


#143 TradeOfferManager v2

Posted by Dr. McKay on 03 March 2016 - 02:10 PM

Here's an idea. Three options for createOffer():

  1. manager.createOffer(steamID); // create an offer without a token. you can set it later
  2. manager.createOffer(steamID, token); // create an offer with a token
  3. manager.createOffer(tradeURL); // automatically extract the SteamID and token from the trade URL

  • Mole and PEPZ like this


#476 Detect when Steam kills my sessions

Posted by Dr. McKay on 03 April 2016 - 11:21 PM

No, the event won't fire if there isn't any HTTP traffic going on. But if you pass the SteamCommunity instance to the constructor of TradeOfferManager, then the manager will use that community for its HTTP requests and so no-session requests triggered by the manager will fire the event.


  • Nogtail likes this


#4629 question About Friends and Group

Posted by Dr. McKay on 09 November 2017 - 11:38 AM

https://github.com/D...up#joincallback


  • Ino likes this


#4592 .logOn just never does anything

Posted by Vanilla on 02 November 2017 - 07:48 AM

maybe this?

var SteamUser = require('steam-user');
var newUser = new SteamUser();


details = {
    accountName: '<username>',
    password: '<password>'
}


newUser.logOn(details);

newUser.on('loggedOn', function (details) {
    console.log('Sucesfully Logged in');
    //do something
});

  • Vanilla likes this


#4567 PollFailure ETIMEDOUT

Posted by Verize on 26 October 2017 - 08:13 AM

If you haven't figured it out by now: The confirmation checker is probably getting you rate-limited. That happens if you are sending many requests in a relatively short period of time. That's why the confirmation checker is deprecated - because it does exactly this. Accept all incoming and outgoing offers manually with the method 

acceptConfirmationForObject()

  • Dr. McKay likes this


#4406 how can i get the token in the offerURL

Posted by Andrei Elvis on 27 September 2017 - 07:14 AM

To get just the token from a tradeurl you can use this example:

var tradelink = 'https://steamcommunity.com/tradeoffer/new/?partner=6969696969&token=testtest123';
var token = tradelink.split('token=')[1];
console.log(token); //OUTPUT: testtest123

  • Vanilla likes this


#3969 Getting different keys in tags sometimes on tradeOffer.itemsToReceive

Posted by Dr. McKay on 25 July 2017 - 10:03 PM

Steam sends the data differently sometimes. Update to 2.8.1 and I've made the tags objects all be standard (that is, they have all the properties).


  • Eric likes this


#3112 Card Sets

Posted by Dr. McKay on 08 April 2017 - 05:08 PM

The easiest way to determine which game a community item belongs to is to check its market_hash_name. All cards/emoticons/backgrounds have their market_hash_names prefixed with the game's appid and a hyphen (e.g. "440-SCOUT").


  • TomYoki likes this


#2256 How to only accept CSGO keys in 'newOffer'

Posted by Dr. McKay on 10 December 2016 - 12:16 AM

offer.itemsToReceive contains an array of the items you'd receive if you accepted this offer. For each item in this array, check appid to make sure it's CS:GO and name to make sure it's a key. For example:

var allItemsAreGood = offer.itemsToReceive.every(function(item) { return item.appid == 730 && item.name == "CS:GO Case Key"; });

  • Coyeks likes this


#2201 How to Get All Item From CS GO

Posted by maraya on 29 November 2016 - 06:31 AM

sir, can u help me.
i want get all item from this: http://steamcommunit...earch?appid=730

i have tried a few API, but have not been successful.
 
first i'm using this API:
http://api.steampowe...ge=en&appid=730
from here i get a $id.
an i combine it with 
 
but still not successful.

thank you.

  • evirtual_dev likes this


#1547 tradeOffers event and changes in state

Posted by Dr. McKay on 09 August 2016 - 01:15 AM

Correct. steam-tradeoffer-manager will handle all that polling for you.


  • Ryan likes this


#1535 Minimal code to stay logged in forever...

Posted by klonaway on 06 August 2016 - 07:59 PM

I have spent some time checking the node-steamcommunity GitHub wiki, and first of all : Dr. McKay, you are a hero for building up such an easy npm interface for the messy Steam API...

 

I came up with some code to make sure I'm logged in almost 24/7 :

// Modules are required and secret stuff is ready...

function logOnSteam() {
	
  console.log("Logging in to Steam...");
  steamCommunity.login(logOnOptions, function (e, sessionID, cookies, steamguard) {

    if (e) {
      console.log("There was an error logging in ! Error details : " + e.message);
      setTimeout(logOnSteam, 1000*60*4); // try to reconnect in 4 minutes
      return;

    } else {

      console.log("Successfully logged in as " + logOnOptions.accountName + " !");
      steamCommunity.chatLogon(); // to appear online
      tradeOfferManager.setCookies(cookies, function (err) {
        if (err) {
          console.log(err);
          return;
        }
      });
    }
    // automatic confirmation of EVERYTHING every "confirmationPeriod" ms
    steamCommunity.startConfirmationChecker(confirmationPeriod, identitySecret);
  });
}

function checkSteamLogged() {

  steamCommunity.loggedIn( function (err, loggedIn, familyView) {
    if (err) {
      console.log(err);
      setTimeout(checkSteamLogged, 1000*60*4); // check again in 4 min
    } else if ( ! loggedIn ) {
      console.log("Steam login check : NOT LOGGED IN !");
      logOnSteam();
    } else {
      console.log("Steam login check : already logged in !");
    }
  });
}

steamCommunity.on('sessionExpired', function (err) {
  if (err) {console.log(err);}
  logOnSteam();
});

logOnSteam();
setInterval(checkSteamLogged, 1000*60*30);

I guess this is enough to be safe... (unless I made some rookie mistake ?)

 

This code is obviously the starting point for some TradeOfferManager handling, and I was wondering if I didn't go too far :

  • if the 'sessionExpired' event is really triggered whenever we are not logged in, does it mean the 'checkSteamLogged()' function can be safely removed without harm ?
  • '.startConfirmationChecker()' doesn't create a new instance each time it is called ? (I don't want to trigger 10 confirmations checkers leading to 10 times the intended check rate...)

Thanks for any input !


  • yellowish likes this


#1455 Constant RateLimitExceeded

Posted by Dr. McKay on 19 July 2016 - 09:22 AM

You should make it stop restarting the script a lot of times.


  • freaders likes this