CS2 Watchdog Documentation
PowerShell, Telegram Bot API, Discord Webhooks

CS2 Disconnect Watcher

Detects when one of your CS2 instances disconnects from an active match (for example Deathmatch) by monitoring per-instance log files in real time. Sends ASCII-only alerts to Telegram and Discord.

What it does

Watches CS2 instance log files and triggers an alert when disconnect keywords appear.

How you get alerts

Posts plain-text alerts to Discord (webhook) and Telegram (bot token and chat id).

Overview
What the tool does and how it detects disconnects

The CS2 Disconnect Watcher monitors text log files (one per CS2 instance). When an instance disconnects from a match, CS2 (or your launcher wrapper) typically writes a line that includes keywords like "disconnected" or "connection lost". The watcher detects those lines and sends an alert.

Important requirement

Each CS2 instance must write to its own log file. Without per-instance logs, the watcher cannot reliably detect which instance disconnected.

Requirements
What you need before installing
Software
  • Windows 10 or Windows 11
  • PowerShell (built-in)
Access and keys
  • Telegram bot token
  • Telegram chat id
  • Discord webhook URL

Security: do not publish your bot token, chat id, or webhook URL. Treat them like passwords.

Folder structure
Recommended layout for watcher and logs
C:\CS2-Watchdog\
+-- disconnect-watcher.ps1
+-- start-watcher.bat (optional)
+-- logs\
   +-- instance01.log
   +-- instance02.log
   +-- instance15.log
+-- watcher.log (auto-created)

The watcher reads all *.log files from C:\CS2-Watchdog\logs. It keeps an internal file position per log and only processes new lines.

Installation
Create folder, place scripts, prepare logs

1) Create directories

mkdir C:\CS2-Watchdog
mkdir C:\CS2-Watchdog\logs

2) Create the script files

Create the files below by copying the content from the Scripts section: disconnect-watcher.ps1 and optionally start-watcher.bat.

3) Ensure per-instance logs exist

You must have per-instance log files in C:\CS2-Watchdog\logs. Example file names: instance01.log, instance02.log, and so on.

Configuration
Where to put tokens, chat id, webhook, keywords

Open disconnect-watcher.ps1 and set these variables:

$LogDir = 'C:\CS2-Watchdog\logs'
$CheckEverySeconds = 2

$TelegramBotToken = 'YOUR_BOT_TOKEN'
$TelegramChatId   = 'YOUR_CHAT_ID'
$DiscordWebhook   = 'YOUR_DISCORD_WEBHOOK_URL'

Disconnect keywords

If you do not get alerts, your log lines might use different words. Update the list:

$DisconnectKeywords = @(
  'disconnected',
  'connection lost',
  'connection to server lost',
  'kicked',
  'dropped from server',
  'server connection failed'
)

Tip: open a log file and search for the exact disconnect line after a manual disconnect. Add the keyword that appears in your logs.

Scripts
Copy and paste the files (ASCII-only)

Create these files in C:\CS2-Watchdog. All content is ASCII-only (no emojis and no special characters).

disconnect-watcher.ps1

Ready
# CS2 Disconnect Watcher (ASCII only)
# Detects in-game disconnects via log monitoring
# File: C:\CS2-Watchdog\disconnect-watcher.ps1

# ====== CONFIG ======
$LogDir = 'C:\CS2-Watchdog\logs'
$CheckEverySeconds = 2

$TelegramBotToken = 'YOUR_BOT_TOKEN'
$TelegramChatId   = 'YOUR_CHAT_ID'
$DiscordWebhook   = 'YOUR_DISCORD_WEBHOOK_URL'

# Keywords that indicate a disconnect from a match
$DisconnectKeywords = @(
    'disconnected',
    'connection lost',
    'connection to server lost',
    'kicked',
    'dropped from server',
    'server connection failed'
)

# ====== INTERNAL ======
$BaseDir = Split-Path -Parent $PSCommandPath
$State   = @{}
$LocalLogFile = Join-Path $BaseDir 'watcher.log'

function Write-LocalLog($msg) {
    $line = "[{0}] {1}" -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $msg
    Add-Content -Path $LocalLogFile -Value $line
}

function Send-Telegram($text) {
    try {
        Invoke-RestMethod `
            -Uri ("https://api.telegram.org/bot{0}/sendMessage" -f $TelegramBotToken) `
            -Method Post `
            -Body @{ chat_id = $TelegramChatId; text = $text } | Out-Null
    } catch {
        Write-LocalLog ("Telegram error: {0}" -f $_.Exception.Message)
    }
}

function Send-Discord($text) {
    try {
        $payload = @{ content = $text } | ConvertTo-Json -Depth 3
        Invoke-RestMethod `
            -Uri $DiscordWebhook `
            -Method Post `
            -ContentType 'application/json' `
            -Body $payload | Out-Null
    } catch {
        Write-LocalLog ("Discord error: {0}" -f $_.Exception.Message)
    }
}

Write-LocalLog ("Disconnect watcher started. Monitoring: {0}" -f $LogDir)

# Initialize known log files
Get-ChildItem $LogDir -Filter *.log -File -ErrorAction SilentlyContinue | ForEach-Object {
    $State[$_.FullName] = 0
}

while ($true) {
    Get-ChildItem $LogDir -Filter *.log -File -ErrorAction SilentlyContinue | ForEach-Object {

        if (-not $State.ContainsKey($_.FullName)) {
            $State[$_.FullName] = 0
        }

        try {
            $fs = [System.IO.File]::Open($_.FullName, 'Open', 'Read', 'ReadWrite')
            $fs.Seek($State[$_.FullName], 'Begin') | Out-Null
            $sr = New-Object System.IO.StreamReader($fs)

            while (-not $sr.EndOfStream) {
                $line = $sr.ReadLine()
                if ($line) {
                    $lower = $line.ToLower()
                    foreach ($kw in $DisconnectKeywords) {
                        if ($lower -like ("*{0}*" -f $kw)) {
                            $inst = [System.IO.Path]::GetFileNameWithoutExtension($_.Name)
                            $msg = "ALERT: CS2 instance $inst disconnected from match. Time: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
                            Send-Telegram $msg
                            Send-Discord  $msg
                            Write-LocalLog $msg
                            break
                        }
                    }
                }
            }

            $State[$_.FullName] = $fs.Position
            $sr.Close()
            $fs.Close()
        } catch {
            Write-LocalLog ("Read error for {0}: {1}" -f $_.FullName, $_.Exception.Message)
        }
    }

    Start-Sleep -Seconds $CheckEverySeconds
}

start-watcher.bat (optional)

Ready
@echo off
cd /d C:\CS2-Watchdog
powershell.exe -NoProfile -ExecutionPolicy Bypass -File disconnect-watcher.ps1
Windows Task Scheduler
Run automatically at startup

Recommended start file

Create start-watcher.bat inside C:\CS2-Watchdog (see Scripts section).

Create a scheduled task

  1. Open Task Scheduler and click Create Task
  2. Name: CS2 Disconnect Watcher
  3. Enable Run with highest privileges
  4. Trigger: At startup
  5. Action: Start a program
  6. Program: C:\CS2-Watchdog\start-watcher.bat
  7. Start in: C:\CS2-Watchdog

After saving, use Run to test once. Disconnect an instance and confirm you receive an ALERT message.

Troubleshooting
Common issues and quick fixes

No alerts received

  • Verify Discord webhook URL is valid.
  • Verify Telegram bot token and chat id are correct.
  • Check C:\CS2-Watchdog\watcher.log for errors.
  • Your log line may not contain the keywords. Update the keyword list.

Logs not updating

  • Make sure each instance writes to a file in C:\CS2-Watchdog\logs
  • Ensure the log files are not locked exclusively by another process