Offendersearch
Methodology

Data methodology and provenance

Where the records come from, how current they are, how a match is judged, and what each jurisdiction publishes. Written for the person who has to defend the decision to embed this data inside their own product.

Sources of authority

Every record names the registry it came from

Records originate from the official sex-offender registry maintained by each state, territory and federal authority. There is no second class of data: nothing is derived from another aggregator, from private files, or from any source a jurisdiction did not itself publish.

The citation travels with the record

Every record carries source.jurisdiction, source.registryName and source.recordUrl — the registry’s own address for that registrant on its own site. A claim in a response can be taken back to the authority that made it.

One person, every registry they appear on

A registrant listed by more than one authority returns as a single record whose sources[] names each registry with its own link. Someone registered in South Carolina who works in Texas is one person, cited three ways, not three rows to reconcile.

Nothing is manufactured to fill a field

Where a registry publishes a year and not a date, we return the year. Where it publishes an age, we return the age. A birth year is never inferred from an age, and a day and month are never chosen to complete a partial date — an estimate served as a fact is the one error that cannot be audited later.

Coverage

58 registries, and what each of them publishes

A nationwide request covers 58 registries: all 50 states, the District of Columbia, the five US territories, and the federal NSOPW index. Jurisdictions differ in what they release, because each legislature decided that separately. The API states which case applies on every record rather than flattening them.

Date of birth

What the registry publishesJurisdictionsWhat the API returns
A full calendar date of birthThe majority of registries, including California, which publishes an exact date for effectively every registrantdob carries an ISO-8601 date; dobPrecision is "exact"
A birth year onlyMassachusetts, Georgia, North Dakota, Nevada and Pennsylvania — and Kansas on part of its registrydob is null, birthYear carries the year, dobPrecision is "year"
An age, and no date at allArizona, Maryland and Wisconsin, on every surface those registries renderdob and birthYear are null, age carries the value, dobPrecision is "unknown"

A record without a full date is still reachable by a name-and-date search. The widening happens when your query is matched, not when the record is stored, and the result says which kind of check was performed — see match strength.

Physical description

Maine is the statutory case: its registry publishes no physical description at all — no height, weight, eye or hair colour, and no scars, marks or tattoos — because state law releases those details only against a written request naming the requester. Twelve registries publish no scars-marks-and-tattoos field on any page they render: Kentucky, Nebraska, West Virginia, Idaho, South Dakota, Alaska, Texas, Illinois, Virginia, Georgia, Massachusetts and Maine. Around 28 others do, each at its own rate.

Addresses

The District of Columbia publishes block-level addresses by design (“2100 BLOCK OF NEW HAMPSHIRE AVENUE NW”) and no house numbers on any surface. Maine publishes a residence street only for registrants inside its tier scheme and the town alone for everyone else. Residence, employment and school addresses are published independently by a registry and need not agree, so addresses[] is an array with a type on each entry.

Risk classification

offense.riskLevel and offense.tier are the jurisdiction’s own assessment in the jurisdiction’s own vocabulary (“Sexually Violent Predator”, “Level 3”, “Tier II”). There is no cross-state scale and the API does not invent one. Florida publishes a registration status on every registrant and no risk level at all, which is why status lives in its own field rather than being folded in.

Which registry holds a person

registrationState is the registering authority; addressStates is where their published addresses are. They disagree constantly — a meaningful minority of registrants held by a state registry have no address in that state — so the API keeps them as two fields rather than one ambiguous “state”. Tribal registries are their own registering authority and are not mapped onto the state they sit inside.

Fields a single jurisdiction publishes

Some fields exist in one registry and nowhere else. They are named here rather than presented as national coverage, so nobody builds a feature on one of them by accident.

FieldPublished by
offense.federal — federal vs state convictionOklahoma
stateData.sentenceCompletionDateOklahoma
stateData.professionalLicensesUtah
stateData.birthCity / birthState — place of birthWyoming
stateData.shoeSizeTexas
stateData.buildMinnesota
stateData.district / psa / quadrantDistrict of Columbia
stateData.skinTone, residencyRestriction, employmentRestriction, exclusionZonesIowa

Per-jurisdiction fill rates move as registries republish, so they live in the field reference rather than on this page. See the API documentation and coverage by jurisdiction.

Freshness

Cadence is a contract term, not a claim

Records are refreshed against their issuing registry on a continuous nightly cycle. Rather than asserting a general currency figure, every response carries the timestamps and the per-source outcome for the request you actually made.

Per-record timestamps

lastCheckedAt is when that specific record was last confirmed against its source registry. sourceUpdatedAt is the registry’s own last-updated date and is null on most registries, because few publish one — a property of the registry, and stated rather than filled in.

Freshness chosen per request

Each request selects its tier: daily — the default, and the freshest data we hold — or weekly, the same dataset a step behind, at the base rate. It is a per-request parameter, not a property of your key, so batch work and live screening can run on one integration.

Every response states its own scope

counts.sourcesQueried, sourcesComplete, sourcesIncomplete and sourcesSkippedByScope report how many registries the request reached and how each resolved, and sourceStatus[] names them individually. An integrator branches on the scope of the answer rather than assuming it.

Matching

You set the confidence threshold, not us

A match is labelled with the evidence that produced it, so the decision about what counts as a hit stays inside your product. matchState is the field to branch on: it says how the record was checked against the date of birth or age you supplied, in terms of what the registry actually published.

matchStateWhat it means
dob_matchThe registry holds a full date of birth and it equals the date you queried. The strongest identity confirmation this API can return.
year_matchThe registry publishes only a birth year and that year equals your date’s year. The day and month were never checked, because the jurisdiction never published them.
age_matchThe registry publishes an age rather than a date, and that age agrees with the age your date implies, within a year for birthday drift.
no_dob_age_yearThe registry publishes no date, year or age for this registrant. The record is returned because the name matched, and it is flagged unverified so it can never be read as an identification.
age_mismatchThe name matched, the registry publishes an age, and that age contradicts your date. Returned only when you ask for it with onAgeMismatch: "flag" — "omitted" and "checked, and it disagrees" are different facts, and you decide which you want.
nullYou supplied no date of birth and no age, so there was nothing to verify against. Not a failed check.

Why not a single score

matchConfidence is published too, but it measures how much identity evidence is held — not the probability that this is your person. Two records at the same score can rest on different evidence, which is why the labelled state is the field to filter on and the score is the field to rank with.

Why a record was returned

matchBasis gives the qualified reason — lastName:exact, firstName:nickname, alias:prefix — and matchedName says whether the registered name or an alias matched. An alias hit and a legal-name hit are distinguishable at a glance.

Recall is a request parameter

match selects strict (exact names only), balanced (the default: nicknames, variants, initials, single typos) or broad (prefix and typo tolerance on the surname too). The same rules apply uniformly across all 58 registries.

Jurisdictional variation

Differences are returned, not smoothed over

Fifty-eight authorities publish to fifty-eight standards. The contract’s job is to make that difference legible in code rather than leave an integrator to infer it from an empty string.

Precision is a field, not an inference

dobPrecision states what the registry published — exact, year or unknown — so a year the registry printed is distinguishable from a year read off a full date. Every date inside offense and stateData carries its own datePrecision, and datesAsPublished preserves the registry’s literal text alongside the normalised ISO-8601 value.

Three-state flags, so absence is not a false

flags.absconder and flags.predator are true, false or null. null means the registry publishes no such designation, which is a different fact from a registry affirmatively reporting that the person does not carry it. A falsy check would merge the two.

The durable key is the registry’s own

sources[].recordUrl, with its jurisdiction, is the registry’s permanent address for that registrant. It is the value to store and to diff on, because it is the identifier the issuing authority will still honour next year — and it is what makes a record we return traceable by anyone who wants to check it.

Status and risk are separate questions

Whether someone is currently confined, absconded, deported, deceased or living in the community is stateData.status, in the jurisdiction’s own words. It is not a risk level, and the two are never merged — Florida’s nine status values and a New York tier answer different questions.

Corrections

Disputing or correcting a record

A registry entry is maintained by the authority that issued it, and that authority is the only party that can amend the official record. Both routes below are open to anyone, with no account and no charge.

If a record is about you

Ask the issuing jurisdiction to correct its entry — that is the change that lasts — and tell us at support@offendersearch.app. Include the name as published, the jurisdiction, and the link to the entry if you have it. We acknowledge within one business day, re-verify against what the registry currently publishes, and bring our copy into line with it. Full detail on the about page.

If you are integrating

Send the recordId, the source.recordUrl and the query that produced the response to support. Those three make the result reproducible on our side, which is what turns a report into a fix.

Every field, defined

The API reference documents each field, each enum value and each response guarantee, with per-jurisdiction detail.