World Bank API in R#
by Michael T. Moen, Vishank Patel, and Adam M. Nguyen
The World Bank offers a suite of APIs providing access to a vast array of global development data, including economic indicators, project information, and more. These APIs enable users to programmatically retrieve data for analysis, application development, and research purposes.
Please see the following resources for more information on API usage:
Documentation
Terms
Data Reuse
NOTE: Please see access details and rate limit requests for this API in the official documentation.
These recipe examples were tested on April 2, 2026.
Setup#
Import Libraries#
The following external libraries need to be installed into your environment to run the code examples in this tutorial:
We import the libraries used in this tutorial below:
library(countrycode)
library(httr)
library(jsonlite)
library(plotly)
DataBank Bulk Download#
The World Bank offers bulk downloads of specific datasets from DataBank Bulk Download or DataBank Bulk Microdata Download. If you require extensive or complete data, consider using these bulk downloads. For smaller requests or interactive analysis, the standard API calls work well.
1. Comparing GDP per Capita by Country#
In this example, we look at the GDP per capita of each country using the NY.GDP.PCAP.CD indicator. Note we examine both countries and dependent territories defined as having ISO 3166-1 alpha-3 (also known here as ISO 3) codes.
BASE_URL <- "http://api.worldbank.org/v2/country/all/indicator/"
indicator <- "NY.GDP.PCAP.CD" # Indicator code for GDP per capita (current USD)
params <- list(
date = 2024,
format = "json",
per_page = 500
)
response <- GET(paste0(BASE_URL, indicator), query = params)
# Status code 200 indicates success
response$status_code
## [1] 200
# Extract JSON data from response
df <- fromJSON(rawToChar(response$content))[[2]]
# Drop unneeded columns
df <- df[, !(names(df) %in% c("country", "indicator", "unit", "obs_status", "decimal"))]
# Print first result
head(df)
## countryiso3code date value
## 1 AFE 2024 1615.396
## 2 AFW 2024 1411.337
## 3 ARB 2024 7583.812
## 4 CSS 2024 19903.811
## 5 CEB 2024 24604.807
## 6 EAR 2024 4450.187
Below, we use the countrycode package to retrieve the names of the countries based on their ISO 3 codes. Since the World Bank also maintains listings for different aggregations, we also drop those from the data below:
# Get country names by ISO 3 codes
df$country_name <- countrycode(
df$countryiso3code,
origin = "iso3c",
destination = "country.name"
)
# Drop rows that don't have a related country name
df <- df[!is.na(df$country_name), ]
# Find and sort top 20
top20 <- head(df[order(-df$value), ], 20)
# Display results
top20
## countryiso3code date value country_name
## 180 MCO 2024 288001.43 Monaco
## 71 BMU 2024 142855.37 Bermuda
## 166 LUX 2024 137781.68 Luxembourg
## 143 IRL 2024 112894.95 Ireland
## 238 CHE 2024 103998.19 Switzerland
## 221 SGP 2024 90674.07 Singapore
## 197 NOR 2024 86785.43 Norway
## 138 ISL 2024 86040.53 Iceland
## 256 USA 2024 84534.04 United States
## 209 QAT 2024 76688.69 Qatar
## 115 FRO 2024 74119.66 Faroe Islands
## 167 MAC 2024 72004.74 Macao SAR China
## 103 DNK 2024 71026.48 Denmark
## 189 NLD 2024 67520.42 Netherlands
## 60 AUS 2024 64603.99 Australia
## 61 AUT 2024 58268.88 Austria
## 237 SWE 2024 57117.49 Sweden
## 68 BEL 2024 56614.57 Belgium
## 123 DEU 2024 56103.73 Germany
## 85 CAN 2024 54340.35 Canada
# Margins adjusted for rotated labels
par(mar = c(5, 5, 4, 2) + 0.1)
# Create barplot
bp <- barplot(
top20$value / 1000,
col = "#4C72B0",
border = NA,
names.arg = NA,
main = "Top 20 Countries by GDP per Capita (2024)",
xlab = NA,
ylab = "GDP per Capita (Thousand USD)"
)
# Add rotated bar labels
text(
x = bp,
y = par("usr")[3] - 0.04 * diff(par("usr")[3:4]),
labels = top20$country_name,
srt = 30,
adj = 1,
xpd = TRUE,
cex = 0.8
)
# Draw axis again so it appears above grid
box(bty = "l", col = "#CCCCCC")

2. Comparing Scientific and Technical Journal Articles by Country#
In this example, we look at the “scientific and technical journal articles” of each country using the IP.JRN.ARTC.SC indicator and the total population of each country using the SP.POP.TOTL. Note we examine both countries and dependent territories defined as having ISO 3166-1 alpha-3 (also known here as ISO 3) codes.
BASE_URL <- "https://api.worldbank.org/v2/country/all/indicator/"
indicators <- c(
"IP.JRN.ARTC.SC" = "Article Count",
"SP.POP.TOTL" = "Population"
)
params <- list(
date = 2021,
format = "json",
per_page = 500
)
dfs <- list()
for (indicator in names(indicators)) {
colname <- indicators[[indicator]]
response <- GET(paste0(BASE_URL, indicator), query = params)
response <- fromJSON(rawToChar(response$content))
df_temp <- response[[2]]
df_temp <- df_temp[, c("countryiso3code", "value")]
names(df_temp)[names(df_temp) == "value"] <- colname
dfs[[indicator]] <- df_temp
}
# Merge both datasets
df <- merge(dfs[[1]], dfs[[2]], by = "countryiso3code")
# Get country names by ISO 3 codes
df$`Country Name` <- countrycode(
df$countryiso3code,
origin = "iso3c",
destination = "country.name"
)
# Remove aggregates like "World", "High income", etc.
df <- df[!is.na(df$`Country Name`), ]
head(df)
## countryiso3code Article Count Population Country Name
## 26 ABW NA 107700 Aruba
## 28 AFG 177.39 40000412 Afghanistan
## 30 AGO 42.35 34532429 Angola
## 31 ALB 241.09 2489762 Albania
## 32 AND 9.44 78364 Andorra
## 34 ARE 5266.62 9575152 United Arab Emirates
# Calculate article count per million people
df$`Article Count per Million` = df$`Article Count` / df$`Population` * 1000000
head(df)
## countryiso3code Article Count Population Country Name
## 26 ABW NA 107700 Aruba
## 28 AFG 177.39 40000412 Afghanistan
## 30 AGO 42.35 34532429 Angola
## 31 ALB 241.09 2489762 Albania
## 32 AND 9.44 78364 Andorra
## 34 ARE 5266.62 9575152 United Arab Emirates
## Article Count per Million
## 26 NA
## 28 4.434704
## 30 1.226383
## 31 96.832549
## 32 120.463478
## 34 550.029911
fig <- plot_ly(
data = df,
type = "choropleth",
locations = ~countryiso3code,
z = ~`Article Count per Million`,
text = ~`Country Name`,
colorscale = "Viridis",
locationmode = "ISO-3",
hovertemplate = paste(
"<b>%{text}</b><br>",
"Article Count per Million: %{z:.2f}",
"<extra></extra>"
),
colorbar = list(
title = list(text = "Article Count per Million")
)
) %>%
layout(
title = list(text = "Technical Journal Articles by Country (2021)"),
margin = list(l = 50, r = 50, b = 50, t = 50),
geo = list(
projection = list(type = "natural earth"),
showframe = FALSE,
showcoastlines = TRUE,
coastlinecolor = "lightgray"
)
)
fig