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/v1The 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.
| Route | What comes back | Parameters | Formats |
|---|---|---|---|
/data | The 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. | fields | JSON |
/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, format | JSON, 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, format | JSON, 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. | format | JSON, CSV |
/areas/{slug}/data | Everything 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, format | JSON, CSV, GeoJSON |
/areas/scores | Every 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, format | JSON, 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:
| Header | What it is for |
|---|---|
Cache-Control | public, max-age=3600 with stale-while-revalidate. Data responses are cached for an hour, because the snapshot behind them only changes on a schedule. |
ETag | A 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-Licence | The licence name, so a script can check it without parsing the body. |
X-Sheff-API | The 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-14How fresh it is, and how hard you may push
| Thing | The answer |
|---|---|
| Refresh schedule | Each 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 from | Site 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 limit | 300 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 download | Ask 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 data | There 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.csvStraight 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.geojsonInto 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.geojsonA 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
| Status | Code | What it means |
|---|---|---|
| 403 | sheff_not_redistributed | The 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. |
| 404 | sheff_provider_not_found | No dataset has that key. The catalogue at /data lists every valid key. |
| 404 | sheff_part_not_found | No part has that name. The message lists the parts this provider does have. |
| 404 | sheff_chart_not_found | That provider has no chart of that kind right now. |
| 404 | sheff_area_not_found | No neighbourhood has that id. List them at /areas. |
| 429 | sheff_rate_limited | Too 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.