Home / Guides / XBRL & financials
XBRL & financials

Download XBRL XSD and instance files from a filing

List a filing's XBRL files (schema, linkbases, instance), download the .xsd and _htm.xml, and inspect extension elements and facts with Python.

Most of the time XBRL-to-JSON is what you want: statements already grouped, facts already resolved. Sometimes you need the raw files instead, for example to load a filing into an XBRL processor, archive the original taxonomy, or read the company's own extension elements. Every XBRL filing ships the same set:

FileWhat it holds
*.xsdThe company's extension schema: elements it defined itself, such as its own segment members
*_htm.xmlThe instance document: every fact with its context (period, dimensions) and unit
*_cal.xmlCalculation linkbase: which facts add up to which totals
*_def.xmlDefinition linkbase: dimension and hypercube relationships
*_lab.xmlLabel linkbase: human readable labels for every element
*_pre.xmlPresentation linkbase: the order facts appear in each statement
*-xbrl.zipAll of the above in one archive

The script

/v1/files lists every document in a filing. /v1/download fetches any of them as filed. This script downloads the schema and the instance of Alphabet's fiscal 2025 10-K, then inspects both with the standard library.

import os
import re
import requests
import xml.etree.ElementTree as ET

BASE = "https://secfeedapi.com"
HEADERS = {"Authorization": f"Bearer {os.environ['SECFEED_KEY']}"}

# Alphabet's 10-K for fiscal 2025
cik, accession = "1652044", "0001652044-26-000018"
files = requests.get(f"{BASE}/v1/files", params={"cik": cik, "accessionNo": accession},
                     headers=HEADERS, timeout=60).json()

print("XBRL files in the filing:")
xbrl = [f for f in files if re.search(r"\.xsd$|_(cal|def|lab|pre|htm)\.xml$|-xbrl\.zip$", f["name"])]
for f in xbrl:
    print(f"  {f['name']:<42} {int(f['size'] or 0):>10,} bytes")

os.makedirs("xbrl", exist_ok=True)
for f in xbrl:
    if f["name"].endswith((".xsd", "_htm.xml")):
        r = requests.get(f"{BASE}/v1/download", params={"url": f["url"]}, headers=HEADERS, timeout=120)
        r.raise_for_status()
        open(os.path.join("xbrl", f["name"]), "wb").write(r.content)

# the schema: the company's own (extension) elements
xsd = next(f["name"] for f in xbrl if f["name"].endswith(".xsd"))
schema = ET.parse(os.path.join("xbrl", xsd)).getroot()
XS = "{http://www.w3.org/2001/XMLSchema}"
elements = [e.get("name") for e in schema.iter(f"{XS}element")]
print(f"\n{xsd}: {len(elements)} extension elements, for example:")
for name in elements[:6]:
    print("  ", name)

# the instance: every fact, by namespace prefix
inst = next(f["name"] for f in xbrl if f["name"].endswith("_htm.xml"))
root = ET.parse(os.path.join("xbrl", inst)).getroot()
ns = {uri: p for p, uri in re.findall(r'xmlns:(\w[\w-]*)="([^"]+)"', open(os.path.join("xbrl", inst)).read(20000))}
facts = [el for el in root if el.get("contextRef")]
by_prefix = {}
for el in facts:
    prefix = ns.get(el.tag[1:].split("}")[0], "?")
    by_prefix[prefix] = by_prefix.get(prefix, 0) + 1
print(f"\n{inst}: {len(facts):,} facts, {len(root.findall('{http://www.xbrl.org/2003/instance}context'))} contexts")
for p, n in sorted(by_prefix.items(), key=lambda x: -x[1]):
    print(f"   {p:<8} {n:>6,}")

Output

XBRL files in the filing:
  0001652044-26-000018-xbrl.zip                 695,448 bytes
  goog-20251231.xsd                              78,861 bytes
  goog-20251231_cal.xml                         176,813 bytes
  goog-20251231_def.xml                         444,460 bytes
  goog-20251231_htm.xml                       2,880,903 bytes
  goog-20251231_lab.xml                       1,100,588 bytes
  goog-20251231_pre.xml                         762,080 bytes

goog-20251231.xsd: 136 extension elements, for example:
   CapitalClassCMember
   A2.375SeniorNotesDue2028Member
   A2.500SeniorNotesDue2029Member
   A2.875SeniorNotesDue2031Member
   A3.000SeniorNotesDue2033Member
   A3.125SeniorNotesDue2034Member

goog-20251231_htm.xml: 1,861 facts, 444 contexts
   us-gaap   1,602
   goog        143
   dei          77
   ecd          21
   cyd          15
   srt           3

The instance holds 1,861 facts. Most use standard us-gaap elements. 143 use Alphabet's own goog elements, defined in the .xsd: mostly members such as share classes and individual bond issues. The ecd facts are executive compensation disclosures and cyd facts are cybersecurity disclosures, both added to the SEC taxonomy in recent years.

Tips

  • Inline XBRL. Since 2019 to 2021 (phased by filer size) the primary HTML document is itself inline XBRL. The _htm.xml instance is the SEC's extracted copy, which is easier to parse than the tagged HTML.
  • Use the zip for archives. One request instead of seven, and it is what XBRL tools expect.
  • Older filings. Filings before inline XBRL name the instance <ticker>-<date>.xml without _htm. Match on the extension and the absence of _cal, _def, _lab and _pre.
  • Fair access. If you download many filings, keep your request rate moderate and cache files: filings never change once accepted.

Next steps

More xbrl & financials guides

Run this guide with your own key

500 free API calls a month. Every example on this page works on the free plan.

Get free API key →