Hi Chuck,
I tried you code and put together a working example that should get you past the error in
Step 5.
The script below retrieves data for multiple tables (Parts 1, 2, and 3) and can be adapted
for state or county.
For Parts 3 "Flow" tables, it seems necessary to use parameters "for"
and "d-for" to identify the origin and destination geographies.
For tables in Part 1 and Part 2, I feel it is more convenient to use 'for'
instead of 'geo'. I’m still a bit unsure about the geoid—it appears to have
different prefix codes depending on the geographic summary level used in each table.
Here’s a starting point, feel free to tweak.
#1. load the R libraries jsonlite and httr
library(jsonlite)
library(httr)
#2. Save your API key
api_key <- ("XXXXXXXX")
#3. Define API Endpoint: Specify the URL of the API endpoint you want to access
url <- "https://ctppdata.transportation.org/api/data/2021"
#4. Set Headers: Create a list of headers required for the API request, including the API
key.
headers <- c(Accept = "application/json", "x-api-key" = api_key)
#5. Prepare Parameters: Define the parameters needed for your API call. # may include
specifying the type of data you want (like geographic IDs)
#6. Make the Request: Use the httr package send a GET request to the API.
## Part 1 residence - table b101100 total population
params <- list(get = "b101100_e1,b101100_m1",
geo ="C0300US06001,C0300US06005,C0300US06019")
response <- GET(url, add_headers(.headers = headers), query = params)
res_data <- fromJSON(rawToChar(response$content))
print(res_data$data)
### Use `for` instead of `geo`
params <- list(get = "b101100_e1,b101100_m1",
`for` ="county:001,005,019", #
County FIPS
`in` ="state:06") #
state FIPS
response <- GET(url, add_headers(.headers = headers), query = params)
res_data <- fromJSON(rawToChar(response$content))
print(res_data$data)
## Part 2 workplace - table b202101 age of worker, read entire group
params <- list(get = "group(b202101)",
geo ="C2300US06001,C2300US06005,C2300US06019")
response <- GET(url, add_headers(.headers = headers), query = params)
res_data <- fromJSON(rawToChar(response$content))
print(res_data$data)
### get the variables name
url_group <-
"https://ctppdata.transportation.org/api/groups/b202101/variables"
params <- list(year="2021")
response <- GET(url_group, add_headers(.headers = headers), query = params)
res_data_name <- fromJSON(rawToChar(response$content))
print(res_data_name$data)
res_data_name$data$label[which(res_data_name$data$name=='B202101_e8')]
## Part 3 Flow - b302100 Total workers
### selected state to state
params <- list(get = "b302100_e1,b302100_m1",
`for` ="state:06",`d-for` = "state:32,53") # Origin:CA
, Destination: Nevada, Washington
response <- GET(url, add_headers(.headers = headers), query = params)
res_data <- fromJSON(rawToChar(response$content))
print(res_data$data)
### selected county to county
params <- list(get = "b302100_e1,b302100_m1",
`for` ="county:001,005,019", #
From: County FIPS
`in` ="state:06", #
From: State FIPS
`d-for` = "county:001,005,019", #
To: County FIPS
`d-in` ="state:06") #
To: State FIPS
response <- GET(url, add_headers(.headers = headers), query = params)
res_data <- fromJSON(rawToChar(response$content))
print(res_data$data)
I’m not an API expert myself — this one’s new to me too — so if anyone else on the list
has a better or more efficient solution, please chime in. Always great to see different
approaches.
I've found the CTPP API Explorer page very helpful for understanding the data
structures. It would be great if it included an example for a Part 3 table, since the
flow data is probably what people are most interested in when working with CTPP. A
codebook in CSV format would also be super handy for searching variable names.
Best,
Shichen
---
Shichen Fan, AICP
Senior Regional Planner
Fresno Council of Governments
sfan@fresnocog.org<mailto:sfan@fresnocog.org> | 559-233-4148 ext. 243
________________________________
From: Charles Purvis <clpurvis(a)att.net>
Sent: Tuesday, August 12, 2025 2:23 PM
To: The Census Transportation Products Program Community of Practice/Users discussion and
news list <ctpp(a)listserv.transportation.org>
Subject: [CTPP News] CTPP Data Portal / AI chatbot
CAUTION: This email originated from outside of the organization. Do not click links or
open attachments unless you recognize the sender and know the content is safe.
I’ve tested the new chatbot on the CTPP Data Portal, with generally positive results.
Questions I’ve asked include:
1. How can I modify the API scripts to work in the R statistical package?
2. How do I store my API key in an r statistical package environment variable?
The chatbot gave full and easy-to-implement code to store my personal CTPP API key. Good
Various versions of my request for API scripts in R package gave various results.
It was awkward to cut-and-paste my question and the answer I received from the AI
chatbot.
Basically:
1. load the R libraries jsonlite and httr
library(jsonlite)
library(httr)
2. Save your API key in your R environment
# Edit your R profile
usethis::edit_r_profile()
Sys.setenv(CTPP_KEY = "mytopsecretapikeyxxxxxxx")
api_key <- Sys.getenv("CTPP_KEY”)
3. Define API Endpoint: Specify the URL of the API endpoint you want to access
url <-
"https://linkprotect.cudasvc.com/url?a=https%3a%2f%2fctppdata.transportation.org%2fapi%2fdata%2f2021%e2%80%9d&c=E,1,LM9kkJ8p23BfAjP2MDY7SMjMqETMt5dsPpf8FDgJt8GLvGGHungZ_WJcZKsjW2x9aRyrp9yVgfpghQFx0Lo-8VxGZax-FlkpLQd4esdnPCbvdifzwTo,&typo=1
4. **Set Headers**: Create a list of headers required for the API request, including the
API key.
headers <- c(Accept = "application/json", "x-api-key" = api_key)
5. Prepare Parameters: Define the parameters needed for your API call.
# may include specifying the type of data you want (like geographic IDs)
params <- list(get = "b302100_e1,b302100_m1",geo =
"C0300US06001,C0300US06005",
size = 10,page = 1)
6. Make the Request: Use the httr package send a GET request to the API.
response <- GET(url, add_headers(.headers = headers), query = params)
############################################################################
The code is failing around step 5: defining the tables and geography for the API data
pull….
I really could use some human assistance to fix this R code. I heard there is a cabal of
MPO data people who can code anything and everything in R or Python. Can somebody help
me?
I’d like to develop examples, in R script, to retrieve data for various tables (Parts 1, 2
and 3) for various geographies (state, county, place, tract). Obviously I’ll share my R
code in my bithub repository.
I just need a collaborator / hand-holder.
I received no feedback on my April 4, 2025 post to this CTPP listserv. My guess is that
too few people have actually tried to use the API, or they’re too shy to provide
feedback.
Hope to hear from you!
Chuck Purvis,
Hayward, California
PS, The single-year 2024 ACS data is scheduled for release in one month, on September 11,
2025. Should keep us busy for a few days. And the five-year, 2020-2024 ACS is scheduled
for December 11, 2025.
###
_______________________________________________
CTPP mailing list -- ctpp(a)listserv.transportation.org
To unsubscribe send an email to ctpp-leave(a)listserv.transportation.org