How to get ETF holdings as data

Issuers publish ETF holdings daily, each in its own format; the SEC publishes them quarterly, two months late. Which to use, and what each one leaves out.

There are two free sources and they answer different questions. Most issuers publish each ETF's full holdings every business day as a spreadsheet on their own site, each in its own layout and under its own terms. The SEC publishes the same funds' holdings from Form N-PORT, structured and uniform, but only for the last month of each fiscal quarter and up to 60 days after it. Daily files are current and overwritten every day; N-PORT is uniform and archived.

The short way

N-PORT is filed per series — the fund — and a ticker is a share class of a series, so the first step is the SEC's own ticker map. Then list the series' N-PORT filings and read one:

import json, re, time, urllib.request
import xml.etree.ElementTree as ET

UA = {"User-Agent": "Your Name you@example.com"}  # the SEC asks you to declare yourself
NS = {"n": "http://www.sec.gov/edgar/nport"}

def get(url):
    time.sleep(0.15)  # stay under ten requests a second
    with urllib.request.urlopen(urllib.request.Request(url, headers=UA)) as r:
        return r.read()

# ticker -> registrant CIK, series ID, class ID
mf = json.loads(get("https://www.sec.gov/files/company_tickers_mf.json"))
cik, series, cls, sym = next(r for r in mf["data"] if r[3] == "IVV")

atom = get("https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany"
           f"&CIK={series}&type=NPORT-P&count=10&output=atom").decode()
filings = re.findall(r"<accession-number>([^<]+)</accession-number>.*?"
                     r"<filing-type>([^<]+)</filing-type>", atom, re.S)
acc = next(a for a, t in filings if t == "NPORT-P")  # skip the amendments for now

x = ET.fromstring(get(f"https://www.sec.gov/Archives/edgar/data/{cik}/"
                      f"{acc.replace('-', '')}/primary_doc.xml"))
print(x.findtext(".//n:seriesName", namespaces=NS), x.findtext(".//n:repPdDate", namespaces=NS))
for h in x.iterfind(".//n:invstOrSec", NS):
    print(h.findtext("n:name", namespaces=NS), h.findtext("n:cusip", namespaces=NS),
          h.findtext("n:balance", namespaces=NS), h.findtext("n:units", namespaces=NS),
          h.findtext("n:valUSD", namespaces=NS), h.findtext("n:pctVal", namespaces=NS),
          h.findtext("n:assetCat", namespaces=NS))

Run on 4 October 2026, the iShares Core S&P 500 ETF's latest report describes 30 June 2026 and was filed on 25 August: 508 holdings, of which 503 are equities, three short-term investments, one an S&P 500 E-mini futures contract and one a contingent value right on Hologic. The same day, State Street's daily file for SPY describes 1 October.

What the options are

The issuer's daily file. Not a card, because it is not a product: it is a download link on each fund's page, free, refreshed every business day, and the most current holdings anywhere. State Street's SPY file is an Excel workbook with three rows of fund details above the table, eight columns — name, ticker, CUSIP, SEDOL, weight, sector, shares, currency — and several rows of legal text below it. Every other sponsor's file has a different layout. For one or two funds this is the shortest path; for a hundred funds across six sponsors it is six parsers and six sets of terms.

The regulator's copy. SEC EDGAR holds every N-PORT as XML, keyless, the day it is filed, plus quarterly flat-file data sets covering October 2019 onward. The structure is identical for every fund, which is the whole point: asset category, issuer category, country, fair-value level, securities-lending flags and a full derivatives block per holding. The second quarter of 2026 data set is a 440 MB zip (the SEC's page prints 420.28, in binary megabytes), updated quarterly; the SEC's description is information from filings that have been publicly disseminated, with the usual disclaimer that it is not a substitute for them.

Somebody else's parser. Financial Modeling Prep serves ETF and fund holdings by symbol on its Ultimate tier, $149 a month billed annually, beside statements, prices and transcripts. Intrinio sells an ETF holdings feed through the same API, CSV, S3 and Snowflake routes as its other data, marked Enterprise. sec-api.io parses N-PORT to JSON, Enterprise-only.

History for a backtest. Neither free source keeps a dated archive of issuer files. QuantConnect does: its ETF constituents dataset is built from issuers' published holdings from June 2009, mounted inside the backtester rather than sold as a download. Historical index constituents explains why an ETF's holdings are the cheapest proxy for an index's membership, and where the proxy is wrong.

Where this breaks

N-PORT is public four times a year, two months late. Funds file a report for every month, but under the rules in force today only the third month of each fiscal quarter is made public, and it is due 60 days after that month ends; the first two months stay confidential. The SEC adopted amendments in August 2024 requiring every monthly report within 30 days and making each public 60 days after month end, which would triple the public data. In April 2025 it delayed them to 17 November 2027 for larger fund groups and May 2028 for smaller ones, and in February 2026 it proposed going back: 45 days to file and quarterly publication restored. Until November 2027 at the earliest, and for good if that proposal is adopted, a holdings series from EDGAR has one point per quarter, and the most recent point is two to five months old.

Fiscal quarters belong to the fund. The public month is the third month of the fund's fiscal quarter, not the calendar's. A fund whose fiscal year ends in March, June, September or December publishes calendar quarter-ends; one whose year ends in October publishes January, April, July and October. Join two funds on "Q2" and you may be joining holdings two months apart. Key on repPdDate, the date the holdings describe.

Amendments arrive months later, under the same name. EDGAR's type filter for NPORT-P returns NPORT-P/A too. Among the iShares Core S&P 500 ETF's last ten reports is an amendment filed on 13 July 2026 for the period ending 30 September 2025 — nine months after the fact. Key each report on series and period, keep the latest version, and re-read periods you thought were closed.

Issuer files are not one format, and they are not data products. Columns, header rows, footers, date formats and identifiers all differ by sponsor, and change when the sponsor redesigns its site. A download link that moved can still answer with status 200 and a CSV content type while the body is an HTML page — which is what one large sponsor's long-circulated link returned on 4 October 2026 — so check the first bytes, not the headers. And the files carry terms: State Street's ends with a notice that no part of it may be reproduced or transmitted without its written consent. Downloading for your own analysis and republishing the table are different things.

Not every row is a security. The SPY daily file of 1 October lists 506 rows, among them a US DOLLAR line with an internal identifier that is not a CUSIP, and a contingent value right left over from a takeover, carried under a made-up ticker. Its weights sum to 100.23%. N-PORT classifies the same kinds of rows — the iShares fund's index futures as a derivative, SPY's contingent value right as "other derivative" — but a pipeline that treats every row as a stock with a ticker will produce a few that do not exist.

Derivatives are exposure, not holdings. An index fund keeps a futures contract to equitise cash; a leveraged, inverse or "buffer" ETF may hold little but swaps and options. In N-PORT those sit in a derivativeInfo block with counterparties, notional amounts and the reference instrument, and the value reported for the row is the contract's value, not the exposure it creates. Summing pctVal across a swap-based fund tells you almost nothing about what it is long. Issuer files are less consistent still: some list swaps by counterparty, some by underlying, some not at all.

A ticker is a class; holdings belong to the fund. The SEC's ticker map puts VTI and VTSAX on the same series, because Vanguard's ETF is one share class of a mutual fund. Their N-PORT is one report covering both, and the percentages are the fund's. Treat a ticker as a pointer to a series before you treat it as a portfolio.

The identifier is a licensed one, and sometimes it is zeros. Holdings are keyed by CUSIP, which is licensed — what that means for a database you build is in CUSIP, ISIN and FIGI. A ticker for each holding is optional in N-PORT, and SPY's report fills it in for none of them. In SPY's 30 June 2026 report, 29 of 504 holdings carry 000000000 as the CUSIP — companies incorporated outside the US, such as Allegion plc — and only the ISIN identifies them. The iShares fund's report for the same date writes N/A in the same place, on 30 rows: the placeholder is the filer's choice. Join on CUSIP alone and those rows fall out.

Not every exchange-traded product files. N-PORT is for registered management investment companies and ETFs organised as unit investment trusts, excluding money market funds. Commodity trusts that are not registered investment companies do not file it, and their holdings are whatever their own reports say. Missing from EDGAR does not mean missing from the market.

EDGAR's limits still apply. Ten requests a second and a declared User-Agent, per the SEC's fair-access policy. Walking every ETF's report one XML at a time is several thousand requests a quarter; the quarterly data set is the better route for the whole market.

If you outgrow this

When you need every month, not every quarter, do not plan on November 2027 — the SEC has proposed keeping publication quarterly — and buy it instead: the private monthly reports are not public, so a vendor's monthly series comes from something other than N-PORT — usually the issuers' own files, archived.

When you need a dated history of daily files, start archiving them yourself today, or use QuantConnect's constituents dataset inside its platform. There is no way to download the past from the sponsors.

When the question is a fund manager rather than a fund, the quarterly 13F is the form; see How to get 13F holdings as data.

The tools that do this

In the order this page recommends trying them. Paid placement does not affect this order.

  1. SEC EDGAR

    N-PORT as XML per fund the day it is filed, and quarterly flat files since late 2019. Free and keyless, one quarter-end per quarter, up to 60 days late.

    Every US filing since 1994, free and keyless — the limit is ten requests a second.

    FreeFree tier

  2. Financial Modeling Prep

    ETF and mutual-fund holdings by symbol beside prices and statements, on the $149-a-month Ultimate tier. Display or redistribution is Enterprise-only.

    Financial statements, ratios and filings for 70,000+ securities across 60+ exchanges.

    $22/moFree tier

  3. QuantConnect

    ETF constituents built from issuers' published holdings since June 2009, mounted inside its backtester rather than sold as a download.

    The open-source LEAN engine, plus a hosted cloud that runs it against real brokers.

    $84/moFree tierOpen source

  4. Intrinio

    An ETF holdings feed by API, CSV, S3 or Snowflake, marked Enterprise on its pricing page, so a sales call rather than a number.

    XBRL-standardised US financials, options analytics and an MCP server.

    $150/mo

  5. sec-api.io

    N-PORT already parsed to JSON beside 13F and Form 4, but only on the quote-only Enterprise tier.

    Every EDGAR filing since 1993 as JSON, plus a websocket push of new ones.

    $55/mo

FAQ

How often is ETF holdings data published by the SEC?

Funds file Form N-PORT for every month, but until the SEC's 2024 amendments take effect only the report for the third month of each fiscal quarter is made public, and it is due 60 days after that month ends. The amendments, which make every month public 60 days after month end, were delayed in April 2025 to 17 November 2027 for larger fund groups, and in February 2026 the SEC proposed restoring quarterly publication instead.

Where can I download an ETF's holdings every day for free?

From the issuer. Most large ETF sponsors publish each fund's complete holdings every business day as a spreadsheet or CSV on the fund's page. The files are free to download, differ in layout from sponsor to sponsor, and carry the sponsor's own terms — State Street's SPY file, for example, says no part of it may be reproduced without its written consent.

Do all ETFs file N-PORT?

No. N-PORT is filed by registered management investment companies and ETFs organised as unit investment trusts. Exchange-traded products that are not registered investment companies — most physically backed commodity trusts, for example — do not file it, and neither do money market funds. If a ticker returns nothing, check what the product is registered as before assuming the data is missing.

Sources

  1. Form N-PORT Data Sets — U.S. Securities and Exchange Commission, read
  2. Form N-PORT and Form N-CEN Reporting; Guidance on Open-End Fund Liquidity Risk Management Programs (89 FR 73764) — Securities and Exchange Commission,
  3. Form N-PORT and Form N-CEN Reporting; Delay of Effective and Compliance Dates (90 FR 16812) — Securities and Exchange Commission,
  4. Form N-PORT Reporting, proposed rule (91 FR 8582) — Securities and Exchange Commission,
  5. SPDR S&P 500 ETF Trust — daily holdings file — State Street Investment Management, read
  6. Accessing EDGAR Data — U.S. Securities and Exchange Commission, read

The catalogue next door

This page names a handful of cards. The rest of them are in Fundamental Data & Stock Research Platforms, each filled in against the same schema, with the fields to narrow it yourself.

Last updated . Corrected in place: this is a reference page, not a dated post.