Skip to content

Data Access

pyrf includes a client for the FootyIQ watcher data API and the bet3 ratings API.

Setup

Set your API tokens as environment variables (or place them in a .env file):

export FOOTYIQ_TOKEN=your_footyiq_token_here
export BET3_TOKEN=your_bet3_token_here

Fetching Scores

from pyrf_data import PyRfDataClient

client = PyRfDataClient()

# All scores
df = client.fetch_scores()

# Only games where watchers agree on the score (recommended)
df = client.fetch_scores_agreed()

# Games with score discrepancies (data quality investigation)
df = client.fetch_scores_disagreed()

Full Match Export

Detailed match statistics including goals, chances, half-chances, deliveries, and more:

df = client.fetch_full_export()

The full export includes per-team, per-half breakdowns of:

  • Goals and assists
  • Chances and half-chances
  • Ooohs and choos (near-miss events)
  • Deliveries into the box

Team Ratings

Fetch model-derived team ratings (alpha/beta/lambda parameters, supremacy, total goals) for upcoming matchups:

df = client.fetch_ratings_club()

Data Quality

Use fetch_scores_agreed() for reliable score data. The agreed/disagreed split helps identify matches where watcher observations may be unreliable.

API Reference

pyrf_data

Client for accessing Ringfinity match data (FootyIQ watcher API + bet3 ratings).

PyRfDataClient dataclass

Client for the FootyIQ watcher data API.

Returns DataFrames with flattened data by default. Use *_raw methods for the original nested JSON response.

__post_init__() -> None

Initialize tokens and paths from environment if not provided.

fetch_scores_raw(limit: int = 1000, from_date: pd.Timestamp | None = None, to_date: pd.Timestamp | None = None, scores_agree: bool | None = None) -> list[dict[str, Any]]

Fetch game scores from the API as raw nested JSON.

Parameters:

Name Type Description Default
limit int

Maximum number of records to fetch.

1000
from_date Timestamp | None

Start date as pd.Timestamp (defaults to 2000-07-07).

None
to_date Timestamp | None

End date as pd.Timestamp (defaults to 2029-08-07).

None
scores_agree bool | None

If True, only return games where watcher and NowGoal agree. If False, only return games where they disagree. If None, return all games regardless.

None

Returns:

Type Description
list[dict[str, Any]]

Raw nested JSON response (country -> comps -> seasons -> rounds -> fixtures).

fetch_full_export_raw(limit: int = 500000, from_date: pd.Timestamp | None = None, to_date: pd.Timestamp | None = None) -> dict[str, Any]

Fetch full export data as raw JSON.

Returns:

Type Description
dict[str, Any]

Raw JSON with 'fixtures' list and metadata.

fetch_scores(limit: int = 1000, from_date: pd.Timestamp | None = None, to_date: pd.Timestamp | None = None, scores_agree: bool | None = None) -> pd.DataFrame

Fetch game scores as a flattened DataFrame.

Parameters:

Name Type Description Default
limit int

Maximum number of records to fetch.

1000
from_date Timestamp | None

Start date as pd.Timestamp (defaults to 2000-07-07).

None
to_date Timestamp | None

End date as pd.Timestamp (defaults to 2029-08-07).

None
scores_agree bool | None

If True, only return games where watcher and NowGoal agree. If False, only return games where they disagree. If None, return all games regardless.

None

Returns:

Type Description
DataFrame

DataFrame with columns: fixture_id, start_time, country, comp_id, comp_name,

DataFrame

comp_short, season, round, team1_id, team1_name, team2_id, team2_name,

DataFrame

score_ft, score_ht, team1_goals, team2_goals, scores_agree, pitch,

DataFrame

weather, temp.

fetch_scores_agreed(limit: int = 500000, from_date: pd.Timestamp | None = None, to_date: pd.Timestamp | None = None) -> pd.DataFrame

Fetch all trusted data where watcher and NowGoal scores agree.

This is the recommended method for fetching reliable historical data.

Returns:

Type Description
DataFrame

DataFrame with one row per fixture.

fetch_scores_disagreed(limit: int = 1000, from_date: pd.Timestamp | None = None, to_date: pd.Timestamp | None = None) -> pd.DataFrame

Fetch games where watcher score differs from NowGoal score.

Useful for investigating data quality or discrepancies.

Returns:

Type Description
DataFrame

DataFrame with one row per fixture.

fetch_full_export(limit: int = 500000, from_date: pd.Timestamp | None = None, to_date: pd.Timestamp | None = None) -> pd.DataFrame

Fetch full export with detailed match statistics as DataFrame.

Includes per-team stats: goals, chances, half-chances, deliveries, ooohs, choos - broken down by half.

Returns:

Type Description
DataFrame

DataFrame with detailed match statistics.

fetch_ratings_club_raw() -> list[dict[str, Any]]

Fetch club team ratings as raw JSON.

Returns:

Type Description
list[dict[str, Any]]

List of rating objects, one per home/away club matchup, each

list[dict[str, Any]]

containing alpha/beta/lambda parameters, supremacy (sup), total

list[dict[str, Any]]

goals (tg), and team/league metadata.

fetch_ratings_club() -> pd.DataFrame

Fetch club team ratings as a DataFrame.

Returns:

Type Description
DataFrame

DataFrame with one row per club matchup, including alpha/beta/lambda

DataFrame

parameters, supremacy, total goals, and team/league metadata.

DataFrame

The updated_at column is parsed to datetime.

fetch_ratings_international_raw() -> list[dict[str, Any]]

Fetch international (national-team) ratings as raw JSON.

Returns:

Type Description
list[dict[str, Any]]

List of rating objects, one per nation, each containing supremacy

list[dict[str, Any]]

(sup), total goals (tg, goals), per-side goal expectations,

list[dict[str, Any]]

normalised alpha/beta, and team/NowGoal metadata.

fetch_ratings_international() -> pd.DataFrame

Fetch international (national-team) ratings as a DataFrame.

Returns:

Type Description
DataFrame

DataFrame with one row per nation, including supremacy, total goals,

DataFrame

per-side goal expectations, normalised alpha/beta, and team/NowGoal

DataFrame

metadata. The updated_at column is parsed to datetime.

load_wcplayer_export_raw() -> dict[str, Any]

Load the local wcplayerexport.json file as raw JSON.

Returns:

Type Description
dict[str, Any]

Dict with keys wcteamplayers (list of player records),

dict[str, Any]

exportedAt, and count.

load_wcplayer_export() -> pd.DataFrame

Load the local wcplayerexport.json as a flat DataFrame.

Nested fs / ng / tm sub-objects are flattened with dot-separated column names (e.g. tm.cpm, ng._id). Date columns (createdAt, updatedAt, v1StarRatingChangedAt, v2StarRatingChangedAt) are parsed to datetime.

Returns:

Type Description
DataFrame

DataFrame with one row per player.

fetch_wcplayer_export_raw(limit: int = 5000) -> dict[str, Any]

Fetch the wcteamplayers export from the API as raw JSON.

Returns:

Type Description
dict[str, Any]

Dict with keys wcteamplayers (list of player records),

dict[str, Any]

exportedAt, and count.

fetch_wcplayer_export(limit: int = 5000, *, cache: bool = True) -> pd.DataFrame

Fetch the wcteamplayers export from the API as a flat DataFrame.

When cache is True (default) and rf_local_path is set, the raw JSON response is written to <rf_local_path>/wcplayerexport.json, overwriting any existing file.

Returns:

Type Description
DataFrame

DataFrame with one row per player, matching load_wcplayer_export.

fetch_wc2026_squads(*, update: bool = False, cache_path: Path | str | None = None, url: str = WC2026_SQUADS_URL) -> pd.DataFrame

Return the 2026 World Cup squads as one row per (nation, player).

Reads data/wc2026_players_flashscore.parquet (or rf_local_path equivalent) by default. Pass update=True to re-scrape the FlashScore article at url and overwrite the cache.

See docs/specs/wc2026_v2.md for the column contract.