sheff.events

The open data endpoints

Free, keyless, yours to build on

Everything this site gathers about Sheffield is available back out again as data. There is no key, no sign-up and no charge, and the licence and credit of every original publisher travels with the response. Take it for a dissertation, a class exercise, a community map, a newsroom chart or a weekend project. The only thing asked in return is that you credit the people who published it.

Datasets you can download
50
Records in those snapshots
37,789
Datasets with coordinates
24
Listed but not redistributable
11

Start here

Every endpoint is a GET, is read only, answers cross-origin so a browser can call it directly, and lives under one base:

https://sheff.events/wp-json/sheff/v1

The catalogue is the map of everything else. It names every dataset, its licence, the credit it asks for, when it last refreshed, how many records it holds, and the exact download URLs:

curl -s 'https://sheff.events/wp-json/sheff/v1/data' | jq '.data[] | select(.redistributed) | {key, label, record_count, licence: .licence.name}'

The endpoints

Six routes cover the whole open data surface. A dataset is called a provider and has a key, such as listed or sewage; a provider is split into parts, such as listed, scheduled and park.

Open data endpoints
RouteWhat comes backParametersFormats
/dataThe catalogue: every provider with licence, attribution, source URL, last refresh, record count, its parts, its download URLs and a ready-made citation line. Providers that cannot be redistributed are listed too, with the reason.fieldsJSON
/data/{provider}Every stored record of one provider, flattened. Parts are merged and each row gains a part field saying where it came from.page, per_page (1 to 1,000, or 0 for everything up to 20,000 rows), fields, formatJSON, CSV, NDJSON, GeoJSON
/data/{provider}/{part}One part of a provider on its own, which is usually what you actually want. The catalogue lists the parts and the record count of each.page, per_page, fields, formatJSON, CSV, NDJSON, GeoJSON
/data/{provider}/chart/{kind}The series behind a chart on the site: labels, one or more named series, a unit and a suggested style. Useful when you want the shape of a trend rather than every row.formatJSON, CSV
/areas/{slug}/dataEverything the site holds inside one of the 147 Sheffield neighbourhoods: every redistributable record whose point falls in the polygon, grouped by provider and part, plus the derived census, sold price, broadband, monthly sales, correlation and scorecard figures the neighbourhood page shows.fields, formatJSON, CSV, GeoJSON
/areas/scoresEvery neighbourhood scored 0 to 100 on quiet, green, connected, affordable, safe, lively and served, with the overall score, the rank and the must-have flags. Add workings=1 and each dimension arrives with the inputs behind it: value, unit, percentile, source and licence.workings, fields, formatJSON, CSV

The format parameter decides the body. JSON arrives in the shared envelope; CSV, NDJSON and GeoJSON arrive as the raw file with the licence carried in the headers and, for CSV, as comment lines at the top. fields takes a comma separated list of column names and trims every row to those columns.

What a JSON response looks like

Four keys, always the same. data is the payload, meta carries the paging and the licence, sources names every publisher involved, and citation is the line to quote.

{
  "data":   [ { "part": "listed", "id": "nhle-1025119", "name": "Church of St Winifred", ... } ],
  "meta":   { "total": 1147, "page": 1, "per_page": 100, "has_more": true,
              "licence": { "name": "Open Government Licence v3.0", "url": "..." },
              "attribution": "...", "citation_text": "...",
              "derived_licence": { "name": "CC BY 4.0", "url": "..." } },
  "sources": [ { "key": "listed", "name": "...", "licence": "...", "updated": "2026-09-14T..." } ],
  "citation": { "title": "...", "url": "...", "retrieved": "2026-09-14T..." }
}

Every response also carries these headers:

Response headers
HeaderWhat it is for
Cache-Controlpublic, max-age=3600 with stale-while-revalidate. Data responses are cached for an hour, because the snapshot behind them only changes on a schedule.
ETagA hash of the body. CSV, NDJSON and GeoJSON hash the data only, so If-None-Match gives you a 304 whenever the snapshot has not moved. The JSON envelope carries a generated timestamp, so its ETag turns over each second: rely on the hour of cache rather than on conditional requests there.
Link: rel="license"The licence URL for the data in that response.
X-Sheff-LicenceThe licence name, so a script can check it without parsing the body.
X-Sheff-APIThe API version.

What you must credit

This is the part that matters, so it is stated plainly. Sheffield Events does not own this data and does not relicense it. Each dataset travels under the licence its publisher chose, and that licence comes with the response.

  • Credit the original publisher, not this site. The attribution field in meta is the exact wording the publisher asks for. Use it verbatim where you can.
  • Open Government Licence v3.0 datasets need the words "Contains public sector information licensed under the Open Government Licence v3.0".
  • CC BY and CC BY-SA datasets need the publisher named and the licence linked, and CC BY-SA needs anything you build from it shared on the same terms.
  • ODbL datasets, including OpenStreetMap, need the source credited and any derived database shared alike.
  • Figures worked out here rather than fetched, which means neighbourhood placement, counts, medians, correlations and the scorecards, are CC BY 4.0 and ask only that you credit Sheffield Events (sheff.events).
  • 11 datasets are listed in the catalogue but are not served, because their terms do not allow it. The catalogue says which, and why, and where to get them from the publisher instead. Please do not scrape them from the pages either.

Every response hands you a finished citation line, so there is no excuse for getting it wrong:

curl -s 'https://sheff.events/wp-json/sheff/v1/data/listed' | jq -r '.meta.citation_text'

# Data from Historic England National Heritage List, Open Government Licence v3.0,
# via Sheffield Events (sheff.events), retrieved 2026-09-14

How fresh it is, and how hard you may push

Refresh and limits
ThingThe answer
Refresh scheduleEach dataset has its own, from every fifteen minutes for live sensors to quarterly for the census. The sources page lists the schedule and the last good snapshot for every one of them, and last_refreshed in the catalogue is the machine-readable version.
Where the data comes fromSite cron fetches each publisher on its own schedule and stores a validated snapshot. Nothing you request here triggers a fetch, and no page render ever calls a publisher, so what you get is always the last good stored copy.
Rate limit300 requests per 5 minutes per address. Going over returns 429 with a Retry-After header. It is a guard against one crawler becoming everyone else's problem, not a paywall.
The polite way to bulk downloadAsk for the whole provider once with per_page=0 and cache it, rather than paging through it repeatedly. One CSV of everything costs one request.
Personal dataThere is none. Snapshots hold organisations, places, readings and public records. These endpoints never read member accounts, saves or messages.

Worked examples

Plain curl: one dataset as a spreadsheet

This downloads every listed building and scheduled monument in the city as a CSV you can open in Excel, LibreOffice or Google Sheets. The licence and the credit arrive as comment lines at the top of the file.

curl -sL 'https://sheff.events/wp-json/sheff/v1/data/listed/listed?format=csv&per_page=0' -o sheffield-listed-buildings.csv
head -5 sheffield-listed-buildings.csv

Straight onto a map

Any dataset whose records carry coordinates can come back as GeoJSON, which QGIS, Leaflet, Mapbox, R and geopandas all open without converting anything. Drop these two files into QGIS and you have every street tree the council has recorded and every food hygiene rating in the city, on a map, in about a minute.

curl -sL 'https://sheff.events/wp-json/sheff/v1/data/council_more/trees?format=geojson&per_page=0' -o sheffield-street-trees.geojson
curl -sL 'https://sheff.events/wp-json/sheff/v1/data/fsa/items?format=geojson&per_page=0'      -o sheffield-food-hygiene.geojson

Into pandas, with the credit kept

Fifteen lines that pull a whole neighbourhood scorecard table into a dataframe and print the attribution beside it, so the credit never gets separated from the numbers.

import pandas as pd, requests

BASE = 'https://sheff.events/wp-json/sheff/v1'
r = requests.get(f'{BASE}/areas/scores', params={'workings': 1}, timeout=30)
r.raise_for_status()
body = r.json()

scores = pd.DataFrame(body['data'])
print(scores[['name', 'overall', 'quiet', 'green', 'connected']].sort_values('overall', ascending=False).head(10))

print('\nCredit:', body['meta']['citation_text'])
for s in body['sources']:
    print(' -', s['name'], '|', s['licence'])

One neighbourhood, whole

The single most useful call on the site: everything inside one neighbourhood polygon in one response, with the derived figures alongside the raw points.

curl -s 'https://sheff.events/wp-json/sheff/v1/areas/crookes/data' | jq '.data.point_counts'
curl -s 'https://sheff.events/wp-json/sheff/v1/areas/crookes/data' | jq '.data.derived | keys'
curl -sL 'https://sheff.events/wp-json/sheff/v1/areas/crookes/data?format=geojson' -o crookes.geojson

A chart series, without the rows

curl -s 'https://sheff.events/wp-json/sheff/v1/data/healthstats/chart/le_male' | jq '{labels: .data.labels[-3:], unit: .data.unit}'
curl -sL 'https://sheff.events/wp-json/sheff/v1/data/deprivation/chart/deciles?format=csv'

In a browser, no build step

const res  = await fetch('https://sheff.events/wp-json/sheff/v1/data/nhs/rows?per_page=0');
const body = await res.json();
console.log(body.meta.attribution);
console.table(body.data.slice(0, 20));

When something comes back wrong

Error responses
StatusCodeWhat it means
403sheff_not_redistributedThe dataset exists and is used on the site, but its licence does not allow it to be served here. The message says why, and the body carries the licence and the publisher URL so you can go to the source.
404sheff_provider_not_foundNo dataset has that key. The catalogue at /data lists every valid key.
404sheff_part_not_foundNo part has that name. The message lists the parts this provider does have.
404sheff_chart_not_foundThat provider has no chart of that kind right now.
404sheff_area_not_foundNo neighbourhood has that id. List them at /areas.
429sheff_rate_limitedToo many requests from one address. Wait for Retry-After and cache what you already fetched.

Go and build something

This exists because public information about a city should not end up locked inside one person's website, and this is one person's website. Coursework, a dissertation, a school project, a community campaign, a newsroom graphic, a hobby map: all fine, all free, no permission needed. Commercial use is fine too wherever the original licence allows it, which for the Open Government Licence datasets it does.

If a record is wrong, the fix usually belongs upstream with the publisher, and the sources page says who that is. If the API itself is wrong, say so and it gets fixed.