Which ETFs hold a stock, by API

View as Markdown What changed

Which ETFs hold a given stock, and at what weight? GET /api/v1/sec/{ticker}.json lists every covered fund that holds the stock: holders from the issuers' own files, holders_sec_nport from SEC Form N-PORT filings, and holders_all with both, heaviest first, each row naming its layer. Every row carries the date of its fund's file.

Live example

The request: GET /api/v1/sec/nvda.json

NVDA on this build: held by 177 funds read from their issuers' files and 569 read from SEC filings. The five heaviest of the first list, each with the date of its fund's file:

Part of the answer, data through 2026-10-12
{
  "ticker": "NVDA",
  "name": "Nvidia",
  "held_by": 177,
  "held_by_sec_nport": 569,
  "holders": [
    ["GXPT", 19.82, "2026-10-12"],
    ["VGT", 17.7869, "2026-08-31"],
    ["VUSG", 16.9219, "2026-10-13"],
    ["IYW", 16.7687, "2026-10-12"],
    ["TOPT", 16.1038, "2026-10-12"]
  ]
}

Code

Each block below is a file that runs against each night's build of this site that has the files it reads, before it is published, through the same Worker that answers the API: the code shown is the code that ran. A program that calls the API on its own should name its project in its User-Agent; it is a request, not a condition.

cURL

Prints the whole answer as JSON; add | jq to pick fields.

Terminal
curl -s https://tickerinside.com/api/v1/sec/nvda.json

Python

Needs Python 3.9 or later and the tickerinside client, pip install tickerinside, which uses only the standard library.

stock-holders.py
import tickerinside as ti

nvda = ti.holders("NVDA")
print(nvda.data["counts"]["issuer"], nvda.data["counts"]["sec_nport"])
for row in nvda.data["issuer"][:5]:
    print(row["fund"], row["weight_pct"], row["holdings_as_of"])

JavaScript

Runs as a module in Node.js 20 or later (save it as a .mjs file), in Deno, or in a browser page: CORS is open.

stock-holders.mjs
const url = "https://tickerinside.com/api/v1/sec/nvda.json";
const nvda = await (await fetch(url)).json();
console.log(nvda.held_by, nvda.held_by_sec_nport);
for (const [fund, weight, date] of nvda.holders.slice(0, 5)) {
  console.log(fund, weight, date);
}

Google Sheets

Paste it into a cell: Sheets fills the rows below with the CSV twin of the answer, the date on every row. Excel and Power BI read the same address with Power Query; the queries are on ETF holdings in Excel and Google Sheets.

Cell A1
=IMPORTDATA("https://tickerinside.com/api/v1/sec/nvda.csv")

Fields to read

  • holders: The funds read from their issuers' own files that hold the stock: fund, percent weight, date of the file. Heaviest first.
  • holders_sec_nport: The funds read from their latest SEC Form N-PORT filing, in the same form, dated to the quarter end of the filing.
  • holders_all: Both lists in one, heaviest first: fund, weight, date, layer, rank of the stock in the fund, the fund's positions and the value held in millions of US dollars.
  • held_by: How many funds read from issuer files hold it.
  • held_by_sec_nport: How many funds read from SEC filings hold it.
  • cite_as: A line to print under a figure.

Limits

  • Only covered funds are counted: US ETFs read from their issuers' own files or from SEC filings, not mutual funds or funds listed outside the US.
  • Rows from SEC filings are dated to the quarter end their filing describes, two to four months before it is read, and the issuer rows to their own file. The two are kept in separate lists, and holders_all names the layer of each row.
  • A security that covered funds hold and that has no stock file of its own answers at the same address, with its holders and no market data.
  • /api/v1/sec/{ticker}.csv is the same list as CSV, heaviest first.

Reference