---
title: "Second update on ICE removals data released to the Deportation Data Project"
authors:
- name: "Graeme Blair"
url: "https://graemeblair.com"
affiliation: "Professor of Political Science, UCLA"
- name: "David Hausman"
url: "https://www.david-hausman.com"
affiliation: "Assistant Professor, UC Berkeley School of Law"
date: "2/17/2026" # make sure to change date
format:
html:
code-tools: true
fig-cap-location: top
reference-location: margin
appendix-cite-as: display
---
```{r}
library(tidyverse)
label_months <- function(x) {
labs <- format(x, "%B")
is_jan <- !is.na(x) & month(x) == 1
labs[is_jan] <- paste0(labs[is_jan], "\n", format(x[is_jan], "%Y"))
first_ok <- which(!is.na(x))[1]
if (!is.na(first_ok)) {
labs[first_ok] <- paste0(
format(x[first_ok], "%B"),
"\n",
format(x[first_ok], "%Y")
)
}
labs
}
knitr::opts_chunk$set(
dev = "svglite",
dev.args = list(
bg = "transparent",
system_fonts = list(sans = "Arial")
)
)
theme_minimal_transparent <- function(sz = 13) {
theme_minimal(base_size = sz) +
theme(
plot.background = element_rect(fill = "transparent", color = NA),
panel.background = element_rect(fill = "transparent", color = NA),
legend.background = element_rect(fill = "transparent", color = NA),
legend.box.background = element_rect(fill = "transparent", color = NA),
legend.position = "bottom",
axis.title.y = element_text(color = "grey30", margin = margin(r = 15)),
axis.title.x = element_text(color = "grey30", margin = margin(t = 15))
)
}
```
```{r}
#| label: setup
f_august <- tempfile(fileext = ".xlsx")
download.file(
"https://ucla.app.box.com/index.php?rm=box_download_shared_file&shared_name=9d8qnnduhus4bd5mwqt7l95kz34fic2v&file_id=f_1998579549029",
f_august,
mode = "wb"
)
removals_august <- readxl::read_excel(path = f_august, sheet = 1, skip = 6)
f_november <- tempfile(fileext = ".xlsx")
download.file(
"https://ucla.box.com/shared/static/8sf3s6hqfdcko9hngnl7mg6dabt0boy8.xlsx",
f_november,
mode = "wb"
)
removals_november <- readxl::read_excel(path = f_november, sheet = 1, skip = 6)
f_november_arrests <- tempfile(fileext = ".xlsx")
download.file(
"https://ucla.app.box.com/index.php?rm=box_download_shared_file&shared_name=9d8qnnduhus4bd5mwqt7l95kz34fic2v&file_id=f_2060643196534",
f_november_arrests,
mode = "wb"
)
arrests_november <- readxl::read_excel(path = f_november_arrests, sheet = 1, skip = 6) |> janitor::clean_names()
f_november_detention_stints <- tempfile(fileext = ".xlsx")
download.file(
"https://ucla.app.box.com/index.php?rm=box_download_shared_file&shared_name=9d8qnnduhus4bd5mwqt7l95kz34fic2v&file_id=f_2060645836144",
f_november_detention_stints,
mode = "wb"
)
detention_stints_november <-
bind_rows(
readxl::read_excel(path = f_november_detention_stints, sheet = 1, skip = 6),
readxl::read_excel(path = f_november_detention_stints, sheet = 2, skip = 6)
) |> janitor::clean_names()
f_august_arrests <- tempfile(fileext = ".xlsx")
download.file(
"https://ucla.app.box.com/index.php?rm=box_download_shared_file&shared_name=9d8qnnduhus4bd5mwqt7l95kz34fic2v&file_id=f_1998578415974",
f_august_arrests,
mode = "wb"
)
arrests_august <- readxl::read_excel(path = f_august_arrests, sheet = 1, skip = 6) |> janitor::clean_names()
f_august_detention_stints <- tempfile(fileext = ".xlsx")
download.file(
"https://ucla.app.box.com/index.php?rm=box_download_shared_file&shared_name=9d8qnnduhus4bd5mwqt7l95kz34fic2v&file_id=f_1951496267013",
f_august_detention_stints,
mode = "wb"
)
detention_stints_august <-
bind_rows(
readxl::read_excel(path = f_august_detention_stints, sheet = 1, skip = 6),
readxl::read_excel(path = f_august_detention_stints, sheet = 2, skip = 6)
) |> janitor::clean_names()
removals <-
bind_rows(
"Late Jul. 2025" = removals_august |>
janitor::clean_names() |>
mutate(in_arrests = unique_identifier %in% arrests_august$unique_identifier,
in_detention_stints = unique_identifier %in% detention_stints_august$unique_identifier) |>
select(departed_date, in_arrests, in_detention_stints, final_program),
"Mid-Oct. 2025" = removals_november |>
janitor::clean_names() |>
mutate(in_arrests = unique_identifier %in% arrests_november$unique_identifier,
in_detention_stints = unique_identifier %in% detention_stints_november$unique_identifier) |>
select(departed_date, in_arrests, in_detention_stints, final_program),
.id = "release"
) |>
filter(as.Date(departed_date) <= as.Date("2025-07-29"))
```
```{r, eval = FALSE}
removals |>
count(release, in_arrests, in_detention_stints)
```
```{r, eval = FALSE}
removals |>
filter(!in_arrests) |>
count(release, final_program == "Border Patrol") |>
mutate(prop = n / sum(n), .by = release)
removals |>
filter(!in_detention_stints) |>
count(release, final_program == "Border Patrol") |>
mutate(prop = n / sum(n), .by = release)
removals |>
# count(release, in_arrests, in_detention_stints, final_program == "Border Patrol") |>
summarize(prop_bp = mean(final_program == "Border Patrol"), .by = c(release, in_arrests, in_detention_stints)) |>
mutate(cat = case_when(
in_arrests & in_detention_stints ~ "In both",
in_arrests & !in_detention_stints ~ "In arrests only",
!in_arrests & in_detention_stints ~ "In detentions only",
TRUE ~ "In neither"
)) |>
select(-in_arrests, -in_detention_stints) |>
pivot_wider(names_from = cat, values_from = prop_bp)
```
In the Deportation Data Project’s most recent ICE data release, which runs through October 15, 2025, we did not post the removals or encounters files that ICE provided. We post these files now, despite our view that they likely contain significant errors, because we have not received a satisfactory explanation or a corrected version from ICE.
The Deportation Data Project seeks and posts original immigration enforcement data from the U.S. government. Generally, we post all data that we receive, but we do not post datasets when we believe they contain significant errors. Instead, we engage with the agency to seek corrected versions. Despite repeated efforts, we have not received corrected versions of these datasets, and we are therefore releasing them now with this short report describing the reasons that we believe they contain errors. Given these problems with the datasets, we recommend using them only to the extent that they can be joined with one of the tables that we believe are accurate: arrests, detainers, and detentions.^[We did not post the February or early June releases at all. The February release recorded 11,524 removals and the early June release 17,371 removals in fiscal year 2024, vastly below the counts from the ICE annual report for that year which states there were 271,484 removals (for the Feb. file, the data start 45 days late in the fiscal year on Nov. 15, 2023; the count is still vastly below expected for the period it does cover). We initially posted part of the data from the late June release: we believed at the time that the data for calendar year 2025 was correct, while the data before that clearly represented an undercount. After receiving the data ending in late July, we came to believe that the data in that earlier release for 2025 was in fact an overcount. We posted the data from late July. We did not post the data ending in Oct. until today while we sought clarification and correction.]
<!-- [The 2024 ICE [annual report](https://www.ice.gov/doclib/eoy/iceAnnualReportFY2024.pdf) -->
In this post, we explain the problems we have identified in the removals and encounters data and post the data to invite further analysis.
## Problems in the ICE removals data
When we receive data from the government, we compare it to past data releases and published government statistics.
When we received the October 2025 dataset (in late November), we found a problem with the removals and encounters table: the number of removals was drastically higher than the number in same period in the preceding release, and the number of encounters was substantially higher.^[The Oct. dataset records 656,436 removals, and the previous dataset ending in Jul. counted 528,441.] We believe that this indicates errors in the newer dataset; as we explained in a previous report, we believe, after discussions with the agency, that the late July 2025 removals release was correct.
We focus here on the problems with the removals dataset; the problems with the encounters data appear to be related, and they are on a smaller scale.
A simple way to see the problem with the October removals data is to compare weekly counts over time to those in the late July removals data, which we show in @fig-weekly-removals-plot. Until the last few weeks of the overlapping period, the datasets have strikingly different numbers in every week.
```{r}
#| label: fig-weekly-removals-plot
#| fig-cap: "Late July vs. Mid-October ICE removals counts by week. The green line shows removals according to the mid-October release; the orange line shows removals according to the late July release."
#| dev: "svglite"
#| dev.args: { bg: "transparent", system_fonts: { sans: "Arial" } }
plot_df <-
removals |>
mutate(week = lubridate::floor_date(departed_date, "week")) |>
# filter to before June 28
filter(
departed_date >= as.Date("2023-10-01"),
departed_date <= as.Date("2025-06-26")
) |>
mutate(release = factor(release)) |>
group_by(release, week) |>
count()
# filter(week < as.Date("2025-06-20"))
ggplot(plot_df, aes(week, n, color = release)) +
geom_line(lwd = 1) +
geom_vline(
xintercept = as.POSIXct(as.Date("2024-10-01")),
lty = 5,
color = "gray50"
) +
# add label for the line
annotate(
"text",
x = as.POSIXct(as.Date("2024-10-07")),
y = 10000,
label = "FY 2025",
# align left
hjust = 0,
color = "gray50"
) +
annotate(
"text",
x = as.POSIXct(as.Date("2024-09-25")),
y = 10000,
label = "FY 2024",
# align right
hjust = 1,
color = "gray50"
) +
scale_y_continuous(labels = scales::comma, limits = c(0, NA)) +
labs(
y = "Number of reported ICE removals per week",
color = "Data release"
) +
scale_color_manual(
values = c("Late Jul. 2025" = "#D95F02", "Mid-Oct. 2025" = "#1B9E77")
) +
# mak the dates show up as "May 2025"
scale_x_date(
breaks = function(x) {
seq(
floor_date(min(x, na.rm = TRUE), "quarter"),
ceiling_date(max(x, na.rm = TRUE), "quarter"),
by = "quarter"
)
},
labels = label_months
) +
theme_minimal_transparent() +
theme(
# add space between y axis and axis title
axis.title.y = element_text(margin = margin(r = 10)),
# remove x axis title
axis.title.x = element_blank(),
legend.position = "bottom"
)
```
## Why we believe the Jul. 2025 dataset is accurate and the Oct. 2025 dataset is not
We came to the conclusion that the end-of-July 2025 release was correct after ICE provided a detailed explanation of why it differed from the three previous releases and after we conducted our own comparisons to other sources.^[ We detail ICE’s explanation and our analyses in a [Sep. 2025 post](https://deportationdata.org/news/2025-09-29-update-ICE-removals.html) and in a [working paper](https://deportationdata.org/docs/ice/ice-data-preprint.pdf).] Comparing fiscal-year-by-fiscal-year and day-by-day, the end-of-July dataset lines up roughly with publicly-available ICE data and statistics and the October dataset does not.
First, we compare each dataset to the numbers in the relevant ICE annual report, from FY2024. That report states that “ERO removed 271,484 noncitizens with final orders of removal” (pg. 3). The dataset ICE released to us in late July reports a similar number: 282,214. By contrast, the October dataset records 342,582, more than 70,000 more removals than ICE’s annual report.
The late July dataset also more closely matches ICE’s detention management spreadsheets, published twice a month by Congressional mandate. The spreadsheets include a running cumulative count of the number of removals in the current fiscal year. We extracted each one and calculated the same running total from the data released by ICE to us ending in Jul. 2025 and in Oct. 2025. @fig-removals-vs-dtm shows that the numbers line up roughly for the late July 2025 release (blue, compared to detention management in red), and nearly exactly for fiscal year 2024. The newer dataset released to us ending in Oct. (green) includes many more removals than ICE’s own published figures (red).
```{r}
#| label: fig-removals-vs-dtm
#| fig-cap: "Comparison of Removals Counts for Late July and Mid October ICE Data Releases to ICE's Detention Management Spreadsheet. For the counts from the detention management spreadsheets in these figures, we use the date that the data was extracted (noted in the Footnotes tab). For example, the last count in the right panel comes from the July 7, 2025 detention management spreadsheet, for which the removals data was extracted on 6/28/2025."
#| dev: "svglite"
#| dev.args: { bg: "transparent", system_fonts: { sans: "Arial" } }
# removals |>
# mutate(fiscal_year = year(departed_date) + if_else(month(departed_date) >= 10, 1L, 0L)) |>
# count(release, fiscal_year)
dtm_df <-
arrow::read_feather("~/github/ice-detention-management/data/removals.feather") |>
mutate(fiscal_year = fiscal_year |> str_replace("FY", "") |> as.numeric() + 2000) |>
mutate(fiscal_year = if_else(file_date == as.Date("2024-11-15"), 2025, fiscal_year)) |>
arrange(pull_date) |>
mutate(diff = removals - lag(removals), .by = c("fiscal_year"))
core_counts_matching_dtm_dates <-
removals |>
group_by(release) |>
summarize(
`n_2023-10-10` = sum(as.Date(departed_date) >= as.Date("2023-10-01") & as.Date(departed_date) <= as.Date("2023-10-10")),
`n_2023-11-13` = sum(as.Date(departed_date) >= as.Date("2023-10-01") & as.Date(departed_date) <= as.Date("2023-11-13")),
`n_2023-11-27` = sum(as.Date(departed_date) >= as.Date("2023-10-01") & as.Date(departed_date) <= as.Date("2023-11-27")),
`n_2023-12-11` = sum(as.Date(departed_date) >= as.Date("2023-10-01") & as.Date(departed_date) <= as.Date("2023-12-11")),
`n_2023-12-26` = sum(as.Date(departed_date) >= as.Date("2023-10-01") & as.Date(departed_date) <= as.Date("2023-12-26")),
`n_2024-01-12` = sum(as.Date(departed_date) >= as.Date("2023-10-01") & as.Date(departed_date) <= as.Date("2024-01-12")),
`n_2024-01-22` = sum(as.Date(departed_date) >= as.Date("2023-10-01") & as.Date(departed_date) <= as.Date("2024-01-22")),
`n_2024-02-05` = sum(as.Date(departed_date) >= as.Date("2023-10-01") & as.Date(departed_date) <= as.Date("2024-02-05")),
`n_2024-02-20` = sum(as.Date(departed_date) >= as.Date("2023-10-01") & as.Date(departed_date) <= as.Date("2024-02-20")),
`n_2024-03-04` = sum(as.Date(departed_date) >= as.Date("2023-10-01") & as.Date(departed_date) <= as.Date("2024-03-04")),
`n_2024-03-18` = sum(as.Date(departed_date) >= as.Date("2023-10-01") & as.Date(departed_date) <= as.Date("2024-03-18")),
`n_2024-04-01` = sum(as.Date(departed_date) >= as.Date("2023-10-01") & as.Date(departed_date) <= as.Date("2024-04-01")),
`n_2024-04-15` = sum(as.Date(departed_date) >= as.Date("2023-10-01") & as.Date(departed_date) <= as.Date("2024-04-15")),
`n_2024-04-29` = sum(as.Date(departed_date) >= as.Date("2023-10-01") & as.Date(departed_date) <= as.Date("2024-04-29")),
`n_2024-05-13` = sum(as.Date(departed_date) >= as.Date("2023-10-01") & as.Date(departed_date) <= as.Date("2024-05-13")),
`n_2024-05-13` = sum(as.Date(departed_date) >= as.Date("2023-10-01") & as.Date(departed_date) <= as.Date("2024-05-13")),
`n_2024-06-10` = sum(as.Date(departed_date) >= as.Date("2023-10-01") & as.Date(departed_date) <= as.Date("2024-06-10")),
`n_2024-06-24` = sum(as.Date(departed_date) >= as.Date("2023-10-01") & as.Date(departed_date) <= as.Date("2024-06-24")),
`n_2024-07-08` = sum(as.Date(departed_date) >= as.Date("2023-10-01") & as.Date(departed_date) <= as.Date("2024-07-08")),
`n_2024-08-05` = sum(as.Date(departed_date) >= as.Date("2023-10-01") & as.Date(departed_date) <= as.Date("2024-08-05")),
`n_2024-08-19` = sum(as.Date(departed_date) >= as.Date("2023-10-01") & as.Date(departed_date) <= as.Date("2024-08-19")),
`n_2024-09-03` = sum(as.Date(departed_date) >= as.Date("2023-10-01") & as.Date(departed_date) <= as.Date("2024-09-03")),
`n_2024-10-28` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2024-10-28")),
`n_2024-10-28` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2024-10-28")),
`n_2024-11-12` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2024-11-12")),
`n_2024-11-25` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2024-11-25")),
`n_2024-12-09` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2024-12-09")),
`n_2024-12-23` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2024-12-23")),
`n_2025-01-06` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2025-01-06")),
`n_2025-01-21` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2025-01-21")),
`n_2025-01-21` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2025-01-21")),
`n_2025-02-18` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2025-02-18")),
`n_2025-02-18` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2025-02-18")),
`n_2025-03-03` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2025-03-03")),
`n_2025-03-17` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2025-03-17")),
`n_2025-03-31` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2025-03-31")),
`n_2025-04-14` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2025-04-14")),
`n_2025-04-28` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2025-04-28")),
`n_2025-05-12` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2025-05-12")),
`n_2025-05-27` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2025-05-27")),
`n_2025-06-09` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2025-06-09")),
`n_2025-06-23` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2025-06-23")),
`n_2025-07-07` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2025-07-07")),
`n_2025-07-21` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2025-07-21")),
`n_2025-08-04` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2025-08-04")),
`n_2025-08-18` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2025-08-18")),
`n_2025-09-02` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2025-09-02")),
`n_2025-09-15` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2025-09-15")),
`n_2025-11-10` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2025-11-10")),
`n_2025-11-28` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2025-11-28")),
`n_2025-12-11` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2025-12-11")),
`n_2025-12-26` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2025-12-26")),
`n_2026-01-22` = sum(as.Date(departed_date) >= as.Date("2024-10-01") & as.Date(departed_date) <= as.Date("2026-01-22"))
) |>
pivot_longer(-release, names_to = "week", values_to = "n") |>
mutate(week = as.Date(week, format = "n_%Y-%m-%d"),
fiscal_year = year(week) + if_else(month(week) >= 10, 1L, 0L)
) |>
arrange(release, week) |>
mutate(diff = n - lag(n), .by = c(release, fiscal_year))
bind_rows(
"CILP v. ICE" = core_counts_matching_dtm_dates,
"Detention Management" = dtm_df |> rename(week = pull_date, n = removals), .id = "source"
) |>
mutate(source = str_c(source, if_else(source == "CILP v. ICE", str_c("\n(", release, ")"), ""))) |>
filter(week >= as.Date("2023-10-01"), week <= as.Date("2025-06-26")) |>
ggplot(aes(week, n, color = source, group = interaction(source, fiscal_year))) +
geom_line(lwd = 1) +
scale_x_date(
breaks = function(x) {
seq(
floor_date(min(x, na.rm = TRUE), "quarter"),
ceiling_date(max(x, na.rm = TRUE), "quarter"),
by = "quarter"
)
},
labels = label_months
) +
scale_y_continuous(labels = scales::comma, limits = c(0, NA)) +
labs(y = "Number of removals", x = "Release date of ICE detention management spreadsheet", color = "Source") +
theme_minimal_transparent() +
theme(legend.position = "bottom")
```
## What are the extra removals in the October data?
We do not know why these releases differ, but our best guess is that the October release contains more removals that began with an arrest by Customs and Border Protection. This would match the fact that newly included removals do not match records from the arrests or detentions table, suggesting that ICE was only involved in their deportation (if in fact these are ICE removals at all).
Another piece of evidence for this hypothesis comes from the removals table itself. The “final program” field in the removals dataset indicates whether a removal began with a CBP arrest (although we are not sure that it does so consistently). In the Jul. release, among records that did not have a match in the detentions data, 96% were labeled “Border Patrol” under final program. By contrast, in the Oct. release, that figure was only 88%, suggesting that the newly included removals were likely border removals.
## What this means for our understanding of ICE data
The data from ICE in Oct. 2025 cannot reliably be used to study all ICE removals for the reasons outlined above. However, it is nonetheless possible, using information from the detentions table, to study the removals of noncitizens arrested in the interior of the United States (away from the border) who were then detained by ICE before being removed. We reported on those data in our [Jan. 2026 report](https://deportationdata.org/analysis.html), which showed that removals after detention quadrupled between the end of the Biden administration and the month leading up to the end of the Oct. 2025 data.
---
Download the Oct. 15, 2025 data:
* [Removals](https://ucla.box.com/shared/static/94ewjbpdhk8cn6uh7ndqvwx1df91vl4o.xlsx)
* [Encounters](https://ucla.box.com/shared/static/j8cvb5ekxhoedmg47yp6khe73qdkovwa.xlsx)