Open-source project
PySport/kloppy avatar
PySport/kloppy

kloppy gives every soccer data provider one event and tracking model to read

kloppy: standardizing soccer tracking- and event data

565 stars109 forksPythonBSD-3-Clause

At a glance

What is it?
kloppy is a Python library from PySport that standardizes soccer event and tracking data across providers with proprietary formats, covering fourteen vendors from StatsBomb to Tracab. The interesting engineering is not the loading but the shape of the result, a dataset you can filter with a regular expression, and the fact that the library can read compressed files and pull straight from the cloud.
Who is it for?
Adopt kloppy if you work with soccer data from more than one provider, because the point of the library is the vendor-independent model and the same filter syntax across all of them. Do not adopt it if you need a single provider's richest features, since the table shows several providers with partial support and joint tracking data is not yet supported for Hawkeye.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 6 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One model, fourteen providers, and a table that tells you the gaps

kloppy is described as standardizing soccer tracking and event data, and the problem statement in the README is the reason the project exists. Each data provider uses its own proprietary formats, event definitions and coordinate system to capture soccer match data, and that lack of standardization makes it difficult to build software or perform analysis across multiple providers.

The solution is a vendor-independent data model for both event and tracking data, plus data preprocessing that fits into analysis and video analysis workflows.

The provider table is the most useful page in the repository, and it is honest about its gaps. DataFactory, Impect, Metrica, PFF, SecondSpectrum, Signality, SkillCorner, Sportec, StatsBomb, Stats Perform, Opta, Tracab and Wyscout all appear, and each cell is either implemented or marked as in progress or partial support. The legend at the bottom of the table is a check mark for implemented and a different mark for in progress or partial support. Several rows carry notes, and they are the ones worth reading: Hawkeye joint tracking data is not yet supported, StatsBomb includes 360 freeze frame data support, Stats Perform includes support for MA1, MA3 and MA25 data feeds, Opta includes support for F7, F24 and F73 XML data feeds, and Wyscout includes support for v2 and v3 data.

So the library covers a wide surface, but not evenly. A provider marked with the partial mark gives you something and not everything, and which something is exactly the kind of question the per provider documentation pages exist to answer.

Loading a match is three lines, and the file location is not your problem

The loading example in the README is deliberately short, and it shows a per provider namespace inside the package:

python
from kloppy import sportec

dataset = sportec.load_open_event_data(match_id="J03WMX")

Each provider gets its own submodule, so the import tells you which format you are loading, and the function name tells you what you are getting. The match_id here is a Sportec identifier for open event data, and several providers have open sample datasets linked from the table, including Metrica, PFF, SkillCorner, StatsBomb and Wyscout, so you can run the examples without a commercial contract.

The more interesting claim is about where the data lives. Kloppy implements a standardized data model that can load event and tracking data from the most common data providers, supporting both public and proprietary data, and it does not matter where or how the data is stored. The library can handle compressed files and load data directly from the cloud.

That last point is the one that changes how you build on it. A provider whose files sit behind a signed URL, or in a bucket, does not need a bespoke loader. The dependency list explains how it works: fsspec with the http extra is a core dependency, and the s3 extra adds fsspec with s3, so a cloud path is a configuration change rather than a code change. lxml does the XML parsing for the providers that use it, sortedcontainers and python-dateutil handle ordering and time parsing, and pytz handles time zones, which matters when different providers stamp events in different time zones.

Querying is a regular expression over the event stream

The second feature section starts from the analyst's problem rather than the data format's. Video analysts spend a lot of time searching for bespoke moments, and those moments often follow recognizable patterns, like pass, pass, shot.

Kloppy provides a search mechanism based on regular expressions, and the call is a filter on the dataset:

python
goals = dataset.filter("shot.goal")

That is the whole interface. The pattern is not a Python expression evaluated against objects, it is a regular expression over the event stream, which means a query is a string you can store, put in a config file, or hand to a colleague who does not write Python.

The repository layout backs this up with a directory of examples devoted to pattern matching, alongside examples/datasets/, examples/epts/ and a playing_time.py example, so the intended usage is a workflow where the analyst writes patterns and the analyst tooling consumes them.

The dotted syntax in shot.goal is doing real work. It is a qualified event type, and a qualified path is what lets the same expression match a shot that is a goal in one provider's vocabulary and a different event in another's. That property is the practical payoff of the vendor-independent model, because a filter written once keeps working when you switch providers.

Extras decide whether you can query, tabulate or scale

The pyproject.toml keeps the core deliberately narrow. The required dependencies are lxml, sortedcontainers, pytz, python-dateutil, typing_extensions on Python below 3.11, and fsspec with the http extra. Everything else is an optional extra, and the choice of extras tells you what the library considers the common case.

There is a query extra that pulls in networkx, which is the graph library behind the pattern matching, so a query that needs relationship traversal is opt in rather than always paid for. There is an s3 extra pinning fsspec with s3 below a version, a pandas extra for pandas 2.0.3 or newer, a polars extra for polars 0.16.6 or newer, and a pyarrow extra for pyarrow 17.0.0 or newer.

The pandas and polars extras together are the interesting pairing. Both dataframe libraries are supported as extras, which tells you the dataset object is not tied to one of them, and the query extra sits alongside them so the analysis path is: load a dataset, filter it with a pattern, and hand the result to whichever dataframe library you use.

There is also a command line entry point, kloppy-query, wired to kloppy.cmdline:run_query. That matters for the video analyst audience, because a person looking for moments should not have to open a Python shell. A CLI means the filter strings can be run from a script or a workflow tool, which is exactly how these tools tend to be used in practice.

Where standardising costs you the provider's edge features

The limitation is inherent in the design rather than a missing feature, and it is worth naming before you commit.

A vendor-independent model is necessarily the intersection of what the vendors do. If StatsBomb offers 360 freeze frame data, that is a provider specific enrichment, and the standard model has to either carry a field that only one provider populates or leave it out. The table shows a few of these asymmetries, and they are the same kind of thing across the board. SecondSpectrum is marked as in progress or partial for event data with a link to a pull request, and PFF carries the same mark, so both are usable but incomplete on that column.

The Hawkeye note is the sharpest version of this. Joint tracking data, meaning the joint positions of players rather than a single point per player, is not yet supported, even though Hawkeye 2D tracking is. If joint data is what you need, this library will not get you there.

The second limitation is on the data access side. Several providers require a commercial relationship, and the repository distinguishes public from proprietary data, with public sample datasets linked for the ones that publish them. Loading a proprietary feed means you have the credentials and the contract, and kloppy handles the format but not the licensing.

The alternative to weigh is the provider's own client library. The difference in approach is that a vendor SDK gives you every field that vendor produces, including the ones the standard model has to leave out, and usually a more direct route to their documentation. Kloppy earns its place when you have to work across providers, or when you want the same analysis code to run over a public sample dataset today and a commercial feed later, which is the case the project is built for. If you will only ever read one provider, the vendor client is the shorter path and gives you more.

The version line moves, and the documentation is versioned with it

On maintenance, the project is active in the ordinary sense. The last push was on 2026-10-17 and the repository is not archived. The release history shows v3.19.1 on 2026-10-03, v3.19.0 on 2026-06-07 and v3.18.0 on 2025-10-23, the last of them noted as adding IMPECT data, and the current version in pyproject.toml is 3.19.1.

The version numbering is a minor line increment, so the API is treated as stable within the 3.x series, which is the right convention for a library that other people's analysis code depends on.

The package targets Python 3.9 and later, with classifiers listing 3.9 through 3.13, and the build backend is hatchling. The docs are built with MkDocs, given the mkdocs.toml at the root, and the documentation site is kloppy.pysport.org, with per provider pages under a user guide path for loading data. There are separate requirements files for development and for the docs, a uv.lock for reproducible environments, a runtime.txt, and a pre-commit configuration, so the project has the tooling of a library that expects to be installed and used rather than read.

The licence is BSD-3-Clause, recorded in the LICENSE file at the root and in the package metadata, which is a permissive grant with the three clause notice and no copyleft obligation on the code you build. That is a licensing note rather than legal advice, and it applies to the library rather than to the underlying provider data.

The README has a Where to get it section, and the PyPI badge points at the project page on pypi.org, which is where the distribution lives. The PySport badge and the project homepage tell you where this sits. PySport describes itself as a standard for football data, and kloppy is the piece of that standard you can install, which is why the provider table and the per provider documentation are maintained together rather than the provider list being left to rot.

Editorial conclusion

Adopt kloppy if you work with soccer data from more than one provider, because the point of the library is the vendor-independent model and the same filter syntax across all of them. Do not adopt it if you need a single provider's richest features, since the table shows several providers with partial support and joint tracking data is not yet supported for Hawkeye. Verify first which of the fourteen providers you actually need and whether the cell for your data type is implemented or marked in progress, that your Python is 3.9 or later, and which optional extras you want, since the query, s3, pandas, polars and pyarrow extras are installed separately.

Frequently asked questions

Which soccer data providers does kloppy support?

The provider table lists fourteen, with DataFactory, Hawkeye, Impect, Metrica, PFF, SecondSpectrum, Signality, SkillCorner, Sportec, StatsBomb, Stats Perform, Opta, Tracab and Wyscout. Each provider's row shows whether event data, tracking data and public data are implemented or only in progress.

How do I find specific moments in a soccer match with kloppy?

Use dataset.filter with a regular expression over the event stream, for example dataset.filter("shot.goal") to find goals. The README describes this as a search mechanism for the recognizable patterns analysts look for, and the repository ships an examples/pattern_matching/ directory.

Can kloppy read tracking data from providers with joint tracking?

Not yet. The provider table notes that joint tracking data is not yet supported for Hawkeye, even though Hawkeye 2D tracking data is. The same table marks several providers as in progress or partial for event data, so the per provider documentation pages are the place to check what you get.

What Python version and optional dependencies does kloppy need?

The package requires Python 3.9 or later. Core dependencies are lxml, sortedcontainers, pytz, python-dateutil, typing_extensions for Python below 3.11, and fsspec with the http extra, while networkx for queries, s3, pandas, polars and pyarrow are installed as separate optional extras.

Does kloppy support reading data directly from the cloud?

Yes. The README states that it does not matter where or how the data is stored, and that kloppy can handle compressed files and load data directly from the cloud. The fsspec dependency is in the core set, and an s3 extra adds fsspec with s3 support.

Official sources

  1. License: BSD-3-Clause
  2. Project website
  3. PySport/kloppy on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/pysport-kloppy.svg)](https://hysenlabs.com/projects/pysport-kloppy)

Was this useful?