Using OpenF1 with authentication

This guide explains how to access the OpenF1 API as an authenticated user. Authentication removes rate limits, provides access to both historical and real-time data, and enables live data streaming through MQTT or WebSocket.

The following sections will walk you through these features and how to make use of them.

Don’t have an account yet? Apply by completing this form.

Obtaining an OAuth2 access token

To access real-time data, you'll need to obtain an OAuth2 access token. This token proves your identity to the API.

You can get an access token by sending a POST request to the https://api.openf1.org/token endpoint with your username and password.

Bash/cURL example

curl -X POST "https://api.openf1.org/token" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d "username=YOUR_USERNAME&password=YOUR_PASSWORD"

Python example

import requests

token_url = "https://api.openf1.org/token"
payload = {
    "username": "YOUR_USERNAME",
    "password": "YOUR_PASSWORD"
}
headers = {
    "Content-Type": "application/x-www-form-urlencoded"
}

response = requests.post(token_url, data=payload, headers=headers)

if response.status_code == 200:
    token_data = response.json()
    print(f"Access token: {token_data.get('access_token')}")
    print(f"Expires in: {token_data.get('expires_in')} seconds")
else:
    print(f"Error obtaining token: {response.status_code} - {response.text}")

JavaScript example

async function getAccessToken() {
    const tokenUrl = "https://api.openf1.org/token";
    const params = new URLSearchParams();
    params.append("username", "YOUR_USERNAME");
    params.append("password", "YOUR_PASSWORD");

    try {
        const response = await fetch(tokenUrl, {
            method: "POST",
            headers: {
                "Content-Type": "application/x-www-form-urlencoded",
            },
            body: params,
        });

        if (response.ok) {
            const tokenData = await response.json();
            console.log("Access token:", tokenData.access_token);
            console.log("Expires in:", tokenData.expires_in, "seconds");
            return tokenData.access_token;
        } else {
            console.error("Error obtaining token:", response.status, await response.text());
            return null;
        }
    } catch (error) {
        console.error("Network error or other issue:", error);
        return null;
    }
}

// Example usage:
// getAccessToken().then(token => {
//     if (token) {
//         // Use the token
//     }
// });

Response

A successful request will return a JSON object containing your access token and its expiry time:

{
    "expires_in": "3600",
    "access_token": "YOUR_ACCESS_TOKEN",
    "token_type": "bearer"
}

Important: Tokens expire after 1 hour. Your application should be designed to handle token expiry gracefully by requesting a new one.

Authenticated requests to the REST API

To access real-time data, you must include your access token in the Authorization header as a Bearer token.

Bash/cURL example

# Replace YOUR_ACCESS_TOKEN with the token you obtained
curl -X 'GET' \
    'https://api.openf1.org/v1/sessions?year=2024' \
    -H 'accept: application/json' \
    -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'

Python example

import requests

# Assume 'access_token' is a variable holding your obtained token
access_token = "YOUR_ACCESS_TOKEN"
api_url = "https://api.openf1.org/v1/sessions?year=2024" # Example

headers = {
    "accept": "application/json",
    "Authorization": f"Bearer {access_token}"
}

response = requests.get(api_url, headers=headers)

if response.status_code == 200:
    data = response.json()
    print(data)
else:
    print(f"Error fetching data: {response.status_code} - {response.text}")

JavaScript example

async function fetchDataWithToken(accessToken) {
    const apiUrl = "https://api.openf1.org/v1/sessions?year=2024"; // Example

    try {
        const response = await fetch(apiUrl, {
            method: "GET",
            headers: {
                "accept": "application/json",
                "Authorization": `Bearer ${accessToken}`,
            },
        });

        if (response.ok) {
            const data = await response.json();
            console.log(data);
            return data;
        } else {
            console.error("Error fetching data:", response.status, await response.text());
            return null;
        }
    } catch (error) {
        console.error("Network error or other issue:", error);
        return null;
    }
}

// Example usage:
// getAccessToken().then(token => {
//     if (token) {
//         fetchDataWithToken(token);
//     }
// });

Real-time data with MQTT & Websockets

For the most efficient access to real-time data, we offer MQTT and Websocket connections. These methods push data to your application as soon as it's available, eliminating the need for constant polling of the REST API.

This is the recommended method for accessing live data.

Connection Details

Authentication

Both MQTT and Websocket connections use the OAuth2 access token as the password for authentication. The username can typically be any non-empty string, or your registered email if preferred/required by your client library for token-based auth.

Topics

Topics for MQTT/Websockets directly correspond to the REST API endpoint paths. For example:

You can subscribe to specific topics or use wildcards (e.g., # to subscribe to all topics if your client library supports it).

Message Format

Messages received via MQTT/Websockets are JSON objects, mirroring the data from the corresponding REST API endpoint. However, they include two additional fields:

Example message (topic: v1/location)

{
    "meeting_key": 1257,
    "session_key": 10007,
    "driver_number": 31,
    "date": "2025-04-11T11:21:16.603025+00:00",
    "x": 0,
    "y": 0,
    "z": 0,
    "_key": "1744370476603_31",
    "_id": 1747235800206
}

Code examples

Python (MQTT with `paho-mqtt`)

import paho.mqtt.client as mqtt
import ssl

# Assume 'access_token' is a variable holding your obtained token
access_token = "YOUR_ACCESS_TOKEN"
mqtt_broker = "mqtt.openf1.org"
mqtt_port = 8883

# Optional: Provide a username. Can be an email or any non-empty string.
mqtt_username = "your_username_or_email@example.com"

def on_connect(client, userdata, flags, rc, properties=None):
    if rc == 0:
        print("Connected to OpenF1 MQTT broker")
        client.subscribe("v1/location")
        client.subscribe("v1/laps")
        # client.subscribe("#") # Subscribe to all topics
    else:
        print(f"Failed to connect, return code {rc}")

def on_message(client, userdata, msg):
    print(f"Received message on topic '{msg.topic}': {msg.payload.decode()}")
    # Example: data = json.loads(msg.payload.decode())

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
client.username_pw_set(username=mqtt_username, password=access_token)
client.tls_set(cert_reqs=ssl.CERT_REQUIRED, tls_version=ssl.PROTOCOL_TLS_CLIENT)

client.on_connect = on_connect
client.on_message = on_message

try:
    client.connect(mqtt_broker, mqtt_port, 60)
    client.loop_forever() # Starts a blocking network loop
except Exception as e:
    print(f"Connection error: {e}")

JavaScript (Websockets using `mqtt` library)

This example uses the popular mqtt library (MQTT.js), which works in both Node.js and browsers.

// In Node.js: npm install mqtt
// In Browser: <script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>

// Assume 'accessToken' is a variable holding your obtained token
const accessToken = "YOUR_ACCESS_TOKEN";
const websocketUrl = "wss://mqtt.openf1.org:8084/mqtt";

const options = {
    username: "your_username_or_email@example.com", // Optional, can be any string
    password: accessToken // Access token is used as the password
};

const client = mqtt.connect(websocketUrl, options);

client.on('connect', function () {
    console.log('Connected to OpenF1 via Websockets');
    client.subscribe('v1/location', function (err) {
        if (!err) {
            console.log('Subscribed to v1/location');
        } else {
            console.error('Subscription error for v1/location:', err);
        }
    });
    client.subscribe('v1/laps', function (err) {
        if (!err) {
            console.log('Subscribed to v1/laps');
        } else {
            console.error('Subscription error for v1/laps:', err);
        }
    });
    // client.subscribe('#'); // Subscribe to all topics
});

client.on('message', function (topic, message) {
    console.log(`Received on ${topic}: ${message.toString()}`);
    // const data = JSON.parse(message.toString());
    // Process data
});

client.on('error', function (error) {
    console.error('MQTT Connection Error:', error);
});

client.on('close', function () {
    console.log('MQTT Connection closed');
});

client.on('offline', function() {
    console.log('MQTT Client is offline');
});

client.on('reconnect', function() {
    console.log('MQTT Client is attempting to reconnect');
});

Choosing the right tool: REST vs. MQTT vs. Websockets

Understanding when to use each method will help you build more efficient and responsive applications.

Please prioritize MQTT or Websockets for any application needing live F1 data. They are significantly more efficient and provide data as soon as it's available.

Security best practices

The most important security consideration is the handling of your API credentials (username and password used to obtain the OAuth2 token) and the access token itself.

Backend authentication

The process of obtaining the OAuth2 access token (exchanging your username and password) MUST be implemented in your backend application code. Never embed your direct username and password into client-side applications (like JavaScript running in a user's browser or in a desktop application that can be easily decompiled).

Token storage

Backend

If your backend needs to make authenticated calls, store the access token securely.

Client-Side

If your architecture involves your backend providing a token to a client application (e.g., a single-page web app) for direct OpenF1 API calls:

Token exposure

Do not embed access tokens directly into your client-side source code if it's publicly accessible. For client applications, the ideal pattern is for your application to communicate with *your* backend, and your backend then makes authenticated requests to the OpenF1 API.