# ETF Data Extractor | TER, Returns, Holdings, Risk | justETF (`bovi/etf-data-extractor`) Actor

Extract deep ETF data from justETF: ISIN, TER, live quote, returns (YTD/1M/3M/6M/1Y/3Y/5Y/MAX + yearly), volatility, max drawdown, top-10 holdings, country and sector weights. Search by query or pass exact ISINs. No login required. Pay per ETF record.

- **URL**: https://apify.com/bovi/etf-data-extractor.md
- **Developed by:** [Vitalii Bondarev](https://apify.com/bovi) (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 $31.04 / 1,000 etf-records

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

For portfolio trackers, robo-advisors, fintech dashboards, and AI agents that need structured
ETF data — TER, live quote, returns, volatility, drawdown, and holdings — without a paid data
terminal or manual copy-paste from fund fact sheets.

**No API key required.** No login, no cookies, no crumb tokens. Every record includes
`parse_confidence` (0.0–1.0) and `warnings` so you can tell a complete record from a partial one.
Pay Per Event — see the Store pricing tab for the current rate.

Extract deep ETF data from **justETF** — one of the largest independent ETF databases in Europe.
Give it exact ISINs or a free-text search query and it returns a rich, flat JSON record per fund:
identity, cost, live-ish quote, multi-horizon returns, risk metrics, and portfolio composition.

---

### What data you get

One record per ETF, ~60 fields:

#### Identity & structure
`isin`, `wkn`, `name`, `url`, `entity_type`, `active`, `index_name`, `investment_focus`,
`fund_provider`, `fund_currency`, `domicile_country`, `legal_structure`, `launch_date`,
`sustainable`, `strategy_risk`, `currency_hedge`, `distribution_policy`, `distribution_interval`,
`replication_method`, `replication_type`

#### Cost & size
`ter` (`{"raw": 0.07, "localized": "0.07% p.a."}`), `fund_size_mln`

#### Quote
`quote`, `latest_quote`, `latest_quote_date`, `previous_quote`, `previous_quote_date`,
`first_quote_date`, `available_chart_periods`, `day_change_pct`, `day_change_amount`,
`quote_trading_venue`, `quote_day_low`, `quote_day_high`

#### Returns
`return_ytd`, `return_1m`, `return_3m`, `return_6m`, `return_1y`, `return_3y`, `return_5y`,
`return_max`, `yearly_returns` (per-calendar-year breakdown), `returns_1y_platform`

#### Risk
`volatility_1y` / `_3y` / `_5y`, `return_risk_1y` / `_3y` / `_5y`,
`max_drawdown_1y` / `_3y` / `_5y` / `_max`

#### Composition
`top_holdings` (name + weight %), `top_holdings_weight`, `top_holdings_count`,
`holdings_reference_date`, `countries` (name + weight %), `sectors` (name + weight %),
`etf_description`

Dual-valued fields (`ter`, `quote`, `latest_quote`, `previous_quote`) come straight from the
source API as `{"raw": <float>, "localized": "<display string>"}` — both a machine-usable number
and the site's own display formatting. Everything sourced from the HTML profile page (returns,
volatility, drawdown, holding weights) is normalized to plain floats.

All records include `scraped_at`, `parse_confidence`, and `warnings`.

---

### Input

| Field | Type | Default | Notes |
|---|---|---|---|
| `isins` | array of strings | `["IE00B5BMR087", "IE00B4L5Y983"]` | Exact ISINs — takes priority over `searchQuery` |
| `searchQuery` | string | `"S&P 500"` | Free-text ETF discovery; used only when `isins` is empty |
| `universeCountry` | string (enum) | `"DE"` | Country context for search-mode discovery (`DE`/`AT`/`CH`/`IT`/`FR`/`ES`/`NL`/`GB`) |
| `currency` | string (enum) | `"EUR"` | Display currency for quote/pricing fields (`EUR`/`USD`/`CHF`/`GBP`) |
| `maxResults` | integer | `10` | Cap on ETFs returned in search mode |
| `proxyConfiguration` | object | Apify RESIDENTIAL | Works out of the box — no external proxy key required |

---

### How it works

justETF's fund-profile pages are server-rendered (no headless browser needed), so this actor
combines one HTML page fetch with two small JSON API calls per ETF:

1. `GET /en/etf-profile.html?isin=<ISIN>` — the full fund profile page (basics, returns, risk,
   holdings, countries, sectors, description).
2. `GET /api/etfs/cards?isin=...` — identity, TER, quote, and fund-size figures, batched across
   every requested ISIN in a single call.
3. `GET /api/etfs/<isin>/quote` — a live-ish quote with day-to-day change and trading venue.

All requests run through the Apify Proxy (RESIDENTIAL by default) so the actor works reliably
out of the box — you never need to supply your own proxy or API key.

---

### Example use cases

- Feed a portfolio tracker with live TER, returns, and risk data for a client's ETF holdings.
- Build a robo-advisor screening tool that ranks candidate ETFs by cost, volatility, and drawdown.
- Monitor country/sector drift in an index-tracking fund over time.
- Enrich a fintech dashboard with fund-level metadata (replication method, distribution policy,
  domicile) that most brokers don't surface.

# Actor input Schema

## `isins` (type: `array`):

Exact ISIN codes to fetch (e.g. IE00B5BMR087). Takes priority over Search query — if this list is non-empty, it is used and Search query is ignored.
## `searchQuery` (type: `string`):

Free-text search (index name, provider, ticker, keyword — e.g. 'S&P 500', 'MSCI World', 'iShares'). Used only when ISINs is empty. Matches justETF's own ETF search.
## `universeCountry` (type: `string`):

Country whose justETF universe (available ETFs, currency defaults) to search from. Affects which ETFs are visible/ranked in Search query mode.
## `currency` (type: `string`):

Currency for quote/TER/fund-size values.
## `maxResults` (type: `integer`):

Maximum number of ETFs to fetch and output. In Search query mode this also caps how many search hits are resolved into full records.
## `proxyConfiguration` (type: `object`):

Apify Proxy is required for reliable access — no external key needed, works out of the box.

## Actor input object example

```json
{
  "isins": [
    "IE00B5BMR087",
    "IE00B4L5Y983"
  ],
  "searchQuery": "S&P 500",
  "universeCountry": "DE",
  "currency": "EUR",
  "maxResults": 10,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
````

# Actor output Schema

## `results` (type: `string`):

Dataset containing ETF Data Extractor records (isin, name, ter, quote, returns, volatility, max\_drawdown, top\_holdings, countries, sectors, ...).

# 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 = {
    "isins": [
        "IE00B5BMR087",
        "IE00B4L5Y983"
    ],
    "searchQuery": "S&P 500",
    "universeCountry": "DE",
    "currency": "EUR",
    "maxResults": 10,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("bovi/etf-data-extractor").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 = {
    "isins": [
        "IE00B5BMR087",
        "IE00B4L5Y983",
    ],
    "searchQuery": "S&P 500",
    "universeCountry": "DE",
    "currency": "EUR",
    "maxResults": 10,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("bovi/etf-data-extractor").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "isins": [
    "IE00B5BMR087",
    "IE00B4L5Y983"
  ],
  "searchQuery": "S&P 500",
  "universeCountry": "DE",
  "currency": "EUR",
  "maxResults": 10,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call bovi/etf-data-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=bovi/etf-data-extractor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "ETF Data Extractor | TER, Returns, Holdings, Risk | justETF",
        "description": "Extract deep ETF data from justETF: ISIN, TER, live quote, returns (YTD/1M/3M/6M/1Y/3Y/5Y/MAX + yearly), volatility, max drawdown, top-10 holdings, country and sector weights. Search by query or pass exact ISINs. No login required. Pay per ETF record.",
        "version": "0.1",
        "x-build-id": "NtGVT76mtiIUrIMs6"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/bovi~etf-data-extractor/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-bovi-etf-data-extractor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/bovi~etf-data-extractor/runs": {
            "post": {
                "operationId": "runs-sync-bovi-etf-data-extractor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/bovi~etf-data-extractor/run-sync": {
            "post": {
                "operationId": "run-sync-bovi-etf-data-extractor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "proxyConfiguration"
                ],
                "properties": {
                    "isins": {
                        "title": "ISINs",
                        "type": "array",
                        "description": "Exact ISIN codes to fetch (e.g. IE00B5BMR087). Takes priority over Search query — if this list is non-empty, it is used and Search query is ignored.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "searchQuery": {
                        "title": "Search query",
                        "type": "string",
                        "description": "Free-text search (index name, provider, ticker, keyword — e.g. 'S&P 500', 'MSCI World', 'iShares'). Used only when ISINs is empty. Matches justETF's own ETF search."
                    },
                    "universeCountry": {
                        "title": "Investor country",
                        "enum": [
                            "DE",
                            "AT",
                            "CH",
                            "IT",
                            "FR",
                            "ES",
                            "NL",
                            "GB"
                        ],
                        "type": "string",
                        "description": "Country whose justETF universe (available ETFs, currency defaults) to search from. Affects which ETFs are visible/ranked in Search query mode."
                    },
                    "currency": {
                        "title": "Currency",
                        "enum": [
                            "EUR",
                            "USD",
                            "CHF",
                            "GBP"
                        ],
                        "type": "string",
                        "description": "Currency for quote/TER/fund-size values."
                    },
                    "maxResults": {
                        "title": "Max ETFs",
                        "minimum": 1,
                        "maximum": 500,
                        "type": "integer",
                        "description": "Maximum number of ETFs to fetch and output. In Search query mode this also caps how many search hits are resolved into full records."
                    },
                    "proxyConfiguration": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Apify Proxy is required for reliable access — no external key needed, works out of the box."
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
