A Go library for downloading Steam app content and Workshop items without the Steam client.
- Anonymous downloads for publicly accessible apps (no account required)
- Authenticated downloads for paid games and Workshop items
- Incremental updates — only downloads chunks that differ from what is already on disk
- Concurrent chunk downloads with configurable parallelism
- Supports VZip-ZSTD, VZip-LZMA, ZIP, and ZLib chunk formats
- Steam Guard support: TOTP authenticator (automatic) and email (via callback)
- Local cache for sessions, depot keys, and CDN tokens across runs
Go 1.26+
import steam "github.com/BirknerAlex/go-steam"
ctx := context.Background()
client, err := steam.New(ctx, steam.Config{
// Omit Username/Password for anonymous access (free/public apps only).
Username: "myaccount",
Password: "mypassword",
// SteamGuardCallback is called when Steam Guard is required.
// Use steam.InteractiveSteamGuard to prompt stdin, or provide your own.
SteamGuardCallback: steam.InteractiveSteamGuard,
// CachePath defaults to ~/.cache/go-steam
})
if err != nil {
log.Fatal(err)
}
defer client.Close()
// Download a Steam app.
ch, err := client.DownloadApp(ctx, steam.AppDownloadRequest{
AppID: 1623730, // Palworld
OS: "linux",
TargetDir: "/opt/palworld",
})
if err != nil {
log.Fatal(err)
}
for p := range ch {
if p.Err != nil {
log.Fatal(p.Err)
}
fmt.Printf("[%s] %d/%d chunks\n", p.Phase, p.DoneChunks, p.TotalChunks)
}// Download a Steam Workshop item (requires authenticated session).
ch, err := client.DownloadWorkshopItem(ctx, steam.WorkshopDownloadRequest{
ItemID: 3625223587,
TargetDir: "/tmp/workshop-item",
})go run ./cmd/app-download \
-app 1623730 \
-os linux \
-username myaccount \
-password mypassword \
-output /opt/palworld \
-v
Flags:
| Flag | Default | Description |
|---|---|---|
-app |
— | Steam App ID |
-depots |
all | Comma-separated depot IDs to restrict download |
-branch |
public |
Branch name |
-branch-password |
— | Password for protected beta branches |
-os |
linux |
OS filter: linux, windows, macos, or empty for all |
-lang |
all | Language filter (e.g. english) |
-username |
— | Steam account username (omit for anonymous) |
-password |
— | Steam account password |
-totp-secret |
— | Base64 TOTP shared secret for automatic Steam Guard |
-output |
./output |
Destination directory |
-validate |
false | Verify on-disk files without re-downloading |
-cache |
~/.cache/go-steam |
Cache directory |
-v |
false | Verbose logging |
go run ./cmd/workshop-download \
-item 3625223587 \
-username myaccount \
-password mypassword \
-output /tmp/workshop \
-v
Flags:
| Flag | Default | Description |
|---|---|---|
-item |
— | Workshop Published File ID |
-username |
— | Steam account username (required) |
-password |
— | Steam account password |
-totp-secret |
— | Base64 TOTP shared secret for Steam Guard |
-output |
./output |
Destination directory |
-cache |
~/.cache/go-steam |
Cache directory |
-v |
false | Verbose logging |
go run ./cmd/guard -secret <base64-totp-secret>
- Connects to a Steam CM (Connection Manager) server over WebSocket (TLS)
- Performs an AES encryption handshake using Steam's RSA public key
- Authenticates anonymously or via the Steam Authentication v2 flow (RSA-encrypted password → optional Steam Guard → access token)
- Caches the access token to disk so subsequent runs skip re-authentication
- Fetches app info via the PICS protocol to discover depots and manifest GIDs
- Obtains a manifest request code from the CM (required for modern CDN auth)
- Downloads and decrypts the depot manifest (AES-CBC, then LZMA decompression)
- Diffs the manifest against existing on-disk content using per-chunk SHA-1
- Downloads only the missing/changed chunks from Steam CDN servers concurrently
- For each chunk: decrypts (AES-256 ECB-IV+CBC), detects format (VZip-ZSTD / VZip-LZMA / ZIP / ZLib), decompresses, verifies SHA-1, and writes to disk
- Workshop downloads require an authenticated session with ownership of the parent app
- Email-based Steam Guard works interactively via
SteamGuardCallback; TOTP is fully automatic with-totp-secret - Anonymous sessions only work for apps that expose anonymous depot access
- Branch password support is wired up but not widely tested
This project stands on a great deal of knowledge from the SteamKit project — the wire formats, the CM protocol, the manifest and depot-chunk layouts (VZip-LZMA, VZip-ZSTD, PKZip), and Steam's AES symmetric scheme were all learned from SteamKit's implementation and documentation. Several of our regression tests are direct ports of SteamKit's own test fixtures (real depot chunks, manifests, and PICS packets) so our decoders can be validated against the same ground truth. We are very grateful to the SteamKit maintainers and contributors for their excellent, long-running work.
This project's source code is licensed under the MIT License.
The binary test fixtures vendored under internal/*/testdata/ are copied from SteamKit's test suite and remain under the LGPL-2.1 license — they are used only by go test and are never compiled into the library. See THIRD_PARTY_NOTICES.md for full attribution.