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:

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