One of the app's features lets you select VanEck ETFs in the Watchlist and aggregate their holdings to see how often each ticker appears across the selected funds. Repeated holdings make overlapping exposure visible: the more selected funds include a ticker, the greater its potential influence on the portfolio; gains in that holding may help, while declines may hurt, and actual impact also depends on each fund's position size. Another feature makes it faster and easier to find funds with stronger growth over different periods, higher dividend yields or distributions, greater Total Return (price performance plus dividends), and other key performance metrics. A single-file client-side tool reading the generated ./api/vaneck static feed (VanEck ETF catalog, per-fund product pages, daily holdings and NAV history downloads, VanEck's own performance and distribution history, SEC EDGAR N-PORT-P and Yahoo Finance as fallbacks) into a searchable ETF/asset-class catalog with per-fund tabs, watchlist aggregation, ticker copy and CSV/TXT export — the same look, feel, columns and business logic as the sibling applications.
bunx degit daggerok/VanEck#main ./12345 && cd $_
bunx serve . -p 1234
open http://0:1234The published application is available at https://daggerok.github.io/VanEck/. No build step, no bundler, no server — index.html carries the markup and a Babel-standalone bootstrap that transpiles app.tsx in the browser. The app reads only relative ./api/vaneck/** files generated by scripts/update-data.ts; the committed feed is complete, so the site works offline with no update run at all.
Run the updater with Bun:
bun test scripts/update-data.test.ts
./scripts/update-data.tsRun ./scripts/update-data.ts -h (or --help) to print every configuration variable with its default and usage examples.
The Update VanEck ETF data GitHub Actions workflow (.github/workflows/update-data.yml, workflow_dispatch only) exposes the same settings as manual inputs and commits api/vaneck/** and nothing else — a data run never rewrites app code or CI config. All supplied filters use AND logic.
| Block | Source | Notes |
|---|---|---|
| Fund universe, name, ticker, gross/net expense ratio, AUM, category | vaneck-etfs-fees.pdf ("VanEck ETF Guide") |
91 ETFs: the guide's 88 plus RSX/RSXJ (kept in the finder while in liquidation) and VEEM (launched 09/09/2026, after the guide's as-of date) |
| NAV, YTD, Total Net Assets, Expense Ratio, Inception Date, 30-Day SEC Yield*, Exchange*, CUSIP*, ISIN*, fund name, breadcrumb | https://www.vaneck.com/us/en/investments/<slug>/ |
Canonical slugs come from scripts/vaneck-slugs.ts, harvested from the Investment Finder; etf-<ticker> is a greedy 302 for unknown tickers, so the slug table is authoritative. * only where VanEck server-renders the field. |
| Holdings (daily) | …/investments/<slug>/downloads/holdings/ |
A real .xlsx (OOXML) workbook, not HTML — see below |
| NAV / premium-discount history | …/investments/<slug>/downloads/fundhistoprices/ |
Also .xlsx; descending, inception → present |
| Declared distribution frequency, 30-Day SEC / Distribution / 12M yields, YTD + tenor fallbacks | Verified Investment Finder transcription in scripts/vaneck-finder.ts (tabs are client-rendered, read 2026-09-20) |
Official VanEck figures; the updater prefers them over anything inferred |
| Listing exchange | Nasdaq Trader symbol directory, Yahoo Finance chart meta.exchangeName as fallback |
Neither is in the VanEck page payload, so both resolve at refresh time |
| Fund documents (fact sheet, prospectuses, SAI, reports) | Deterministic VanEck URL schemes (vaneckFundDocuments()) |
Verified against the finder ?tab=lit Resources panels |
| Holdings fallback | SEC EDGAR Form N-PORT-P, VanEck ETF Trust CIK 0001137360 | Used only when the VanEck download is unavailable (EDGAR_FALLBACK=1) |
| Performance (TR/CAGR/SI Ann.) | VanEck's Average Annual Total Returns block (JSON) | See Performance and distributions below |
| Distribution history | VanEck's own Distribution History block (JSON) | Yahoo Finance chart feed is the fallback for the handful of fund pages without this block |
vaneck.com sits behind a WAF that answers with a redirectVE=generic cookie-and-redirect dance and throttles with 403; fetchWithRetry/fetchVanEckWithManualRedirect in scripts/update-data.ts handle both with a small cookie jar and bounded backoff.
The holdings and history "downloads" endpoints serve genuine .xlsx workbooks, not server-rendered HTML tables. scripts/update-data.ts includes a minimal, dependency-free ZIP + SpreadsheetML reader (readZipEntries / parseXlsxSheet / loadSharedStrings) that tolerates VanEck's own namespaced worksheet XML (<x:row>, <x:c>, <x:v>).
VanEck ships two different holdings column sets from the same URL:
- Equity:
Number | Ticker | Holding Name | Identifier (FIGI) | Shares | Asset Class | Market Value (US$) | Notional Value | % of Net Assets.Notional Valueis--for every position. Non-US listings keep their local exchange suffix (NST AU,EDV LN), and cash balances appear as-USD CASH-. - Fixed income:
Number | Holding Name | Maturity | Identifier (FIGI) | Coupon | Asset Class | Par Value/Contracts | Market Value | Notional Value | % of Net Assets | Country | Currency— no Ticker column at all, so the FIGI is the only identifier. The same issuer can appear once per maturity, which is why the Watchlist dedupes on identifier when no ticker exists.
Both are normalised onto one shared column contract by parseVanEckHoldings(), which detects the fixed-income sheet by the presence of a Maturity header. OUNZ (a physically-backed gold trust) publishes no holdings workbook at all, same as SPDR's GLD/SLV.
The fund page's "Average Annual Total Returns" and "Distribution History" widgets are populated by a React component after load, but the component itself just calls a plain, unauthenticated JSON endpoint keyed by the block's own id — no browser or JS execution is needed:
GET /Main/PerformanceHistoryBlock/GetContent/?blockid=<id>&pageid=<id>&ticker=<TICKER>&reactlang=en&reactctr=us&epieditmode=false&latest=false&contextmode=Default
GET /Main/NavDistributionsBlock/GetContent/?blockid=<id>&pageid=<id>&ticker=<TICKER>&…
parseVanEckFundPage() reads each block's blockid/pageid straight off the page's own <ve-performancehistoryblock> / <ve-navdistributionsblock> tags (they differ per fund and are never guessed), then fetchVanEckPerformance() / fetchVanEckDistributions() call the endpoint directly. PerformanceHistoryBlock returns both a NAV-basis and a Market-Price-basis row; this feed uses the NAV row, matching every other return figure. Where the block publishes a quarter-end row it is kept as returns.quarterEnd. A too-young fund's longer tenors come back JSON null from VanEck itself (verified against ETHV, a 2024-inception fund) — never invented as 0 or backfilled.
| Metric | Status | Reason |
|---|---|---|
| TR 1Y / 3Y / 5Y / 10Y, CAGR 3Y / 5Y / 10Y, SI Ann. | published from VanEck's own Average Annual Total Returns block; — only for a tenor the fund hasn't existed long enough to report |
See Performance and distributions above |
| SEC Yield (30-day) | official Investment Finder value first, else the server-rendered fund header stat | — only where VanEck publishes none (8 funds: non-distributing, pre-income or liquidating) |
| Dividend Yield | official Investment Finder Distribution Yield where published, else the indicated yield — and only when the latest payout is recent (≤400 days) | Stale payouts (e.g. BUZZ Dec-2024) no longer annualise into a phantom yield; — where neither source yields a figure |
| Distribution Yield / 12M Yield | official Investment Finder figures, published verbatim | The finder's impossible EMBX 12M cell (-777.30%, a VanEck site bug) is stored as null, never copied |
| RSX / RSXJ tenors | annualised 1/3/5/10Y + SI from the Investment Finder month-end table, flagged as liquidation figures | Cumulative tenors were never published and stay null; both funds suspended since 2022 |
| CUSIP / ISIN | published where the Fund Details panel server-renders it, otherwise null |
VanEck's holdings sheet publishes a FIGI per holding; CUSIP/ISIN are fund-level only |
| Environment variable | Default | Meaning |
|---|---|---|
MAX_FETCHES |
0 |
Funds to process; 0 = full pass. A positive value resumes after the cursor in api/vaneck/update-state.json. |
TICKERS |
"" |
Space/comma separated ticker allowlist; ANDed with the other filters, never overriding them. |
CATEGORY |
"" |
Substring match on the vaneck.com asset class. |
AUM / TER / DIVIDEND_YIELD / SEC_YIELD |
"" |
min:max ranges; AUM also accepts nano/micro/small/mid/large. |
CONCURRENCY / REQUEST_SLEEP |
3 / 1.5 |
Politeness. vaneck.com throttles with 403, retried with backoff. |
HOLDINGS_PAGE_SIZE / HISTORY_PAGE_SIZE |
250 / 1000 |
Rows per generated JSON page. |
MAX_RETRIES |
3 |
Retries after the initial request for network errors and HTTP 408/425/429/5xx. |
EDGAR_FALLBACK |
off | Use N-PORT-P when a holdings download is unavailable. |
SKIP_YAHOO / SKIP_VANECK |
off | Skip the Yahoo Finance or vaneck.com fetch stages. |
STORE_RAW_DOWNLOADS |
off | Keep one raw sample under api/vaneck/raw. |
OFFLINE_SEED |
off | Replay scripts/vaneck-verified.ts instead of fetching, for a network-free run. |
TICKERS combines with the AUM/TER/yield filters using AND logic; it does not override them. Funds not selected for a successful update keep their prior published metadata and data files, so a bounded or partly failed run can never empty the site.
MAX_FETCHES=10 ./scripts/update-data.ts
TICKERS="GDX SMH MOAT" ./scripts/update-data.ts
AUM="1B:" TER=":0.5" ./scripts/update-data.tsThe browser app is intentionally build-free: index.html carries the markup, styles and bootstrap, and app.tsx is TypeScript compiled in the browser with Babel standalone — no build step, no bundler, no tsconfig.json needed. Bun runs TypeScript out of the box.
Verification before every publish: bun install --frozen-lockfile, bun test, and git diff --check.
| Brand | Where to get the data |
|---|---|
| abrdn (Aberdeen) | aberdeeninvestments.com | aberdeen |
| Amplify | amplifyetfs.com | Amplify |
| Fidelity | fidelity.com | Fidelity |
| Franklin Templeton | franklintempleton.com | Franklin |
| Global X | globalxetfs.com/explore | Global X |
| Goldman Sachs | am.gs.com | Goldman-Sachs |
| Invesco | invesco.com | Invesco |
| iShares | ishares.com | iShares |
| JPMorgan | am.jpmorgan.com | JPMorgan |
| NEOS | neosfunds.com | Neos |
| ProShares | proshares.com | ProShares |
| Schwab | schwabassetmanagement.com | Schwab |
| SPDR | ssga.com | SPDR |
| VanEck | vaneck.com | VanEck |
| Vanguard | investor.vanguard.com | Vanguard |
| WisdomTree | wisdomtree.com | WisdomTree |
| Application | Data provider | Repository |
|---|---|---|
| abrdn (Aberdeen) | Official Aberdeen gateway + SEC N-PORT holdings fallback + Yahoo history/dividends | aberdeen |
| Amplify | Amplify ETFs (Firestore data feed) | Amplify |
| Fidelity | SEC EDGAR N-PORT-P + Yahoo Finance | Fidelity |
| Franklin Templeton | franklintempleton.com ETF listings + product pages + SEC EDGAR N-PORT-P | Franklin |
| Global X | globalxetfs.com Next.js catalog and fund pages + dated full-holdings CSV | Global X |
| Goldman Sachs | am.gs.com fund finder + detail pages + SEC EDGAR N-PORT-P | Goldman-Sachs |
| Invesco | invesco.com CSV downloads + Yahoo Finance | Invesco |
| iShares | iShares (BlackRock) product workbooks | iShares |
| JPMorgan | am.jpmorgan.com fund explorer + product-data JSON | JPMorgan |
| NEOS | neosfunds.com lineup table + official fund pages + daily holdings CSV | Neos |
| ProShares | proshares.com ETF finder + fund pages + official data host | ProShares |
| Schwab | schwabassetmanagement.com product pages + CSV exports | Schwab |
| SPDR | SSGA / State Street public feeds | SPDR |
| VanEck | vaneck.com ETF finder + product pages | VanEck |
| Vanguard | Vanguard product pages + SEC EDGAR N-PORT-P | Vanguard |
| WisdomTree | WisdomTree product table + SEC EDGAR N-PORT-P + Yahoo Finance | WisdomTree |
MIT — same as all sibling ETF repositories.
VanEck® and the fund names/tickers referenced here are trademarks of Van Eck Associates Corporation. This is an independent, unofficial tool; it is not affiliated with, endorsed by, or sponsored by VanEck. All data is reproduced from VanEck's own public downloads, with public SEC EDGAR filings and Yahoo Finance as fallbacks, for research purposes. All other trademarks, including index names, are the property of their respective owners.