epidatr v5 API demo

Code
library(dplyr)
library(ggplot2)
library(epidatr)

Metadata

Let’s check the source-specific metadata for nssp.

Code
meta_nssp <- epidata_meta(source = "nssp")
meta_nssp$nssp$signals
#> [1] "pct_ed_visits_ari"       "pct_ed_visits_combined" 
#> [3] "pct_ed_visits_covid"     "pct_ed_visits_influenza"
#>  [ reached 'max' / getOption("max.print") -- omitted 5 entries ]
meta_nssp$nssp$geo_types
#> [1] "census_division" "census_region"   "county"          "hhs"            
#>  [ reached 'max' / getOption("max.print") -- omitted 5 entries ]
meta_nssp$nssp$version_range
#> NULL
meta_nssp$nssp$time_value_range
#> NULL

Basic Queries

We can pull the latest snapshot of a signal. We bound the request with reference_time to keep the download small; leaving it at the default "*" fetches the full history.

Code
nssp_data <- epidata_snapshot(
  source = "nssp",
  signal = "pct_ed_visits_influenza",
  geo_type = "state",
  reference_time = epirange("2024-10-01", "2025-01-01")
)
head(nssp_data)
#> # A tibble: 6 × 7
#>   signal         report_time geo_type geo_value fill_method reference_time value
#>   <chr>          <date>      <chr>    <chr>     <chr>       <date>         <dbl>
#> 1 pct_ed_visits… 2026-06-26  state    ak        source      2024-10-05     0.320
#> 2 pct_ed_visits… 2026-06-26  state    ak        source      2024-10-12     0.410
#> 3 pct_ed_visits… 2026-06-26  state    ak        source      2024-10-19     0.400
#> 4 pct_ed_visits… 2026-06-26  state    ak        source      2024-10-26     0.770
#> # ℹ 2 more rows

If you want to inspect the API request URL or query structure without actually fetching the data, you can use the dry_run argument via fetch_args_list():

Code
dry_run_call <- epidata_snapshot(
  source = "nssp",
  signal = "pct_ed_visits_influenza",
  geo_type = "state",
  fetch_args = fetch_args_list(dry_run = TRUE)
)
dry_run_call
#> 
#> ── <epidata_call> object: ──────────────────────────────────────────────────────
#> • Pipe this object into `fetch()` to actually fetch the data
#> • Request URL:
#>   https://delphi.cmu.edu/epidata/v5/snapshot/?source=nssp&signal=pct_ed_visits_influenza&geo_type=state

Filtering by specific geographies and versions:

Code
pa_ca_data <- epidata_snapshot(
  source = "nssp",
  signal = "pct_ed_visits_influenza",
  geo_type = "state",
  geo_values = c("PA", "CA"),
  reference_time = epirange("2024-10-01", "2025-01-01"),
  snapshot_date = "2025-01-01" # fetch data as it was known on this date
)
head(pa_ca_data)
#> # A tibble: 6 × 7
#>   signal         report_time geo_type geo_value fill_method reference_time value
#>   <chr>          <date>      <chr>    <chr>     <chr>       <date>         <dbl>
#> 1 pct_ed_visits… 2024-12-27  state    ca        source      2024-10-05     0.140
#> 2 pct_ed_visits… 2024-12-27  state    ca        source      2024-10-12     0.140
#> 3 pct_ed_visits… 2024-12-27  state    ca        source      2024-10-19     0.160
#> 4 pct_ed_visits… 2024-12-27  state    ca        source      2024-10-26     0.200
#> # ℹ 2 more rows

Archive Queries

If you want to track how data for a specific time period was revised over time, you can use epidata_archive(). Archive queries return every revision of each observation, so bounding reference_time matters even more here — the full archive of a signal can be enormous.

Code
archive_data <- epidata_archive(
  source = "nssp",
  signal = "pct_ed_visits_influenza",
  geo_type = "state",
  reference_time = epirange("2024-12-01", "2025-01-01")
)
head(archive_data)
#> # A tibble: 6 × 7
#>   signal         report_time geo_type geo_value fill_method reference_time value
#>   <chr>          <date>      <chr>    <chr>     <chr>       <date>         <dbl>
#> 1 pct_ed_visits… 2024-12-13  state    ak        source      2024-12-07     1.99 
#> 2 pct_ed_visits… 2024-12-13  state    al        source      2024-12-07     1.36 
#> 3 pct_ed_visits… 2024-12-13  state    ar        source      2024-12-07     0.480
#> 4 pct_ed_visits… 2024-12-13  state    az        source      2024-12-07     3.35 
#> # ℹ 2 more rows

Other Sources

Here are some examples for NHSN (hospitalizations), POPHIVE, and NWSS (wastewater).

Code
# NHSN: Hospital Admissions
meta_nhsn <- epidata_meta(source = "nhsn")
meta_nhsn$nhsn$signals
#> [1] "confirmed_admissions_covid_ew"        
#> [2] "confirmed_admissions_flu_ew"          
#> [3] "confirmed_admissions_rsv_ew"          
#> [4] "hosprep_confirmed_admissions_covid_ew"
#>  [ reached 'max' / getOption("max.print") -- omitted 4 entries ]
meta_nhsn$nhsn$geo_types
#> [1] "census_division" "census_region"   "hhs"             "nation"         
#> [5] "state"
meta_nhsn$nhsn$version_range
#> NULL
meta_nhsn$nhsn$time_value_range
#> NULL
nhsn_data <- epidata_snapshot(
  source = "nhsn",
  signal = "confirmed_admissions_flu_ew",
  geo_type = "state",
  reference_time = epirange("2024-10-01", "2025-01-01")
)
head(nhsn_data)
#> # A tibble: 6 × 7
#>   signal         report_time geo_type geo_value fill_method reference_time value
#>   <chr>          <date>      <chr>    <chr>     <chr>       <date>         <dbl>
#> 1 confirmed_adm… 2026-06-26  state    ak        source      2024-12-28        35
#> 2 confirmed_adm… 2026-06-26  state    ak        source      2024-12-21        22
#> 3 confirmed_adm… 2026-06-26  state    ak        source      2024-12-14        27
#> 4 confirmed_adm… 2026-06-26  state    ak        source      2024-12-07        18
#> # ℹ 2 more rows

# POPHIVE
meta_pophive <- epidata_meta(source = "pophive")
meta_pophive$pophive$signals
#> [1] "all_n_encounters_ed" "covid_n_ed"          "covid_pct_ed"       
#> [4] "flu_n_ed"           
#>  [ reached 'max' / getOption("max.print") -- omitted 3 entries ]
meta_pophive$pophive$geo_types
#> [1] "hhs"    "nation" "state"
meta_pophive$pophive$version_range
#> NULL
meta_pophive$pophive$time_value_range
#> NULL
pophive_data <- epidata_snapshot(
  source = "pophive",
  signal = "covid_pct_ed",
  geo_type = "state",
  reference_time = epirange("2024-10-01", "2025-01-01")
)
head(pophive_data)
#> # A tibble: 6 × 8
#>   signal     report_time geo_type geo_value fill_method reference_time age_group
#>   <chr>      <date>      <chr>    <chr>     <chr>       <date>         <chr>    
#> 1 covid_pct… 2026-07-31  state    ak        source      2024-10-05     <1       
#> 2 covid_pct… 2026-07-31  state    ak        source      2024-10-05     1-4      
#> 3 covid_pct… 2026-07-31  state    ak        source      2024-10-05     18-49    
#> 4 covid_pct… 2026-07-31  state    ak        source      2024-10-05     5-17     
#> # ℹ 2 more rows
#> # ℹ 1 more variable: value <dbl>

# NWSS: Wastewater Surveillance
meta_nwss <- epidata_meta(source = "nwss")
meta_nwss$nwss$signals
#> [1] "covid_avg_conc"     "covid_avg_conc_lin" "covid_flowpop_lin" 
#> [4] "covid_mic_lin"     
#>  [ reached 'max' / getOption("max.print") -- omitted 32 entries ]
meta_nwss$nwss$geo_types
#> [1] "sewershed"
meta_nwss$nwss$version_range
#> NULL
meta_nwss$nwss$time_value_range
#> NULL
nwss_data <- epidata_snapshot(
  source = "nwss",
  signal = "covid_avg_conc",
  geo_type = "sewershed",
  reference_time = epirange("2024-12-01", "2025-01-01")
)
head(nwss_data)
#> # A tibble: 6 × 10
#>   signal   report_time geo_type geo_value fill_method reference_time nwss_source
#>   <chr>    <date>      <chr>    <chr>     <chr>       <date>         <chr>      
#> 1 covid_a… 2026-06-26  sewersh… 128       source      2024-12-19     CDC_Verily 
#> 2 covid_a… 2026-06-26  sewersh… 131       source      2024-12-16     State_Terr…
#> 3 covid_a… 2026-06-26  sewersh… 732       source      2024-12-31     CDC_Verily 
#> 4 covid_a… 2026-06-26  sewersh… 2217      source      2024-12-03     State_Terr…
#> # ℹ 2 more rows
#> # ℹ 3 more variables: sample_index <chr>, pcr_target <chr>, value <dbl>

Auxiliary Data

Some sources ship extra columns connected to the signal data, such as the population served by each NWSS sewershed. epidata_aux() retrieves it, either on its own or merged onto a signal pull.

You can pull auxiliary data directly by source. Two things control download size and speed by shrinking the returned data. Pass named filters on the key columns through ... to filter to fewer rows (each key accepts one or more values), and use columns to choose which columns are returned.

Code
aux_data <- epidata_aux(
  source = "nwss",
  pcr_target = "sars-cov-2",
  sample_index = c("92012", "92013")
)
head(aux_data)
#> # A tibble: 6 × 36
#>   report_time geo_value reference_time nwss_source sample_index pcr_target
#>   <date>      <chr>     <date>         <chr>       <chr>        <chr>     
#> 1 2026-06-26  162       2026-01-27     CDC_Verily  92012        sars-cov-2
#> 2 2026-06-19  162       2026-01-27     CDC_Verily  92012        sars-cov-2
#> 3 2026-06-12  162       2026-01-27     CDC_Verily  92012        sars-cov-2
#> 4 2026-06-05  162       2026-01-27     CDC_Verily  92012        sars-cov-2
#> # ℹ 2 more rows
#> # ℹ 30 more variables: report_ts_nominal_end <chr>, state_territory <chr>,
#> #   county_fips <chr>, counties_served <chr>, population_served <chr>,
#> #   sample_type <chr>, sample_matrix <chr>, sample_location <chr>,
#> #   flow_rate <chr>, concentration_method <chr>, pasteurized <chr>,
#> #   pcr_type <chr>, extraction_method <chr>, major_lab_method <chr>,
#> #   inhibition_detect <chr>, inhibition_adjust <chr>, ntc_amplify <chr>, …

You may want the auxiliary columns attached to the original signal pull. The output of epidata_snapshot() or epidata_archive can be passed directly to epidata_aux(). In this use case, epidata_aux() uses the source parameter from the original signal pull function. It fetches the matching auxiliary data and left-joins it onto the shared key columns, keeping only the sample data from the original signal pull.

Code
# Filter the base dataset to only one site, so the auxiliary
# pull stays small for this example
nwss_small <- nwss_data %>%
  dplyr::filter(geo_value == first(geo_value))

nwss_merged <- nwss_small %>%
  epidata_aux()
head(nwss_merged)
#> # A tibble: 6 × 40
#>   signal   report_time geo_type geo_value fill_method reference_time nwss_source
#>   <chr>    <date>      <chr>    <chr>     <chr>       <date>         <chr>      
#> 1 covid_a… 2026-06-26  sewersh… 128       source      2024-12-19     CDC_Verily 
#> 2 covid_a… 2026-06-26  sewersh… 128       source      2024-12-03     CDC_Verily 
#> 3 covid_a… 2026-06-26  sewersh… 128       source      2024-12-17     CDC_Verily 
#> 4 covid_a… 2026-06-26  sewersh… 128       source      2024-12-12     CDC_Verily 
#> # ℹ 2 more rows
#> # ℹ 33 more variables: sample_index <chr>, pcr_target <chr>, value <dbl>,
#> #   report_ts_nominal_end <chr>, state_territory <chr>, county_fips <chr>,
#> #   counties_served <chr>, population_served <chr>, sample_type <chr>,
#> #   sample_matrix <chr>, sample_location <chr>, flow_rate <chr>,
#> #   concentration_method <chr>, pasteurized <chr>, pcr_type <chr>,
#> #   extraction_method <chr>, major_lab_method <chr>, inhibition_detect <chr>, …

If you don’t pass any key filters, epidata_aux() infers them from the base dataset. Any key column the base narrows to at most 10 distinct values (like geo_value) is used to automatically narrow the auxiliary request, so you download only the auxiliary rows you need.

The same key filters work on epidata_snapshot() and epidata_archive(), where they are sent server-side to shrink the download:

Code
epidata_snapshot(
  source = "nwss",
  signals = "pcr_conc_smoothed",
  geo_type = "county",
  pcr_target = c("sars-cov-2", "influenza")
)