14 KiB
Steam Bot Setup Guide
🤖 Overview
The Steam bot system handles trade offers for buying items from users. When a user sells items, instead of immediately crediting funds, the system:
- ✅ Creates a trade offer via Steam bot
- ⏳ Tracks trade state (pending, accepted, declined, etc.)
- 💰 Credits user balance ONLY after trade is accepted
- 🔄 Handles failures, expirations, and retries
📋 Prerequisites
1. Steam Bot Account
You need a separate Steam account for the bot:
- ✅ Account with Steam Mobile Authenticator enabled
- ✅ Public inventory
- ✅ Valid trade URL
- ✅ API key from https://steamcommunity.com/dev/apikey
- ✅ Not limited (must have spent $5+ on Steam)
- ✅ Trade cooldown period expired (if newly set up)
2. Required Packages
Already installed in package.json:
{
"steam-user": "^5.0.0",
"steamcommunity": "^3.47.0",
"steam-tradeoffer-manager": "^2.10.6",
"steam-totp": "^2.1.1"
}
Install if needed:
npm install steam-user steamcommunity steam-tradeoffer-manager steam-totp
🔐 Getting Steam Bot Credentials
Step 1: Get Shared Secret & Identity Secret
-
Enable Steam Mobile Authenticator on bot account
-
Use one of these tools to extract secrets:
- SDA (Steam Desktop Authenticator): https://github.com/Jessecar96/SteamDesktopAuthenticator
- Android: Use app like "Steam Guard Mobile Authenticator"
- Manual extraction: Follow guides online
-
You'll need:
shared_secret- For generating 2FA codesidentity_secret- For confirming trades
Step 2: Get Steam API Key
- Go to: https://steamcommunity.com/dev/apikey
- Register domain:
turbotrades.com(or your domain) - Copy the API key
Step 3: Get Bot Trade URL
- Login to bot account
- Go to: https://steamcommunity.com/id/me/tradeoffers/privacy
- Copy the trade URL (looks like:
https://steamcommunity.com/tradeoffer/new/?partner=XXXXX&token=XXXXXXXX)
⚙️ Configuration
Environment Variables
Add to your .env file:
# Steam Bot Credentials
STEAM_BOT_USERNAME=your_bot_username
STEAM_BOT_PASSWORD=your_bot_password
STEAM_BOT_SHARED_SECRET=your_shared_secret_here
STEAM_BOT_IDENTITY_SECRET=your_identity_secret_here
# Steam API
STEAM_API_KEY=your_steam_api_key
# Bot Trade URL
STEAM_BOT_TRADE_URL=https://steamcommunity.com/tradeoffer/new/?partner=XXXXX&token=XXXXXXXX
# Optional: Bot Settings
STEAM_BOT_POLL_INTERVAL=30000
STEAM_BOT_AUTO_START=true
Security Notes
- ⚠️ NEVER commit
.envto git - ⚠️ Keep secrets secure
- ⚠️ Use different account from your personal Steam
- ⚠️ Enable Steam Guard on bot account
- ⚠️ Use strong password
🚀 Starting the Bot
Automatic Start (Recommended)
Bot starts automatically when backend launches if STEAM_BOT_AUTO_START=true
npm run dev
You'll see:
🔐 Logging into Steam...
✅ Steam bot logged in successfully
✅ Steam web session established
🤖 Steam bot ready for trades
Manual Start
import { getSteamBot } from './services/steamBot.js';
const bot = getSteamBot();
await bot.login();
console.log('Bot ready:', bot.isOnline());
🔄 How It Works
User Sells Items Flow
1. User selects items on Sell page
2. User clicks "Sell Selected Items"
↓
3. Backend creates Trade record (state: pending)
- Does NOT credit balance yet
↓
4. Steam bot creates trade offer
- Requests items from user
- User sees trade offer in Steam
↓
5. User accepts trade in Steam app
↓
6. Bot receives "trade accepted" event
↓
7. Backend:
- Updates Trade state to "accepted"
- Creates Transaction record
- Credits user balance
- Updates WebSocket
↓
8. User sees balance update in UI
Trade States
| State | Description | User Balance | Can Retry |
|---|---|---|---|
| pending | Trade offer sent, waiting for user | ❌ Not credited | ✅ Yes |
| accepted | User accepted, items received | ✅ Credited | ❌ No |
| declined | User declined the offer | ❌ Not credited | ⚠️ Maybe |
| expired | Trade offer expired (10min timeout) | ❌ Not credited | ✅ Yes |
| canceled | Trade was canceled | ❌ Not credited | ✅ Yes |
| failed | Technical error occurred | ❌ Not credited | ✅ Yes |
| escrow | Trade in Steam escrow | ❌ Not credited | ⏳ Wait |
📊 Database Schema
Trade Model
{
offerId: String, // Steam trade offer ID
userId: ObjectId, // User who's selling
steamId: String, // User's Steam ID
state: String, // pending, accepted, declined, etc.
items: [{
assetId: String,
name: String,
price: Number,
image: String,
// ... item details
}],
totalValue: Number, // Total price of all items
fee: Number, // Platform fee (e.g., 5%)
feePercentage: Number, // Fee percentage
userReceives: Number, // Amount user gets (after fees)
tradeUrl: String, // User's trade URL
tradeOfferUrl: String, // Link to view offer on Steam
sentAt: Date, // When trade was sent
acceptedAt: Date, // When user accepted
completedAt: Date, // When balance was credited
expiresAt: Date, // When trade expires (10min)
transactionId: ObjectId, // Transaction created after acceptance
sessionId: ObjectId, // User's session
errorMessage: String, // If failed
retryCount: Number, // How many times retried
metadata: Mixed // Additional data
}
🎮 Bot Events
The bot emits events you can listen to:
const bot = getSteamBot();
// Bot is ready
bot.on('ready', () => {
console.log('Bot is ready!');
});
// Trade accepted
bot.on('tradeAccepted', async (offer, tradeData) => {
console.log('Trade accepted:', offer.id);
// Credit user balance here
});
// Trade declined
bot.on('tradeDeclined', async (offer, tradeData) => {
console.log('Trade declined:', offer.id);
// Notify user
});
// Trade expired
bot.on('tradeExpired', async (offer, tradeData) => {
console.log('Trade expired:', offer.id);
// Can retry or cancel
});
// Bot error
bot.on('error', (err) => {
console.error('Bot error:', err);
});
// Bot disconnected
bot.on('disconnected', () => {
console.warn('Bot disconnected, will reconnect...');
});
🛠️ API Endpoints
Create Trade Offer
POST /api/trade/create
Authorization: Bearer <token>
{
"items": [
{
"assetId": "123456789",
"name": "AK-47 | Redline (Field-Tested)",
"price": 12.50,
"image": "https://...",
// ... other item data
}
]
}
Response:
{
"success": true,
"trade": {
"id": "trade_id",
"offerId": "steam_offer_id",
"state": "pending",
"totalValue": 12.50,
"userReceives": 11.88,
"items": [...],
"tradeOfferUrl": "https://steamcommunity.com/tradeoffer/...",
"expiresAt": "2024-01-10T12:10:00Z"
},
"message": "Trade offer sent! Check your Steam app to accept."
}
Get Trade Status
GET /api/trade/:tradeId
Authorization: Bearer <token>
Response:
{
"success": true,
"trade": {
"id": "trade_id",
"offerId": "steam_offer_id",
"state": "accepted",
"totalValue": 12.50,
"userReceives": 11.88,
"acceptedAt": "2024-01-10T12:05:00Z",
"timeElapsed": "5m ago"
}
}
Cancel Trade
POST /api/trade/:tradeId/cancel
Authorization: Bearer <token>
Retry Trade
POST /api/trade/:tradeId/retry
Authorization: Bearer <token>
🔧 Bot Management
Check Bot Status
const bot = getSteamBot();
const health = bot.getHealth();
console.log(health);
// {
// isReady: true,
// isLoggedIn: true,
// activeTradesCount: 5,
// username: "bot_username"
// }
Get Active Trades
const activeTrades = bot.getActiveTrades();
console.log(`${activeTrades.length} trades active`);
Cancel All Pending Trades
const pendingTrades = await Trade.getPendingTrades();
for (const trade of pendingTrades) {
if (trade.isExpired) {
await bot.cancelTradeOffer(trade.offerId);
await trade.markAsExpired();
}
}
🧪 Testing
Test Bot Login
node -e "import('./services/steamBot.js').then(async m => {
const bot = m.getSteamBot();
await bot.login();
console.log('Bot logged in:', bot.isOnline());
bot.logout();
process.exit(0);
})"
Test Trade Creation
const bot = getSteamBot();
await bot.login();
const result = await bot.createTradeOffer({
tradeUrl: "https://steamcommunity.com/tradeoffer/new/?partner=XXX&token=XXX",
itemsToReceive: [
{ assetid: "123456789", appid: 730, contextid: 2 }
],
message: "Test trade offer"
});
console.log('Trade created:', result);
📈 Monitoring
Database Queries
// Get all pending trades
const pending = await Trade.find({ state: 'pending' });
// Get expired trades
const expired = await Trade.getExpiredTrades();
// Get trade stats
const stats = await Trade.getStats();
console.log(`
Total trades: ${stats.total}
Accepted: ${stats.accepted}
Pending: ${stats.pending}
Declined: ${stats.declined}
`);
// Get user's trades
const userTrades = await Trade.getUserTrades(userId);
Admin Panel Integration
Add to admin panel:
- ✅ View pending trades
- ✅ Cancel stale trades
- ✅ Retry failed trades
- ✅ View trade statistics
- ✅ Bot health status
🐛 Troubleshooting
Bot Won't Login
Check:
- ✅ Username and password correct
- ✅ Shared secret is valid
- ✅ Steam account not limited
- ✅ No active VAC ban
- ✅ No trade cooldown
Solution:
# Test credentials
node -e "console.log('Username:', process.env.STEAM_BOT_USERNAME)"
node -e "console.log('Has password:', !!process.env.STEAM_BOT_PASSWORD)"
node -e "console.log('Has shared secret:', !!process.env.STEAM_BOT_SHARED_SECRET)"
Trades Not Confirming
Check:
- ✅ Identity secret is correct
- ✅ Mobile authenticator is active
- ✅ Bot has trade URL
Solution:
- Manually confirm in Steam app first time
- Check if identity secret is correct
- Regenerate secrets if needed
Trades Stuck in Pending
Reasons:
- User hasn't accepted yet
- Trade expired (10 minutes)
- Steam API issues
- User's inventory is private
Solution:
// Cancel expired trades
const expired = await Trade.find({
state: 'pending',
expiresAt: { $lt: new Date() }
});
for (const trade of expired) {
await bot.cancelTradeOffer(trade.offerId);
await trade.markAsExpired();
}
Bot Keeps Disconnecting
Check:
- ✅ Network connection stable
- ✅ Steam not under maintenance
- ✅ No rate limiting
Solution:
- Implement auto-reconnect (already built-in)
- Use connection pooling
- Monitor logs for error patterns
🔒 Security Best Practices
1. Secure Credentials
- ✅ Never hardcode credentials
- ✅ Use environment variables
- ✅ Keep .env out of git
- ✅ Rotate secrets regularly
2. Trade Validation
- ✅ Verify user owns items before creating trade
- ✅ Check item values match database
- ✅ Validate trade URLs
- ✅ Prevent duplicate trades
3. Rate Limiting
- ✅ Limit trades per user per hour
- ✅ Limit total trades per minute
- ✅ Queue trades during high load
4. Monitoring
- ✅ Log all trade events
- ✅ Alert on failed trades
- ✅ Track bot uptime
- ✅ Monitor Steam API status
📊 Performance Optimization
Trade Queue System
For high volume, implement trade queue:
// Redis-based queue
import Bull from 'bull';
const tradeQueue = new Bull('trades', {
redis: { host: 'localhost', port: 6379 }
});
tradeQueue.process(async (job) => {
const { userId, items } = job.data;
return await createTradeOffer(userId, items);
});
// Add to queue
await tradeQueue.add({ userId, items }, {
attempts: 3,
backoff: {
type: 'exponential',
delay: 2000
}
});
Retry Strategy
async function createTradeWithRetry(data, maxRetries = 3) {
let lastError;
for (let i = 0; i < maxRetries; i++) {
try {
return await bot.createTradeOffer(data);
} catch (error) {
lastError = error;
await sleep(Math.pow(2, i) * 1000); // Exponential backoff
}
}
throw lastError;
}
🎯 Next Steps
Phase 1: Basic Setup (You are here)
- Install packages
- Create bot service
- Create Trade model
- Configure environment variables
- Test bot login
Phase 2: Integration
- Update sell endpoint to create trades
- Add trade event handlers
- Credit balance on acceptance
- Add trade status polling
Phase 3: Frontend
- Show trade status in UI
- Add "View Trade" button
- Show pending trades list
- Add trade notifications
Phase 4: Admin Tools
- Bot health dashboard
- Trade management panel
- Retry/cancel controls
- Statistics and reports
Phase 5: Advanced
- Trade queue system
- Multiple bot support
- Automatic retries
- Fraud detection
📚 Additional Resources
- Steam Web API: https://developer.valvesoftware.com/wiki/Steam_Web_API
- Trade Offer Manager: https://github.com/DoctorMcKay/node-steam-tradeoffer-manager
- Steam User: https://github.com/DoctorMcKay/node-steam-user
- Steam TOTP: https://github.com/DoctorMcKay/node-steam-totp
✅ Configuration Checklist
Before going live:
- Bot account created and funded ($5+ spent)
- Steam Mobile Authenticator enabled
- Shared secret and identity secret extracted
- API key obtained from Steam
- Environment variables configured
- Bot successfully logs in
- Test trade offer sent and accepted
- Trade events properly handled
- Balance credits on acceptance
- Error handling tested
- Monitoring set up
- Backup credentials stored securely
Status: Implementation Ready Next: Configure bot credentials and test login Priority: High - Required for production sell functionality