Skip to contents

The uscis package provides tools to access and analyze USCIS (United States Citizenship and Immigration Services) processing times data through their API. This vignette demonstrates how to use the package to retrieve information about forms, their processing locations, and current processing times.

Setup

First, let’s load the required packages:

Basic Usage

Initialize Session

First, we need to initialize a session with USCIS to get the necessary cookies:

uscis_init_session()
#> [1] TRUE

Available Forms

Let’s retrieve the list of available USCIS forms:

forms <- uscis_forms()
head(forms)
#>                                                                 form_description_en
#> 1       Application for Replacement/Initial Nonimmigrant Arrival-Departure Document
#> 2                                                Petition for a Nonimmigrant Worker
#> 3                         Petition for a CNMI-Only Nonimmigrant Transitional Worker
#> 4                                                      Petition for Alien Fiancé(e)
#> 5                                                       Petition for Alien Relative
#> 6 Application for Travel Documents, Parole Documents, and Arrival/Departure Records
#>                                                                                  form_description_es
#> 1                     Solicitud para Reemplazar/Obtener Documento de Entrada/Salida de No Inmigrante
#> 2                                                               Petición de Trabajador No Inmigrante
#> 3                                   Petición de Trabajador Transicional No Inmigrante – Solo de CNMI
#> 4                                                            Petición de Prometido(a) Extranjero (2)
#> 5                                                                    Petición de Familiar Extranjero
#> 6 Solicitud de Documentos de Viaje, Documentos de Libertad Condicional y Registros de Entrada/Salida
#>   form_name
#> 1     I-102
#> 2     I-129
#> 3   I-129CW
#> 4    I-129F
#> 5     I-130
#> 6     I-131

Form Types

For each form, we can get its available subtypes:

form_types <- uscis_form_types(forms)
head(form_types)
#>   form_name form_key form_type
#> 1     I-102      142       142
#> 2     I-129    137-E     137-E
#> 3     I-129   137-E3    137-E3
#> 4     I-129 137-H1B1  137-H1B1
#> 5     I-129 137-H1B2  137-H1B2
#> 6     I-129 137-H1B3  137-H1B3
#>                                      form_type_description_en
#> 1              Initial issuance or replacement of a Form I-94
#> 2                            E - Treaty traders and investors
#> 3            E3 - Specialty occupation workers from Australia
#> 4      H-1B - Specialty occupation - Visa to be issued abroad
#> 5  H-1B - Specialty occupation - Change of status in the U.S.
#> 6 H-1B - Specialty occupation - Extension of stay in the U.S.
#>                                                        form_type_description_es
#> 1                               Emisión o reemplazo inicial del Formulario I-94
#> 2                                             E - Comerciantes e inversionistas
#> 3                 E-3 para Trabajadores Australianos en Trabajos Especializados
#> 4               H-1B - Ocupación especial - visa que se expedirá en el exterior
#> 5 H-1B - Ocupación especial - cambio de la condición migratoria en los E.E.U.U.
#> 6           H-1B - Ocupación especial - extensión de la estadía en los E.E.U.U.

Processing Offices

Now let’s get the offices that process each form type:

form_offices <- uscis_form_offices(form_types)
head(form_offices)
#>   form_name form_type office_code        office_description
#> 1     I-102       142         CSC California Service Center
#> 2     I-102       142         NBC  National Benefits Center
#> 3     I-102       142         NSC   Nebraska Service Center
#> 4     I-102       142         SSC      Texas Service Center
#> 5     I-102       142         ESC    Vermont Service Center
#> 6     I-129     137-E         CSC California Service Center

Processing Times

Finally, let’s get the current processing times. For this example, let’s just look at a subset of forms to keep the API calls manageable:

# Let's look at just I-130 forms as an example
i130_offices <- form_offices |>
  filter(form_name == "I-130")

processing_times <- uscis_processing_times(i130_offices)
head(processing_times)
#> # A tibble: 6 × 13
#>   form_name form_subtype office_code publication_date form_note_en form_note_es
#>   <fct>     <fct>        <fct>       <chr>            <lgl>        <lgl>       
#> 1 I-130     134A-F21     SCD         October 18, 2024 NA           NA          
#> 2 I-130     134A-F21     NBC         October 18, 2024 NA           NA          
#> 3 I-130     134A-F21     FOD         October 18, 2024 NA           NA          
#> 4 I-130     134A-IR      SCD         October 18, 2024 NA           NA          
#> 5 I-130     134A-IR      NBC         October 18, 2024 NA           NA          
#> 6 I-130     134A-IR      FOD         October 18, 2024 NA           NA          
#> # ℹ 7 more variables: range_upper <dbl>, range_upper_unit <fct>,
#> #   range_lower <dbl>, range_lower_unit <fct>, service_request_date <chr>,
#> #   subtype_info_en <chr>, subtype_info_es <chr>

Analysis Examples

Let’s turn now to do some basic analysis of the processing times data.

Before we begin, let’s standardize all times to months:

processing_in_months <- standardize_to_months(processing_times)
head(processing_in_months)
#> # A tibble: 6 × 13
#>   form_name form_subtype office_code publication_date form_note_en form_note_es
#>   <fct>     <fct>        <fct>       <chr>            <lgl>        <lgl>       
#> 1 I-130     134A-F21     SCD         October 18, 2024 NA           NA          
#> 2 I-130     134A-F21     NBC         October 18, 2024 NA           NA          
#> 3 I-130     134A-F21     FOD         October 18, 2024 NA           NA          
#> 4 I-130     134A-IR      SCD         October 18, 2024 NA           NA          
#> 5 I-130     134A-IR      NBC         October 18, 2024 NA           NA          
#> 6 I-130     134A-IR      FOD         October 18, 2024 NA           NA          
#> # ℹ 7 more variables: range_upper <dbl>, range_upper_unit <chr>,
#> #   range_lower <dbl>, range_lower_unit <chr>, service_request_date <chr>,
#> #   subtype_info_en <chr>, subtype_info_es <chr>

Overall Processing Times by Form

Let’s create a boxplot showing the distribution of processing times for each form:

ggplot(data = processing_in_months) +
  aes(x = form_name, y = range_upper) + 
  geom_boxplot() +
  labs(
    title = "Upper Range of Time (Months) for I-130 Form Across Offices", 
    subtitle = "Based on USCIS Processing Times", 
    y = "Months",
    x = "Form"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))

This visualization shows the overall distribution of processing times for each form type, helping identify which forms typically take longer to process.

Processing Times by Form and Office

We can also break this down by processing office to see variations in processing times across locations:

ggplot(data = processing_in_months) + 
  aes(x = reorder(office_code, range_upper), y = range_upper, color = office_code) + 
  geom_boxplot() +
  labs(
    title = "Upper Range of Time (Months) for the I-130 Form", 
    subtitle = "By Processing Office", 
    caption = "Based on USCIS Processing Times",
    y = "Months",
    x = "Form",
    color = "Office"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))

Refine by Form Subtype

We can further refine the analysis by looking at specific form subtypes:

ggplot(data = processing_in_months) + 
  aes(x = reorder(office_code, range_upper), y = range_upper, fill = office_code) + 
  geom_bar(stat = "identity") +
  facet_wrap(~ form_subtype, scales = "free", ncol = 2) +
  labs(
    title = "Upper Range of Time (Months) for the I-130 Form Across Subtypes", 
    subtitle = "By Processing Office",
    caption = "Based on USCIS Processing Times",
    y = "Months",
    x = "Form",
    color = "Office"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))

With this visualization, we can:

  1. Identify offices with consistently faster or slower processing times
  2. Understand the variation in processing times for specific forms
  3. Plan application submissions based on office processing speeds

Office Performance Analysis

We can also analyze which offices are generally faster or slower across all forms:

office_summary <- processing_in_months |>
  group_by(office_code) |>
  summarise(
    mean_processing_time = mean(range_upper, na.rm = TRUE),
    median_processing_time = median(range_upper, na.rm = TRUE),
    n_forms = n()
  ) |>
  arrange(mean_processing_time)

head(office_summary) |>
  knitr::kable(
    caption = "Fastest Processing Offices (Average Across All Forms)",
    digits = 1
  )
Fastest Processing Offices (Average Across All Forms)
office_code mean_processing_time median_processing_time n_forms
NBC 61.1 57.0 6
SCD 90.8 92.5 6
FOD 129.7 127.8 6

Summary Statistics

processing_times |>
  summarise(
    mean_upper = mean(range_upper),
    mean_lower = mean(range_lower),
    median_upper = median(range_upper),
    median_lower = median(range_lower),
    n_offices = n()
  )
#> # A tibble: 1 × 5
#>   mean_upper mean_lower median_upper median_lower n_offices
#>        <dbl>      <dbl>        <dbl>        <dbl>     <int>
#> 1       93.9       75.0         81.8         59.5        18

Saving Data

You can save the retrieved data to CSV files for later use:

write.csv(
  processing_times,
  file = paste0("processing-times-", Sys.Date(), ".csv"),
  row.names = FALSE
)

This will allow you to analyze the data further across time or share it with others.

Common Issues

  1. If you get authentication errors, try running init_uscis_session() again
  2. The API may have rate limits, so consider adding delays between requests for large queries
  3. Processing times data is updated periodically by USCIS, so results may vary

Important

The actual data may vary from when this vignette was built since the USCIS updates their processing times randomly.

Additional Options

You can also use the uscis package to:

  • Filter for specific form types
  • Compare processing times across different time periods
  • Analyze processing times by region
  • Track changes in processing times over time

The skies the limit with the data you have at your disposal!

Session Information

sessionInfo()
#> R version 4.4.2 (2024-10-31)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 22.04.5 LTS
#> 
#> Matrix products: default
#> BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3 
#> LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.20.so;  LAPACK version 3.10.0
#> 
#> locale:
#>  [1] LC_CTYPE=C.UTF-8       LC_NUMERIC=C           LC_TIME=C.UTF-8       
#>  [4] LC_COLLATE=C.UTF-8     LC_MONETARY=C.UTF-8    LC_MESSAGES=C.UTF-8   
#>  [7] LC_PAPER=C.UTF-8       LC_NAME=C              LC_ADDRESS=C          
#> [10] LC_TELEPHONE=C         LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C   
#> 
#> time zone: UTC
#> tzcode source: system (glibc)
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#> [1] ggplot2_3.5.1 dplyr_1.1.4   uscis_0.1.0  
#> 
#> loaded via a namespace (and not attached):
#>  [1] vctrs_0.6.5       cli_3.6.3         knitr_1.48        rlang_1.1.4      
#>  [5] xfun_0.48         purrr_1.0.2       generics_0.1.3    jsonlite_1.8.9   
#>  [9] labeling_0.4.3    glue_1.8.0        colorspace_2.1-1  htmltools_0.5.8.1
#> [13] rappdirs_0.3.3    scales_1.3.0      fansi_1.0.6       rmarkdown_2.28   
#> [17] grid_4.4.2        munsell_0.5.1     evaluate_1.0.1    tibble_3.2.1     
#> [21] fastmap_1.2.0     yaml_2.3.10       lifecycle_1.0.4   httr2_1.0.5      
#> [25] compiler_4.4.2    codetools_0.2-20  pkgconfig_2.0.3   farver_2.1.2     
#> [29] digest_0.6.37     R6_2.5.1          tidyselect_1.2.1  utf8_1.2.4       
#> [33] curl_5.2.3        pillar_1.9.0      magrittr_2.0.3    withr_3.0.2      
#> [37] tools_4.4.2       gtable_0.3.6