Case study

CrimeStats.co.nz

Python/FastAPI + Next.js

PythonFastAPINext.jsSupabaseRedis

Key outcomes

Fast APIs via caching
SEO at scale
Automated ingest pipeline

The Problem

New Zealand Police publish crime statistics, but they are released as bulk data dumps—spreadsheets and PDFs that require significant processing to be useful. Citizens looking for safety information about a suburb have nowhere to go except the raw data or outdated news articles.

The platform turns that raw data into a fast, searchable, SEO-indexed resource: every suburb in New Zealand with its own crime profile, safety score, and historical trend data.

What Was Built

CrimeStats.co.nz is a full-stack analytics platform with two primary components: a Python/FastAPI data backend and a Next.js frontend with per-suburb static pages.

Automated Ingest Pipeline

The ingest pipeline runs on a schedule and:

  1. Fetches the latest NZ Police crime data from published endpoints
  2. Validates the schema against expected column names, types, and value ranges
  3. Deduplicates records using a composite key (location + crime type + date period)
  4. Writes clean records to Supabase with backfill detection for late-arriving data

The pipeline is idempotent—re-running it on the same data produces the same database state. This is critical for reliability: if the pipeline fails mid-way, re-running it does not corrupt the data.

Safety Score Engine

Each suburb receives a Safety Score computed by the NZ-CHI v7.3 algorithm—a composite index that weights crime types by severity, adjusts for population density, and applies fairness controls to avoid penalising areas with high reporting rates (which often indicate better police coverage, not worse safety).

The fairness controls were an important design requirement. A naive crime-count-per-capita metric systematically disadvantages urban areas and Māori communities with historically high police presence. The NZ-CHI weighting corrects for this.

Geospatial Processing

Suburb boundaries come from Statistics New Zealand shapefiles. GeoPandas and Shapely handle the geometry: point-in-polygon queries for assigning crime records to suburbs, area calculations for density normalisation, and boundary simplification for efficient map rendering.

SEO at Scale

Every suburb in New Zealand has a statically generated page with:

  • Its own URL (/suburb/[suburb-name])
  • Structured JSON-LD markup (LocalBusiness, Place schemas)
  • Meta description with the suburb's safety score and top crime categories
  • Historical trend charts rendered server-side

Static generation means Google indexes every page efficiently. The site ranks for "[suburb name] crime statistics" queries because each page is genuinely useful, not a thin content farm.

Caching Architecture

The FastAPI backend uses Redis for two caching layers:

  • API response cache: suburb summary data is cached for 1 hour. Crime statistics do not change minute-to-minute.
  • Aggregation cache: city-wide and regional aggregates are expensive to compute and cached for 24 hours.

This keeps API costs low and response times under 100ms for cached paths.

Key Engineering Decisions

Fairness controls in the scoring algorithm. The decision to implement NZ-CHI v7.3 rather than a simpler crime-count metric was driven by the client's commitment to responsible data presentation. The algorithm is documented in the codebase so users can understand how scores are derived.

Idempotent ingestion. The composite deduplication key was designed from day one to support re-runs. This made the scheduled ingest safe to run without human supervision.

Per-suburb static pages over a single map UI. The SEO impact of per-page static generation is dramatically higher than a single-page application with dynamic data loading. Google can index and cache 2,000+ suburb pages independently.

Scope

  • Automated NZ Police data ingest with validation & deduplication
  • Safety Score engine (NZ-CHI v7.3) with fairness controls
  • FastAPI + Supabase + Redis caching for fast APIs
  • SEO: per-suburb static pages, JSON-LD markup
  • GeoPandas/Shapely for geospatial data processing
Like what you see?

Waqas Raza

AI-Native Full-Stack Engineer. Top Rated on Upwork · $180K+ earned · 93% job success. I build production AI agents, LLM systems, Web3 platforms, and full-stack applications.

Hire me on Upwork