Migrating from pub_covidcast to the new Epidata API¶
The Delphi Epidata API is moving from its V4 endpoints (pub_covidcast()
and other {pub/pvt}_* endpoints, such as pub_fluview(), pub_flusurv(),
and pvt_quidel()) to a new set of V5 endpoints, served by
epidata_snapshot(), epidata_archive(), and epidata_meta(). The
transition is in progress: sources are moving to the new API one at a time,
and the V4 functions still work for sources that have not moved yet. New
analyses should start with the new functions and fall back to a V4 function
only when a source is not yet available there.
Starting in October 2026, the V4 functions are tentatively deprecated in
favor of the V5 API, and calling them raises a UserWarning pointing back
to this guide.
For the current list of sources and indicators available on the new API, see the V5 signals documentation.
This guide walks through pub_covidcast()’s arguments and columns in
detail, since it’s the most widely used V4 endpoint, but the mapping is the
same for the other {pub/pvt}_* endpoints.
from epidatpy import EpiDataContext, EpiRange
epidata = EpiDataContext()
Function mapping¶
Old |
New |
Purpose |
|---|---|---|
|
|
Data as it appeared on a given date (or the latest) |
|
|
Full revision history of a signal |
|
|
Discover sources, signals, geo types, and date ranges |
epidata() is a convenience wrapper that routes to epidata_snapshot() or
epidata_archive() based on which versioning argument you pass.
Argument changes¶
|
New argument |
Notes |
|---|---|---|
|
same |
|
|
none |
Dropped. Times in the new API are always dates. |
|
|
Accepts dates or |
|
|
|
|
|
|
|
none |
Compute it yourself: |
The new functions also add fill_method, which has no covidcast equivalent.
Some sources publish several variants of the same signal that differ in how
nulls were handled during geographic aggregation: "source" (raw source
data, no imputation), "fill_ave" (nulls filled with the average of
neighboring values), and "fill_zero" (nulls filled with zero). The default
None returns all variants, so filter on this column (or pass the argument)
if you want exactly one time series per location.
Column changes¶
|
New column |
Notes |
|---|---|---|
|
same |
|
|
|
The date the value describes. Always a date. |
|
|
The date the value was published. Present in both snapshot and archive output. |
|
dropped |
You queried by source; add it back with |
|
dropped |
No longer needed since times are dates. |
|
dropped |
Compute as |
|
dropped |
Was already deprecated in the covidcast API. |
|
|
Uncertainty is now expressed as confidence interval bounds on |
|
dropped |
Missingness is now expressed through |
none |
|
Which null-handling variant of the signal this row belongs to. See above. |
Some sources also carry extra columns in the new API, for example
age_group (pophive) and nwss_source, sample_index, pcr_target
(nwss).
Uncertainty columns¶
The covidcast columns stderr and sample_size have no fixed replacement.
The shared schema carries only value; a source that quantifies
uncertainty adds its own columns, such as ci_lower and ci_upper. Use
the metadata or the documentation
to see which value columns a source returns:
meta_sleepcycle = epidata.epidata_meta(source="sleepcycle")
meta_sleepcycle["sleepcycle"]["value_columns"]
['ci_lower', 'ci_upper', 'value']
A query, before and after¶
Fetching NSSP influenza ED visit percentages for two states, as the data looked on January 1, 2025:
old = epidata.pub_covidcast(
data_source="nssp",
signals="pct_ed_visits_influenza",
geo_type="state",
time_type="week",
geo_values=["pa", "ca"],
time_values=EpiRange(202440, 202501),
as_of=20250101,
).df()
old.head()
/home/runner/work/epidatpy/epidatpy/epidatpy/_endpoints.py:708: UserWarning: `pub_covidcast` uses the V4 Epidata API. Starting in October 2026, V4 is tentatively deprecated in favor of the V5 API. See the migration guide (https://cmu-delphi.github.io/epidatpy/migration_guide.html) for the V5 endpoints and how to move to them.
_warn_v4_sunset("pub_covidcast")
/home/runner/work/epidatpy/epidatpy/epidatpy/_call.py:367: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
df[info.name] = to_datetime(df[info.name])
| source | signal | geo_type | geo_value | time_type | time_value | issue | lag | value | stderr | sample_size | direction | missing_value | missing_stderr | missing_sample_size | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | nssp | pct_ed_visits_influenza | state | ca | week | 202440 | 2026-03-05 | 100 | 0.14 | <NA> | <NA> | <NA> | 0 | 1 | 1 |
| 1 | nssp | pct_ed_visits_influenza | state | pa | week | 202440 | 2026-03-05 | 100 | 0.05 | <NA> | <NA> | <NA> | 0 | 1 | 1 |
| 2 | nssp | pct_ed_visits_influenza | state | ca | week | 202441 | 2026-03-05 | 99 | 0.14 | <NA> | <NA> | <NA> | 0 | 1 | 1 |
| 3 | nssp | pct_ed_visits_influenza | state | pa | week | 202441 | 2026-03-05 | 99 | 0.07 | <NA> | <NA> | <NA> | 0 | 1 | 1 |
| 4 | nssp | pct_ed_visits_influenza | state | ca | week | 202442 | 2026-03-05 | 98 | 0.16 | <NA> | <NA> | <NA> | 0 | 1 | 1 |
new = epidata.epidata_snapshot(
source="nssp",
signals="pct_ed_visits_influenza",
geo_type="state",
geo_values=["pa", "ca"],
reference_time=EpiRange("2024-10-01", "2025-01-01"),
snapshot_date="2025-01-01",
).df()
new.head()
| signal | report_time | geo_type | geo_value | fill_method | reference_time | value | |
|---|---|---|---|---|---|---|---|
| 573 | pct_ed_visits_influenza | 2024-12-27 | state | ca | source | 2024-10-05 | 0.14 |
| 574 | pct_ed_visits_influenza | 2024-12-27 | state | ca | source | 2024-10-12 | 0.14 |
| 575 | pct_ed_visits_influenza | 2024-12-27 | state | ca | source | 2024-10-19 | 0.16 |
| 576 | pct_ed_visits_influenza | 2024-12-27 | state | ca | source | 2024-10-26 | 0.2 |
| 577 | pct_ed_visits_influenza | 2024-12-27 | state | ca | source | 2024-11-02 | 0.25 |
Revision history queries¶
Where you used to pass issues to pub_covidcast(), use
epidata_archive() with report_time:
revisions = epidata.epidata_archive(
source="nssp",
signals="pct_ed_visits_influenza",
geo_type="state",
geo_values="pa",
reference_time=EpiRange("2024-10-01", "2025-01-01"),
report_time="<2025-06-01",
).df()
revisions.head()
| signal | report_time | geo_type | geo_value | fill_method | reference_time | value | |
|---|---|---|---|---|---|---|---|
| 82656 | pct_ed_visits_influenza | 2024-11-08 | state | pa | source | 2024-10-05 | 0.05 |
| 82657 | pct_ed_visits_influenza | 2024-11-08 | state | pa | source | 2024-10-12 | 0.07 |
| 82658 | pct_ed_visits_influenza | 2024-11-08 | state | pa | source | 2024-10-19 | 0.08 |
| 82659 | pct_ed_visits_influenza | 2024-11-08 | state | pa | source | 2024-10-26 | 0.13 |
| 82660 | pct_ed_visits_influenza | 2024-11-08 | state | pa | source | 2024-11-02 | 0.14 |
If you filtered by lag, fetch the archive and filter afterwards:
revisions[(revisions["report_time"] - revisions["reference_time"]) <= pd.Timedelta(days=7)]
| signal | report_time | geo_type | geo_value | fill_method | reference_time | value | |
|---|---|---|---|---|---|---|---|
| 82660 | pct_ed_visits_influenza | 2024-11-08 | state | pa | source | 2024-11-02 | 0.14 |
| 88124 | pct_ed_visits_influenza | 2024-11-23 | state | pa | source | 2024-11-16 | 0.17 |
| 99223 | pct_ed_visits_influenza | 2024-12-07 | state | pa | source | 2024-11-30 | 0.35 |
| 104846 | pct_ed_visits_influenza | 2024-12-13 | state | pa | source | 2024-12-07 | 0.55 |
| 110634 | pct_ed_visits_influenza | 2024-12-20 | state | pa | source | 2024-12-14 | 0.85 |
| 116472 | pct_ed_visits_influenza | 2024-12-27 | state | pa | source | 2024-12-21 | 1.78 |
| 122360 | pct_ed_visits_influenza | 2025-01-03 | state | pa | source | 2024-12-28 | 3.78 |
Checking whether a source has moved¶
Use epidata_meta() to see what a source offers in the new API. It
returns signals, geo types, and the available reference_time and
report_time ranges:
meta = epidata.epidata_meta(source="nssp")
meta["nssp"]["signals"]
['pct_ed_visits_ari',
'pct_ed_visits_combined',
'pct_ed_visits_covid',
'pct_ed_visits_influenza',
'pct_ed_visits_rsv',
'smoothed_pct_ed_visits_combined',
'smoothed_pct_ed_visits_covid',
'smoothed_pct_ed_visits_influenza',
'smoothed_pct_ed_visits_rsv']
meta["nssp"]["reference_time_range"]
{'latest': '2026-08-22', 'first': '2022-10-01'}
If epidata_meta() does not know the source yet, keep using
pub_covidcast() for it and check back after package updates. The API
mailing
list
announces sources as they move.
Endpoints kept for historical reference¶
Not every V4 endpoint is moving to V5. The functions below cover data sources whose collection has already ended (e.g. Google Flu Trends, the HealthTweets signal, the various nowcasts). They are not part of the V4-to-V5 transition, so they are not deprecated and will keep working. The historical data they return is frozen and will remain available. They will just no longer receive new data.
Function |
Data source |
|---|---|
|
CDC total and by-topic webpage visits |
|
COVID hospitalization facility lookup |
|
COVID hospitalizations by facility |
|
COVID hospitalizations by state |
|
Delphi’s ILINet outpatient doctor visits forecasts |
|
Delphi’s PAHO dengue nowcasts (Americas) |
|
PAHO dengue digital surveillance sensors (Americas) |
|
ECDC ILI incidence (Europe) |
|
Google Flu Trends flu search volume |
|
Google Health Trends health topics search volume |
|
KCDC ILI incidence (Korea) |
|
Metadata for the NoroSTAT endpoint |
|
NIDSS dengue cases (Taiwan) |
|
NIDSS flu doctor visits (Taiwan) |
|
CDC NoroSTAT norovirus outbreaks |
|
Delphi’s wILI nowcasts |
|
PAHO dengue data (Americas) |
|
Influenza and dengue digital surveillance sensors |
|
HealthTweets total and influenza-related tweets |
|
Wikipedia webpage counts by article |