Josh Bruce Online

F1 Fantasy Data Format Documentation

Version: 3.1
Last Updated: August 11, 2025
Repository: https://github.com/JoshCBruce/fantasy-data


πŸ“ Directory Structure

latest/
β”œβ”€β”€ driver_data/
β”‚   β”œβ”€β”€ {DRIVER_ABBREVIATION}.json (21 files)
β”‚   └── ...
β”œβ”€β”€ constructor_data/
β”‚   β”œβ”€β”€ {CONSTRUCTOR_ABBREVIATION}.json (10 files)
β”‚   └── ...
└── summary_data/
    β”œβ”€β”€ weekend_summary.json
    β”œβ”€β”€ constructor_weekend_summary.json
    β”œβ”€β”€ extraction_summary.json
    β”œβ”€β”€ team_summary.json
    β”œβ”€β”€ percentage_picked_ranking.json
    └── constructor_percentage_picked_ranking.json

🏎️ Individual Driver Data Format

File Path: latest/driver_data/{ABBREVIATION}.json
Example: ALO.json, NOR.json, VER.json

Core Driver Object Structure

{
  "driverId": "string",
  "name": "string",
  "displayName": "string",
  "abbreviation": "string",
  "team": "string",
  "position": number,
  "value": "string",
  "seasonTotalPoints": number,
  "percentagePicked": number,
  "isInactive": boolean,
  "teamSwap": boolean,
  "teams": ["string"],
  "races": [RaceObject],
  "extractedAt": "ISO8601 timestamp"
}

Field Descriptions

Field Type Required Description Example
driverId String Yes Unique driver identifier from F1 Fantasy "landonorrisdriver"
name String Yes Driver’s name (lowercase, no spaces) "landonorris"
displayName String Yes Driver’s display name "landonorris"
abbreviation String Yes 3-letter driver code "NOR"
team String Yes Current team name "McLaren"
position Number Yes Championship position 1
value String Yes Fantasy value with currency "31.4M"
seasonTotalPoints Number Yes Total fantasy points this season 500
percentagePicked Number Yes Percentage of users who picked driver 23
isInactive Boolean Yes Whether driver is currently inactive false
teamSwap Boolean No Whether driver switched teams mid-season false
teams Array No List of teams if team swap occurred ["Red Bull Racing", "Racing Bulls"]
races Array Yes Array of race data objects See Race Object Structure
extractedAt String Yes ISO8601 timestamp of data extraction "2025-08-10T20:16:57.036Z"

Race Object Structure

{
  "round": "string",
  "raceName": "string",
  "totalPoints": number,
  "race": {
    "dotd": number,
    "position": number,
    "qualifyingPosition": number,
    "fastestLap": number,
    "overtakeBonus": number,
    "positionsGained": number,
    "positionsLost": number,
    "disqualificationPenalty": number
  },
  "qualifying": {
    "position": number,
    "disqualificationPenalty": number
  },
  "sprint": {
    "position": number,
    "qualifyingPosition": number,
    "fastestLap": number,
    "overtakeBonus": number,
    "positionsGained": number,
    "positionsLost": number,
    "disqualificationPenalty": number
  }
}

Race Field Descriptions

Field Type Description Points
round String Race round number "1", "2", etc.
raceName String Official race name "Australia", "Monaco"
totalPoints Number Total fantasy points for this race Can be negative
race.dotd Number Driver of the Day bonus 0 or 10
race.position Number Race finishing position points Variable based on position
race.qualifyingPosition Number Qualifying position points 0 (handled in qualifying object)
race.fastestLap Number Fastest lap bonus 0 or 10
race.overtakeBonus Number Overtaking bonus points Variable
race.positionsGained Number Positions gained during race Positive number
race.positionsLost Number Positions lost during race Negative number or 0
race.disqualificationPenalty Number Disqualification penalty 0 or negative
qualifying.position Number Qualifying finishing position points Variable
qualifying.disqualificationPenalty Number Qualifying penalties 0 or negative
sprint.* Various Sprint race data (same structure as race) Only present for sprint weekends

Team Swap Driver Special Fields

For drivers with teamSwap: true:

{
  "teamSwap": true,
  "teams": ["Previous Team", "Current Team"],
  "teamSwapDetails": [
    {
      "team": "Previous Team",
      "position": number,
      "value": "string",
      "points": number
    },
    {
      "team": "Current Team", 
      "position": number,
      "value": "string",
      "points": number
    }
  ],
  "versions": number,
  "races": [
    {
      "round": "string",
      "raceName": "string",
      "totalPoints": number,
      "team": "string",
      "source": "single|merged",
      "race": {},
      "qualifying": {},
      "sprint": {}
    }
  ]
}

🏁 Constructor Data Format

File Path: latest/constructor_data/{ABBREVIATION}.json
Example: MCL.json, FER.json, RBR.json

Constructor Object Structure

{
  "constructorId": "string",
  "name": "string", 
  "displayName": "string",
  "abbreviation": "string",
  "position": number,
  "value": "string",
  "seasonTotalPoints": number,
  "percentagePicked": number,
  "races": [ConstructorRaceObject],
  "extractedAt": "ISO8601 timestamp"
}

Constructor Race Object

{
  "round": "string",
  "raceName": "string", 
  "totalPoints": number,
  "race": {
    "position": number,
    "qualifyingPosition": number,
    "fastestLap": number,
    "pitStopBonus": number,
    "fastestPitStop": number,
    "worldRecordBonus": number,
    "disqualificationPenalty": number,
    "positionsGained": number,
    "positionsLost": number,
    "overtakes": number
  },
  "qualifying": {
    "q2Bonus": number,
    "q3Bonus": number,
    "disqualificationPenalty": number
  },
  "sprint": {
    "position": number,
    "qualifyingPosition": number,
    "fastestLap": number,
    "disqualificationPenalty": number,
    "positionsGained": number,
    "positionsLost": number,
    "overtakes": number
  }
}

πŸ“Š Summary Data Formats

1. Weekend Summary (weekend_summary.json)

Race-by-race points for all drivers:

{
  "1": {
    "raceName": "Australia",
    "drivers": {
      "NOR": 59,
      "PIA": 10,
      "VER": 29,
      "RUS": 25,
      "HAM": 4
    }
  },
  "2": {
    "raceName": "China", 
    "drivers": {
      "NOR": 41,
      "PIA": 45
    }
  }
}

2. Constructor Weekend Summary (constructor_weekend_summary.json)

Race-by-race points for all constructors:

{
  "1": {
    "raceName": "Australia",
    "constructors": {
      "MCL": 71,
      "FER": 36,
      "MER": 67,
      "RBR": 19
    }
  }
}

3. Extraction Summary (extraction_summary.json)

Overall statistics and metadata:

{
  "extractedAt": "2025-08-10T20:20:31.427Z",
  "totalDrivers": 21,
  "totalConstructors": 10,
  "teamSwapDrivers": 2,
  "totalRaces": 309,
  "averagePercentagePicked": 23,
  "averageConstructorPercentagePicked": 20,
  "drivers": [
    {
      "abbreviation": "NOR",
      "name": "landonorris",
      "team": "McLaren",
      "position": 1,
      "value": "31.4M",
      "seasonTotal": 500,
      "percentagePicked": 23,
      "racesFound": 15,
      "teamSwap": false,
      "teams": []
    }
  ],
  "constructors": [
    {
      "abbreviation": "MCL",
      "name": "mclaren",
      "position": 1,
      "value": "34.2M", 
      "seasonTotal": 1215,
      "percentagePicked": 40,
      "racesFound": 15
    }
  ]
}

4. Team Summary (team_summary.json)

Grouped data by team:

{
  "McLaren": {
    "drivers": [
      {
        "abbreviation": "NOR",
        "name": "landonorris",
        "points": 500,
        "percentagePicked": 23,
        "value": "31.4M",
        "position": 1
      },
      {
        "abbreviation": "PIA",
        "name": "oscarpiastri", 
        "points": 489,
        "percentagePicked": 40,
        "value": "26.4M",
        "position": 2
      }
    ],
    "totalPoints": 989,
    "averagePercentagePicked": 32
  }
}

5. Percentage Picked Ranking (percentage_picked_ranking.json)

Drivers ranked by popularity:

{
  "HAD": 54,
  "BEA": 44, 
  "PIA": 40,
  "SAI": 39,
  "ALO": 37,
  "HUL": 34,
  "ALB": 29,
  "BOR": 25,
  "OCO": 24,
  "NOR": 23
}

6. Constructor Percentage Picked Ranking (constructor_percentage_picked_ranking.json)

Constructors ranked by popularity:

{
  "MCL": 40,
  "RB": 26,
  "WIL": 25,
  "FER": 21,
  "HAS": 20,
  "MER": 17,
  "AMR": 16,
  "SAU": 15,
  "RBR": 10,
  "ALP": 10
}

🌐 Data Access URLs

GitHub Raw URLs (Live Data)

Base URL: https://raw.githubusercontent.com/JoshCBruce/fantasy-data/refs/heads/main/latest

Individual Driver Data:

https://raw.githubusercontent.com/JoshCBruce/fantasy-data/refs/heads/main/latest/driver_data/{ABBREVIATION}.json

Constructor Data:

https://raw.githubusercontent.com/JoshCBruce/fantasy-data/refs/heads/main/latest/constructor_data/{ABBREVIATION}.json

Summary Data:

https://raw.githubusercontent.com/JoshCBruce/fantasy-data/refs/heads/main/latest/summary_data/weekend_summary.json
https://raw.githubusercontent.com/JoshCBruce/fantasy-data/refs/heads/main/latest/summary_data/extraction_summary.json
https://raw.githubusercontent.com/JoshCBruce/fantasy-data/refs/heads/main/latest/summary_data/team_summary.json
https://raw.githubusercontent.com/JoshCBruce/fantasy-data/refs/heads/main/latest/summary_data/percentage_picked_ranking.json

πŸ† Current Season Drivers (2025)

Active Driver Abbreviations

const ACTIVE_DRIVERS = [
  'NOR', 'PIA', 'VER', 'RUS', 'HAM', 'LEC', 'HUL', 'ANT',
  'STR', 'OCO', 'ALB', 'BEA', 'TSU', 'ALO', 'HAD', 'BOR', 
  'SAI', 'LAW', 'GAS', 'COL', 'DOO'
];

Team Swap Drivers

Constructor Abbreviations

const CONSTRUCTORS = [
  'MCL', 'FER', 'MER', 'RBR', 'HAS', 'SAU', 
  'AMR', 'RB', 'WIL', 'ALP'
];

πŸ”„ Race Calendar & Naming

2025 Season Races

Round Race Name Type Sprint Weekend
1 Australia Regular No
2 China Sprint Yes
3 Japan Regular No
4 Bahrain Regular No
5 Saudi Arabia Regular No
6 United States Sprint Yes
7 Italy Regular No
8 Monaco Regular No
9 Spain Regular No
10 Canada Regular No
11 Austria Sprint Yes
12 United Kingdom Regular No
13 Belgium Sprint Yes
14 Hungary Regular No
15 Netherlands Regular No

Sprint Weekend Structure

Sprint weekends include additional data:

{
  "sprint": {
    "position": number,
    "qualifyingPosition": number, 
    "fastestLap": number,
    "overtakeBonus": number,
    "positionsGained": number,
    "positionsLost": number,
    "disqualificationPenalty": number
  }
}

πŸ’° Fantasy Scoring System

Driver Points Structure

Category Points Conditions
Race Position Variable 1st: 25pts, 2nd: 20pts, etc.
Qualifying Position Variable 1st: 10pts, 2nd: 9pts, etc.
Driver of the Day 10 Awarded by fan vote
Fastest Lap 10 Must finish in top 10
Overtake Bonus +3 per position Net positions gained
Position Lost -2 per position Net positions lost
Sprint Position Variable Reduced points scale
Sprint Qualifying Variable Reduced points scale
Disqualification -20 Full race/qualifying DSQ

Constructor Points Structure

Category Points Conditions
Race Position Variable Combined driver positions
Qualifying Variable Combined qualifying positions
Fastest Lap 10 Team achieves fastest lap
Fastest Pit Stop 10 Team has fastest pit stop
Pit Stop Bonus 5 Exceptional pit stop performance
Q2/Q3 Bonus 5/10 Both cars reach Q2/Q3
World Record 15 Breaking track/sector records
Overtakes +1 per overtake Successful overtaking moves

πŸ› οΈ Data Processing Guidelines

Error Handling

// Always check for data availability
if (!driver.races || driver.races.length === 0) {
  return 0; // or appropriate default
}

// Handle missing sprint data
const sprintData = race.sprint || null;
if (sprintData) {
  // Process sprint data
}

// Handle team swap drivers
if (driver.teamSwap) {
  // Use merged data with team context
  const raceWithTeam = race.team || driver.team;
}

Data Validation

// Validate required fields
const requiredFields = ['abbreviation', 'seasonTotalPoints', 'races'];
const isValid = requiredFields.every(field => 
  driver.hasOwnProperty(field) && driver[field] !== undefined
);

// Validate race data
race.totalPoints = race.totalPoints || 0;
race.round = String(race.round); // Ensure string format

Common Calculations

// Average points per race
const avgPoints = driver.seasonTotalPoints / driver.races.length;

// Recent form (last 3 races)
const recentRaces = driver.races.slice(-3);
const recentForm = recentRaces.reduce((sum, race) => 
  sum + race.totalPoints, 0) / recentRaces.length;

// Value efficiency
const value = parseFloat(driver.value.replace('M', ''));
const efficiency = driver.seasonTotalPoints / value;

// Consistency (standard deviation)
const mean = avgPoints;
const variance = driver.races.reduce((sum, race) => 
  sum + Math.pow(race.totalPoints - mean, 2), 0) / driver.races.length;
const consistency = Math.sqrt(variance);

🚨 Important Notes

Data Freshness

Team Changes

Missing Data Handling

Rate Limiting

Data Integrity


πŸ“ˆ Usage Examples

JavaScript Data Fetching

// Base URL for all data
const BASE_URL = 'https://raw.githubusercontent.com/JoshCBruce/fantasy-data/refs/heads/main/latest';

// Fetch individual driver
async function fetchDriver(abbreviation) {
  const response = await fetch(`${BASE_URL}/driver_data/${abbreviation}.json`);
  return response.json();
}

// Fetch all summary data
async function fetchSummaryData() {
  const response = await fetch(`${BASE_URL}/summary_data/extraction_summary.json`);
  return response.json();
}

// Fetch weekend summary
async function fetchWeekendSummary() {
  const response = await fetch(`${BASE_URL}/summary_data/weekend_summary.json`);
  return response.json();
}

Python Data Analysis

import requests
import json

BASE_URL = "https://raw.githubusercontent.com/JoshCBruce/fantasy-data/refs/heads/main/latest"

def fetch_driver_data(abbreviation):
    url = f"{BASE_URL}/driver_data/{abbreviation}.json"
    response = requests.get(url)
    return response.json()

def fetch_all_drivers():
    drivers = ['NOR', 'PIA', 'VER', 'RUS', 'HAM', 'LEC', 'HUL']
    return {abbrev: fetch_driver_data(abbrev) for abbrev in drivers}

# Calculate team totals
def calculate_team_performance():
    summary = requests.get(f"{BASE_URL}/summary_data/team_summary.json").json()
    return {team: data['totalPoints'] for team, data in summary.items()}

πŸ”„ Version History

v3.1 (Current)

v3.0

Future Considerations


Last Updated: August 11, 2025
Documentation Version: 3.1
Data Repository: https://github.com/JoshCBruce/fantasy-data