Health — entry 020 of 23

Open Data NHS Scotland

Verified Jul 2026

Public Health Scotland's open-data portal is a keyless CKAN instance covering GP practices, prescribing, hospital admissions, and population health statistics for Scotland, queryable via the standard CKAN Action API (datastore_search, datastore_search_sql) with no registration. A live GET against the site's api/3/action endpoints succeeds without a key. A live Origin-header probe (both a plain GET and an OPTIONS preflight) against the same host returns no Access-Control-Allow-Origin header, so the stored 'unknown' cors resolved to 'no'.

Public Health Scotland's open-data portal is a keyless CKAN instance covering GP practices, prescribing, hospital admissions, and population health statistics for Scotland, queryable via the standard CKAN Action API (`package_show`, `datastore_search`, `datastore_search_sql`) with no registration. A live GET against `datastore_search` this run succeeded without a key and returned a real GP-practice record; both a plain GET and an OPTIONS preflight with an `Origin` header returned no `access-control-allow-origin` header at all, confirming the stored `cors: no`.

healthgovernmentscotlandopen-datastatistics
AuthenticationNone requiredCall it straight away — no key, no signup.
HTTPSSupportedTraffic is encrypted in transit.
CORSDisabledBrowser calls need a server-side proxy.
PricingFreeNo paid tier — free for the documented use case.
FormatsJSONResponses can be requested as JSON.

GreatAPIs Score

Score88out of 100
Authentication25/25No authentication required
Pricing20/20Free to use
Docs14/20Documentation URL provided
Formats9/15Single response format
Freshness20/20Verified within 6 months

Embed this badge

Scored 88 on greatapis.com
<a href="https://greatapis.com/api/open-data-nhs-scotland/"><img src="https://greatapis.com/badge/open-data-nhs-scotland.svg" alt="Scored 88 on greatapis.com"></a>

Auth quickstart

  1. No API key required. Every action is a GET (or POST) against `/api/3/action/<action_name>` with query params -- confirmed live this run against `package_show` and `datastore_search`.
Stored keyNo key stored

Your key is stored only in this browser (localStorage) and sent directly to the API — never to greatapis.

Query one record from a GP-practice datastore resource

GEThttps://www.opendata.nhs.scot/api/3/action/datastore_search?resource_id=0032ce94-f7f6-44dd-879c-7d3074d8e2e8&limit=1

200 application/json;charset=utf-8

{"help": "https://www.opendata.nhs.scot/api/3/action/help_show?name=datastore_search", "success": true, "result": {"include_total": true, "resource_id": "0032ce94-f7f6-44dd-879c-7d3074d8e2e8", "fields": [{"type": "int", "id": "_id"}, {"type": "numeric", "id": "PracticeCode"}, {"type": "text", "id": "GPPracticeName"}, {"type": "numeric", "id": "PracticeListSize"}, {"type": "text", "id": "AddressLine1"}, {"type": "text", "id": "AddressLine2"}, {"type": "text", "id": "AddressLine3"}, {"type": "text", "id": "AddressLine4"}, {"type": "text", "id": "Postcode"}, {"type": "text", "id": "TelephoneNumber"}, {"type": "text", "id": "PracticeType"}, {"type": "text", "id": "HB"}, {"type": "text", "id": "HSCP"}, {"type": "text", "id": "DataZone"}, {"type": "text", "id": "GPCluster"}], "records_format": "objects", "records": [{"_id":1,"PracticeCode":10002,"GPPracticeName":"Muirhead Medical Centre","PracticeListSize":8559,"AddressLine1":"Muirhead Medical Centre","AddressLine2":"Liff Road","AddressLine3":"Muirhead","AddressLine4":"","Postcode":"DD2 5NH","TelephoneNumber":"01382 580 264","PracticeType":"GMS","HB":"S08000030","HSCP":"S37000007","DataZone":"S01007129","GPCluster":"Dundee 4"}], "limit": 1, "_links": {"start": "/api/3/action/datastore_search?limit=1&resource_id=0032ce94-f7f6-44dd-879c-7d3074d8e2e8", "next": "/api/3/action/datastore_search?offset=1&limit=1&resource_id=0032ce94-f7f6-44dd-879c-7d3074d8e2e8"}, "total": 879}}

Developer reference

Base URLhttps://www.opendata.nhs.scot/api/3/action/

Gotchas & limits

  • `resource_id` values are tied to a specific quarterly CSV upload, not a stable long-lived identifier for "the current GP practice list": the id pinned above (`0032ce94-f7f6-44dd-879c-7d3074d8e2e8`) is this run's July 2026 release -- a live `package_show?id=gp-practice-contact-details-and-list-sizes` this run listed a fresh `resource_id` for every quarter back to 2018, so re-discover the current one via `package_show` before hardcoding it.
  • An invalid `resource_id` is a real HTTP 404 with a CKAN error envelope, not a 200: a live `datastore_search?resource_id=00000000-0000-0000-0000-000000000000` this run returned `{"success": false, "error": {"message": "Not found: Resource \"00000000-0000-0000-0000-000000000000\" was not found.", "__type": "Not Found Error"}}` at status 404 -- check both the HTTP status and `success` before reading `result`.
  • The SQL variant `datastore_search_sql` is enabled and equally keyless: a live `SELECT * FROM "<resource_id>" LIMIT 1` against the same resource this run returned 200 with a `success: true` envelope and the matching row -- useful for filters CKAN's own `datastore_search` query params can't express, but it accepts arbitrary read-only SQL, so treat it as a public read replica rather than a locked-down endpoint.
  • No CORS support at all, even for preflight: a live `OPTIONS` request with `Origin` and `Access-Control-Request-Method` headers this run returned HTTP 200 with `Allow: HEAD, GET, POST, OPTIONS` but no `access-control-allow-origin` or any other CORS response header -- browser-side calls need a server-side proxy.