# UK Road Collision Records — DfT STATS19 (`nexgensignal/uk-road-collision-records`) Actor

Keyless, pay-per-record UK DfT STATS19 collision data. One row per collision — date, location, road, junction, conditions, severity, vehicle/casualty counts. Collision table ONLY; casualty/vehicle person tables never fetched; OGL v3.0; no person data.

- **URL**: https://apify.com/nexgensignal/uk-road-collision-records.md
- **Developed by:** [NexGen Signal](https://apify.com/nexgensignal) (community)
- **Categories:** Business, Developer tools, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $33.50 / 1,000 collision records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## UK Road Collision Records — DfT STATS19

**Keyless. Pay per record. Every reported road collision in Great Britain — collision facts only, no person data.**

This actor turns the **UK Department for Transport** STATS19 road-safety data into clean, per-collision records — the official record of road collisions reported by police across Great Britain. Each run reads the DfT's keyless **collision table** for the year you choose and delivers one row per collision: when and where it happened, the road and junction, the conditions, the severity, and the collision-level counts of vehicles and casualties. Collision grain, structured for engineering use, under the Open Government Licence, with a **hard privacy design: the casualty and vehicle person-attribute tables — sex, age, journey purpose, any person data — are never fetched, joined, or emitted.**

### What this is, in one paragraph

Police in Great Britain record every road collision involving personal injury under the STATS19 system, and the DfT publishes the result as three linked tables: collisions, casualties, and vehicles. The casualty and vehicle tables carry person-level attributes (the sex and age of drivers and casualties, journey purpose, and more). This actor reads **only the collision table** — the collision-level facts — and flattens each collision into a single analysis-ready record: date, time, and location, the police force, the road classes and junction detail, the speed limit, the light, weather, and road-surface conditions, the severity, and the collision-level counts of vehicles and casualties involved. The person tables are never touched. Values are exactly as reported. You are billed only for records actually delivered.

### Who buys this and for what job

- **Road-safety analysts, local authorities, and transport planners** mapping collisions by location, road type, severity, and conditions.
- **Insurance, telematics, and risk-modelling teams** enriching routes and areas with historical collision frequency and severity.
- **Researchers and journalists** studying road-safety trends by year, force, road type, and condition.
- **Data engineers** who want the STATS19 collision table as clean rows — with the person tables provably excluded — without downloading and reshaping the yearly CSVs.

### Open Government Licence — free commercial reuse

One licence rider travels on every record. DfT STATS19 data is published under the **Open Government Licence v3.0 (OGL v3.0)** — free to copy, publish, distribute, and adapt, **including commercially**, with the required attribution: "Contains public sector information licensed under the Open Government Licence v3.0." One honest caveat rides every record too: these are collisions as reported by police forces, not a legal determination of fault, and the collision-level counts are totals, not person records.

### Hard privacy design — collision table only, never the person tables

This is the defining property of this actor. The STATS19 casualty and vehicle tables carry **person attributes** — the sex and age of drivers and casualties, journey purpose, casualty class, home-area type. This actor **never fetches, joins, or emits any of them.** There is deliberately **no code path** to the casualty or vehicle files anywhere in the actor — the collision file is the only data door it knows. What it emits is strictly collision-level: geography, road, junction, conditions, severity, and the two collision-level **counts** (`number_of_vehicles`, `number_of_casualties`), which are totals, not people. A person-attribute guard runs on every record as a structural backstop, and the acceptance suite feeds a record deliberately polluted with driver and casualty sex, age, journey purpose, and a person name, and asserts that not one of those attributes — key or value — can ever appear in output. This mirrors the fleet's standing privacy posture: person-attributable content is a hard exclusion, not a narrowing exercise.

### Product grain — no person data

The unit of every record is a collision, never a person. Casualty and vehicle counts are carried verbatim as collision-level totals; no person, no name, no age, no sex, no journey purpose is read or emitted.

### Pricing

| Event | Free plan | Bronze | Silver | Gold / Platinum / Diamond |
|-------|-----------|--------|--------|---------------------------|
| `collision_record` | $0.05 | $0.045 | $0.04 | $0.0335 |

Delivered before charged. Blocked runs and empty results cost nothing.

### Input

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `reportingYear` | integer | 2023 | STATS19 collision reporting year. |
| `policeForce` | string | — | Optional. Keep only collisions for this police-force code. |
| `severity` | string | — | Optional. Keep only collisions of this severity code (1 fatal, 2 serious, 3 slight). |
| `maxRecords` | integer | 500 | Ceiling on records delivered and billed. |

### Output

One JSON object per collision. Real example (values as reported):

```json
{
  "record_id": "2023170L30113",
  "collision_index": "2023170L30113",
  "collision_year": 2023,
  "date": "18/01/2023",
  "day_of_week": "4",
  "time": "08:45",
  "police_force": "17",
  "collision_severity": "3",
  "number_of_vehicles": 1,
  "number_of_casualties": 1,
  "longitude": "-1.077081",
  "latitude": "54.611942",
  "road_type": "6",
  "speed_limit": 30,
  "light_conditions": "1",
  "weather_conditions": "1",
  "urban_or_rural_area": "1",
  "source": "UK DfT STATS19 collision table",
  "licence": "UK Department for Transport road safety (STATS19) ... Open Government Licence v3.0 ...",
  "disclaimer": "Road collision records ... casualty and vehicle person-attribute tables ... never fetched, joined, or emitted ...",
  "observed_at": "2026-08-21T00:00:00Z"
}
```

An unbilled `RUN_RECEIPT` records the robots check, the year and filters, rows seen and delivered, and whether charged equals delivered — plus a notice that only the collision table is read.

### Field reference

Each record is one collision. Identity: `record_id` / `collision_index` and `collision_year`. When: `date`, `day_of_week`, and `time`. Where: `longitude`, `latitude`, `location_easting_osgr`, `location_northing_osgr`, `local_authority_district`, `local_authority_ons_district`, `local_authority_highway`, and `lsoa_of_accident_location`. Road and junction: `first_road_class`, `first_road_number`, `road_type`, `speed_limit`, `junction_detail`, `junction_control`, `second_road_class`, and `second_road_number`. Crossings and conditions: `pedestrian_crossing_human_control`, `pedestrian_crossing_physical_facilities`, `light_conditions`, `weather_conditions`, `road_surface_conditions`, `special_conditions_at_site`, and `carriageway_hazards`. Context: `police_force`, `collision_severity`, `urban_or_rural_area`, `did_police_officer_attend_scene_of_accident`, and `trunk_road_flag`. Counts (collision-level totals): `number_of_vehicles` and `number_of_casualties`. Provenance: `source`, `source_url`, `licence`, `attribution`, `disclaimer`, and `observed_at`.

Note: `pedestrian_crossing_*` are **site facility** codes (what crossing control exists at the location), not person attributes; `number_of_casualties` is a **count**, not a person record.

### How a run works

A run first re-reads the source host's robots posture from your runtime — the DfT data host — and stops at the door if a Disallow ever covers the collision path. It then streams the **collision** CSV for your chosen year — the only file the actor knows how to reach — and flattens each collision to one record, reading a strict collision-only whitelist of fields and carrying the vehicle and casualty **counts** verbatim, delivered **before** it is charged, so a blocked or empty run costs you nothing. Your optional `policeForce` and `severity` filters are applied before delivery, and the actor stops at your `maxRecords` ceiling and records `charge_equals_delivered` in the receipt.

### Coverage and scope

A single reporting year holds on the order of **100,000+ reported collisions** across Great Britain. Because each record carries `collision_year` and `collision_index`, year-over-year work is a simple join, and the geography, road, and condition fields support mapping and hotspot analysis. Pull one year to analyse, several years to build a trend, or filter by `policeForce` or `severity` to isolate a region or the fatal/serious subset.

### Cost guidance

One `collision_record` per delivered collision: cost = collisions delivered × your plan's per-record price. Scope with `severity` or `policeForce`, and cap with `maxRecords`. A whole year is ~100,000 collisions; 1,000 collisions is **$50** (Free) / **$33.50** (Gold).

### Honest limitations

- **Collision table only.** By design, this actor reads only the collision table; the casualty and vehicle person-attribute tables are never fetched, joined, or emitted.
- **Counts, not people.** `number_of_vehicles` and `number_of_casualties` are collision-level totals, not person records.
- **As reported.** Values are coded exactly as police forces report them (STATS19 codes); this actor reformats, it does not decode or interpret fault.
- **No person data** of any kind.

### Differentiation

This is a **net-new** category for the NexGenData fleet — no existing fleet actor covers UK road collisions. It is distinct from any vehicle-recall, emissions, or transport-freight cell, and — critically — from the person-level STATS19 casualty and vehicle tables, which this actor deliberately excludes. Its specific job is the **DfT STATS19 collision table** — collision facts and counts, with the person tables provably out of scope.

### The NexGen Signal family

Part of the NexGen Signal family of pay-per-record data products:

- [UK Company Status Records — Companies House](https://apify.com/nexgensignal/uk-company-status-records)
- [UK Tariff Commodity Records — HS Codes & Taxonomy](https://apify.com/nexgensignal/uk-tariff-commodity-records)
- [UK Gender Pay Gap Records — Employer Reports](https://apify.com/nexgensignal/uk-gender-pay-gap-records)
- [UK Contract Opportunity Records](https://apify.com/nexgensignal/uk-contract-opportunity-records)
- [EU Regulatory Change Records — CELLAR](https://apify.com/nexgensignal/eu-regulatory-change-records)

*Source: UK Department for Transport, STATS19 road safety data (data.dft.gov.uk). Contains public sector information licensed under the Open Government Licence v3.0 — free to reuse, including commercially, with attribution. Collision table only; the casualty and vehicle person-attribute tables (sex, age, journey purpose, any person data) are never fetched, joined, or emitted. Casualty and vehicle counts are collision-level totals, not person records. Collisions as reported by police, not a determination of fault.*

# Actor input Schema

## `reportingYear` (type: `integer`):

STATS19 collision reporting year (e.g. 2023).

## `policeForce` (type: `string`):

Optional. Keep only collisions for this police-force code.

## `severity` (type: `string`):

Optional. Keep only collisions of this severity code (1 fatal, 2 serious, 3 slight).

## `maxRecords` (type: `integer`):

Maximum records delivered and billed.

## Actor input object example

```json
{
  "reportingYear": 2023,
  "maxRecords": 500
}
```

# Actor output Schema

## `results` (type: `string`):

Delivered records.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "reportingYear": 2023,
    "maxRecords": 500
};

// Run the Actor and wait for it to finish
const run = await client.actor("nexgensignal/uk-road-collision-records").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "reportingYear": 2023,
    "maxRecords": 500,
}

# Run the Actor and wait for it to finish
run = client.actor("nexgensignal/uk-road-collision-records").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "reportingYear": 2023,
  "maxRecords": 500
}' |
apify call nexgensignal/uk-road-collision-records --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nexgensignal/uk-road-collision-records"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/grVwcXgsChvww8AFe/builds/ybhYLiJyvvcdmxzUX/openapi.json
