23 KiB
Multi-Bot Setup with Proxies & Verification Codes
🎯 Overview
TurboTrades now supports multiple Steam bots with:
- ✅ Load Balancing - Automatically distributes trades across bots
- ✅ Proxy Support - Each bot can use different proxy (SOCKS5/HTTP)
- ✅ Verification Codes - 6-digit codes shown on site and in trade
- ✅ Automatic Failover - If one bot fails, others take over
- ✅ Health Monitoring - Track bot status and performance
🔐 Why Verification Codes?
Security Feature: Prevents scam bots from impersonating your trade offers.
How it works:
- User clicks "Sell Items" on website
- System generates unique 6-digit code (e.g.,
A3K9P2) - Code is shown prominently on website
- Same code is included in Steam trade offer message
- User MUST verify code matches before accepting
Benefits:
- ✅ User can verify trade is legitimate
- ✅ Prevents phishing/fake trade offers
- ✅ Adds extra layer of security
- ✅ Easy to implement and understand
📋 Prerequisites
For Each Bot Account:
-
Separate Steam Account
- Not your personal account!
- Must have spent $5+ (not limited)
- Public inventory
- Valid trade URL
-
Steam Mobile Authenticator
- Enabled on each bot account
- Trade cooldown period expired (7 days)
-
Shared Secret & Identity Secret
- Extract using SDA (Steam Desktop Authenticator)
- Or use mobile app extraction tools
-
Steam API Key
- Get from: https://steamcommunity.com/dev/apikey
- Can use same API key for all bots
-
Proxy (Optional but Recommended)
- SOCKS5 or HTTP/HTTPS proxy
- One proxy per bot
- Prevents IP rate limiting
🛠️ Bot Configuration
Configuration File Format
Create config/steam-bots.json:
{
"bots": [
{
"accountName": "turbobot_01",
"password": "secure_password_1",
"sharedSecret": "abcdef1234567890",
"identitySecret": "xyz9876543210abc",
"steamApiKey": "YOUR_STEAM_API_KEY",
"proxy": {
"type": "socks5",
"host": "proxy1.example.com",
"port": 1080,
"username": "proxy_user",
"password": "proxy_pass"
},
"maxConcurrentTrades": 10,
"pollInterval": 30000,
"tradeTimeout": 600000
},
{
"accountName": "turbobot_02",
"password": "secure_password_2",
"sharedSecret": "fedcba0987654321",
"identitySecret": "cba0123456789xyz",
"steamApiKey": "YOUR_STEAM_API_KEY",
"proxy": {
"type": "http",
"host": "proxy2.example.com",
"port": 8080,
"username": "proxy_user2",
"password": "proxy_pass2"
},
"maxConcurrentTrades": 10,
"pollInterval": 30000,
"tradeTimeout": 600000
},
{
"accountName": "turbobot_03",
"password": "secure_password_3",
"sharedSecret": "1234567890abcdef",
"identitySecret": "0987654321zyxwvu",
"steamApiKey": "YOUR_STEAM_API_KEY",
"proxy": null,
"maxConcurrentTrades": 10,
"pollInterval": 30000,
"tradeTimeout": 600000
}
]
}
Environment Variables (Alternative)
Or use environment variables:
# Bot 1
STEAM_BOT_1_USERNAME=turbobot_01
STEAM_BOT_1_PASSWORD=secure_password_1
STEAM_BOT_1_SHARED_SECRET=abcdef1234567890
STEAM_BOT_1_IDENTITY_SECRET=xyz9876543210abc
STEAM_BOT_1_PROXY=socks5://user:pass@proxy1.example.com:1080
# Bot 2
STEAM_BOT_2_USERNAME=turbobot_02
STEAM_BOT_2_PASSWORD=secure_password_2
STEAM_BOT_2_SHARED_SECRET=fedcba0987654321
STEAM_BOT_2_IDENTITY_SECRET=cba0123456789xyz
STEAM_BOT_2_PROXY=http://user2:pass2@proxy2.example.com:8080
# Bot 3
STEAM_BOT_3_USERNAME=turbobot_03
STEAM_BOT_3_PASSWORD=secure_password_3
STEAM_BOT_3_SHARED_SECRET=1234567890abcdef
STEAM_BOT_3_IDENTITY_SECRET=0987654321zyxwvu
# No proxy for bot 3
# Global Settings
STEAM_API_KEY=YOUR_STEAM_API_KEY
STEAM_BOT_COUNT=3
🌐 Proxy Configuration
Why Use Proxies?
- ✅ Prevent Rate Limiting - Each bot has own IP
- ✅ Geographic Distribution - Bots appear from different locations
- ✅ Avoid Bans - If one IP gets rate limited, others continue
- ✅ Better Performance - Distribute load across proxies
Proxy Types Supported
1. SOCKS5 (Recommended)
{
"type": "socks5",
"host": "proxy.example.com",
"port": 1080,
"username": "user",
"password": "pass"
}
Best for:
- Steam connections
- High performance
- Full protocol support
2. HTTP/HTTPS
{
"type": "http",
"host": "proxy.example.com",
"port": 8080,
"username": "user",
"password": "pass"
}
Best for:
- Web requests
- Simple setup
- Most proxy providers
3. No Proxy
{
"proxy": null
}
Use when:
- Testing locally
- VPS with good IP reputation
- Low trade volume
Proxy Providers
Recommended Providers:
- Bright Data (formerly Luminati) - Premium, reliable
- Oxylabs - High quality, expensive
- IPRoyal - Good balance of price/quality
- Webshare - Budget friendly
- SmartProxy - Good for Steam
Requirements:
- Dedicated or semi-dedicated IPs
- SOCKS5 support preferred
- Good uptime (99%+)
- Reasonable speed (<500ms latency)
🚀 Starting Multiple Bots
Method 1: Using Configuration File
// index.js or startup file
import { getSteamBotManager } from './services/steamBot.js';
import botsConfig from './config/steam-bots.json' assert { type: 'json' };
const botManager = getSteamBotManager();
// Initialize all bots
await botManager.initialize(botsConfig.bots);
console.log('✅ All bots initialized');
Method 2: Using Environment Variables
import { getSteamBotManager } from './services/steamBot.js';
const botManager = getSteamBotManager();
// Build config from environment
const botsConfig = [];
const botCount = parseInt(process.env.STEAM_BOT_COUNT || '1');
for (let i = 1; i <= botCount; i++) {
const prefix = `STEAM_BOT_${i}_`;
if (!process.env[prefix + 'USERNAME']) continue;
botsConfig.push({
accountName: process.env[prefix + 'USERNAME'],
password: process.env[prefix + 'PASSWORD'],
sharedSecret: process.env[prefix + 'SHARED_SECRET'],
identitySecret: process.env[prefix + 'IDENTITY_SECRET'],
steamApiKey: process.env.STEAM_API_KEY,
proxy: process.env[prefix + 'PROXY']
? parseProxyUrl(process.env[prefix + 'PROXY'])
: null,
});
}
await botManager.initialize(botsConfig);
Method 3: Auto-Start on Backend Launch
// In your main server file
import { getSteamBotManager } from './services/steamBot.js';
// After fastify.listen()
if (process.env.STEAM_BOT_AUTO_START === 'true') {
console.log('🤖 Auto-starting Steam bots...');
const botManager = getSteamBotManager();
// Load config
const botsConfig = loadBotsConfig(); // Your config loading logic
await botManager.initialize(botsConfig);
console.log('✅ Steam bots ready');
}
🎮 Creating Trades with Verification Codes
Backend Example
import { getSteamBotManager } from '../services/steamBot.js';
import Trade from '../models/Trade.js';
// User sells items
fastify.post('/api/trade/create', async (request, reply) => {
const { items } = request.body;
const userId = request.user._id;
const steamId = request.user.steamId;
const tradeUrl = request.user.tradeUrl;
// Calculate values
const totalValue = items.reduce((sum, item) => sum + item.price, 0);
const fee = totalValue * 0.05; // 5% fee
const userReceives = totalValue - fee;
// Create trade offer with automatic bot selection
const botManager = getSteamBotManager();
const result = await botManager.createTradeOffer({
tradeUrl: tradeUrl,
itemsToReceive: items.map(item => ({
assetid: item.assetId,
appid: 730, // CS2
contextid: 2
})),
userId: userId,
metadata: {
itemCount: items.length,
totalValue: totalValue
}
});
// Create trade record in database
const trade = await Trade.createTrade({
offerId: result.offerId,
userId: userId,
steamId: steamId,
state: 'pending',
items: items,
totalValue: totalValue,
fee: fee,
feePercentage: 5,
userReceives: userReceives,
tradeUrl: tradeUrl,
verificationCode: result.verificationCode,
botId: result.botId,
expiresAt: new Date(Date.now() + 10 * 60 * 1000), // 10 minutes
sessionId: request.session?.id,
});
return reply.send({
success: true,
trade: {
id: trade._id,
offerId: trade.offerId,
verificationCode: trade.verificationCode, // ⭐ IMPORTANT: Show to user
state: 'pending',
totalValue: totalValue,
userReceives: userReceives,
expiresAt: trade.expiresAt,
message: 'Trade offer sent! Please check your Steam app.'
}
});
});
What User Sees on Website
┌────────────────────────────────────────────┐
│ Trade Offer Sent! │
├────────────────────────────────────────────┤
│ │
│ Verification Code: │
│ ┏━━━━━━━━━━━━━━━┓ │
│ ┃ A 3 K 9 P 2 ┃ <- Large, clear │
│ ┗━━━━━━━━━━━━━━━┛ │
│ │
│ ⚠️ IMPORTANT: │
│ Check that this code appears in your │
│ Steam trade offer. DO NOT accept trades │
│ without this code! │
│ │
│ Status: Waiting for acceptance... │
│ Expires in: 9:45 │
│ │
│ [View in Steam] [Cancel Trade] │
│ │
└────────────────────────────────────────────┘
What User Sees in Steam Trade Offer
Trade Offer from turbobot_01
TurboTrades Trade
Verification Code: A3K9P2
Please verify this code matches the one shown
on our website before accepting.
Do not accept trades without a valid
verification code!
You will receive:
- Nothing
You will give:
- AK-47 | Redline (Field-Tested)
- AWP | Asiimov (Battle-Scarred)
[Accept] [Decline]
🔄 Load Balancing
How Bot Selection Works
-
Filter Available Bots
- Must be logged in
- Must be healthy (low error count)
- Must have capacity (< max concurrent trades)
-
Sort by Load
- Bots with fewer active trades ranked higher
- Distributes load evenly
-
Select Best Bot
- Returns bot with lowest current load
- If all bots busy, throws error
Example Load Distribution
Bot 1: 3 active trades <- Selected (lowest)
Bot 2: 5 active trades
Bot 3: 7 active trades
Next trade goes to Bot 1
After assignment:
Bot 1: 4 active trades
Bot 2: 5 active trades <- Next trade goes here
Bot 3: 7 active trades
Manual Bot Selection (Advanced)
// Get specific bot
const bot = botManager.getBot('bot_1');
// Create trade with specific bot
const result = await bot.createTradeOffer({
tradeUrl: userTradeUrl,
itemsToReceive: items,
verificationCode: 'MANUAL1',
metadata: {}
});
📊 Monitoring & Health
Check Bot Health
const botManager = getSteamBotManager();
// Get all bots health
const health = botManager.getAllBotsHealth();
console.log(health);
Output:
[
{
"botId": "bot_1",
"isReady": true,
"isLoggedIn": true,
"isHealthy": true,
"activeTrades": 3,
"tradeCount": 150,
"errorCount": 2,
"lastTradeTime": "2024-01-10T12:05:00Z",
"username": "turbobot_01",
"proxy": "socks5://proxy1.example.com:1080"
},
{
"botId": "bot_2",
"isReady": true,
"isLoggedIn": true,
"isHealthy": true,
"activeTrades": 5,
"tradeCount": 180,
"errorCount": 1,
"lastTradeTime": "2024-01-10T12:03:00Z",
"username": "turbobot_02",
"proxy": "http://proxy2.example.com:8080"
}
]
System-Wide Stats
const stats = botManager.getStats();
console.log(stats);
Output:
{
"totalBots": 3,
"readyBots": 3,
"healthyBots": 3,
"totalTrades": 450,
"totalActiveTrades": 12,
"totalErrors": 5,
"verificationCodesStored": 12
}
Admin Dashboard Integration
Add to admin panel:
// GET /api/admin/bots/health
fastify.get('/admin/bots/health', async (request, reply) => {
const botManager = getSteamBotManager();
return reply.send({
success: true,
bots: botManager.getAllBotsHealth(),
stats: botManager.getStats()
});
});
🎯 Trade Events
Listen to Trade Events
const botManager = getSteamBotManager();
// Trade accepted - Credit user balance!
botManager.on('tradeAccepted', async (offer, tradeData, botId) => {
console.log(`✅ Trade ${offer.id} accepted on ${botId}`);
const trade = await Trade.getByOfferId(offer.id);
const user = await User.findById(trade.userId);
// Credit user balance
user.balance += trade.userReceives;
await user.save();
// Create transaction
const transaction = await Transaction.createTransaction({
userId: trade.userId,
steamId: trade.steamId,
type: 'sale',
status: 'completed',
amount: trade.userReceives,
fee: trade.fee,
feePercentage: trade.feePercentage,
balanceBefore: user.balance - trade.userReceives,
balanceAfter: user.balance,
metadata: {
tradeId: trade._id,
offerId: trade.offerId,
itemCount: trade.items.length
}
});
// Update trade
await trade.markAsCompleted(transaction._id);
// Notify user via WebSocket
websocketManager.sendToUser(trade.steamId, {
type: 'trade_accepted',
data: {
tradeId: trade._id,
balance: user.balance,
amount: trade.userReceives
}
});
});
// Trade declined
botManager.on('tradeDeclined', async (offer, tradeData, botId) => {
console.log(`❌ Trade ${offer.id} declined on ${botId}`);
const trade = await Trade.getByOfferId(offer.id);
await trade.markAsDeclined();
// Notify user
websocketManager.sendToUser(trade.steamId, {
type: 'trade_declined',
data: {
tradeId: trade._id,
message: 'Trade offer was declined'
}
});
});
// Trade expired
botManager.on('tradeExpired', async (offer, tradeData, botId) => {
console.log(`⏰ Trade ${offer.id} expired on ${botId}`);
const trade = await Trade.getByOfferId(offer.id);
await trade.markAsExpired();
// Optionally retry
if (trade.retryCount < 3) {
console.log('🔄 Retrying expired trade...');
// Retry logic here
}
});
// Bot error
botManager.on('botError', (err, botId) => {
console.error(`❌ Bot ${botId} error:`, err.message);
// Send alert to admins
// Log to monitoring service
});
🔒 Security Best Practices
1. Secure Credentials
# ✅ Good - Use environment variables
STEAM_BOT_1_PASSWORD=secure_password
# ❌ Bad - Never hardcode in config files
"password": "my_password_123"
2. Rotate Proxies
- Change proxies monthly
- Use different proxy providers
- Monitor proxy performance
- Replace slow/banned proxies
3. Bot Account Security
- ✅ Use unique passwords for each bot
- ✅ Enable Steam Guard on all bots
- ✅ Don't share bot accounts
- ✅ Keep secrets in secure vault
- ✅ Use 2FA on bot accounts
4. Verification Code Validation
// Always verify code before crediting balance
const isValid = botManager.verifyTradeCode(offerId, userEnteredCode);
if (!isValid) {
throw new Error('Invalid verification code');
}
5. Rate Limiting
// Limit trades per user per hour
const userTrades = await Trade.find({
userId: userId,
createdAt: { $gte: new Date(Date.now() - 60 * 60 * 1000) }
});
if (userTrades.length >= 10) {
throw new Error('Trade limit exceeded. Try again later.');
}
🐛 Troubleshooting
Bot Won't Login
Symptoms:
- Bot stuck at "Logging in..."
- Error: "Invalid credentials"
- Error: "SteamGuardMobile needed"
Solutions:
- Check credentials are correct
- Verify shared secret is valid
- Disable proxy temporarily to test
- Check Steam is not under maintenance
- Verify bot account not limited/banned
Proxy Connection Failed
Symptoms:
- Bot disconnects frequently
- Error: "ECONNREFUSED"
- Error: "Proxy authentication failed"
Solutions:
- Test proxy with curl:
curl -x socks5://user:pass@proxy:1080 https://steamcommunity.com - Verify proxy credentials
- Check proxy IP not banned by Steam
- Try different proxy
- Contact proxy provider
Verification Codes Not Showing
Symptoms:
- Trade offer created but no code
- Code is null/undefined
Solutions:
- Check
verificationCodesaved in database - Verify frontend is receiving code
- Check trade creation response
- View logs for code generation
Trades Not Accepting
Symptoms:
- User accepts trade in Steam
- Balance not credited
- Trade stuck in pending
Solutions:
- Check bot event handlers are working
- Verify bot polling is active
- Check trade state in database
- Manually check trade status in Steam
- Review bot logs for errors
📈 Performance Optimization
1. Optimal Bot Count
Small Sites (<100 trades/day):
- 2-3 bots sufficient
- No proxies needed initially
Medium Sites (100-500 trades/day):
- 3-5 bots recommended
- 1 proxy per bot
Large Sites (>500 trades/day):
- 5-10 bots
- Multiple proxies per region
- Redis queue for trade management
2. Proxy Pool Management
// Rotate proxies periodically
setInterval(() => {
console.log('🔄 Checking proxy health...');
const health = botManager.getAllBotsHealth();
health.forEach(bot => {
if (bot.errorCount > 20) {
console.warn(`⚠️ ${bot.botId} has high error count, consider rotating proxy`);
}
});
}, 60 * 60 * 1000); // Check every hour
3. Trade Queue System
For high volume, implement queue:
import Bull from 'bull';
const tradeQueue = new Bull('steam-trades', {
redis: { host: 'localhost', port: 6379 }
});
tradeQueue.process(5, async (job) => { // Process 5 at a time
const { userId, items, tradeUrl } = job.data;
return await botManager.createTradeOffer({
tradeUrl,
itemsToReceive: items,
userId
});
});
// Add to queue
await tradeQueue.add({ userId, items, tradeUrl }, {
attempts: 3,
backoff: { type: 'exponential', delay: 5000 }
});
✅ Production Checklist
Before going live:
- All bot accounts created and funded
- Steam Mobile Authenticator enabled on all bots
- Shared/identity secrets extracted
- Proxies tested and working
- Configuration file created
- All bots successfully login
- Test trade offer sent and accepted
- Verification codes displayed correctly
- Balance credits after acceptance
- Trade events firing properly
- Error handling tested
- Monitoring dashboard set up
- Rate limiting implemented
- Backup bots configured
- Documentation updated
- Team trained on bot management
🎓 Example: 3-Bot Setup
Complete Configuration
{
"bots": [
{
"accountName": "turbotrades_bot1",
"password": "StrongPass123!@#",
"sharedSecret": "Xj9mK3pL2qN5vB8cD4fG7hJ1kM6nP0rT",
"identitySecret": "Aa1Bb2Cc3Dd4Ee5Ff6Gg7Hh8Ii9Jj0Kk",
"steamApiKey": "YOUR_STEAM_API_KEY_HERE",
"proxy": {
"type": "socks5",
"host": "us-proxy1.example.com",
"port": 1080,
"username": "proxyuser1",
"password": "ProxyPass123"
},
"maxConcurrentTrades": 15,
"pollInterval": 25000,
"tradeTimeout": 600000
},
{
"accountName": "turbotrades_bot2",
"password": "AnotherStrong456!@#",
"sharedSecret": "Yh8jM2kL4pN7vC9dF3gH6jK0mP5qR1tS",
"identitySecret": "Bb2Cc3Dd4Ee5Ff6Gg7Hh8Ii9Jj0Kk1Ll",
"steamApiKey": "YOUR_STEAM_API_KEY_HERE",
"proxy": {
"type": "socks5",
"host": "eu-proxy1.example.com",
"port": 1080,
"username": "proxyuser2",
"password": "ProxyPass456"
},
"maxConcurrentTrades": 15,
"pollInterval": 25000,
"tradeTimeout": 600000
},
{
"accountName": "turbotrades_bot3",
"password": "SecureBot789!@#",
"sharedSecret": "Zi7kN1mL3oP6wD8eG2hJ5lM9qT4rU0vX",
"identitySecret": "Cc3Dd4Ee5Ff6Gg7Hh8Ii9Jj0Kk1Ll2Mm",
"steamApiKey": "YOUR_STEAM_API_KEY_HERE",
"proxy": {
"type": "http",
"host": "asia-proxy1.example.com",
"port": 8080,
"username": "proxyuser3",
"password": "ProxyPass789"
},
"maxConcurrentTrades": 15,
"pollInterval": 25000,
"tradeTimeout": 600000
}
]
}
Startup Script
import { getSteamBotManager } from './services/steamBot.js';
import fs from 'fs';
async function startBots() {
console.log('🤖 Starting TurboTrades Bot System...\n');
// Load configuration
const config = JSON.parse(
fs.readFileSync('./config/steam-bots.json', 'utf8')
);
// Initialize bot manager
const botManager = getSteamBotManager();
// Start all bots
const results = await botManager.initialize(config.bots);
// Show results
results.forEach(result => {
if (result.success) {
console.log(`✅ ${result.botId} - Ready`);
} else {
console.log(`❌ ${result.botId} - Failed: ${result.error}`);
}
});
console.log('\n📊 System Status:');
console.log(botManager.getStats());
return botManager;
}
// Start bots
const botManager = await startBots();
// Handle graceful shutdown
process.on('SIGINT', () => {
console.log('\n👋 Shutting down bots...');
botManager.shutdown();
process.exit(0);
});
📚 Additional Resources
- Steam Web API: https://developer.valvesoftware.com/wiki/Steam_Web_API
- node-steam-user: https://github.com/DoctorMcKay/node-steam-user
- steam-tradeoffer-manager: https://github.com/DoctorMcKay/node-steam-tradeoffer-manager
- SOCKS Proxy Agent: https://www.npmjs.com/package/socks-proxy-agent
🎉 Summary
You now have:
- ✅ Multiple Steam bots with load balancing
- ✅ Proxy support for each bot
- ✅ Verification codes for security
- ✅ Automatic failover
- ✅ Health monitoring
- ✅ Event-driven architecture
- ✅ Production-ready setup
Next Steps:
- Set up bot accounts
- Configure proxies
- Create configuration file
- Test bot login
- Create test trade with verification code
- Integrate with sell endpoint
- Add UI for verification code display
- Deploy to production
The system will now:
- Accept sell requests from users
- Generate unique verification code
- Select best available bot
- Create trade offer with code in message
- Wait for user to accept
- Credit balance ONLY after trade accepted
- Handle failures gracefully
🚀 Your marketplace is now secure and scalable!