Methodology
Data sources
Agency data is compiled from the following sources:
- ICE 287(g) participants list — the current official list of participating agencies published by ICE. Scraped and archived regularly.
- appelson/Tracking_287g — a community archiving effort that maintains historical ICE spreadsheets and individual MOA PDFs going back to 2016.
- FBI Law Enforcement Employees (LEE) — jurisdiction population, sworn officer and civilian counts, and staffing ratios (officers per 1,000 residents). Each row carries its own data year; we keep the most recent.
- Wikidata — agency website URLs sourced via SPARQL queries against the Wikidata knowledge graph.
- MuckRock — linked FOIA requests for individual agencies, sourced from MuckRock's public request database.
- U.S. Census Bureau Gazetteer — county, place, and county-subdivision centroid coordinates used to position agencies on the map.
- Geocod.io — a geocoding service used to locate the handful of agencies (university and airport police, regional authorities) the Census files don't recognize by name.
Matching agencies
Agency names vary across sources. We normalize names and use fuzzy string matching to link records across datasets, then hand-review ambiguous matches. Each agency in our index includes a confidence score for its cross-source matches.
Placing agencies on the map
The source data gives each agency's state and usually its county, but not a precise address. We place each agency at a representative point: municipal police are mapped to the center of their town or city, and county sheriffs and other county-level agencies to the center of their county, using U.S. Census Bureau gazetteer coordinates. A handful of agencies the Census files don't recognize — university and airport police, a few regional authorities — are located with the Geocod.io geocoding service. These are approximate points showing where an agency is based, not the area it operates in; jurisdiction boundaries are in the works.
Statewide agencies — state police, departments of corrections, and similar bodies — are not shown on the map, because a single dot would misrepresent a jurisdiction that covers the whole state. They remain in the data and in all counts.
A note about jurisdiction and population
Population jurisdiction has always been a fraught but useful metric in understanding the activities of law enforcement agencies. We include it here to provide a very rough sense of the scale of law enforcement involved in 287(g) agreements, while taking care not to overcount overlapping jurisdictions (e.g. the population of a city is contained by the population of the county).
Population data is from the FBI's Law Enforcement Employment dataset and reflects each agency's jurisdictional residential population — the residents of the area the agency serves, not necessarily the people encountering immigration enforcement. And jurisdiction size and enforcement scope diverge sharply by agency type and program model: a state highway patrol's jurisdiction is the whole state but its work looks nothing like a small-town police department's, and a county sheriff running a Jail Enforcement Model only touches people who get booked into the jail.
Limitations
- Some agencies have had agreements lapse and rejoin. Historical participation dates may be incomplete.
- MOA PDFs are not available for all agencies. We link to the appelson archive where available.
Automated summaries and data extraction
Two things on this site are produced with the help of a large language model. The per-state news roundups are generated from published coverage and the agencies' signed agreements using PromptQL, with links back to the original sources. And some agreement details shown on agency pages — signatory names and titles, points of contact, and budget or population figures — are extracted automatically from scanned agreement PDFs.
Automated extraction and summarization can be wrong. A model can misread a scanned document, attribute a figure to the wrong field, or state something with confidence that the source does not support. Treat every automated figure and summary as a lead to verify, not a settled fact — always check it against the linked original agreement or news article before relying on or republishing it. If you spot an error, please tell us.
How the per-state news is gathered
For each state the pipeline runs a statewide sweep that pulls candidate coverage from two complementary sources, then screens it. The two are paired on purpose, because they miss different things: Google News indexes a narrow, SEO-invested palette of mainstream outlets, while Perplexity casts a wider net across the open web — Substack, blogs, podcasts, and independent creators, where the long-tail, small-agency stories tend to live. Results from both are merged and de-duplicated by headline before anything else happens.
Perplexity (the sonar model) is queried with three angle prompts per state — one for hard news, one for online discourse (social posts, Substack, podcasts, and creator commentary), and one for legal actions (lawsuits, filings, and advocacy challenges). Scoping every prompt to a single state, rather than one national query, is deliberate: it forces much deeper recall, since an open-ended national prompt only surfaces the famous handful of stories. The three prompts, verbatim:
"Find news [from AFTER to BEFORE] about the ICE 287(g) program in the state of [STATE]: which local law enforcement agencies signed, expanded, or ended 287(g) agreements, and any reporting or controversy about immigration enforcement cooperation with ICE. Name specific agencies and counties, with sources."
"[AFTER to BEFORE], what are people saying on social media, Substack, blogs, podcasts, YouTube, and from independent content creators, advocates, and local commentators about the ICE 287(g) program in the state of [STATE]? Include 'discourse' beyond mainstream hard news — activist threads, creator commentary, community reaction. Name specific agencies/counties and link sources where possible."
"[AFTER to BEFORE], are there any lawsuits, court filings, legal challenges, ACLU/advocacy legal actions, or settlements related to the ICE 287(g) program in the state of [STATE]? Name the agencies/counties involved, the nature of the legal action, and cite sources."
Each call carries a fixed system instruction to stay factual, cite sources, and prefer recent reporting that names specific agencies and counties. The cost is trivial — roughly half a cent per call, about two cents per state for all three angles.
In parallel, the state is swept through the free Google News RSS search endpoint, bounded to the same date window, using six query variants to widen coverage:
"287(g)" [STATE] 287g [STATE] ICE [STATE] sheriff immigration enforcement ICE agreement [STATE] police 287g immigration ICE 287(g) [STATE] county jail [STATE] immigration enforcement local law enforcement ICEGoogle News returns opaque, redirect-style article links rather than clean publisher URLs. These are decoded downstream in a residential build, because they don't resolve from a datacenter IP.
Screening for relevance
The merged candidates pass through a language-model relevance screen that reads each item's headline, publication, and snippet and decides whether it is genuinely about the 287(g) program or local cooperation with ICE. The same pass extracts which agencies and counties an article is actually about, under strict rules: only sheriff's offices, police departments, state police and highway patrol, and jails or corrections that are a named subject of the story count — city councils, commissions, legislatures, mayors, governors, courts, and advocacy groups are excluded, and the list is left empty when uncertain rather than guessed. This is what filters out the classic false positives: wrong-state matches (Christian County, Missouri versus Christian County, Kentucky), weather stories about an 'ice storm,' and unrelated crime coverage. Only articles marked relevant feed the summary.
Grounding against authoritative data
News is treated as a point-in-time snapshot that can be stale or simply wrong, so it is never trusted on its own. Before any summary is written, the pipeline downloads ICE's current participating-agency roster, filters it to the state, and computes the authoritative agency count and county coverage. The narrative is anchored to that roster: where a story's claim conflicts with it, the roster wins, and program 'growth' is framed only as what the roster shows.
Each state also gets a statewide legislative posture — whether state law compels 287(g) participation, prohibits it, or leaves the choice to local agencies. The classifier is deliberately anchored: it defaults to no statewide law, moves to compels or prohibits only for a concrete, enacted, in-force statewide instrument (a statute, a governor's executive order, or established policy), keys off the substance of a law rather than whether it literally names '287(g),' and never changes a stance without a statutory basis in the text. A standing quality check then re-audits every state's stance against its own description — a text-only contradiction scan — to catch mislabels, such as an enacted anti-sanctuary law that the summary describes but that was wrongly scored as having no statewide law.
The result is written in plain, news-style prose — a two-sentence summary up top, with events and agencies as the subject — carries inline source links, and is produced in both English and Spanish from an identical set of links.
Updates
The pipeline is re-run regularly to capture new ICE announcements. The data snapshot date is shown on each page.
License & citation
Data compiled by this project is made available under a Creative Commons Attribution 4.0 International (CC BY 4.0) license. If you use this data, please attribute: Recovered Factory / 287(g) Watch (287g.recoveredfactory.net).
Contact
Questions, tips, corrections, or collaboration:
- Tory Lysik — lysiktory@gmail.com · tlysik.com
- David Eads — davideads@grupovisual.org · davideads.com
- Recovered Factory — recoveredfactory.net