Introduction
The Hydrology API provides access to historic and recent hydrological data including river flows, river levels, groundwater levels, rainfall and water quality. You can watch a video explaining APIs here.
Revised service
This release of the hydrology service represents a substantial expansion of the range and volume of the data available. It provides data from nearly eight thousand monitoring stations, and includes sub-daily (typically 15 min) resolution time series as well as wider range of daily time series.
The available parameters and time series now available are:
parameterName | periodName | valueType | qualifier | unitName |
---|---|---|---|---|
Flow | 15min | instantaneous | m3/s | |
Flow | daily | mean, min, max | m3/s | |
Level | 15min | instantaneous | m | |
Level | daily | min, max | m | |
Rainfall | 15min | total | mm | |
Rainfall | daily | total | mm | |
GroundwaterLevel | instantaneous | Groundwater Dipped | mAOD | |
GroundwaterLevel | sub-daily | instantaneous | Groundwater Logged | mAOD |
Dissolved Oxygen | 15min | instantaneous | % | |
Dissolved Oxygen | 15min | instantaneous | mg/L | |
Fluorescent Dissolved Organic Matter | 15min | instantaneous | RFU | |
Blue-Green Algae | 15min | instantaneous | RFU | |
Turbidity | 15min | instantaneous | NTU | |
Chlorophyll | 15min | instantaneous | µg/L | |
Conductivity | 15min | instantaneous | µS/cm | |
Temperature | 15min | instantaneous | oC | |
Ammonium | 15min | instantaneous | mg/L | |
Nitrate | 15min | instantaneous | mg/L (as N) | |
PH | 15min | instantaneous |
The column names match the metadata property names returned by the API. The table entries show the metadata values returned by the API.
Note that for logged groundwater data the sub-daily values may be a mix of 15min and hourly intervals. The API supports estimation of daily logged groundwater by filtering to 9:00am values, see examples below.
Data volume and fair use
The service provides access to over four billion rows of readings.
Given this volume of data users should be careful of the volume of data they request and only request the resolution and time span required. In particular, the entire history of a single sub-daily time series can be up to two million rows. If downloaded as a single CSV file, that size of data exceeds the number of rows that can be opened in tools such as Excel or LibreOffice.
The API calls that return readings data have a soft limit of 100,000 rows per-call which can be overridden by setting a _limit
parameter.
However, we current set a hard limit of 2,000,000 rows, which cannot be overridden.
This is sufficient to return the whole history of a sub-daily time series, or return all values across all stations for two days.
To request more data at a time we provide a batch api alternative which will queue up larger requests, which will then be processed one at a time.
N.B. the current hard limit of 2,000,000 rows of data per-call is subject to review. If the service becomes overloaded the limit may be reduced and users may need to either switch to use of the batch api or split a request for a sub-daily time series into a series of requests for different spans of time.
N.B.We ask that users who are automatically downloading bulk data to limit the number of non-batch API requests they make at any one time. Ideally limit to one request in flight at a time, waiting for each request to finish before issuing the next. We reserve the right to enforce limits on the number of concurrent requests (per IP address or identifiable group of IP addresses) and may find it necessary to block users who place excessive demands on the service to the detriment of other users.
Identifiers
The primary identifier for most stations uses a GUID style identifier called an SUID (Station Unique IDentifier).
For Water Quality stations it is based on a shorter ID code.
These are used in the URL for the station and given as the value of the notation
property in the station metadata.
In some cases the SUID is not unique, for example due to co-location of multiple distinct sampling points at the same physical station.
In those cases the station is identified using a composite key combining the SUID with a disambiguating string (typically a Wiski identifier).
The actual SUID is always available as the stationGuid
property of the station metadata, even in cases where the station notation has been disambiguated.
A number of additional identifier schemes are also available for different subsets of the stations. These include:
- wiski identifier (
wiskiID
) - the River Levels on the Internet or Check for Flooding identifier (
RLOIid
andrloiStationLink
) - National Flood Forecasting Service identifier (
stationReference
) - National River Flow Archive station identifier (
nrfaStationID
andnrfaStationURL
)
API Summary
This is a brief summary of the APIs available, see below for details.
Note that the HTML views are offered as an aid to debugging and development,
but they are not intended for presentation to consumers.
All URIs are relative to the service base URI of http://environment.data.gov.uk/hydrology
.
Monitoring Stations
Information on monitoring stations at which flows and levels are monitored.
Description | API | Parameters |
---|---|---|
Details for a single monitoring station. | /hydrology/id/stations/{id} [json] [html] |
id={value}
_view={default}
|
List of all monitoring stations can be filtered by name, location and other parameters. | /hydrology/id/stations [json] [html] |
RLOIid={id}
wiskiID={id}
stationGuid={id}
sampleOf={waterbody}
status.label={Active|Suspended|Closed}
observedProperty={waterFlow|waterLevel|rainfall|groundwaterLevel|dissolved-oxygen|fdom|bga|turbidity|chlorophyll|conductivity|temperature|ammonium|nitrate|ph}
_view={default|minimal}
search={x}
lat={x}&long={y}&dist={d} easting={x}&northing={y}&dist={d}
|
Lists monitoring stations that are open between from and to dates. | /hydrology/id/open/stations [json] [html] |
from={yyyy-mm-dd}
to={yyyy-mm-dd}
status.label={Active|Suspended|Closed}
observedProperty={waterFlow|waterLevel|rainfall|groundwaterLevel|dissolved-oxygen|fdom|bga|turbidity|chlorophyll|conductivity|temperature|ammonium|nitrate|ph}
_view={default|minimal}
search={x}
lat={x}&long={y}&dist={d} easting={x}&northing={y}&dist={d}
|
Measures
Measurement timeseries available.
Description | API | Parameters |
---|---|---|
Description of a single measurement timeseries | /hydrology/id/measures/{id} [json] [html] |
id={value}
_view={default}
|
List of all available measurement timeseries in the hydrology dataset. | /hydrology/id/measures [json] [html] |
station={guid}
station.wiskiID={id}
observationType={Qualified|Measured}
observedProperty={waterFlow|waterLevel|rainfall|groundwaterLevel|dissolved-oxygen|fdom|bga|turbidity|chlorophyll|conductivity|temperature|ammonium|nitrate|ph}
_view={default}
|
List the timeseries for a station. | /hydrology/id/stations/{station}/measures [json] [html] |
station={value}
observationType={Qualified|Measured}
observedProperty={waterFlow|waterLevel|rainfall|groundwaterLevel|dissolved-oxygen|fdom|bga|turbidity|chlorophyll|conductivity|temperature|ammonium|nitrate|ph}
_view={default}
|
Readings
Readings (aka observations or datapoints) within a measurement timeseries
Description | API | Parameters |
---|---|---|
Readings for a single measure timeseries. | /hydrology/id/measures/{measure}/readings [json] [html] |
measure={value}
date={yyyy-mm-dd}
min-date={yyyy-mm-dd}
mineq-date={yyyy-mm-dd}
max-date={yyyy-mm-dd}
maxeq-date={yyyy-mm-dd}
earliest={}
latest={}
_view={default|flow|full|min}
|
Readings for one or more measure time series. | /hydrology/data/readings [json] [html] |
measure={id}
date={yyyy-mm-dd}
min-date={yyyy-mm-dd}
mineq-date={yyyy-mm-dd}
max-date={yyyy-mm-dd}
maxeq-date={yyyy-mm-dd}
earliest={}
latest={}
station={guid}
station.RLOIid={id}
station.wiskiID={id}
observationType={Qualified|Measured}
observedProperty={waterFlow|waterLevel|rainfall|groundwaterLevel|dissolved-oxygen|fdom|bga|turbidity|chlorophyll|conductivity|temperature|ammonium|nitrate|ph}
period={number}
_view={default|flow|full|min}
|
API Structure
Each API endpoint provides REST style access to the data via HTTP GET requests. Data can be returned in a range of formats including JSON, CSV and web pages.
Simple Requests
For example fetching a list of resources from: /hydrology/id/stations.json?_limit=5
will return a JSON data packet similar to the following:
{
"meta": {
"comment": "Hydrology API for sub-daily data",
"license": "http://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/",
"licenseName": "OGL 3",
"publisher": "Environment Agency",
"version": "2.0.0",
"limit": 10
},
"items": [
{
"@id": "http://environment.data.gov.uk/hydrology/id/stations/353a6f59-bc41-5bb8-a00e-82b67897d052",
"easting": 275112,
"label": "AUSTINS BRIDGE",
"lat": 50.479041,
"long": -3.761515,
"measures": { ... }
"northing": 65841,
...
}
...
]
}
All of the JSON descriptions returned by the API are comprised by metadata
and items
blocks.
Metadata and Versioning
The metadata description included in JSON and RDF results provides information about the API,
such as the publisher and applicable licence.
If the resource is also available in other formats,
then the hasFormat
or dct:hasFormat
property will give list of URLs for those alternative formats.
See content types for more information about the available content types.
{
"meta": {
"comment": "Hydrology API for sub-daily data",
"license": "http://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/",
"licenseName": "OGL 3",
"publisher": "Environment Agency",
"version": "2.0.0",
"limit": 10
},
...
}
The metadata block also includes version number information. The intention is that, after initial release,
updates to the API should maintain backward compatibility. If an incompatible change to the API is required
then we will attempt to provide access to the prior version for a transitional period. In that case the
meta
block will also provide replaces
and isReplacedBy
links between
the new and the old versions of the affected API endpoints.
When a list of resources is requested,
the metadata description will include any applied limit to the length of the list and offset from the start of the list.
They will be shown in the metadata as limit
and offset
values, as in the example above.
Items
The items
element in the JSON response will be an array containing objects describing resources in the data.
When requesting a description of a single item the items
element will still be an array (just with one element).
If a list request returns no results then the items
array will be empty.
Each item will normally be identified by a URI given in the @id
field.
"items": [
{
"@id": "http://environment.data.gov.uk/hydrology/id/stations/353a6f59-bc41-5bb8-a00e-82b67897d052",
"easting": 275112,
"label": "AUSTINS BRIDGE",
"lat": 50.479041,
"long": -3.761515,
"measures": { ... }
"northing": 65841,
...
}
...
]
When one resource references another, the API will typically include key attributes of the referenced resource in-line. Alternatively, you can fetch (i.e. HTTP GET) the URI of the referenced resource to obtain a full description (depending on the URI, the descriptions of related resources may not be served by this API).
Content Types
The descriptions of individual resources can be obtained in multiple formats. When accessing the API through your browser, the format will be HTML, but JSON and RDF formats (RDF/XML and Turtle) are also supported.
Similarly, lists of resources can be obtained in JSON, CSV and HTML and RDF formats. For resources with associated geometries, GeoJSON format is also supported.
To request a specific content type, use standard HTTP content negotiation, for example:
curl -i -H "Accept: text/csv" /hydrology/id/stations.json?_limit=5
You can also request a specific content type by appending a path extension to the URI,
or by supplying the extension as the _format
query parameter.
The supported values are:
Suffix | Type |
---|---|
.csv | text/csv |
.geojson | application/geo+json |
.html | text/html |
.json | application/json |
.rdf | application/rdf+xml |
.ttl | text/turtle |
So the earlier example is equivalent to simply fetching the URL:
By default, the CSV results will use column names matching the property paths in the corresponding JSON format.
Lists: Filtering and Paging
Some endpoints return information describing a single identified item but many return information on a list of items. Such list endpoints support query parameters to filter the list to only include some items. In most cases these filters take the form:
prop1.prop2...propn=value
Here, the props
are the short property names that appear in the JSON format and the
value
is the value that the property is required to have. The value might be a number, a string, a
date or a URI. In the case of the URI then you can often use the last segment of the URI on its own.
For example, to list just stations which include observations about temperature use:
If the same filter is used twice with different values then the API will return results for both values (i.e. it acts as a disjunction).
You can apply prefixes to the parameter in order to apply standard filters to your query:
Prefix | Meaning |
---|---|
min- |
Applies a strictly greater than filter. |
mineq- |
Applies a greater than or equal to filter. |
max- |
Applies a strictly less than filter. |
maxeq- |
Applies a less than or equal to filter. |
For example, supply the parameter min-dateTime=12/03/2021
to query hydrology readings recorder after 12/03/2021.
You can also specify a filter range using (
and )
for exclusive bounds,
and (*
and *)
for inclusive bounds.
The upper and lower boundary values are separated with ..
.
Note that you can use both kinds of boundaries in a single query, eg. value=(1.4..3.17*)
.
Note When filtering on a range of date-times, to ensure accurate comparison,
you should include the timezone on the timestamp that you want to compare values to.
For example, to write a timestamp in UTC time, append a Z
to the end.
See here for more information.
When filtering on resource values, you can reference the resource by its URI or its compact URI, based on the defined namespace prefixes. Note that when URIs are supplied in query parameters, they must be correctly encoded.
type=http%3A%2F%2Fwww.w3.org%2F2004%2F02%2Fskos%2Fcore%23Concept
type=skos:Concept
Some endpoints also support referencing resources by just their short names, for example type=Concept
.
List endpoints also support view modification parameters. These are distinguished by starting with an underscore character. The commonly supported modifiers are:
Query | Meaning |
---|---|
_view=full|.. |
An alternative view of the items. The default view includes just summary properties. The full view includes everything. |
_limit=x |
Return only x items from the list, some endpoints may impose a default limit and/or a maximum to which the limit can be set. |
_offset=x |
Return the list of items starting with the x th item, together with _limit this enables paging through a long set of results. |
_sort=prop.prop... |
Reorder the list of results in ascending order of the given property (or property chain). To sort in descending order use _sort=-prop . More than one sort can be included in which case they will be applied in order. |
_count=prop1,prop2... |
Request an aggregated count query on the given properties. Use @id to denote a count on the total number of results. |
_groupBy=prop1,prop2... |
When requesting an aggregated query using _count , perform a grouping on the given properties. |
If a limit or offset is applicable, whether explicit in the query or implicitly imposed by the API, then the
metadata object will include a limit
or offset
field to show what limits were applied.
Projection
The _projection
query parameter lets you specify a set of properties to return for each resource.
The properties that are returned by each endpoint by default are defined in "Returned Data" section.
You can also specify any of the properties that are documented on the class corresponding to the endpoint result.
- Use
.
to specify nested properties:prop1.prop2
- Use
,
to separate properties or property paths. - Use
()
in case you want to specify multiple child properties:prop1(prop2,prop3)
.
This is just a shorthand forprop1.prop2,prop1.prop3
- Use wildcard
*
to request all nested properties:prop1(*)
.
The wildcard is not recursive and will only include the immediate child properties.
You can also supply the _withView
query parameter (no value is required) to include the properties on
selected view in addition to your projection.
The view can be selected with the _view
query parameter, otherwise the API will use the default view.
Batch API
As noted under fair use we limit the maximum number of readings that can be returned from a single synchronous API call. The limit is current 2 million rows, but it may be reduced in the future depending usage levels.
The batch API provides an alternative query mechanism for obtaining measurements. It allows larger requests to be made but manages them so only a small number of batch requests are processed at a time.
The batch API endpoint is:
This endpoint only accepts a subset of filter parameters supported by the /hydrology/data/readings
endpoint.
It only accepts parameters that are returned by the endpoint, namely measure
, dateTime
,
date
, value
, quality
and completeness
.
If the requested set of readings has previously been generated then the batch call will return (a redirection to) a cached copy of the results
(currently in CSV format only).
If no one has requested that particular set of measurements already then a new batch request
will be scheduled on a queue and the call will return (a redirection to) a /status
page.
The status page shows the status of that request in the queue and is available in JSON and HTML format.
Repeated fetches of the status page will show the current progress of the request.
The request status in JSON looks like:
{
"key" : "bf679fd0-8d8f-4815-a569-ec798d81f324-level-i-900-m-qualified" ,
"status" : "InProgress" ,
"positionInQueue" : 0 ,
"eta" : 86333 ,
"started" : "2/3/22 8:36 PM"
}
Where the status can be one of Pending
InProgress
Completed
or Failed
.
The eta element shows the expected time to completion.
While this estimate is given in ms in practice the estimate may be wildly inaccurate and should not be relied upon.
When the batch processing has completed then the status response will change to show a URL from which the result can be download:
{
"key": "bf679fd0-8d8f-4815-a569-ec798d81f324-level-i-900-m-qualified",
"status": "Completed",
"url": "https://s3-eu-west-1.amazonaws.com/environment-open-data/hydrology/cache/bf679fd0-8d8f-4815-a569-ec798d81f324-level-i-900-m-qualified.csv"
}
In addition, it is also possible to POST a query to the same batch API.
The filter settings can still be provided in the query parameters, just as for GET requests, b
ut in addition it is possible to send the filter parameters in the body of the POST request in application/x-www-form-urlencoded
format.
This allows larger sets of filters values to be sent, for example in order to request information from a large number of specific stations.
The result of a successful batch query POST submission will be a 201 (Created) response with a location header giving the URL of the status information on the request, in the same format as the above.
Monitoring Stations
Information on monitoring stations at which river flows, river levels, groundwater levels, rainfall or water quality are monitored.
These endpoints limits the number of returned results to 100, to override that please set _limit={x}`
query parameter where {x}
is your custom limit.
See below for examples of useful filter parameters for each endpoint.
Description | API | Parameters |
---|---|---|
Details for a single monitoring station. | /hydrology/id/stations/{id} [json] [html] |
id={value}
_view={default}
|
List of all monitoring stations can be filtered by name, location and other parameters. | /hydrology/id/stations [json] [html] |
RLOIid={id}
wiskiID={id}
stationGuid={id}
sampleOf={waterbody}
status.label={Active|Suspended|Closed}
observedProperty={waterFlow|waterLevel|rainfall|groundwaterLevel|dissolved-oxygen|fdom|bga|turbidity|chlorophyll|conductivity|temperature|ammonium|nitrate|ph}
_view={default|minimal}
search={x}
lat={x}&long={y}&dist={d} easting={x}&northing={y}&dist={d}
|
Lists monitoring stations that are open between from and to dates. | /hydrology/id/open/stations [json] [html] |
from={yyyy-mm-dd}
to={yyyy-mm-dd}
status.label={Active|Suspended|Closed}
observedProperty={waterFlow|waterLevel|rainfall|groundwaterLevel|dissolved-oxygen|fdom|bga|turbidity|chlorophyll|conductivity|temperature|ammonium|nitrate|ph}
_view={default|minimal}
search={x}
lat={x}&long={y}&dist={d} easting={x}&northing={y}&dist={d}
|
Examples
Find the station with WIKSI identifier S11512_FW:
Find the station corresponding to River Levels On the Internet/Check for Flooding reference 5022:
Stations on the River Exe which measure water flow:
Groundwater stations with only dipped measurements:
Closed stations:
All stations with 3km of the given coordinates:
Find all stations that were open between 10/05/2020 and 10/08/2020:
Find all stations that measure conductivity:
Find all stations that are currently suspended (can also use statusActive and statusClosed):
Returned data
Measures
Measurement time series available.
See below for examples of useful filter parameters for each endpoint.
Description | API | Parameters |
---|---|---|
Description of a single measurement timeseries | /hydrology/id/measures/{id} [json] [html] |
id={value}
_view={default}
|
List of all available measurement timeseries in the hydrology dataset. | /hydrology/id/measures [json] [html] |
station={guid}
station.wiskiID={id}
observationType={Qualified|Measured}
observedProperty={waterFlow|waterLevel|rainfall|groundwaterLevel|dissolved-oxygen|fdom|bga|turbidity|chlorophyll|conductivity|temperature|ammonium|nitrate|ph}
_view={default}
|
List the timeseries for a station. | /hydrology/id/stations/{station}/measures [json] [html] |
station={value}
observationType={Qualified|Measured}
observedProperty={waterFlow|waterLevel|rainfall|groundwaterLevel|dissolved-oxygen|fdom|bga|turbidity|chlorophyll|conductivity|temperature|ammonium|nitrate|ph}
_view={default}
|
Examples
Time series available for station with give GUID identifier:
All time series of water level data from station identified by WISKIid SS92F014 (that measures both flows and levels):
Sub-daily (15min) time series of water level data from station identified by WISKIid SS92F014:
Returned data
Readings
These endpoints return readings (aka observations or datapoints) within a measure timeseries, or set of timeseries.
Each reading has a date-time stamp, a value (usually) and the identifier for the measure (timeseries). For Qualified data there can be up to three quality flags:
Quality flag | Meaning | Values |
---|---|---|
quality | The quality of this reading |
Good
Estimated
Suspect
Unchecked
Missing
|
completeness | Whether the value is based on complete data or not |
Complete
Incomplete
|
qflag | Other qualifying information. |
Edited WithinRating NoRating ExtrapolateUpperPart ExtrapolateLowerPart BeyondUpperLimit BeyondLowerLimit WeirModularHead WeirNonModularHead WeirExtremelyNonModularHead WeirModularTail WeirNonModularTail WeirExtremelyNonModularTail WeirModularCrest WeirNonModularCrest WeirExtremelyNonModularCrest WeirHeadOnly RasteredTimeStamp Apportioned Dry Snow Trace |
For Qualified data then readings with quality annotation Missing
will not include a value at all.
Data is returned in sorted order, earliest to latest.
These endpoints limits the number of returned results to 100000, to override that please set _limit={x}
query parameter where {x}
is your custom limit. The hard limit is set to 2 million records.
See below for examples of useful filter parameters for each endpoint.
Description | API | Parameters |
---|---|---|
Readings for a single measure timeseries. | /hydrology/id/measures/{measure}/readings [json] [html] |
measure={value}
date={yyyy-mm-dd}
min-date={yyyy-mm-dd}
mineq-date={yyyy-mm-dd}
max-date={yyyy-mm-dd}
maxeq-date={yyyy-mm-dd}
earliest={}
latest={}
_view={default|flow|full|min}
|
Readings for one or more measure time series. | /hydrology/data/readings [json] [html] |
measure={id}
date={yyyy-mm-dd}
min-date={yyyy-mm-dd}
mineq-date={yyyy-mm-dd}
max-date={yyyy-mm-dd}
maxeq-date={yyyy-mm-dd}
earliest={}
latest={}
station={guid}
station.RLOIid={id}
station.wiskiID={id}
observationType={Qualified|Measured}
observedProperty={waterFlow|waterLevel|rainfall|groundwaterLevel|dissolved-oxygen|fdom|bga|turbidity|chlorophyll|conductivity|temperature|ammonium|nitrate|ph}
period={number}
_view={default|flow|full|min}
|
Examples
Earliest reading available from Felsted for 15min flow:
Latest reading available from Felsted for daily max level:
All readings available available from Felsted 15min flow for first week of January 2021:
All readings available available from Felsted daily mean flow for January 2020 as json:
All readings available available from Felsted daily mean flow for January 2020 as CSV:
All 9am readings for logged groundwater data from Moss Edge Farm for January 2021:
Latest reading from two groundwater sites:
Readings for all daily flow time series from station with wiski ID SS92F014 for a particular day:
Readings for all max daily flow time series with period one day, for a particular day (slow):
Latest dissolved oxygen measurement at RIVER BLAKEWATER US
Returned data
Namespace Prefixes
Listed below are supported namespace prefixes.
You can use them to specify the URI values of query parameters in short form.
For example, ?type=type=http%3A%2F%2Fwww.w3.org%2F2004%2F02%2Fskos%2Fcore%23Concept
is equivalent to
the prefixed short form, ?type=skos:Concept
.
Data reference
- RLOIid
- Station
- TimeSeries
- catchmentArea
- catchmentName
- category
- colocatedStation
- dataQualityEndDate
- dataQualityInspectionDate
- dataQualityMessage
- dataQualityStartDate
- dateClosed
- dateOpened
- datum
- datumType
- description
- explanation
- hasTelemetry
- inManagementUnit
- inRegion
- label
- measurementRange
- measures
- notation
- nrfaStationID
- nrfaStationURL
- observationType
- parameter
- parameterName
- period
- periodName
- qualifier
- regime
- regimeThreshold
- riverName
- rloiStationLink
- sampleOf
- sampledBy
- station
- stationGuid
- stationReference
- status
- statusReason
- timeseriesID
- town
- type
- unit
- unitName
- valueStatistic
- valueType
- wiskiID