Published on

Monitor Monero Mining Rewards with Python

Authors

Monitor Monero Mining Rewards with Python

By Adam Johnston – Infinite Curios

Why trust this content? I've tracked my own Monero rigs and several friends' side-hustle miners since 2017, iterating through half a dozen pool APIs and countless scripts. This walkthrough distils what actually works when you want reliable numbers instead of guesswork.

When a mining rig hums away in a spare room, it's tempting to trust the pool dashboard and move on. The risk is missing an unpaid balance threshold or overlooking stale shares that quietly erode profitability. A lean Python workflow keeps the ledger transparent without adding another bloated dashboard or subscription to maintain.

This expanded guide distils the routines I use on personal and client rigs. We'll interpret the pool metrics that matter, harden the script against flaky networks, keep a history you can audit, and automate alerts so you hear about payouts before they land.

Image idea: an annotated diagram showing your mining rig, pool API, Python script, and notification channel.

Why Track Your Monero Balance Proactively

Laptop displaying code with reflection, perfect for tech and programming themes.

Monero's privacy-first design still leaves your mining pool with rich telemetry. Focus on the metrics below so the unpaid balance never lives in isolation.

How pool payouts are calculated

  • Share contributions: Pools such as SupportXMR pay according to valid shares submitted, not raw hash rate.
  • Payment threshold: Minimum payout amounts (often 0.01–0.1 XMR) dictate your cashflow cadence.
  • Luck and variance: Track average vs. current hash rates to separate bad luck from a configuration problem; the Monero pool primer shows how variance normalises over time.

Callout: If your unpaid balance stalls for multiple days, check for stale shares or downtime on the pool status page before blaming your hardware.

Key metrics worth logging

  1. amtDue or balance: The unpaid amount waiting to be disbursed.
  2. hash and hash2: Short-term and long-term average hash rate—useful for spotting throttled GPUs or thermal issues.
  3. lastShare timestamps and payments: Confirm each worker is active and reconcile payouts against your wallet.

Keeping a local log gives you leverage when contacting support or measuring the impact of undervolting, new miners, or firmware tweaks.

Tooling Checklist Before You Code

A young person coding at a desk with a computer and drinking from a mug.

Getting the basics right now prevents noisy alerts later. Install Python 3.10 or newer, create an isolated virtual environment, and add requests, python-dotenv, and pydantic to handle HTTP calls, secrets, and validation.

python3 -m venv venv
source venv/bin/activate
pip install requests python-dotenv pydantic

Configuration hygiene

Store wallet addresses and API tokens (if required) in a .env file, document which machines run the script, and version-control your code so experiments are reversible. Our GitHub Actions automation guide shows how to run checks whenever you push a change.

Hands-On Example: Building the Balance Checker

Let's turn theory into a resilient script. We'll fetch data from SupportXMR, validate the payload, and print a tidy summary.

from __future__ import annotations

import os
from datetime import datetime, timezone

import requests
from pydantic import BaseModel, Field
from dotenv import load_dotenv

load_dotenv()

POOL = "https://supportxmr.com/api/miner"
WALLET = os.environ["XMR_WALLET"]

class MinerStats(BaseModel):
    balance: float = Field(alias="balance")
    hashrate: float = Field(alias="hash")
    hashrate_24h: float = Field(alias="hash2")
    last_share: int = Field(alias="lastShare")

class ApiResponse(BaseModel):
    stats: MinerStats


def fetch_stats(wallet: str) -> MinerStats:
    url = f"{POOL}/{wallet}/stats"
    response = requests.get(url, timeout=15)
    response.raise_for_status()
    payload = ApiResponse.model_validate(response.json())
    return payload.stats


def human_time(epoch: int) -> str:
    return datetime.fromtimestamp(epoch, tz=timezone.utc).strftime("%Y-%m-%d %H:%M UTC")


def main() -> None:
    stats = fetch_stats(WALLET)
    balance_xmr = stats.balance / 1e12
    print(f"Unpaid balance: {balance_xmr:.6f} XMR")
    print(f"Current hash rate: {stats.hashrate / 1e3:.2f} kH/s")
    print(f"24h average: {stats.hashrate_24h / 1e3:.2f} kH/s")
    print(f"Last share submitted: {human_time(stats.last_share)}")


if __name__ == "__main__":
    main()

Key upgrades from the original snippet:

  • pydantic guarantees that the JSON structure matches expectations, so you'll see immediate validation errors if the API changes.
  • Timestamps are converted to human-readable UTC output for faster troubleshooting.
  • The script raises on non-200 responses, making it easy to catch outages in logs or monitoring tools.

Tip: When experimenting with different pool payloads, drop the raw JSON into our Regex Tester tool to quickly validate keys or extract worker IDs from long strings.

Persisting Data for Trend Analysis

Knowing today's balance is useful; seeing the trend lines prevents surprises. Two lightweight approaches cover most solo miners.

Append to a CSV ledger

import csv
from pathlib import Path

LEDGER = Path("balance_history.csv")


def log_balance(amount: float, hashrate: float) -> None:
    is_new = not LEDGER.exists()
    with LEDGER.open("a", newline="") as fh:
        writer = csv.writer(fh)
        if is_new:
            writer.writerow(["timestamp", "balance_xmr", "hashrate_khs"])
        writer.writerow([datetime.now(timezone.utc).isoformat(), amount, hashrate])

CSV works everywhere and lets you whip up quick charts in Excel or Google Sheets. Commit the file to a private repo if you track long-term earnings.

Log to SQLite for richer queries

SQLite adds minimal overhead and lets you answer questions like “What was my average hash rate after undervolting the GPUs last month?” Use the sqlite3 module to create a balances table with timestamp, balance, and hash rate columns, then insert rows whenever the cron job runs. Once data accumulates, plug the database into Grafana or a minimal Flask dashboard to visualise progress. Image suggestion: screenshot of a Grafana panel showing balance trend lines.

Automating Alerts Before Payouts

A script you have to remember to run defeats the point. Automation ensures you get nudges without babysitting terminals.

Schedule the script

  • Linux / macOS: Add a cron entry such as 0 * * * * /home/miner/venv/bin/python /home/miner/check_balance.py >> /home/miner/logs/balance.log 2>&1 to run hourly.
  • Windows: Use Task Scheduler with the "Start in" directory set to your project folder. Trigger every 60 minutes or whenever your rig starts.

Push notifications you can trust

  • Email: Use smtplib with environment variables for credentials and trigger when balance exceeds the pool's threshold.
  • Matrix or Discord: Post to a webhook for mobile-friendly alerts.
  • Home Assistant: Forward the data to a local automation hub for audible warnings.
THRESHOLD = 0.05  # XMR

if balance_xmr >= THRESHOLD:
    requests.post(
        os.environ["DISCORD_WEBHOOK"],
        json={"content": f"🎉 Payout ready: {balance_xmr:.4f} XMR"},
        timeout=10,
    )

Remember to keep webhook URLs secret. Store them in .env and load them like the wallet address.

Beyond SupportXMR: Adapting to Other Pools

Every pool adds quirks. Start by reading the API docs—MineXMR and MoneroOcean expose familiar endpoints but rename fields and units. Normalise everything into XMR before logging, pass API keys through headers when required, and keep sample JSON fixtures so unit tests alert you whenever a provider silently tweaks its payload.

Security, Privacy, and Trust Considerations

Mining balances might seem harmless, but they can reveal wallet activity patterns. Treat your scripts with the same care as you would a hot wallet.

  • Protect wallet addresses: Mask them in logs or only store the last six characters when printing to screen.
  • Rotate credentials: Regenerate API keys regularly and pin dependencies in requirements.txt so supply-chain changes are deliberate.
  • Encrypt history: Use gpg or BitLocker before archiving months of payouts.
  • Verify binaries: When running third-party tools like tray-xmr, build from source or verify release signatures from the maintainer's GitHub tags.

The Monero best practices guide offers further reading on securing wallets and mining endpoints.

Case Study: A Weekend Mining Rig Pays for Itself

In early 2024 I helped a friend tune a three-GPU weekend rig. SupportXMR's 0.03 XMR threshold meant payouts felt random, so we wired in the workflow above, logging hourly balances, dispatching Discord alerts within 0.005 XMR of payout, and flagging any 24-hour hash rate dip greater than 10%.

Two weeks later we caught a failing riser cable before it killed a card, stabilised hash rates, and timed payouts ahead of peak electricity tariffs—an 8% saving that funded quieter fans.

Illustration idea: before/after line chart showing hash rate stability once alerts were in place.

Troubleshooting Checklist

  • Script fails with KeyError: The API payload likely changed. Dump response.json() and adjust your models.
  • requests.exceptions.Timeout: Increase the timeout or run a local pool status check. Pools sometimes throttle frequent polling.
  • Balance reads zero: Confirm your wallet address matches the pool dashboard. Copy/paste errors are common with Monero's long strings.
  • Cron job silent failures: Redirect output to a log file and inspect permissions on the Python interpreter.

FAQ

Can I monitor multiple wallets or workers at once?

Yes. Keep wallet addresses in a list or config file, loop over them, and tag each row with the worker name for quick comparisons.

How often should I poll the API?

SupportXMR tolerates a request each minute, but hourly polling usually balances insight and politeness. Aggressive schedules risk temporary bans.

Will this work for pools that pay in Bitcoin or other coins?

The structure is the same. Swap the endpoint, adjust units, and convert payouts with an exchange-rate API such as CoinGecko.

How do I integrate the data into a tax report?

Export the SQLite table or CSV ledger each quarter and reconcile it with wallet transactions. Accounting tools like Koinly accept CSV imports with timestamps, amounts, and transaction IDs.

What if I prefer a GUI over scripts?

Projects like tray-xmr offer Windows-friendly interfaces. Run them alongside your Python logger for redundancy.

Conclusion: Build Confidence in Every Payout

A dependable mining workflow isn't about flashy dashboards—it's about verifiable numbers and timely alerts. With a few Python modules and sensible logging, you can predict your next Monero payout, surface hardware problems early, and maintain records that satisfy both personal bookkeeping and regulatory needs.

Call to action: Clone the code, tailor it to your pool, and share your improvements with the Infinite Curios community forum. If you discover a slick automation, drop us a note so we can feature it in an upcoming tooling roundup.

Further looks

Laptop displaying code with reflection, perfect for tech and programming themes.
A young person coding at a desk with a computer and drinking from a mug.

Written by Adam Johnston for Infinite Curios.