Back to Guides

Building a Real-Time Match Monitor

A step-by-step guide to building a CLI tool that monitors live Valorant matches, tracks scores, and alerts on key events using VLRdevAPI.

This guide walks through building a real-time match monitor that polls for live matches, displays scores, and tracks team performance. By the end, you'll have a working CLI tool you can extend for your own use cases.

Prerequisites

Before you begin, make sure you have:

  • Python 3.11 or later installed
  • The vlrdevapi package installed: pip install vlrdevapi
  • Basic familiarity with Python and the command line

Project Setup

Create a project directory and virtual environment

mkdir match-monitor
cd match-monitor
python -m venv .venv
source .venv/bin/activate  # Windows: .venv\Scripts\activate
pip install vlrdevapi

Create the main script

Create a file called monitor.py — we'll build it up step by step throughout this guide.

Step 1: Fetch Live Matches

The first thing our monitor needs is the ability to fetch currently live matches from VLR.gg.

Use vlrdevapi.matches.live() to get all ongoing matches. Each entry has match_id, event, stage, and team1/team2 objects.

import vlrdevapi

try:
    page = vlrdevapi.matches.live()
    matches = page.matches
    print(f"Live matches: {len(matches)}")
    if matches:
        for m in matches:
            print(f"  Match #{m.match_id}{m.event}")
    else:
        print("No matches currently live — this is normal.")
except Exception as e:
    print(f"Error: {e}")

Step 2: Display Match Status

Raw match objects aren't human-readable. Let's build a formatter and a display function.

Formatting a single match

import vlrdevapi

def format_match(m):
    """Format a match entry into a readable string."""
    t1 = m.team1.name if m.team1 else "TBD"
    t2 = m.team2.name if m.team2 else "TBD"
    return f"{t1} vs {t2}  |  {m.event}  |  {m.stage}"

def show_matches(matches):
    """Print a formatted list of matches."""
    if not matches:
        print("No live matches at this time.")
        return
    print(f"\n{'='*60}")
    print(f"  LIVE MATCHES ({len(matches)})")
    print(f"{'='*60}")
    for m in matches:
        print(f"  {format_match(m)}")
    print(f"{'='*60}\n")

page = vlrdevapi.matches.live()
show_matches(page.matches)

Match object fields

Each match exposes:

  • match_id — unique match identifier
  • team1 / team2TeamInLiveMatch objects with .name, .tag, .id, .country_name
  • event — tournament name (e.g. "VCT 2025: Masters Madrid")
  • stage — stage within the event (e.g. "Playoffs")
  • status — always "live"

Step 3: Build a Polling Snapshot

A real-time monitor polls the API and alerts when new matches appear. The key is tracking match_id values in a set.

import vlrdevapi
import time

def poll(seen=None, interval=30):
    """Poll for live matches and alert on new ones."""
    if seen is None:
        seen = set()
    print(f"Polling every {interval}s — checking for new matches")

    for _ in range(3):  # run a few cycles for demonstration
        try:
            page = vlrdevapi.matches.live()
            current = page.matches
        except Exception as e:
            print(f"  Poll error: {e}")
            time.sleep(interval)
            continue

        new_matches = [m for m in current if m.match_id not in seen]

        for m in new_matches:
            seen.add(m.match_id)
            t1 = m.team1.name if m.team1 else "TBD"
            t2 = m.team2.name if m.team2 else "TBD"
            print(f"  [NEW] {t1} vs {t2} just went live!")

        if not new_matches:
            print(f"  [{time.strftime('%H:%M:%S')}] No new matches — continuing...")

        time.sleep(interval)

poll(interval=1)

To run this continuously (not just 3 cycles), replace the for loop with while True. Interrupt the process with Ctrl+C to stop.

Step 4: Enrich Matches with Team Details

When a new match appears, use vlrdevapi.team(id) to fetch each team's full info and roster.

import vlrdevapi

def show_team_details(match):
    """Fetch and display detailed team rosters."""
    for team in [match.team1, match.team2]:
        if not team:
            continue
        try:
            obj = vlrdevapi.team(team.id)
            info = obj.info()
            roster = obj.roster()
            print(f"\n  {info.name} (ID: {team.id})")
            for p in roster.players:
                roles = ", ".join(p.roles)
                print(f"    {p.ign}{roles}")
        except Exception as e:
            print(f"  Could not fetch team {team.id}: {e}")

page = vlrdevapi.matches.live()
if page.matches:
    show_team_details(page.matches[0])
else:
    print("No live matches to inspect right now.")

Step 5: Track Completed Matches

Use vlrdevapi.matches.completed() to fetch finished matches and see final scores.

import vlrdevapi

def show_completed():
    """Fetch and display recently completed match results."""
    try:
        results = vlrdevapi.matches.completed(page=1)
    except Exception as e:
        print(f"Error: {e}")
        return

    if not results.matches:
        print("No completed matches found.")
        return

    for m in results.matches[:5]:
        t1, t2 = m.team1, m.team2
        if t1 and t2:
            winner = t1 if t1.is_winner else t2
            print(f"  {t1.name} {t1.score} - {t2.score} {t2.name}")
            print(f"    Winner: {winner.name}")

show_completed()

Completed matches expose these additional fields on each team:

  • score — number of maps won
  • is_winner — whether the team won the match

Step 6: Putting It All Together

This final script combines everything into a standalone snapshot tool:

import vlrdevapi

def format_match(m):
    t1 = m.team1.name if m.team1 else "TBD"
    t2 = m.team2.name if m.team2 else "TBD"
    return f"{t1} vs {t2}  |  {m.event}  |  {m.stage}"

def show_team_details(match):
    for team in [match.team1, match.team2]:
        if not team:
            continue
        try:
            obj = vlrdevapi.team(team.id)
            info = obj.info()
            roster = obj.roster()
            print(f"\n  {info.name}")
            for p in roster.players:
                roles = ", ".join(p.roles)
                print(f"    {p.ign}{roles}")
        except Exception as e:
            print(f"  Could not fetch team {team.id}: {e}")

print("=== CURRENT LIVE MATCHES ===\n")

try:
    page = vlrdevapi.matches.live()
    if page.matches:
        for m in page.matches:
            print(format_match(m))
        print(f"\n--- Team details for first match ---")
        show_team_details(page.matches[0])
    else:
        print("No live matches right now.")
except Exception as e:
    print(f"Error fetching matches: {e}")

Save this as monitor.py and run it directly: python monitor.py.

Next Steps

Ready to build with VLRdevAPI?

Install the Python SDK and start fetching Valorant esports data in minutes. No API key required.

Read the Docs