Encode and decode CS2 masked inspect links
Project description
cs2-masked-inspect (Python)
Pure Python library for encoding and decoding CS2 masked inspect links — no external dependencies.
Installation
pip install vlydev-cs2-masked-inspect
Usage
Deserialize a CS2 inspect link
from cs2_inspect import deserialize
# Accepts a full steam:// URL or a raw hex string
item = deserialize(
'steam://run/730//+csgo_econ_action_preview%20E3F3367440334DE2FBE4C345E0CBE0D3...'
)
print(item.defindex) # 7 (AK-47)
print(item.paintindex) # 422
print(item.paintseed) # 922
print(item.paintwear) # ~0.04121
print(item.itemid) # 46876117973
for s in item.stickers:
print(s.sticker_id) # 7436, 5144, 6970, 8069, 5592
Serialize an item to a hex payload
from cs2_inspect import serialize, ItemPreviewData
data = ItemPreviewData(
defindex=60,
paintindex=440,
paintseed=353,
paintwear=0.005411375779658556,
rarity=5,
)
hex_str = serialize(data)
# 00183C20B803280538E9A3C5DD0340E102C246A0D1
url = f"steam://run/730//+csgo_econ_action_preview%20{hex_str}"
Item with stickers and keychains
from cs2_inspect import serialize, ItemPreviewData, Sticker
data = ItemPreviewData(
defindex=7,
paintindex=422,
paintseed=922,
paintwear=0.04121,
rarity=3,
quality=4,
stickers=[
Sticker(slot=0, sticker_id=7436),
Sticker(slot=1, sticker_id=5144, wear=0.1),
],
)
hex_str = serialize(data)
decoded = deserialize(hex_str) # round-trip
Gen codes
Generate a Steam inspect URL from item parameters (defindex, paintindex, paintseed, paintwear):
from cs2_inspect import generate, to_gen_code, parse_gen_code, ItemPreviewData, Sticker
# Generate a Steam inspect URL from item parameters
url = generate(7, 474, 306, 0.22540508)
# steam://rungame/730/76561202255233023/+csgo_econ_action_preview%20...
# Convert ItemPreviewData to a gen code string
item = ItemPreviewData(defindex=7, paintindex=474, paintseed=306, paintwear=0.22540508)
code = to_gen_code(item) # "!gen 7 474 306 0.22540508"
code = to_gen_code(item, "!g") # "!g 7 474 306 0.22540508"
# With stickers (slot index 0–4, padded to 5 pairs) and keychain
item2 = ItemPreviewData(
defindex=7, paintindex=941, paintseed=2, paintwear=0.22540508,
stickers=[Sticker(slot=2, sticker_id=7203, wear=0.0)],
keychains=[Sticker(slot=0, sticker_id=36, wear=0.0)],
)
to_gen_code(item2, "!g")
# "!g 7 941 2 0.22540508 0 0 0 0 7203 0 0 0 0 0 36 0"
# Parse a gen code back to ItemPreviewData
item3 = parse_gen_code("!gen 7 474 306 0.22540508")
# Convert an existing inspect link directly to a gen code
from cs2_inspect import gen_code_from_link
code = gen_code_from_link("steam://rungame/730/76561202255233023/+csgo_econ_action_preview%20001A...")
# "!gen 7 474 306 0.22540508"
Validation
Use is_masked() and is_classic() to detect the link type without decoding it.
from cs2_inspect import is_masked, is_classic
# New masked format (pure hex blob) — can be decoded offline
masked_url = 'steam://run/730//+csgo_econ_action_preview%20E3F3...'
is_masked(masked_url) # True
is_classic(masked_url) # False
# Hybrid format (S/A/D prefix with hex proto after D) — also decodable offline
hybrid_url = 'steam://rungame/730/.../+csgo_econ_action_preview%20S76561199323320483A50075495125D1101C4C4FCD4AB10...'
is_masked(hybrid_url) # True
is_classic(hybrid_url) # False
# Classic format — requires Steam Game Coordinator to fetch item info
classic_url = 'steam://rungame/730/.../+csgo_econ_action_preview%20S76561199842063946A49749521570D2751293026650298712'
is_masked(classic_url) # False
is_classic(classic_url) # True
Validation rules
deserialize() enforces:
| Rule | Limit | Exception |
|---|---|---|
| Hex payload length | max 4,096 characters | ValueError |
| Protobuf field count | max 100 per message | ValueError |
serialize() enforces:
| Field | Constraint | Exception |
|---|---|---|
paintwear |
[0.0, 1.0] |
ValueError |
customname |
max 100 characters | ValueError |
How the format works
Three URL formats are handled:
-
New masked format — pure hex blob after
csgo_econ_action_preview:steam://run/730//+csgo_econ_action_preview%20<hexbytes> -
Hybrid format — old-style
S/A/Dprefix, but with a hex proto appended afterD(instead of a decimal did):steam://rungame/730/.../+csgo_econ_action_preview%20S<steamid>A<assetid>D<hexproto> -
Classic format — old-style
S/A/Dwith a decimal did; requires Steam GC to resolve item details.
For formats 1 and 2 the library decodes the item offline. For format 3 only URL parsing is possible.
The hex blob (formats 1 and 2) has the following binary layout:
[key_byte] [proto_bytes XOR'd with key] [4-byte checksum XOR'd with key]
| Section | Size | Description |
|---|---|---|
key_byte |
1 byte | XOR key. 0x00 = no obfuscation (tool links). Other values = native CS2 links. |
proto_bytes |
variable | CEconItemPreviewDataBlock protobuf, each byte XOR'd with key_byte. |
checksum |
4 bytes | Big-endian uint32, XOR'd with key_byte. |
Checksum algorithm
import zlib, struct
buffer = b'\x00' + proto_bytes
crc = zlib.crc32(buffer) & 0xFFFFFFFF
xored = ((crc & 0xFFFF) ^ (len(proto_bytes) * crc)) & 0xFFFFFFFF
checksum = struct.pack('>I', xored) # big-endian uint32
paintwear encoding
paintwear is stored as a uint32 varint whose bit pattern is the IEEE 754 representation
of a float32. The library handles this transparently — callers always work with Python float values.
Proto field reference
CEconItemPreviewDataBlock
| Field | Number | Type | Description |
|---|---|---|---|
accountid |
1 | uint32 | Steam account ID (often 0) |
itemid |
2 | uint64 | Item ID in the owner's inventory |
defindex |
3 | uint32 | Item definition index (weapon type) |
paintindex |
4 | uint32 | Skin paint index |
rarity |
5 | uint32 | Item rarity |
quality |
6 | uint32 | Item quality |
paintwear |
7 | uint32* | float32 reinterpreted as uint32 |
paintseed |
8 | uint32 | Pattern seed (0–1000) |
killeaterscoretype |
9 | uint32 | StatTrak counter type |
killeatervalue |
10 | uint32 | StatTrak value |
customname |
11 | string | Name tag |
stickers |
12 | repeated Sticker | Applied stickers |
inventory |
13 | uint32 | Inventory flags |
origin |
14 | uint32 | Origin |
questid |
15 | uint32 | Quest ID |
dropreason |
16 | uint32 | Drop reason |
musicindex |
17 | uint32 | Music kit index |
entindex |
18 | int32 | Entity index |
petindex |
19 | uint32 | Pet index |
keychains |
20 | repeated Sticker | Applied keychains |
Sticker
| Field | Number | Type | Description |
|---|---|---|---|
slot |
1 | uint32 | Slot position |
sticker_id |
2 | uint32 | Sticker definition ID |
wear |
3 | float32 | Wear (fixed32) |
scale |
4 | float32 | Scale (fixed32) |
rotation |
5 | float32 | Rotation (fixed32) |
tint_id |
6 | uint32 | Tint |
offset_x |
7 | float32 | X offset (fixed32) |
offset_y |
8 | float32 | Y offset (fixed32) |
offset_z |
9 | float32 | Z offset (fixed32) |
pattern |
10 | uint32 | Pattern (keychains) |
Known test vectors
Vector 1 — Native CS2 link (XOR key 0xE3)
E3F3367440334DE2FBE4C345E0CBE0D3E7DB6943400AE0A379E481ECEBE2F36F
D9DE2BDB515EA6E30D74D981ECEBE3F37BCBDE640D475DA6E35EFCD881ECEBE3
F359D5DE37E9D75DA6436DD3DD81ECEBE3F366DCDE3F8F9BDDA69B43B6DE81EC
EBE3F33BC8DEBB1CA3DFA623F7DDDF8B71E293EBFD43382B
| Field | Value |
|---|---|
itemid |
46876117973 |
defindex |
7 (AK-47) |
paintindex |
422 |
paintseed |
922 |
paintwear |
≈ 0.04121 |
rarity |
3 |
quality |
4 |
| sticker IDs | [7436, 5144, 6970, 8069, 5592] |
Vector 2 — Tool-generated link (key 0x00)
ItemPreviewData(defindex=60, paintindex=440, paintseed=353,
paintwear=0.005411375779658556, rarity=5)
Expected hex:
00183C20B803280538E9A3C5DD0340E102C246A0D1
Running tests
pip install pytest
pytest tests/
Contributing
Bug reports and pull requests are welcome on GitHub.
- Fork the repository
- Create a branch:
git checkout -b my-fix - Make your changes and add tests
- Ensure all tests pass:
pytest tests/ - Open a Pull Request
All PRs require the CI checks to pass before merging.
Author
VlyDev — vladdnepr1989@gmail.com
License
MIT © VlyDev
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file vlydev_cs2_masked_inspect-1.1.5.tar.gz.
File metadata
- Download URL: vlydev_cs2_masked_inspect-1.1.5.tar.gz
- Upload date:
- Size: 22.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9d770fb55da4e2794b17284b78303ac2b6787e74e78c0f5f98e10395ad12fdbf
|
|
| MD5 |
94746900c1c977c23096c55947df3441
|
|
| BLAKE2b-256 |
0f6ca1079aacb87532761489e20cb8cc96a21a489d50e144cf46a01952f2179a
|
Provenance
The following attestation bundles were made for vlydev_cs2_masked_inspect-1.1.5.tar.gz:
Publisher:
release.yml on vlydev/cs2-masked-inspect-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
vlydev_cs2_masked_inspect-1.1.5.tar.gz -
Subject digest:
9d770fb55da4e2794b17284b78303ac2b6787e74e78c0f5f98e10395ad12fdbf - Sigstore transparency entry: 1437334575
- Sigstore integration time:
-
Permalink:
vlydev/cs2-masked-inspect-python@d947d5b3c4386bfc7c095217077a220f69e69d90 -
Branch / Tag:
refs/tags/v1.1.5 - Owner: https://github.com/vlydev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@d947d5b3c4386bfc7c095217077a220f69e69d90 -
Trigger Event:
release
-
Statement type:
File details
Details for the file vlydev_cs2_masked_inspect-1.1.5-py3-none-any.whl.
File metadata
- Download URL: vlydev_cs2_masked_inspect-1.1.5-py3-none-any.whl
- Upload date:
- Size: 15.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c59eb8e81aa1db32754504ea8f4e6d68a9dd6a486d2c98713cd7e261a888737b
|
|
| MD5 |
6fb3bc52df1d7f88e82713f2f444d875
|
|
| BLAKE2b-256 |
f42600b3a916584142a15519cab9a2078a71119f3f1f5154d08493586788de60
|
Provenance
The following attestation bundles were made for vlydev_cs2_masked_inspect-1.1.5-py3-none-any.whl:
Publisher:
release.yml on vlydev/cs2-masked-inspect-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
vlydev_cs2_masked_inspect-1.1.5-py3-none-any.whl -
Subject digest:
c59eb8e81aa1db32754504ea8f4e6d68a9dd6a486d2c98713cd7e261a888737b - Sigstore transparency entry: 1437334605
- Sigstore integration time:
-
Permalink:
vlydev/cs2-masked-inspect-python@d947d5b3c4386bfc7c095217077a220f69e69d90 -
Branch / Tag:
refs/tags/v1.1.5 - Owner: https://github.com/vlydev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@d947d5b3c4386bfc7c095217077a220f69e69d90 -
Trigger Event:
release
-
Statement type: