INSIDE MICHIGAN/ A humane public-data project
142,592 · records  ·  520,719 · sentences
VOL. I · NO. 01 · A PUBLIC-DATA PROJECT

People,
not offenders.

Michigan public corrections records describe 142,592 lives behind a difficult legacy web form. Inside Michigan turns that public record into a humane research tool. Every figure you see comes from the public record. Every design choice is ours to make.

LAST REVIEWED · 2026-05-29 · SH

Methodology / colophon

Numbers before claims.

This page names the source, the timing, the known gaps, and the public export surface behind People Not Numbers. A reader should be able to cite an aggregate without guessing where it came from.

142,592

records in the local mirror

520,719

sentence rows parsed from source profiles

83

Michigan counties represented

§ source

Source

The primary source is the Michigan Department of Corrections OTIS public search and profile system.1 The scraper records the current OTIS flow first, then falls back to the legacy profile URL when that is the only route that returns a record. The mirror keeps the profile source URL, the scrape timestamp, and the parsed sentence fields.

Primary sourceMichigan Department of Corrections OTIS public profile records.
Current flowGET /otis2/Search, POST /otis2/Search, then POST /OTIS2/Results to load the profile page.
Legacy fallbackOTIS2/otis2profile.aspx?mdocNumber={zero-padded MDOC number}.
Local mirrorSQLite offenders.db, with source_url and scraped_at retained for every mirrored profile.
Photos107,772 local photo files, served only after opt-in.

The public site uses aggregates from the mirror. It does not present the mirror as a court file, a live custody check, or a complete case history. OTIS is an administrative source. That fact is useful. It is also a limit.

§ cadence

Cadence

The local database shows a bulk scrape window from 2026-03-05 to 2026-03-13. A bounded refresh run finished at 2026-05-14T00:57:52Z; the newest row-level scrape timestamp observed locally is 2026-05-13T20:57:51.424308. Aggregate statistics were recomputed at 2026-06-01T01:20:52Z.

That means the dashboard is not a live feed. The citable date for aggregate figures is the stats recompute timestamp. For individual custody, supervision, or release questions, check OTIS directly before publication.

§ aggregates

Aggregates + Census baselines

The current stats payload contains 142,592 records, 520,719 sentence rows, 83 counties, and 31,849 records whose current status is canonicalized as Prisoner. The race comparison columns use Census ACS 5-year data profiles where baseline percentages are shown.2

Baselines are denominators, not explanations. A difference between an OTIS aggregate and an ACS baseline is the start of a reporting question. It is not a causal claim by itself.

  • totalsRecord, sentence, county, custody, and sentence-per-person totals.
  • raceStatewide OTIS race aggregate with the statewide Census baseline column.
  • statusCanonicalized current-status counts from the public mirror.
  • ageAge buckets computed from date-of-birth fields at stats build time.
  • genderMale and female counts as published by the source record.
  • convictionPlea, trial, nolo contendere, and unknown conviction-method counts.
  • sentencingMinimum, maximum, median, and life-or-40-plus sentence summary fields.
  • decadeSentence-row volume grouped by sentence decade.
  • countiesTop county sentence counts with metro labels and Census baseline fields.
  • county-raceTop county race shares with county Census baseline columns.
  • facilitiesCurrent-prisoner facility counts from source location fields.
  • offensesTop offense labels with local category assignment.
  • sentence-lengthMinimum and maximum sentence buckets from parsed sentence rows.
  • census-baselinesStatewide and top-county baseline percentages used for comparison.

§ known gaps

Known gaps

County-jail populations are outside the source. Juvenile and youth records are outside the source. Sealed, expunged, removed, corrected, or delayed records may be absent or stale. The mirror also inherits OTIS field choices: race categories are source categories, offense labels are source labels, and some sentence rows do not carry the same detail as others.

The county and facility views are aggregate views. They should not be read as the full legal geography of a person's case. They are useful for scale and distribution. They are not a docket.

§ privacy defaults

Privacy defaults

Photos are hidden by default. Birth dates are reduced to year-level display where the public interface does not need the full date. Marks, scars, and tattoos are treated as sensitive descriptive fields, not browse material. Lookup pages are excluded from indexing; aggregate and methodology pages are indexable.

These defaults do not make a public record private. They make publication less casual. The design choice is to reveal only what the reader deliberately asks to see.

§ corrections

Corrections

Corrections, photo-removal requests, and source disputes go to [email protected]. Include the MDOC number, the field in dispute, and a public source or document if one exists. If the subject is a person, the first obligation is right-of-reply.

Corrections are handled at the interface and source-note level first. If the source itself changes, the next refresh should carry that change through to the aggregate layer.

§ reproducibility

Reproducibility

Every public aggregate exposed on this page has a CSV route under /api/exports/{slug}. Each row carries computed_at. The route returns the current stats payload when the local FastAPI service is available and falls back to the checked-in launch fixture when it is not.

The build script that produces the stats payload walks offenders.db, parses the sentence JSON, canonicalizes status and race fields, and writes stats.json. The public CSVs are aggregate exports only. They are not a normalized row-level republication of every person in the mirror.

§ last reviewed

Last reviewed

This methodology page was last reviewed on 2026-05-29. The stamp is derived from the latest git commit touching this page, with a static fallback for builds that do not have git metadata.