# ballCoordinates

### What does the include do?

The `ballCoordinates` include allows users to track ball location on the pitch in real-time, essential for strategic analysis and fan engagement. Previously accessible via the `metadata` include, the standalone `ballCoordinates` include now provides faster, targeted access to ball-tracking data.

### Why use ball coordinates?

This feature benefits:

* **Betting insights**: Helps assess whether a team is likely to score or gain a corner based on ball position.
* **Offensive analysis**: Quickly indicates which team is in an attacking position.
* **Tactical analysis**: Track possession zones, attacking patterns, and defensive positioning.
* **Fan engagement**: Build interactive heat maps and ball movement visualizations.
* **Performance analytics**: Analyse ball circulation, territory control, and attacking efficiency.

For deeper analysis, combine `ballCoordinates` with the [Pressure Index](https://claude.ai/football/tutorials-and-guides/tutorials/includes/pressure-index) to understand offensive and defensive pressures in real-time.

### Requesting ball coordinates

To retrieve ball coordinates, use the following include in a fixture request:

```http
https://api.sportmonks.com/v3/football/fixtures/{ID}?api_token=YOUR_TOKEN&include=ballCoordinates
```

**Example:** Track ball movements in a past fixture, such as the Champions League 2025 round 5 (ID: 19568502)

```http
https://api.sportmonks.com/v3/football/fixtures/19568502
?api_token=YOUR_TOKEN&include=ballCoordinates
```

### Response Structure

When you include `ballCoordinates` in your request, you'll receive an array of ball coordinate objects within your fixture response:

```json
{
  "data": {
    "id": 19568502,
    "sport_id": 1,
    "league_id": 2,
    "season_id": 25580,
    "stage_id": 77478049,
    "group_id": null,
    "aggregate_id": null,
    "round_id": 388953,
    "state_id": 5,
    "venue_id": 321614,
    "name": "Chelsea vs FC Barcelona",
    "starting_at": "2025-11-25 20:00:00",
    "result_info": "Chelsea won after full-time.",
    "leg": "1/1",
    "details": null,
    "length": 90,
    "placeholder": false,
    "has_odds": true,
    "has_premium_odds": true,
    "starting_at_timestamp": 1764100800,
    "ballcoordinates": [
      {
        "id": 258909457,
        "fixture_id": 19568502,
        "period_id": 6379940,
        "timer": "93:32",
        "x": "0.91",
        "y": "0.49"
      },
      {
        "id": 258909452,
        "fixture_id": 19568502,
        "period_id": 6379940,
        "timer": "92:49",
        "x": "0.32",
        "y": "0.5"
      },
      {
        "id": 258909446,
        "fixture_id": 19568502,
        "period_id": 6379940,
        "timer": "92:43",
        "x": "0.32",
        "y": "0.5"
      },
      {
        "id": 258909440,
        "fixture_id": 19568502,
        "period_id": 6379940,
        "timer": "92:39",
        "x": "0.32",
        "y": "0.5"
      },
      {
        "id": 258909435,
        "fixture_id": 19568502,
        "period_id": 6379940,
        "timer": "92:33",
        "x": "0.32",
        "y": "0.5"
      },
      {
        "id": 258909427,
        "fixture_id": 19568502,
        "period_id": 6379940,
        "timer": "92:29",
        "x": "0.52",
        "y": "0.65"
      },
      {
        "id": 258909424,
        "fixture_id": 19568502,
        "period_id": 6379940,
        "timer": "92:23",
        "x": "0.52",
        "y": "0.65"
      },
      {
        "id": 258909414,
        "fixture_id": 19568502,
        "period_id": 6379940,
        "timer": "92:19",
        "x": "0.29",
        "y": "0.5"
      },
      {
        "id": 258909405,
        "fixture_id": 19568502,
        "period_id": 6379940,
        "timer": "92:14",
        "x": "0.29",
        "y": "0.5"
      },
      {
        "id": 258909397,
        "fixture_id": 19568502,
        "period_id": 6379940,
        "timer": "92:09",
        "x": "0.35",
        "y": "0.46"
      }
    ]
  }
}
```

### Field descriptions

| Field        | Type    | Description                                                                 |
| ------------ | ------- | --------------------------------------------------------------------------- |
| `id`         | integer | Unique identifier for this ball coordinate entry                            |
| `fixture_id` | integer | ID of the fixture this coordinate belongs to                                |
| `period_id`  | integer | ID of the period (half) when this position was recorded                     |
| `timer`      | string  | Match time in MM:SS format when the ball position was captured              |
| `x`          | string  | Normalized X-coordinate representing the length of the field (0.01 to 1.01) |
| `y`          | string  | Normalized Y-coordinate representing the width of the field (-0.02 to 1.02) |

### Interpreting X and Y Values

#### Coordinate system

* **X-axis (length of the field)**: Range from `0.01` to `1.01`
  * `0.01` = One goal line (attacking team's perspective)
  * `0.51` = Center of the field
  * `1.01` = Opposite goal line
* **Y-axis (width of the field)**: Range from `-0.02` to `1.02`
  * `-0.02` to `0.00` = Slightly outside left sideline
  * `0.00` = Left sideline
  * `0.51` = Center of the field (width)
  * `1.02` = Right sideline
  * `1.02` to `1.04` = Slightly outside right sideline

#### Data frequency

Ball tracking provides an average of **568 data entries per match**, which means you'll know where the ball is located approximately **6.3 times per minute**. High-action matches can have over 1,000 entries, providing up to **12 data points per minute**.

#### Data delay

Ball tracking has a slight delay of **\~15 seconds** but remains faster than live television data, making it suitable for near-real-time applications.

### Building a field display

To build a field display based on the `x` and `y` values provided by the Sportmonks ballCoordinates data, you'll map the values to a coordinate system representing the pitch.

#### Define the field dimensions

The normalized `x` values range from `0.01` to `1.01`, representing the length of the field (goal line to goal line).

The `y` values range from `-0.02` to `1.02`, covering the width (sideline to sideline).

#### Map coordinates

Scale each `x` and `y` value to your field dimensions in pixels or meters.

For example, if the field is displayed as 1000 pixels wide, `x = 0.51` would place the ball at 50% of the field length (500 pixels from one goal).

#### Set boundaries

Use the provided ranges to map boundaries and draw sideline and goal areas at `y = -0.02` to `1.02` and `x = 0.01` to `1.01`.

### Code examples

#### Python Example

```python
import requests

# API configuration
API_TOKEN = "YOUR_TOKEN"
FIXTURE_ID = 19568502

# Request ball coordinates
url = f"https://api.sportmonks.com/v3/football/fixtures/{FIXTURE_ID}"
params = {
    "api_token": API_TOKEN,
    "include": "ballCoordinates"
}

response = requests.get(url, params=params)
data = response.json()

# Extract ball coordinates
ball_coords = data['data'].get('ballcoordinates', [])

print(f"Total ball coordinate entries: {len(ball_coords)}")

# Process ball coordinates
for coord in ball_coords[:5]:  # Show first 5 entries
    x = float(coord['x'])
    y = float(coord['y'])
    timer = coord['timer']
    
    # Convert to field position description
    if x < 0.33:
        zone = "Defensive third"
    elif x < 0.67:
        zone = "Middle third"
    else:
        zone = "Attacking third"
    
    print(f"Time: {timer} - Position: ({x:.2f}, {y:.2f}) - Zone: {zone}")

# Calculate ball possession by zones
def calculate_zone_time(coordinates):
    """Calculate time spent in each third of the field"""
    zones = {"defensive": 0, "middle": 0, "attacking": 0}
    
    for coord in coordinates:
        x = float(coord['x'])
        if x < 0.33:
            zones["defensive"] += 1
        elif x < 0.67:
            zones["middle"] += 1
        else:
            zones["attacking"] += 1
    
    total = sum(zones.values())
    percentages = {k: (v / total * 100) for k, v in zones.items()}
    
    return percentages

zone_percentages = calculate_zone_time(ball_coords)
print(f"\nZone Distribution:")
print(f"Defensive third: {zone_percentages['defensive']:.1f}%")
print(f"Middle third: {zone_percentages['middle']:.1f}%")
print(f"Attacking third: {zone_percentages['attacking']:.1f}%")
```

#### JavaScript example

```javascript
// API configuration
const API_TOKEN = "YOUR_TOKEN";
const FIXTURE_ID = 19568502;

// Request ball coordinates
async function getBallCoordinates() {
    const url = `https://api.sportmonks.com/v3/football/fixtures/${FIXTURE_ID}`;
    const params = new URLSearchParams({
        api_token: API_TOKEN,
        include: "ballCoordinates"
    });

    try {
        const response = await fetch(`${url}?${params}`);
        const data = await response.json();
        
        const ballCoords = data.data.ballcoordinates || [];
        console.log(`Total ball coordinate entries: ${ballCoords.length}`);
        
        // Process ball coordinates
        ballCoords.slice(0, 5).forEach(coord => {
            const x = parseFloat(coord.x);
            const y = parseFloat(coord.y);
            const timer = coord.timer;
            
            // Convert to field position description
            let zone;
            if (x < 0.33) {
                zone = "Defensive third";
            } else if (x < 0.67) {
                zone = "Middle third";
            } else {
                zone = "Attacking third";
            }
            
            console.log(`Time: ${timer} - Position: (${x.toFixed(2)}, ${y.toFixed(2)}) - Zone: ${zone}`);
        });
        
        // Calculate zone distribution
        const zoneDistribution = calculateZoneDistribution(ballCoords);
        console.log("\nZone Distribution:");
        console.log(`Defensive third: ${zoneDistribution.defensive.toFixed(1)}%`);
        console.log(`Middle third: ${zoneDistribution.middle.toFixed(1)}%`);
        console.log(`Attacking third: ${zoneDistribution.attacking.toFixed(1)}%`);
        
    } catch (error) {
        console.error("Error fetching ball coordinates:", error);
    }
}

function calculateZoneDistribution(coordinates) {
    const zones = { defensive: 0, middle: 0, attacking: 0 };
    
    coordinates.forEach(coord => {
        const x = parseFloat(coord.x);
        if (x < 0.33) {
            zones.defensive++;
        } else if (x < 0.67) {
            zones.middle++;
        } else {
            zones.attacking++;
        }
    });
    
    const total = Object.values(zones).reduce((a, b) => a + b, 0);
    
    return {
        defensive: (zones.defensive / total) * 100,
        middle: (zones.middle / total) * 100,
        attacking: (zones.attacking / total) * 100
    };
}

// Example: Visualize on a canvas
function drawBallMovement(coordinates, canvasId) {
    const canvas = document.getElementById(canvasId);
    const ctx = canvas.getContext('2d');
    
    // Define field dimensions (in pixels)
    const fieldWidth = 1000;
    const fieldHeight = 680;
    
    // Draw field background
    ctx.fillStyle = '#228B22';
    ctx.fillRect(0, 0, fieldWidth, fieldHeight);
    
    // Draw field lines
    ctx.strokeStyle = '#FFFFFF';
    ctx.lineWidth = 2;
    ctx.strokeRect(0, 0, fieldWidth, fieldHeight); // Outer boundary
    ctx.beginPath();
    ctx.moveTo(fieldWidth / 2, 0);
    ctx.lineTo(fieldWidth / 2, fieldHeight); // Center line
    ctx.stroke();
    
    // Draw ball positions
    coordinates.forEach((coord, index) => {
        const x = parseFloat(coord.x) * fieldWidth;
        const y = parseFloat(coord.y) * fieldHeight;
        
        // Fade older positions
        const opacity = Math.max(0.1, index / coordinates.length);
        ctx.fillStyle = `rgba(255, 0, 0, ${opacity})`;
        ctx.beginPath();
        ctx.arc(x, y, 3, 0, 2 * Math.PI);
        ctx.fill();
    });
}

// Run the example
getBallCoordinates();
```

### Data availability

Ball coordinates are available for select leagues and fixtures. The data is typically available for:

* **Top-tier European leagues**: Premier League, La Liga, Serie A, Bundesliga, Ligue 1
* **Major cup competitions**: UEFA Champions League, UEFA Europa League
* **International tournaments**: World Cup, European Championship

Not all fixtures have ball coordinate data available. The availability depends on the stadium's tracking technology and data partnerships.

### Use cases

#### 1. **Heat maps**

Create visual heat maps showing where the ball spent most time during a match. Useful for tactical analysis and identifying attacking patterns.

#### 2. **Territory control**

Calculate which team controlled which areas of the pitch by analyzing ball position data combined with possession information.

#### 3. **Attacking patterns**

Identify common attacking routes and build-up play patterns by analyzing ball movement in the attacking third.

#### 4. **Defensive analysis**

Track how teams defend by analyzing ball positions when the opposition has possession.

#### 5. **Live betting insights**

For live betting applications, ball position combined with match state provides valuable insights into scoring probability.

### Nested includes

The `ballCoordinates` include currently does not support nested includes. Each ball coordinate entry contains only the fields described above.

### Related includes

* [**Pressure Index**](https://docs.sportmonks.com/football/tutorials-and-guides/tutorials/includes/pressure-index) - Combine with ball coordinates for comprehensive tactical analysis
* [**Events**](https://docs.sportmonks.com/football/tutorials-and-guides/tutorials/includes/events) - Cross-reference ball positions with match events (goals, shots, corners)
* [**Statistics**](https://docs.sportmonks.com/football/definitions/types/statistics) - Correlate ball position data with match statistics

### Best practices

1. **Cache the data**: Ball coordinate data doesn't change after a match ends. Cache completed matches to reduce API calls.
2. **Filter by time period**: For specific analysis, filter ball coordinates by `timer` to focus on particular match phases.
3. **Normalize your display**: Always normalize your field display dimensions to match the 0.01-1.01 (x) and -0.02-1.02 (y) coordinate system.
4. **Handle missing data**: Not all fixtures have ball coordinate data. Always check if the `ballcoordinates` array exists and has data.
5. **Combine with other includes**: Use `&include=ballCoordinates,events,statistics` to get comprehensive match analysis data in one request.

### Common issues and solutions

#### Issue: No ball coordinate data returned

**Solution**: Ball coordinates are only available for fixtures with advanced tracking technology. Check if the league/fixture supports this feature.

#### Issue: Coordinates seem inverted

**Solution**: Remember that the coordinate system is normalized. Always map to your display system correctly: x represents length (0.01 = one goal, 1.01 = other goal).

#### Issue: Too much data to process

**Solution**: Use filters to get specific time ranges, or sample the data (e.g., every 10th entry) for visualization purposes.

### Summary

The `ballCoordinates` include provides powerful ball tracking data for tactical analysis, visualization, and betting insights. With normalised coordinates and frequent updates (6-12 times per minute), it enables detailed analysis of ball movement, territory control, and attacking patterns. Combine with other includes like Pressure Index and Events for comprehensive match analysis.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.sportmonks.com/v3/tutorials-and-guides/tutorials/includes/ballcoordinates.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
