A lightweight, asynchronous service that polls a platform activity feed API and forwards events to a Discord webhook as rich embeds. Written in Rust for minimal resource usage and long-term stability.
Originally based on work by PomfQ.
Feed Monitor continuously polls sequential feed IDs, deserialises each event, builds a colour-coded Discord embed, and delivers it via webhook. Progress is persisted to disk so the service can be stopped and resumed without missing events.
- Rust 1.75 or later
- A Discord webhook URL
- Network access to the target platform API
git clone $thisrepo
cd feed-monitor
cargo build --releaseThe compiled binary is written to target/release/feed-monitor.
All configuration is read from environment variables. Copy .env.example to .env and fill in the required values.
cp .env.example .env| Variable | Required | Default | Description |
|---|---|---|---|
WEBHOOK_URL |
Yes | Discord webhook URL | |
SERVER_URL |
Yes | Platform base URL, e.g. https://www.kogama.com |
|
START_ID |
Yes | Feed ID to begin from on first run | |
STATE_FILE |
No | state.json |
Path to the progress file |
POLL_INTERVAL |
No | 0.4 |
Seconds between API requests |
WEBHOOK_DELAY |
No | 0.5 |
Seconds to wait before each webhook send |
API_TIMEOUT |
No | 10 |
HTTP timeout in seconds |
LOG_LEVEL |
No | info |
trace, debug, info, warn, or error |
WEBHOOK_URL=https://discord.com/api/webhooks/123456789/your-token
SERVER_URL=https://www.kogama.com
START_ID=32347000# Development
cargo run
# Production (optimised binary)
./target/release/feed-monitorPress Ctrl-C for a clean shutdown. The current position is saved to STATE_FILE before exit.
Progress is stored as a small JSON file:
{ "id": 32347404 }To resume from a specific position, edit this file directly and restart the service. To start fresh, delete it -- the service will fall back to START_ID.
- Open the platform in a browser and open DevTools (F12).
- Go to the Network tab and filter by
/feed/. - Perform any action that creates a feed event (e.g. post a status update).
- Inspect the response and copy the
idfield from the returned JSON. - Set that value as
START_IDin your.env.
| Feed type | Description |
|---|---|
status_updated |
Status post |
POST |
General post |
wall_post |
Wall message |
game_published |
Game publication |
marketplace_buy |
Avatar purchase |
badge_earned |
Badge award |
username_updated |
Username change |
Each type produces a distinctly colour-coded embed. Unknown types are forwarded with a fallback label rather than dropped.
If the monitor encounters 120 or more consecutive missing feed IDs, it assumes a gap in the sequence and jumps forward automatically. This prevents the service from stalling on sparse or inactive ID ranges. The jump size scales with the length of the gap.
Create /etc/systemd/system/feed-monitor.service:
[Unit]
Description=Feed Monitor
After=network.target
[Service]
Type=simple
User=youruser
WorkingDirectory=/opt/feed-monitor
EnvironmentFile=/opt/feed-monitor/.env
ExecStart=/opt/feed-monitor/feed-monitor
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.targetsudo systemctl enable --now feed-monitor
sudo systemctl status feed-monitorFROM debian:bookworm-slim
WORKDIR /app
COPY target/release/feed-monitor .
COPY .env .
CMD ["./feed-monitor"]docker build -t feed-monitor .
docker run -d --name feed-monitor \
-v "$(pwd)/state.json:/app/state.json" \
feed-monitorLogs are written to stdout. Control verbosity with LOG_LEVEL. Use info for normal operation and debug when diagnosing parse or delivery issues.
To persist logs, redirect stdout:
./feed-monitor >> monitor.log 2>&1Parse errors on API responses
Verify SERVER_URL is correct and the API is reachable. Check LOG_LEVEL=debug output for the raw response body.
Webhook delivery failures
Confirm WEBHOOK_URL is valid. The service retries with exponential backoff up to four times before logging a failure and moving on.
Recovery triggering frequently
The current ID range may be sparse. Inspect the state file and jump START_ID forward to a known active range.
Service stops unexpectedly
Check logs for a CRITICAL or ERROR line. Network interruptions are handled gracefully; a crash indicates a bug worth reporting.
This tool is provided for legitimate monitoring and moderation purposes. Users are responsible for ensuring their usage complies with applicable laws, platform terms of service, and data protection requirements. The authors accept no liability for misuse.