# World Bank Indicators API: GDP, Population & WDI by Country (`mouadapi/world-bank-indicators`) Actor

World Bank data API: GDP, population, inflation and 1,400+ World Development Indicators by country and year, or only new and revised values since your last run. Never charged for failed or unchanged rows. Not affiliated with or endorsed by the World Bank.

- **URL**: https://apify.com/mouadapi/world-bank-indicators.md
- **Developed by:** [COMPASS DEV](https://apify.com/mouadapi) (community)
- **Categories:** Business, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 value returneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

Returns World Development Indicators (GDP, population, inflation and 1,400+ other series) by country and year from the
official World Bank API, one flat row per value, or in watch mode only the values that are new (a newly published year) or
revised since your last run. Never charged for failed or unchanged rows.

Give it indicator codes (e.g. `NY.GDP.MKTP.CD` for GDP) and, if you like, countries and years; get clean rows with the
country, year, value, unit, licence and a link to the indicator's page on data.worldbank.org. Built for analysts,
dashboards, spreadsheets and AI agents that need reliable macro data without wrestling with the API's paging and formats.

*Data: The World Bank, World Development Indicators, CC BY 4.0. Not affiliated with or endorsed by the World Bank.*

### Quick start

- The latest GDP and population for three countries (export: every value, every run):

```json
{ "indicators": ["NY.GDP.MKTP.CD", "SP.POP.TOTL"], "countries": ["FR", "DE", "US"] }
```

- Every country's inflation since 2015:

```json
{ "indicators": ["FP.CPI.TOTL.ZG"], "yearFrom": 2015 }
```

- Watch GDP for new years and revisions (the first run is the baseline; later runs return only new or revised values):

```json
{ "indicators": ["NY.GDP.MKTP.CD"], "countries": ["FR", "DE", "US"], "stateName": "gdp-watch" }
```

### What it does

- **One row per value** (country × indicator × year). By default each country's latest published value; set
  `mostRecentValues` or a year range for more. Years without a published value are left out, free.
- **Licence check:** before it returns a series, it reads the series' own licence label from the World Bank's metadata
  (`License_Type`). Only series labelled CC BY 4.0 (or CC0) are returned; any other gives one free `no_data` row. Every row
  carries `licenseType`, `licenseUrl` and the `attribution` the licence asks for.
- **Countries:** two- or three-letter codes (`FR` or `FRA`). Leave `countries` empty for every country and economy;
  regional and income aggregates ("World", "Euro area", "High income") only with `includeAggregates`. A listed country with
  no value in the years gives one free `no_data` row; an unknown code gives one free `failed` row.
- **Watch mode:** remembers every value under your watch list name and returns only:
  - `baseline`: the first run of an indicator on the list;
  - `new`: a year or country that had no value before (the World Bank published it);
  - `changed`: a revised value (`previousValue` holds the old one);
  - unchanged values are free and left out (`includeUnchanged: true` returns them as free rows).
  - A watch run with nothing new or revised returns **exactly one free `no_data` row** that says so.
- **You are never charged for failed results:** failed, no\_data and unchanged rows are free.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `indicators` | list of strings | — (prefilled with GDP and population) | WDI series codes, e.g. NY.GDP.MKTP.CD, SP.POP.TOTL, FP.CPI.TOTL.ZG |
| `countries` | list of strings | — (prefilled FR, DE, US) | ISO2/ISO3 codes; empty = every country and economy |
| `mostRecentValues` | integer 1–70 | `1` | Each country's N most recent published values (1 = the latest); ignored with yearFrom/yearTo |
| `yearFrom`, `yearTo` | integer | — | An explicit year range |
| `includeAggregates` | boolean | `false` | With every country: also World, regions and income groups |
| `mode` | `watch` or `export` | — | Empty: watch when `stateName` is given, otherwise export. An explicit mode wins |
| `stateName` | string | — (prefilled `example-watchlist`) | Watch list name. Watch mode without a name uses the list `default` |
| `includeUnchanged` | boolean | `false` | Watch: also return unchanged values (free) |
| `maxItems` | integer 1–100,000 | `1000` | Most charged rows per run; in watch mode the rest comes next run |

### Output

```json
{
    "status": "ok",
    "attempts": 1,
    "error": null,
    "input": "NY.GDP.MKTP.CD",
    "mode": "export",
    "watchList": null,
    "indicatorId": "NY.GDP.MKTP.CD",
    "indicatorName": "GDP (current US$)",
    "countryIso3": "FRA",
    "countryIso2": "FR",
    "countryName": "France",
    "year": 2024,
    "value": 3160000000000,
    "unit": null,
    "decimals": 0,
    "changeType": null,
    "previousValue": null,
    "url": "https://data.worldbank.org/indicator/NY.GDP.MKTP.CD?locations=FR",
    "sourceName": "World Development Indicators",
    "sourceLastUpdated": "2026-07-01",
    "licenseType": "CC BY-4.0",
    "attribution": "The World Bank: World Development Indicators (and its data providers)",
    "scrapedAt": "2026-09-30T11:00:00.000Z"
}
```

| Status | Meaning | Charged? |
|---|---|---|
| `ok` | A value returned | Export: yes. Watch: `baseline`, `new` and `changed` yes; `unchanged` no |
| `no_data` | Unknown series, a series not labelled CC BY 4.0, no value published, or no changes since the last run | No |
| `failed` | Invalid code, or no answer after retries (`error` says why) | No |

The key-value store holds `RUN_REPORT` (counts, charged and free rows, stop reason) and, when something fails, the raw
response (`SNAPSHOT_*`).

### Use it from AI agents

- One clear main input: `{"indicators": ["<WDI code>"]}` (every country's latest published value, about 200 rows). The same call returns data every time.
- Add `"stateName": "<list>"` to get only new and revised values on later calls; a call with nothing new returns one
  `no_data` row that says "No new or changed values since the last run".
- Every row has `status`, `error`, `url` (data.worldbank.org) and `scrapedAt`.
- Via the Apify MCP server or API: `mouadapi/world-bank-indicators`. Pay per returned value; x402 agentic payments supported.

Copy-paste call (your Apify token in `APIFY_TOKEN`):

```bash
curl -s -X POST "https://api.apify.com/v2/acts/mouadapi~world-bank-indicators/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"indicators": ["SP.POP.TOTL"]}'
```

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('mouadapi/world-bank-indicators').call({ indicators: ['SP.POP.TOTL'] });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### Pricing

Pay per event, one `data-point` event per returned value (export: every value; watch: `baseline`, `new` and `changed`
rows). `no_data`, `failed` and unchanged rows are free.

| Plan | Price per 1,000 values |
|---|---|
| Free | $1.50 |
| Bronze | $1.30 |
| Silver | $1.15 |
| Gold (and higher) | $1.00 |

Apify also charges its small per-run start event. There are no usage fees on top.

### Limits

- World Development Indicators only (the World Bank's main database, source 2); other World Bank databases are not covered.
- One request at a time, at most one a second (the World Bank asks for "reasonable request volume"): one request per
  indicator for its licence, one per 1,000 values, plus one for the country list.
- If the API answers HTTP 429 (rate limit), the run pauses 60, 120 and 240 seconds on the same connection, then stops with
  free `failed` rows. No other IP or proxy is ever tried.

### Known issues

- The World Bank API can be slow (single requests sometimes take 20–30 seconds); timeouts are retried.
- Most WDI series are annual; many countries publish the latest year late, so the newest year is often empty for a while.
  In watch mode those values come as `new` rows when the World Bank publishes them.

### Data and licence

- Source: the World Bank Indicators API (api.worldbank.org), documented on datahelpdesk.worldbank.org.
- World Bank Dataset Terms: "Unless specifically labeled otherwise, these Datasets are provided to you under a Creative
  Commons Attribution 4.0 International License (CC BY 4.0)". This Actor checks each series' label and returns only CC BY
  4.0 (or CC0) series, with the attribution on every row.
- This Actor is not affiliated with, endorsed by or provided by the World Bank. It returns the values as published.

# Actor input Schema

## `indicators` (type: `array`):

World Development Indicators series codes, one per line, e.g. NY.GDP.MKTP.CD (GDP, current US$), SP.POP.TOTL (population), FP.CPI.TOTL.ZG (inflation). Find codes on data.worldbank.org (the code is in each indicator page's address).

## `countries` (type: `array`):

Two- or three-letter country codes (FR or FRA), one per line. Empty: every country and economy (regional and income aggregates such as "World" only with includeAggregates).

## `mostRecentValues` (type: `integer`):

How many of each country's most recent published values to return (1 = the latest published value; years without a value are skipped). Ignored when yearFrom or yearTo is set. Default 1.

## `yearFrom` (type: `integer`):

First year (e.g. 2000). Optional.

## `yearTo` (type: `integer`):

Last year (e.g. 2024). Optional.

## `includeAggregates` (type: `boolean`):

With every country (countries empty): also return aggregates such as World, Euro area or High income. Listed aggregate codes (e.g. WLD) are always returned. Default false.

## `mode` (type: `string`):

watch: only values that are new since your last run (a newly published year) or revised (unchanged values are free and left out). export: every value, every run. Empty: watch when a watch list name is given, otherwise export.

## `stateName` (type: `string`):

Name of your watch list (letters, digits, dashes). The run remembers every value under this name and compares next time. Watch mode without a name uses the list "default".

## `includeUnchanged` (type: `boolean`):

Watch mode: also return values that did not change, as free rows (changeType unchanged). Default false.

## `maxItems` (type: `integer`):

Most charged rows (data points) per run. In watch mode, values over the limit are returned in the next run. Default 1,000.

## Actor input object example

```json
{
  "indicators": [
    "NY.GDP.MKTP.CD",
    "SP.POP.TOTL"
  ],
  "countries": [
    "FR",
    "DE",
    "US"
  ],
  "mostRecentValues": 1,
  "includeAggregates": false,
  "mode": "watch",
  "stateName": "example-watchlist",
  "includeUnchanged": false,
  "maxItems": 1000
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset with one row per returned data point (plus free no\_data / failed rows)

## `runReport` (type: `string`):

Summary of the run (counts, charged and free rows, stop reason)

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "indicators": [
        "NY.GDP.MKTP.CD",
        "SP.POP.TOTL"
    ],
    "countries": [
        "FR",
        "DE",
        "US"
    ],
    "mode": "watch",
    "stateName": "example-watchlist"
};

// Run the Actor and wait for it to finish
const run = await client.actor("mouadapi/world-bank-indicators").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "indicators": [
        "NY.GDP.MKTP.CD",
        "SP.POP.TOTL",
    ],
    "countries": [
        "FR",
        "DE",
        "US",
    ],
    "mode": "watch",
    "stateName": "example-watchlist",
}

# Run the Actor and wait for it to finish
run = client.actor("mouadapi/world-bank-indicators").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "indicators": [
    "NY.GDP.MKTP.CD",
    "SP.POP.TOTL"
  ],
  "countries": [
    "FR",
    "DE",
    "US"
  ],
  "mode": "watch",
  "stateName": "example-watchlist"
}' |
apify call mouadapi/world-bank-indicators --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mouadapi/world-bank-indicators"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/M9ngn8jrbheZOJutL/builds/OMTlQB6OW074j8UCB/openapi.json
