-
-
Notifications
You must be signed in to change notification settings - Fork 0
Advanced Configuration
Version: 1.5.11
- Security & Privacy
- Performance & Scaling
- File Structure Reference
- Variable Reference
- Migration Guides
- Custom Integration Examples
- Backup & Recovery
The bot uses AES-256-CBC encryption for API keys with the following implementation:
Auto-Encryption (Updated in 1.4.3): The bot automatically upgrades legacy keys to AES-256-CBC using a portable salt.
- Plain text (
abc-123) → Encrypted (AES:...) - Legacy Base64 (
OBF:...) → Encrypted (AES:...)
Key Derivation (Portable):
Salt = GlobalConfig.Globals.EncryptionSalt (Random 32-byte hash)
Key = PBKDF2(Salt, Salt, 1000 iter) -> 32 bytes
IV = First 16 bytes of Salt
Why Portable?
Unlike previous versions that tied keys to your Windows User ID (DPAPI), the
EncryptionSalt is stored in your giveaway_config.json.
- ✅ Portable: You can copy your entire
Giveaway Botfolder to another PC, and it will still work. - ✅ Secure: The salt is unique to your installation.
- ✅ Resilient: Survives Windows reinstallations.
Security Warning:
- Do NOT share your
giveaway_config.jsonpublicly, as it contains the salt used to decrypt your keys. -
Always exclude
giveaway_config.jsonfrom public git repositories (add to.gitignore).
What's Stored:
| Data Type | Location | Retention | Purpose |
|---|---|---|---|
| Entry Records | dumps/Main/*.txt |
Manual deletion | Winner verification |
| Logs | logs/General/*.log |
LogRetentionDays (default 90) |
Debugging |
| State Files | state/*.json |
Until profile deleted | Active giveaway data |
| Config | config/*.json |
Permanent | Bot settings |
GDPR Compliance:
- No PII beyond username/UserID (public Twitch data)
- Local storage only (except Wheel API if enabled)
- Users can request data deletion (manual file removal)
-
Never share encrypted blobs (
AES:...) - they contain your key -
Limit API key scope - use Wheel of Names' read-only keys if possible
-
Rotate keys - change periodically (update variable + re-encrypt)
-
Monitor logs - watch for
[Security]warnings -
Monitor logs - watch for
[Security]warnings
You can allow users to specify which game or item they want when entering. This is useful for "Key Dump" giveaways where you have multiple different keys to give away.
In your profile config:
"RequireGameName": false, // If true, users MUST type "!enter <Name>"
"GameNameRequiredMessage": "Please specify a game! Usage: !enter <Game Name>"- User types
!enter Elden Ring - Bot records "Elden Ring" as their
GameNameselection. - When you draw a winner, their selection is shown in:
- The winner announcement message
- The
dumps/..._Winners_GameNames.txtfile
The bot now generates specific files for game names to make distributing keys easier:
-
dumps/Main/Winners_GameNames.txt: Contains only the Game Names of the winners (in order). -
dumps/Main/Entries_GameNames.txt: Contains only the Game Names of all entrants.
{
"MaxEntriesPerMinute": 60,
"StateSyncIntervalSeconds": 30,
"LogLevel": "INFO",
"DumpEntriesOnEntry": false,
"ExposeVariables": true
}Why: Balanced performance, minimal overhead
{
"MaxEntriesPerMinute": 200,
"StateSyncIntervalSeconds": 60,
"LogLevel": "WARN",
"DumpEntriesOnEntry": true,
"DumpEntriesOnEntryThrottle": 30,
"ExposeVariables": true
}Why: Higher rate limits, less frequent disk writes
{
"MaxEntriesPerMinute": 500,
"StateSyncIntervalSeconds": 120,
"LogLevel": "ERROR",
"DumpEntriesOnEntry": false,
"ExposeVariables": false,
"EnableEntropyCheck": true,
"MinAccountAgeDays": 30
}Why: Aggressive rate limiting, bot protection, minimal I/O
Disk I/O (Slow HDD):
- Symptom: Streamer.bot freezes when entries spike
- Solution 1: Set
StatePersistenceMode: GlobalVar(risk: data loss on crash) - Solution 2: Move Streamer.bot folder to SSD
- Solution 3: Increase
StateSyncIntervalSecondsto 120+
CPU (Regex Validation):
- Symptom: High CPU when
UsernamePatternorExternalListenersenabled - Solution: Simplify regex patterns, avoid backtracking (e.g.,
.*is slow) - Test patterns with
!giveaway regex testfor performance
Memory (Large Entry Counts):
- Symptom: Streamer.bot memory usage grows unbounded
- Solution: Close/archive old giveaways regularly
- Estimate: ~100 bytes per entry → 10,000 entries ≈ 1 MB (negligible)
The bot now uses an intelligent "Diff & Sync" system (SetGlobalVarIfChanged).
It only sends updates to Streamer.bot
when variables actually change.
- Impact: Reduces IPC log spam by 99% during idle periods.
-
Benefit: You can leave
ExposeVariables: trueenabled even on lower-end systems with minimal performance penalty.
- Use
MirrorRunMode (best for stability + performance) - Set LogLevel to
INFOor higher (avoidTRACE/DEBUGin production) - Set LogLevel to
INFOor higher. NOTE:TRACElevel will output high-frequency variable sync logs (spammy). - Disable
DumpEntriesOnEntryfor streams >500 viewers - Increase
StateSyncIntervalSecondsif on slow HDD - Enable
EnableEntropyCheckif seeing bot/fake accounts - Use Wheel API Animate mode (lower overhead than interactive)
As of v1.3.3, you can control the bot programmatically by setting specific Global Variables in Streamer.bot. This allows you to start/end giveaways from your own Actions, Stream Deck, or other integration logic without simulating chat commands.
To trigger an action, use the Core -> Global Variables -> Set Global Variable sub-action in Streamer.bot.
| Goal | Variable Name | Set Value to... | Effect |
|---|---|---|---|
| Start Giveaway | Giveaway <Profile> Is Active |
True |
Opens the giveaway (if closed). Triggers HandleStart. |
| End Giveaway | Giveaway <Profile> Is Active |
False |
Closes the giveaway (if open). Triggers HandleEnd. |
| Change Timer | Giveaway <Profile> Timer Duration |
"5m" |
Updates auto-close timer and announces new time. |
Important
System Override: Variable-based triggers bypass the usual "Moderator" permission check, allowing automated systems to control the bot.
C:\Users\<You>\Streamer.bot\data\Giveaway Bot\
│
├── config\
│ └── giveaway_config.json # Main configuration
│ ├── Globals (Bot-wide settings)
│ └── Profiles
│ ├── Main
│ ├── Weekly
│ └── ...
│
├── dumps\ # Entry/Winner exports
│ ├── Main\
│ │ ├── 20260128_Entries.txt # Final snapshot (!end)
│ │ ├── 20260128_Entries_GameNames.txt # (v1.5.3) Just GameNames/Codes
│ │ ├── 20260128_Entries_Incremental.txt # Real-time (if enabled)
│ │ ├── 20260128_Winners.txt # Winner log
│ │ └── 20260128_Winners_GameNames.txt # (v1.5.3) Just Winner GameNames
│ └── Weekly\
│ └── ...
│
├── logs\ # Debug & error logs
│ └── General\
│ ├── 2026-01-28.log # Daily rotation
│ ├── 2026-01-27.log
│ └── ... # Auto-pruned after LogRetentionDays
│
└── state\ # Active giveaway data
├── Main.json # Real-time entry list
└── Weekly.json
File Formats:
giveaway_config.json: Standard JSON, editable in any text editor
state/Main.json: JSON with UTF-8 encoding, contains active entries
dumps/*.txt: Plain text, one entry per line:
[14:23:45] UserName (123456) - Tickets: 3
logs/*.log: Plaintext with ISO 8601 timestamps:
[2026-01-28 14:23:45] [INFO] [GiveawayManager] Giveaway started
(Exposed when ExposeVariables: true in profile)
| Variable Name | Type | Update Frequency | Example |
|---|---|---|---|
Giveaway <Profile> Is Active |
Boolean | Immediate (on start/end) | true |
Giveaway <Profile> Entry Count |
Integer | Per entry (+1) | 47 |
Giveaway <Profile> Ticket Count |
Integer | Per entry (incl. sub luck) | 68 |
Giveaway <Profile> Winner Name |
String | On draw | CoolViewer123 |
Giveaway <Profile> Winner User Id |
String | On draw | 987654321 |
Giveaway <Profile> Last Entry |
String | Per entry | NewUser456 |
Giveaway <Profile> Draw Time |
DateTime | On draw | 2026-01-28 14:30:00 |
Giveaway <Profile> Winner Count |
Integer | Per Draw | 3 |
Giveaway <Profile> Cumulative Entries |
Integer | Per entry | 150 |
Giveaway <Profile> Sub Entry Count |
Integer | Per entry | 12 |
Giveaway <Profile> Timer Duration |
String | On config change | 10m |
Giveaway <Profile> Msg <Key> |
String | On config change | Winner is {0}! |
Giveaway <Profile> Max Entries Per Minute |
Integer | On config change | 100 |
Giveaway <Profile> Require Subscriber |
Boolean | On config change | true |
Giveaway <Profile> Sub Luck Multiplier |
Decimal | On config change | 1.5 |
| Variable Name | Default | Description |
|---|---|---|
Giveaway Global Run Mode |
Mirror |
Config sync mode |
Giveaway Global Log Level |
INFO |
Minimum log severity |
Giveaway Global Log Max File Size MB |
10 |
Max size of a single log file |
Giveaway Global Log Size Cap MB |
100 |
Total log directory size cap |
Giveaway Global Log Prune Probability |
100 |
1-in-N chance to prune logs on startup |
Giveaway Global Wheel Api Key |
(empty) | Wheel API key (Auto-Encrypts if entered as plain text) |
Giveaway Global Wheel Api Key Status |
Missing |
Current status of the API Key |
Giveaway Global Enabled Platforms |
Twitch,YouTube |
Comma-separated list of active platforms |
Giveaway Global Security Toasts |
True |
Toggle for security-related notifications |
(Always available, useful for observability and debugging)
| Variable Name | Type | Description |
|---|---|---|
Giveaway Global Metrics Entries Total |
Integer | Lifetime entries accepted |
Giveaway Global Metrics Entries Rejected |
Integer | Spam/bots/regex-mismatches blocked |
Giveaway Global Metrics Winners Total |
Integer | Total winners drawn |
Giveaway Global Metrics Entries Processed |
Integer | Total entry commands handled |
Giveaway Global Metrics Entry Processing Avg Ms |
Integer | Avg time to process an entry (performance) |
Giveaway Global Metrics File IO Errors |
Integer | Disk write failures (check permissions) |
Giveaway Global Metrics Config Reloads |
Integer | Number of times config was reloaded |
Giveaway Global Metrics Loop Detected |
Integer | Anti-loop protection triggers fired |
Giveaway Global Metrics Api Errors |
Integer | Total API failures (Wheel + General) |
Giveaway Global Metrics System Errors |
Integer | Internal exceptions rooted in bot logic |
Wheel of Names Metrics:
| Variable Name | Type | Description |
|---|---|---|
Giveaway Global Metrics Wheel Api Calls |
Integer | Total calls to Wheel of Names API |
Giveaway Global Metrics Wheel Api Total Ms |
Integer | Total time spent waiting for Wheel API |
Giveaway Global Metrics Wheel Api Avg Ms |
Integer | Avg latency for Wheel API calls |
Giveaway Global Metrics Wheel Api Errors |
Integer | API failures (5xx, Network) |
Giveaway Global Metrics Wheel Api Invalid Keys |
Integer | Auth failures (403) |
Giveaway Global Metrics Wheel Api Timeouts |
Integer | Requests that took too long |
(Read-Only, used for debugging and sync)
| Variable Name | Description |
|---|---|
Giveaway Global Config |
Full JSON content of current config |
Giveaway Global Config Last Write Time |
Timestamp of last config file write |
Giveaway Global Last Config Errors |
Error message if config failed to load |
Giveaway Global Backup Count |
Number of config backups found |
Giveaway Global Instructions |
Header instructions from config file |
Giveaway Global Trigger Help |
Trigger prefix help text |
OBS Usage Example:
Text Source: "Entries: %GiveawayBot_Main_EntryCount% | Winner: %GiveawayBot_Main_WinnerName%"
Old System:
- Nightbot stores list of users
- Manual
!winnercommand picks random from list
Migration Steps:
-
Export old entries (if possible) from Nightbot dashboard
-
Manually add to
state/Main.json(or start fresh) -
Configure external listener:
"AllowedExternalBots": ["Nightbot"], "ExternalListeners": [ { "Pattern": "(?i)giveaway.*open", "Action": "Open" }, { "Pattern": "(?i)giveaway.*close", "Action": "Close" } ]
-
Test: Have Nightbot say "GIVEAWAY OPEN" → Bot should auto-start
Benefits:
- Wheel integration
- Sub luck
- Anti-bot protection
- OBS variables
Old System:
- StreamElements Giveaway module
- Web dashboard management
Migration:
- No direct import - SE doesn't export entry data
- Fresh start recommended
-
Replicate settings manually:
- SE "Subscriber Luck" →
SubLuckMultiplier - SE "Account Age" →
MinAccountAgeDays
- SE "Subscriber Luck" →
Old System:
- Copy/paste usernames to Excel
- Use =RAND() to pick winner
Migration:
-
If you have old entry list, convert to JSON:
[ { "UserId": "123456", "UserName": "OldWinner", "EntryTime": "2026-01-15T10:00:00", "TicketCount": 1 } ] -
Paste into
state/Main.jsonunder"Entries": {} -
Run
!giveaway system testto validate
Edit HandleDrawWinner method in GiveawayBot.cs to add:
// After winner selection
var webhookUrl = "https://discord.com/api/webhooks/YOUR_WEBHOOK";
var payload = new {
content = $"🎉 Giveaway Winner: **{winnerEntry.UserName}**!"
};
var json = JsonConvert.SerializeObject(payload);
using (var client = new System.Net.WebClient())
{
client.Headers.Add("Content-Type", "application/json");
client.UploadString(webhookUrl, json);
}Note: Requires System.Net reference (already included in Streamer.bot).
Create HTML file in OBS Browser Source:
<!DOCTYPE html>
<html>
<head>
<style>
body {
font-family: Arial;
background: transparent;
}
#count {
font-size: 48px;
color: #ffd700;
}
</style>
</head>
<body>
<div id="count">Entries: 0</div>
<script>
// Poll Streamer.bot variable (requires OBS WebSocket)
setInterval(() => {
// Use Streamer.bot API to fetch variable
fetch(
"http://localhost:7474/GetGlobalVar?name=Giveaway Main Entry Count",
)
.then((r) => r.json())
.then((data) => {
document.getElementById("count").textContent =
`Entries: ${data.value}`;
});
}, 1000);
</script>
</body>
</html>Requirements:
- Streamer.bot HTTP Server enabled
- CORS configured
ExposeVariables: true
What to backup:
-
Config:
config/giveaway_config.json -
Active State:
state/*.json(if mid-giveaway) -
Historical Data (optional):
dumps/folder
Backup command (PowerShell):
$source = "$env:APPDATA\Streamer.bot\data\Giveaway Bot"
$dest = "C:\Backups\GiveawayBot_$(Get-Date -Format 'yyyyMMdd').zip"
Compress-Archive -Path $source -DestinationPath $dest- Run
!giveaway config gento create default - Restore from backup if available
- Reconfigure settings via
!giveaway profile configcommands
- Check logs:
logs/General/YYYY-MM-DD.logfor errors - If
state/Main.jsonis corrupt, delete it - Bot will create fresh state (loses active entries)
- Restore from backup if critical
-
Config: Restore
config/folder -
API Keys: Re-enter
WheelOfNamesApiKey(plain text) - Global Variables: Manually recreate in Streamer.bot UI
- Run
!giveaway system testto verify
Create Windows Task Scheduler job:
Trigger: Daily at 3 AM Action: PowerShell script:
$source = "$env:APPDATA\Streamer.bot\data\Giveaway Bot\config"
$dest = "C:\Backups\GiveawayConfig_$(Get-Date -Format 'yyyyMMdd').json"
Copy-Item "$source\giveaway_config.json" -Destination $dest
# Prune old backups (>30 days)
Get-ChildItem "C:\Backups\GiveawayConfig_*.json" |
Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-30) } |
Remove-Item