v1

latestOpenAPI 3.1.0MIT2026-07-1461669.5 KB

Radar

Returns radar rainfall data with 1 km spatial and 5 minute temporal resolution, including a forecast for the next two hours.

Radar data is recorded on a 1200 km (North-South) x 1100 km (East-West) grid, with each pixel representing 1 km². That's quite a lot of data, so use lat/lon or bbox whenever you can (see below). Past radar records are kept for six hours.

Bright Sky can return the data in a few formats. Use the default compressed format if possible – this'll get you the fastest response times by far and reduce load on the server. If you have a small-ish bounding box (e.g. 250 x 250 pixels), using the plain format should be fine.

Quickstart

This request will get you radar data near Münster, reaching 200 km to the East/West/North/South, as a two-dimensional grid of integers:

https://api.brightsky.dev/radar?lat=52&lon=7.6&format=plain

Content

  • The grid is a polar stereographic projection of Germany and the regions bordering it. This is different from the mercator projection used for most consumer-facing maps like OpenStreetMap or Google Maps, and overlaying the radar data onto such a map without conversion (reprojection) will be inaccurate! Check out our radar demo for an example of correctly reprojecting the radar data using OpenLayers. Alternatively, take a look at the dwd:RV-Produkt layer on the DWD's open GeoServer for ready-made tiles you can overlay onto a map.
  • The proj-string for the grid projection is +proj=stere +lat_0=90 +lat_ts=60 +lon_0=10 +a=6378137 +b=6356752.3142451802 +no_defs +x_0=543196.83521776402 +y_0=3622588.8619310018. The radar pixels range from -500 (left) to 1099500 (right) on the x-axis, and from 500 (top) to -1199500 (bottom) on the y-axis, each radar pixel a size of 1000x1000 (1 km²).
  • The DWD data does not cover the whole grid! Many areas near the edges will always be 0.
  • Values represent 0.01 mm / 5 min. I.e., if a pixel has a value of 45, then 0.45 mm of precipitation fell in the corresponding square kilometer in the past five minutes.
  • The four corners of the grid are as follows:
    • Northwest: Latitude 55.86208711, Longitude 1.463301510
    • Northeast: Latitude 55.84543856, Longitude 18.73161645
    • Southeast: Latitude 45.68460578, Longitude 16.58086935
    • Southwest: Latitude 45.69642538, Longitude 3.566994635

You can find details and more information in the DWD's RV product info (German only). Below is an example visualization of the rainfall radar data taken from this document, using the correct projection and showing the radar coverage:

image

Code examples

The radar data is quite big (naively unpacking the default 25-frames response into Python integer arrays will eat roughly 125 MB of memory), so use bbox whenever you can.

compressed format

With Javascript using pako:

fetch(
  'https://api.brightsky.dev/radar'
).then((resp) => resp.json()
).then((respData) => {
  const raw = respData.radar[0].precipitation_5;
  const compressed = Uint8Array.from(atob(raw), c => c.charCodeAt(0));
  const rawBytes = pako.inflate(compressed).buffer;
  const precipitation = new Uint16Array(rawBytes);
});

With Python using numpy:

import base64
import zlib

import numpy as np
import requests

resp = requests.get('https://api.brightsky.dev/radar')
raw = resp.json()['radar'][0]['precipitation_5']
raw_bytes = zlib.decompress(base64.b64decode(raw))

data = np.frombuffer(
    raw_bytes,
    dtype='i2',
).reshape(
    # Adjust `1200` and `1100` to the height/width of your bbox
    (1200, 1100),
)

With Python using the standard library's array:

import array

# [... load raw_bytes as above ...]

data = array.array('H')
data.frombytes(raw_bytes)
data = [
    # Adjust `1200` and `1100` to the height/width of your bbox
    data[row*1100:(row+1)*1100]
    for row in range(1200)
]

Simple plot using matplotlib:

import matplotlib.pyplot as plt

# [... load data as above ...]

plt.imshow(data, vmax=50)
plt.show()

bytes format

Same as for compressed, but add ?format=bytes to the URL and remove the call to zlib.decompress, using just raw_bytes = base64.b64decode(raw) instead.

plain format

This is obviously a lot simpler than the compressed format. It is, however, also a lot slower. Nonetheless, if you have a small-ish bbox the performance difference becomes manageable, so just using the plain format and not having to deal with unpacking logic can be a good option in this case.

With Python:

import requests

resp = requests.get('https://api.brightsky.dev/radar?format=plain')
data = resp.json()['radar'][0]['precipitation_5']

Additional resources

get/radar

Query parameters

bboxinteger[]

Bounding box (top, left, bottom, right) in pixels, edges are inclusive. (Defaults to full 1200x1100 grid.)

Bounding box (top, left, bottom, right) in pixels, edges are inclusive. (Defaults to full 1200x1100 grid.)

distanceinteger

Alternative way to set a bounding box, must be used together with lat and lon. Data will reach distance meters to each side of this location, but is possibly cut off at the edges of the radar grid.

Example:100000

Alternative way to set a bounding box, must be used together with lat and lon. Data will reach distance meters to each side of this location, but is possibly cut off at the edges of the radar grid.

latnumber

Latitude in decimal degrees.

Example:52.52

Latitude in decimal degrees.

lonnumber

Longitude in decimal degrees.

Example:13.4

Longitude in decimal degrees.

datestring date-time

Timestamp of first record to retrieve, in ISO 8601 format. May contain time and/or UTC offset. (Defaults to 1 hour before latest measurement.)

Example:2023-08-07

Timestamp of first record to retrieve, in ISO 8601 format. May contain time and/or UTC offset. (Defaults to 1 hour before latest measurement.)

last_datestring date-time

Timestamp of last record to retrieve, in ISO 8601 format. May contain time and/or UTC offset. (Defaults to 2 hours after date.)

Example:2023-08-08

Timestamp of last record to retrieve, in ISO 8601 format. May contain time and/or UTC offset. (Defaults to 2 hours after date.)

format'compressed' | 'bytes' | 'plain'

Determines how the precipitation data is encoded into the precipitation_5 field:

  • compressed: base64-encoded, zlib-compressed bytestring of 2-byte integers
  • bytes: base64-encoded bytestring of 2-byte integers
  • plain: Nested array of integers

Determines how the precipitation data is encoded into the precipitation_5 field:

  • compressed: base64-encoded, zlib-compressed bytestring of 2-byte integers
  • bytes: base64-encoded bytestring of 2-byte integers
  • plain: Nested array of integers
tzstring

Timezone in which record timestamps will be presented, as <a href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones">tz database name</a>. Will also be used as timezone when parsing date and last_date, unless these have explicit UTC offsets. If omitted but date has an explicit UTC offset, that offset will be used as timezone. Otherwise will default to UTC.

Example:Europe/Berlin

Timezone in which record timestamps will be presented, as <a href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones">tz database name</a>. Will also be used as timezone when parsing date and last_date, unless these have explicit UTC offsets. If omitted but date has an explicit UTC offset, that offset will be used as timezone. Otherwise will default to UTC.

Response

Successful Response

geometryobject

GeoJSON-formatted bounding box of returned radar data, i.e. lat/lon coordinates of the four corners.

bboxinteger[] nullable

Bounding box (top, left, bottom, right) calculated from the supplied position and distance. Only returned if you supplied lat and lon.

latlon_positionobject nullable

Exact x-y-position of the supplied position. Only returned if you supplied lat and lon.

Example response

{
  "radar": [
    {
      "timestamp": "2023-08-07T08:00:00+00:00",
      "source": "RADOLAN::RV::2023-08-08T11:45:00+00:00",
      "precipitation_5": "eF5jGAWjYBTQEQAAA3IAAQ=="
    }
  ],
  "geometry": {
    "coordinates": [
      [
        7.44365,
        52.08712
      ],
      [
        7.45668,
        51.90644
      ],
      [
        7.7487,
        51.914
      ],
      [
        7.73716,
        52.09473
      ]
    ],
    "type": "Polygon"
  },
  "bbox": [
    100,
    100,
    300,
    300
  ],
  "latlon_position": {
    "x": 10.244,
    "y": 10.088
  }
}