Yahoo Finance doesn't give me ETF holdings or fund data by ISIN. What can I use instead?
Yahoo Finance and yfinance cover prices, not factsheets, and key by ticker per exchange rather than ISIN. For holdings, sector weights, TER, risk indicator and KID costs of UCITS funds, use an ISIN-keyed fund data API. Comparison and code.Updated 12 September 2026 · by FundFacts APIShort answer
Yahoo Finance is a price source: yfinance gives you quotes and some summary fields per exchange ticker, but not the factsheet (full top holdings with weights, sector and country tables, TER and KID costs, the 1–7 risk indicator, calendar returns versus benchmark) and it does not key by ISIN, so a UCITS ETF listed on five exchanges is five tickers. FundFacts API returns exactly those figures from the fund house's documents for any ISIN, with a free plan of 15 lookups a month. Keep Yahoo for prices and use the API for the factsheet.
Where each one fits
| Need | Yahoo Finance / yfinance | FundFacts API |
|---|---|---|
| Daily or intraday market price of an ETF | ✓ | ✗ (monthly NAV series only) |
| Look up by ISIN (one identifier per share class) | ✗ (ticker per exchange) | ✓ |
| Top holdings with weights, holdings count | Partial, mostly US ETFs | ✓ from the issuer's holdings file or factsheet |
| Sector, country, asset, credit-quality tables | Partial | ✓ |
| TER / ongoing charges, KID cost table | Sometimes an expense ratio | ✓ TER plus entry, exit, ongoing, transaction, RIY |
| 1–7 SRRI / SRI risk indicator, SFDR article | ✗ | ✓ |
| Calendar and annualised returns vs benchmark | Partial | ✓ as printed on the factsheet |
| UCITS and other European funds | Thin | Core coverage |
| Terms for use in a product | Unofficial scraping | Commercial licence on Pro and above |
The ISIN problem in one example
iShares Core MSCI World UCITS ETF is IWDA on Euronext Amsterdam, SWDA on the London Stock Exchange, EUNL on Xetra and IWDA on Borsa Italiana. In Yahoo Finance those are four tickers with four partially populated profiles. In an ISIN-keyed API it is one identifier, IE00B4L5Y983, with one payload:
pythonimport os, requestsr = requests.get(f"https://fundfactsapi.com/api/v1/funds/IE00B4L5Y983", headers={"Authorization": f"Bearer {os.environ['FUNDFACTS_API_KEY']}"}, timeout=300)d = r.json()["data"]print(d["headlineMetrics"]["ter"], d["riskRating"], d["topHoldings"][:5], d["sector"][:3], d["dataAsOf"])
Using both
A typical stack keeps yfinance (or the broker's feed) for prices and charts and calls the fund API once a day per ISIN for the factsheet fields, cached until expiresAt. NAV vs market price explains why the two numbers differ and which to show where.
The Free plan gives 15 lookups a month without a card, enough to check the funds you care about. Starter is $9.99 a month for 500 requests with batch calls of 10 ISINs, HTML and PDF factsheets and the AI companion kit. Pro is $49 for 9,000 requests, batches of 50, portfolio look-through, holdings overlap, document extraction and a commercial licence. Scale is $249 for 60,000 requests, batches of 200, a change feed, webhooks and bulk export.
Verify it yourself
The demo endpoint returns the live payload for a fund that is already in the store, without a key. Everything on this page can be checked against it.bashcurl -s https://fundfactsapi.com/api/v1/demo/funds/IE00B4L5Y983 | jq '{name, asOf: .data.dataAsOf, ter: .data.headlineMetrics.ter, risk: .data.riskRating, top: .data.topHoldings[:3]}'