entsoe-py: a Python client for European grid data
Python client for the ENTSO-E API (european network of transmission system operators for electricity)
At a glance
- What is it?
- entsoe-py wraps the ENTSO-E transparency platform, the European network of transmission system operators for electricity, with two clients: one that returns the raw XML or zip payloads and one that parses them into pandas objects. The method surface covers day ahead prices, load and generation, crossborder flows, transfer capacity, and unavailability, and the pandas client splits large requests and long time ranges for you.
- Who is it for?
- entsoe-py fits an energy analyst or a researcher who needs day ahead prices, load, generation, or crossborder flows for a bidding zone and does not want to assemble the REST parameters by hand. It does not fit a project that needs a data set for a zone the wrapper does not cover, since ENTSO-E country codes and document types are specific, and it does not fit a workload that must avoid the pandas dependency.
- Can I use it commercially?
- Yes. MIT 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 10 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 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A wrapper for the transparency platform
entsoe-py is a Python client for the ENTSO-E API, which is the European network of transmission system operators for electricity, and the thing the API actually exposes is the transparency platform, which is where the European grid data is published.
That data is the reason to use this kind of library at all. The platform publishes the numbers that describe a power system across Europe, the day ahead clearing prices for each bidding zone, the load, the generation, the crossborder flows between neighbouring zones, the available transfer capacity between them, and the unavailability declarations for plants and transmission assets. All of it is public, all of it is published in a consistent set of document types, and all of it is served over a REST interface with a particular set of parameters.
The work a client saves is the parameter assembly. The API takes a document type, a start and end, a domain or two, and a set of enum values for things like the market agreement type and the process type, and getting those right for each kind of query is the tedious part. The wrapper turns them into named methods with sensible argument names.
The documentation of the API itself is pointed at through a Postman collection, which is the right reference for a wrapper of this kind, because the wrapper is a convenience over the API rather than a replacement for it. The library also ships a CITATION.cff file, which is a small detail that tells you the project expects to be cited in research work.
The project is MIT licensed, the last push was on 2026-10-13, and the recent releases are v0.8.1 from 2026-09-04, v0.8.0 from 2026-04-14, and v0.7.11 from 2026-03-11. The version is read from the source at build time rather than written in the setup file, so the tag and the module always agree.
The install is a single command.
python3 -m pip install entsoe-pyTwo clients, and the difference between them
The package ships two clients for the REST API, and the choice between them is about what you want to do with the bytes that come back.
The EntsoeRawClient returns data in its raw format, which is usually XML or a zip file containing XML documents. The EntsoePandasClient returns data parsed as a pandas Series or a DataFrame.
The raw client is the one to reach for when the data is going somewhere the wrapper does not model. The API returns a set of document types, and some of them, the unavailability declarations in particular, are not a simple time series of one number per interval. When the wrapper has no typed representation for a document type, the raw client still gives you the document.
The pandas client is the one for analysis, and it adds two behaviours that the raw client does not have. Time periods that span more than one year are automatically dealt with, and requests for large numbers of files are split over multiple API calls.
Both of those are work that has to be done somewhere, and doing it in the client rather than in each script is the entire value of the wrapper. The API enforces a range limit on a single request, and a year of hourly data is beyond it, so a client that quietly splits the request is a client that lets you ask for a year without thinking about the limit.
The pandas client has one requirement that is easy to miss. It needs a start and an end parameter, and they have to be pandas timestamps with a timezone. If they are not, it throws an exception rather than guessing, which is the right behaviour for a time series API where a naive timestamp silently means the wrong interval.
The typical shape of a request looks like this.
start = pd.Timestamp('20171201', tz='Europe/Brussels')
end = pd.Timestamp('20180101', tz='Europe/Brussels')
country_code = 'BE' # BelgiumThe timezone is Brussels because that is the ENTSO-E reference zone for the market, and a caller working in local time should keep that in mind when the daylight saving boundary falls inside the range.
What the method surface covers
The list of query methods is long, and it is organised by the kind of data rather than by the API's own document type taxonomy, which is what makes it usable.
On prices there is the day ahead prices, the aggregated bids, the imbalance prices, the imbalance volumes, the contracted reserve prices, the contracted reserve prices for procured capacity, the contracted reserve amount, the procured balancing capacity, and the activated balancing energy prices and volumes.
On physical flows there is the load, the load forecast, the wind and solar forecast and its intraday variant, the generation forecast, the generation, the generation per plant, the installed generation capacity and the installed capacity per unit, the aggregate water reservoirs and hydro storage, and the net position.
On the borders between countries, the crossborder flows, the scheduled exchanges, the net transfer capacity for the day, week, month, and year ahead, the intraday offered capacity, the offered capacity, and the unavailability of transmission between two zones.
On outages, the unavailability of generation units, the unavailability of production units, the unavailability of offshore grid, and the withdrawn unavailability of generation units.
Two details in the list are worth knowing. Several methods take a psr_type parameter, which is the power system resource type that filters a generation or capacity query down to wind, solar, hydro, or a specific technology. And a few take an implicit flag, which changes the capacity request from the explicit form to the implicit one that some bidding zones publish.
The return type also varies by method, and the README marks which ones come back as zip bytes rather than XML, which is the case for the imbalance series and the unavailability documents.
The escape hatch, and the file dumps
Two escape hatches are documented, and both are short.
The first is dumping the result to a file, which is a matter of choosing the right open mode. An XML result is a string and goes into a text file, and a zip result is bytes and goes into a binary file.
xml_string = client.query_day_ahead_prices(country_code, start, end)
with open('outfile.xml', 'w') as f:
f.write(xml_string)
zip_bytes = client.query_unavailability_of_generation_units(country_code, start, end)
with open('outfile.zip', 'wb') as f:
f.write(zip_bytes)The second is making a request that has no method of its own. The README is explicit that the parameters can be looked up in the API documentation, and the base request method takes the parameter dictionary along with the start and the end.
params = {
'documentType': 'A44',
'in_Domain': '10YBE----------2',
'out_Domain': '10YBE----------2'
}
response = client._base_request(params=params, start=start, end=end)
print(response.text)This is the part of the library that tells you how it was built. Every query method is a convenience wrapper over one call with a parameter dictionary, and the base request is that call. When a document type is missing from the list, you can call the base method with the parameters assembled from the API documentation and get the same response object the wrappers use.
The leading underscore marks it as internal, and it is worth being honest about that: the method is stable enough to rely on, since every wrapper in the library routes through it, but it is not covered by the same promise as the public query methods, and it will change shape if the internals are refactored.
The package, the dependencies, and the tests
The distribution is a conventional setuptools project with one small twist.
The setup module reads the long description from the README file, and it reads the version out of the source file by looking for the version assignment, so the published version always matches the code. The metadata names the package entsoe-py, describes it as a python API wrapper for ENTSO-E, points at the EnergieID repository, and credits the two authors. The development status classifier is Production/Stable, and the supported Python version starts at 3.9.
The runtime dependencies are four, and each one is doing a specific job. requests is the HTTP client. pandas is what the second client parses into, and the requirement is a recent 2.2 series. pytz is there for the time zone handling that the timestamps need. And beautifulsoup4 is for parsing the XML, with a 4.11 minimum, which is what makes the pandas client possible without the API returning a different format.
That last one is a design point worth noting. ENTSO-E publishes XML for most document types, so a wrapper that returns dataframes has to parse XML, and the parsing library is the dependency that makes it work. It also means the pandas client covers the document types that are genuinely tabular and leaves the rest to the raw client, which is the sensible division.
The repository holds the package in an entsoe directory, a tests directory, a pytest configuration, a development requirements file, and a manifest file for packaging. The presence of a citation file and of a separate development requirements file suggests a project that expects to be used in published work and to be worked on by several people.
Editorial conclusion
entsoe-py fits an energy analyst or a researcher who needs day ahead prices, load, generation, or crossborder flows for a bidding zone and does not want to assemble the REST parameters by hand. It does not fit a project that needs a data set for a zone the wrapper does not cover, since ENTSO-E country codes and document types are specific, and it does not fit a workload that must avoid the pandas dependency. Verify first that the bidding zone code in use is one the API expects, that the time range is expressed as a timezone aware pandas timestamp when the pandas client is used, and that the API key is provisioned with the transparency platform, since the client signs every request with it.
Frequently asked questions
What is entsoe-py used for?
It is a Python client for the ENTSO-E API of the European network of transmission system operators for electricity, wrapping the transparency platform so that a caller can fetch day ahead prices, load, generation, crossborder flows, transfer capacity, and unavailability data by calling named methods instead of assembling the REST parameters by hand.
What is the difference between EntsoeRawClient and EntsoePandasClient?
The raw client returns the data in its original form, usually XML or a zip file of XML documents, while the pandas client returns a pandas Series or DataFrame and additionally handles time periods longer than a year and splits requests for large numbers of files across multiple API calls.
How do I install entsoe-py?
With python3 -m pip install entsoe-py. The runtime dependencies are requests, pandas, pytz, and beautifulsoup4, and the package is MIT licensed with the version read from the source at build time.
How do I query a data set that has no method in entsoe-py?
Look the parameters up in the API documentation and call the base request method with a parameter dictionary plus the start and end, which returns the same response object the query methods use. The parameters are the API's own document type, in domain, and out domain values.
Why does the entsoe-py pandas client require timezone aware timestamps?
Because it throws an exception when the start and end parameters are not pandas timestamps with a timezone, rather than guessing. For a time series API a naive timestamp silently means the wrong interval, so the client refuses it. The documentation of the API itself is published as a Postman collection.
Official sources
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.
[](https://hysenlabs.com/projects/energieid-entsoe-py)Was this useful?