Live now!

Progress of current post

How-to build a match page with the Sportmonks Football API

Welcome to our how-to build a match page guide. Here you will learn about creating a match page that is filled with events, statistics and lineups. This is a follow-up on the how-to build your Livescore website guide. The Livescore page only shows the live score of the match and sometimes the bigger events such as goals, substitutions, and cards.

For basic knowledge about livescores, includes, and nested includes please see our tutorials.

Published 14 February 2024
Last updated 10 December 2024
Jordy Post
How-to build a match page with the Sportmonks Football API
Contents

Step 1: Gather the tools

You are going to need the following tools:

  • Sportmonks API token
  • Code editor (Visual studio used in examples)
  • Postman or your browser

You can find a link to another article where we discuss the tools in-depth on our Developer Tools Guide.

Step 2: Decide which events and statistics you want to show

At Sportmonks we offer the following events:

  • Goal (as well as own goal, penalty)
  • Cards (Yellow card, Red card, Yellow/Red card)
  • Substitutions
  • VAR (Goal disallowed, Goal under review, VAR Card)
  • Penalty and Missed Penalty
  • Penalty Shootout Missed/Goal
  • Shots (Shot On/Shots off target)
  • Offside
  • Corner

For match statistics, think about anything that can happen during a match, such as: The number of shots, passes, attacks, fouls, corners, offsides, yellow/red cards, saves, substitutions, goal attempts, penalties, injuries, and many more.

Player statistics are all the relevant statistics regarding a player, such as the number of goals scored, how many fouls he made, the number of cards received, passes, tackles, shots etc.

Step 3: Choose the correct endpoint/include

The standard events include, consists of all the events mentioned above.

Player and match statistics and events do not have endpoints, but instead can be evoked with includes.

  • Match statistics use the include statistics.type
  • Player statistics use the include lineups.details.type
  • Events use events.type

Since this is about a single match page with various events and stats, we will need the specific fixture ID. That’s why we’ll work with the fixtures by id endpoint.
It’s also possible to include both stats and lineups includes in the same request, but expect a lengthy response in that case.

i Another nice feature to add is comparing the two teams’ past results against each other. This is often used to see how one team performs against another. This endpoint is called GET Fixture by Head To Head.

{
  {
  "data": {
    "id": 18842501,
    "sport_id": 1,
    "league_id": 8,
    "season_id": 21646,
    "stage_id": 77464011,
    "group_id": null,
    "aggregate_id": null,
    "round_id": 307164,
    "state_id": 5,
    "venue_id": 204,
    "name": "Arsenal vs Liverpool",
    "starting_at": "2024-02-04 16:30:00",
    "result_info": "Arsenal won after full-time.",
    "leg": "1/1",
    "details": null,
    "length": 90,
    "placeholder": false,
    "has_odds": true,
    "starting_at_timestamp": 1707064200,
    "statistics": [
      {
        "id": 26446729,
        "fixture_id": 18842501,
        "type_id": 65,
        "participant_id": 19,
        "data": {
          "value": 18
        },
        "location": "home",
        "type": {
          "id": 65,
          "name": "Successful Headers",
          "code": "successful-headers",
          "developer_name": "SUCCESSFUL_HEADERS",
          "model_type": "statistic",
          "stat_group": "overall"
        }
      },
      {
        "id": 26446693,
        "fixture_id": 18842501,
        "type_id": 59,
        "participant_id": 19,
        "data": {
          "value": 3
        },
        "location": "home",
        "type": {
          "id": 59,
          "name": "Substitutions",
          "code": "substitutions",
          "developer_name": "SUBSTITUTIONS",
          "model_type": "statistic",
          "stat_group": "overall"
        }
      },
      {
        "id": 26446695,
        "fixture_id": 18842501,
        "type_id": 55,
        "participant_id": 19,
        "data": {
          "value": 12
        },
        "location": "home",
        "type": {
          "id": 55,
          "name": "Free Kicks",
          "code": "free-kicks",
          "developer_name": "FREE_KICKS",
          "model_type": "statistic",
          "stat_group": "defensive"
        }
      },
      {
        "id": 26446711,
        "fixture_id": 18842501,
        "type_id": 52,
        "participant_id": 8,
        "data": {
          "value": 1
        },
        "location": "away",
        "type": {
          "id": 52,
          "name": "Goals",
          "code": "goals",
          "developer_name": "GOALS",
          "model_type": "statistic",
          "stat_group": "offensive"
        }
      },
      {
        "id": 26446297,
        "fixture_id": 18842501,
        "type_id": 42,
        "participant_id": 19,
        "data": {
          "value": 15
        },
        "location": "home",
        "type": {
          "id": 42,
          "name": "Shots Total",
          "code": "shots-total",
          "developer_name": "SHOTS_TOTAL",
          "model_type": "statistic",
          "stat_group": "offensive"
        }

Step 4: Example basic requests

Next up is creating the request. For that you will need the base URL of our API for a request regarding Football which is: https://api.sportmonks.com/v3/football/

Then we need to specify the endpoint we would like to receive.

https://api.sportmonks.com/v3/football/fixtures/{ID}

If you add your API token by adding ?api_token=YOUR_TOKEN to your request, you are ready to send your request!

We will use the match between Arsenal and Liverpool at February 4th, 2024. So, this is how our request looks now:

https://api.sportmonks.com/v3/football/fixtures/18842501?api_token=YOUR_TOKEN

After that we need to add the includes mentioned above. You can do that by adding &include=statistics.type;lineups.details to your request. This is how your request should look now:

https://api.sportmonks.com/v3/football/fixtures/18842501?api_token=YOUR_TOKEN&include=statistics.type;lineups.details

At the right side, you can see part of the example response.

Step 5: Evaluate the response

Lineups

First, we want to know what formation both teams used. Luckily, this information is included in the metadata include you can use on our fixtures/livescores endpoints.
Before we fill in the formation, let us first explain formation positions. Players have different formation_positions. So for example, one player has the player’s formation_position: 1, another has formation_position: 2, etc. Our API slots formations from right to left, meaning that the visitorteam_formation will look like the one down below.

How to display formations

You can use the formation numbers in combination with the lineup formation to display formations. The formation number is by order of the lineup formation.

So, for example, formation 4-3-3:
Formation number 1: Keeper
Formation number 2: Right back
Formation number 3: Central defender
Formation number 4: Central defender
Formation number 5: Left back
Formation number 6: Central midfielder
Formation number 7: Central midfielder
Formation number 8: Central midfielder
Formation number 9: Right winger
Formation number 10: Striker
Formation number 11: Left winger

You can add the players to the grid according to their player formation. So, if you look at the example on the right-hand side you will see:

Alisson 1
Alexander-Arnold 2
Ibrahim Konaté 3
Virgil van Dijk 4
Joe Gomez 5
And so on.

{ {
        "id": 6562912139,
        "sport_id": 1,
        "fixture_id": 18842501,
        "player_id": 30062,
        "team_id": 8,
        "position_id": 27,
        "formation_field": "4:1",
        "type_id": 11,
        "formation_position": 9,
        "player_name": "Cody Gakpo",
        "jersey_number": 18,
        "details": [
          {
            "id": 525349118,
            "fixture_id": 18842501,
            "player_id": 30062,
            "team_id": 8,
            "lineup_id": 6562912139,
            "type_id": 119,
            "data": {
              "value": 58
            },
            "type": {
              "id": 119,
              "name": "Minutes Played",
              "code": "minutes-played",
              "developer_name": "MINUTES_PLAYED",
              "model_type": "statistic",
              "stat_group": "NULL"
            }
          },
          {
            "id": 525364733,
            "fixture_id": 18842501,
            "player_id": 30062,
            "team_id": 8,
            "lineup_id": 6562912139,
            "type_id": 94,
            "data": {
              "value": 3
            },
            "type": {
              "id": 94,
              "name": "Dispossessed",
              "code": "dispossessed",
              "developer_name": "DISPOSSESSED",
              "model_type": "statistic",
              "stat_group": "offensive"
            }
          },
          {
            "id": 525356601,
            "fixture_id": 18842501,
            "player_id": 30062,
            "team_id": 8,
            "lineup_id": 6562912139,
            "type_id": 118,
            "data": {
              "value": 6.73
            },
            "type": {
              "id": 118,
              "name": "Rating",
              "code": "rating",
              "developer_name": "RATING",
              "model_type": "statistic",
              "stat_group": "overall"
            }
          },
          {
            "id": 525361238,
            "fixture_id": 18842501,
            "player_id": 30062,
            "team_id": 8,
            "lineup_id": 6562912139,
            "type_id": 42,
            "data": {
              "value": 1
            },
            "type": {
              "id": 42,
              "name": "Shots Total",
              "code": "shots-total",
              "developer_name": "SHOTS_TOTAL",
              "model_type": "statistic",
              "stat_group": "offensive"
            }
          },
          {
            "id": 525357631,
            "fixture_id": 18842501,
            "player_id": 30062,
            "team_id": 8,
            "lineup_id": 6562912139,
            "type_id": 100,
            "data": {
              "value": 1
            },
            "type": {
              "id": 100,
              "name": "Interceptions",
              "code": "interceptions",
              "developer_name": "INTERCEPTIONS",
              "model_type": "statistic",
              "stat_group": "defensive"
            }
          },
          {
            "id": 525362749,
            "fixture_id": 18842501,
            "player_id": 30062,
            "team_id": 8,
            "lineup_id": 6562912139,
            "type_id": 41,
            "data": {
              "value": 1
            },
            "type": {
              "id": 41,
              "name": "Shots Off Target",
              "code": "shots-off-target",
              "developer_name": "SHOTS_OFF_TARGET",
              "model_type": "statistic",
              "stat_group": "offensive"
            }
          },
          {
            "id": 525360203,
            "fixture_id": 18842501,
            "player_id": 30062,
            "team_id": 8,
            "lineup_id": 6562912139,
            "type_id": 1584,
            "data": {
              "value": 55
            },
            "type": {
              "id": 1584,
              "name": "Accurate Passes Percentage",
              "code": "accurate-passes-percentage",
              "developer_name": "ACCURATE_PASSES_PERCENTAGE",
              "model_type": "statistic",
              "stat_group": "offensive"
            }
          },
          {
            "id": 525356613,
            "fixture_id": 18842501,
            "player_id": 30062,
            "team_id": 8,
            "lineup_id": 6562912139,
            "type_id": 105,
            "data": {
              "value": 9
            },
            "type": {
              "id": 105,
              "name": "Total Duels",
              "code": "total-duels",
              "developer_name": "TOTAL_DUELS",
              "model_type": "statistic",
              "stat_group": "offensive"
            }
          },
          {
            "id": 525356625,
            "fixture_id": 18842501,
            "player_id": 30062,
            "team_id": 8,
            "lineup_id": 6562912139,
            "type_id": 96,
            "data": {
              "value": 2
            },
            "type": {
              "id": 96,
              "name": "Fouls Drawn",
              "code": "fouls-drawn",
              "developer_name": "FOULS_DRAWN",
              "model_type": "statistic",
              "stat_group": "overall"
            }
          },
          {
            "id": 525356626,
            "fixture_id": 18842501,
            "player_id": 30062,
            "team_id": 8,
            "lineup_id": 6562912139,
            "type_id": 106,
            "data": {
              "value": 4
            },
            "type": {
              "id": 106,
              "name": "Duels Won",
              "code": "duels-won",
              "developer_name": "DUELS_WON",
              "model_type": "statistic",
              "stat_group": "offensive"
            }
          },
          {
            "id": 525362741,
            "fixture_id": 18842501,
            "player_id": 30062,
            "team_id": 8,
            "lineup_id": 6562912139,
            "type_id": 1491,
            "data": {
              "value": 5
            },
            "type": {
              "id": 1491,
              "name": "Duels Lost",
              "code": "duels-lost",
              "developer_name": "DUELS_LOST",
              "model_type": "statistic",
              "stat_group": "offensive"
            }
          },
          {
            "id": 525360202,
            "fixture_id": 18842501,
            "player_id": 30062,
            "team_id": 8,
            "lineup_id": 6562912139,
            "type_id": 80,
            "data": {
              "value": 11
            },
            "type": {
              "id": 80,
              "name": "Passes",
              "code": "passes",
              "developer_name": "PASSES",
              "model_type": "statistic",
              "stat_group": "overall"
            }
          },
          {
            "id": 525360195,
            "fixture_id": 18842501,
            "player_id": 30062,
            "team_id": 8,
            "lineup_id": 6562912139,
            "type_id": 116,
            "data": {
              "value": 6
            },
            "type": {
              "id": 116,
              "name": "Accurate Passes",
              "code": "accurate-passes",
              "developer_name": "ACCURATE_PASSES",
              "model_type": "statistic",
              "stat_group": "overall"
            }
          },
          {
            "id": 525379411,
            "fixture_id": 18842501,
            "player_id": 30062,
            "team_id": 8,
            "lineup_id": 6562912139,
            "type_id": 78,
            "data": {
              "value": 1
            },
            "type": {
              "id": 78,
              "name": "Tackles",
              "code": "tackles",
              "developer_name": "TACKLES",
              "model_type": "statistic",
              "stat_group": "defensive"
            }
          },
          {
            "id": 525386409,
            "fixture_id": 18842501,
            "player_id": 30062,
            "team_id": 8,
            "lineup_id": 6562912139,
            "type_id": 107,
            "data": {
              "value": 1
            },
            "type": {
              "id": 107,
              "name": "Aerials Won",
              "code": "aeriels-won",
              "developer_name": "AERIALS_WON",
              "model_type": "statistic",
              "stat_group": "overall"
            }
          },
          {
            "id": 525362021,
            "fixture_id": 18842501,
            "player_id": 30062,
            "team_id": 8,
            "lineup_id": 6562912139,
            "type_id": 88,
            "data": {
              "value": 1
            },
            "type": {
              "id": 88,
              "name": "Goals Conceded",
              "code": "goals-conceded",
              "developer_name": "GOALS_CONCEDED",
              "model_type": "statistic",
              "stat_group": "defensive"
            }
          }
        ]
      },

Player statistics

Here, we can see the detailed player statistics of the player named Cody Gakpo. Apart from standard player information, such as which team he belongs to and what his player ID or position is, we can see the total number of shots, goals, fouls, cards, passing, dribbles and duels. There’s also an ‘other’ tab with even more information, but we won’t go into detail for that one. Keep in mind this is only part of the response.

Let’s add one more part for detailed player statistics: ;lineups.details.type.

The API Request is as follows:
https://api.sportmonks.com/v3/football/fixtures/18842501?api_token=YOUR_TOKEN&include=statistics.type;lineups.details.type

Team statistics

As its name suggests, we can see the team statistics of the two teams. We can see the number of shots, passes, attacks, and plenty of other data of both teams. Keep in mind, this is only a part of the response.

{
 "statistics": [
      {
        "id": 26446729,
        "fixture_id": 18842501,
        "type_id": 65,
        "participant_id": 19,
        "data": {
          "value": 18
        },
        "location": "home",
        "type": {
          "id": 65,
          "name": "Successful Headers",
          "code": "successful-headers",
          "developer_name": "SUCCESSFUL_HEADERS",
          "model_type": "statistic",
          "stat_group": "overall"
        }
      },
      {
        "id": 26446693,
        "fixture_id": 18842501,
        "type_id": 59,
        "participant_id": 19,
        "data": {
          "value": 3
        },
        "location": "home",
        "type": {
          "id": 59,
          "name": "Substitutions",
          "code": "substitutions",
          "developer_name": "SUBSTITUTIONS",
          "model_type": "statistic",
          "stat_group": "overall"
        }
      },
      {
        "id": 26446695,
        "fixture_id": 18842501,
        "type_id": 55,
        "participant_id": 19,
        "data": {
          "value": 12
        },
        "location": "home",
        "type": {
          "id": 55,
          "name": "Free Kicks",
          "code": "free-kicks",
          "developer_name": "FREE_KICKS",
          "model_type": "statistic",
          "stat_group": "defensive"
        }
      },
      {
        "id": 26446711,
        "fixture_id": 18842501,
        "type_id": 52,
        "participant_id": 8,
        "data": {
          "value": 1
        },
        "location": "away",
        "type": {
          "id": 52,
          "name": "Goals",
          "code": "goals",
          "developer_name": "GOALS",
          "model_type": "statistic",
          "stat_group": "offensive"
        }
      },
      {
        "id": 26446297,
        "fixture_id": 18842501,
        "type_id": 42,
        "participant_id": 19,
        "data": {
          "value": 15
        },
        "location": "home",
        "type": {
          "id": 42,
          "name": "Shots Total",
          "code": "shots-total",
          "developer_name": "SHOTS_TOTAL",
          "model_type": "statistic",
          "stat_group": "offensive"
        }
      },
      {
        "id": 26446690,
        "fixture_id": 18842501,
        "type_id": 47,
        "participant_id": 19,
        "data": {
          "value": 0
        },
        "location": "home",
        "type": {
          "id": 47,
          "name": "Penalties",
          "code": "penalties",
          "developer_name": "PENALTIES",
          "model_type": "statistic",
          "stat_group": "offensive"
        }
      },
      {
        "id": 26446725,
        "fixture_id": 18842501,
        "type_id": 58,
        "participant_id": 8,
        "data": {
          "value": 2
        },
        "location": "away",
        "type": {
          "id": 58,
          "name": "Shots Blocked",
          "code": "shots-blocked",
          "developer_name": "SHOTS_BLOCKED",
          "model_type": "statistic",
          "stat_group": "offensive"
        }
      },
      {
        "id": 26447274,
        "fixture_id": 18842501,
        "type_id": 50,
        "participant_id": 8,
        "data": {
          "value": 4
        },
        "location": "away",
        "type": {
          "id": 50,
          "name": "Shots Outsidebox",
          "code": "shots-outsidebox",
          "developer_name": "SHOTS_OUTSIDEBOX",
          "model_type": "statistic",
          "stat_group": "offensive"
        }
      },
      {
        "id": 26446691,
        "fixture_id": 18842501,
        "type_id": 43,
        "participant_id": 19,
        "data": {
          "value": 95
        },
        "location": "home",
        "type": {
          "id": 43,
          "name": "Attacks",
          "code": "attacks",
          "developer_name": "ATTACKS",
          "model_type": "statistic",
          "stat_group": "offensive"
        }
      },
      {
        "id": 26446717,
        "fixture_id": 18842501,
        "type_id": 83,
        "participant_id": 8,
        "data": {
          "value": 1
        },
        "location": "away",
        "type": {
          "id": 83,
          "name": "Redcards",
          "code": "redcards",
          "developer_name": "REDCARDS",
          "model_type": "statistic",
          "stat_group": "overall"
        }
      },
      {
        "id": 26446731,
        "fixture_id": 18842501,
        "type_id": 56,
        "participant_id": 19,
        "data": {
          "value": 11
        },
        "location": "home",
        "type": {
          "id": 56,
          "name": "Fouls",
          "code": "fouls",
          "developer_name": "FOULS",
          "model_type": "statistic",
          "stat_group": "defensive"
        }
      },
      {
        "id": 26447026,
        "fixture_id": 18842501,
        "type_id": 1527,
        "participant_id": 8,
        "data": {
          "value": 1
        },
"events": [
      {
        "id": 95727885,
        "fixture_id": 18842501,
        "period_id": 5215213,
        "participant_id": 19,
        "type_id": 18,
        "section": "event",
        "player_id": 537759,
        "related_player_id": 16827155,
        "player_name": "Reiss Nelson",
        "related_player_name": "Bukayo Saka",
        "result": null,
        "info": null,
        "addition": null,
        "minute": 79,
        "extra_minute": null,
        "injured": true,
        "on_bench": false,
        "coach_id": null,
        "sub_type_id": 1524,
        "type": {
          "id": 18,
          "name": "Substitution",
          "code": "substitution",
          "developer_name": "SUBSTITUTION",
          "model_type": "event",
          "stat_group": null
        }
      },
      {
        "id": 95727479,
        "fixture_id": 18842501,
        "period_id": 5215213,
        "participant_id": 19,
        "type_id": 14,
        "section": "event",
        "player_id": 10959356,
        "related_player_id": null,
        "player_name": "Gabriel Martinelli",
        "related_player_name": null,
        "result": "2-1",
        "info": "Shot",
        "addition": "3rd Goal",
        "minute": 67,
        "extra_minute": null,
        "injured": null,
        "on_bench": false,
        "coach_id": null,
        "sub_type_id": null,
        "type": {
          "id": 14,
          "name": "Goal",
          "code": "goal",
          "developer_name": "GOAL",
          "model_type": "event",
          "stat_group": null
        }
      },
      {
        "id": 95728028,
        "fixture_id": 18842501,
        "period_id": 5215213,
        "participant_id": 8,
        "type_id": 18,
        "section": "event",
        "player_id": 31857,
        "related_player_id": 1453,
        "player_name": "Thiago Alcântara",
        "related_player_name": "Joe Gomez",
        "result": null,
        "info": null,
        "addition": null,
        "minute": 85,
        "extra_minute": null,
        "injured": false,
        "on_bench": false,
        "coach_id": null,
        "sub_type_id": null,
        "type": {
          "id": 18,
          "name": "Substitution",
          "code": "substitution",
          "developer_name": "SUBSTITUTION",
          "model_type": "event",
          "stat_group": null
}
      },
      {
        "id": 95727583,
        "fixture_id": 18842501,
        "period_id": 5215213,
        "participant_id": 19,
        "type_id": 19,
        "section": "event",
        "player_id": 8403613,
        "related_player_id": null,
        "player_name": "Jakub Kiwior",
        "related_player_name": null,
        "result": null,
        "info": "Foul",
        "addition": null,
        "minute": 69,
        "extra_minute": null,
        "injured": null,
        "on_bench": false,
        "coach_id": null,
        "sub_type_id": 1496,
        "type": {
          "id": 19,
          "name": "Yellowcard",
          "code": "yellowcard",
          "developer_name": "YELLOWCARD",
          "model_type": "event",
          "stat_group": null
        }
      },

Match Events

You also want to show events on all matchpages. Just add ;events.type to see every event in the match.

Events show goals, cards, and substitutions and at which exact minute this happened. So, we can see that there was a substitute in the 79th minute. Reiss Nelson came into the team, and Bukayo Saka left the pitch. Gabriel Martinelli scored the third goal of the match, resulting in a 2-1 lead for Arsenal in the 67th minute. He didn’t need an assist, as you can see by the related player name field being ‘null’. Last but not least, you can see Jakub Kiwior got a yellow card in the 69th minute.

https://api.sportmonks.com/v3/football/fixtures/18842501?api_token=YOUR_TOKEN&include=statistics.type;lineups.details.type;
events.type

Written by Jordy Post

Jordy Post is a seasoned football data and marketing expert with over 3 years of industry experience. With an in-depth understanding of Football Data, he stands out as a leading authority in delivering comprehensive insights. Jordy specializes in uncovering new stats, tracking market trends, and identifying emerging patterns, consistently providing innovative analyses that offer invaluable insights to Sports Data lovers.

Ready to create your own match page?

Inspired and ready to create your own match page? Or do you have other questions? Don’t hesitate to contact us. We are here to help you create the best application around.

Let’s ride!

Contact Sportmonks