← All posts · Published 2026-07-23
Working with SEC EDGAR XBRL Data: A Tutorial
XBRL submissions unlock machine-readable SEC filings, but parsing them requires understanding concept mappings, validation rules, and the EDGAR API. Here's how to extract structured financial data correctly.
Why XBRL Matters for Quants
If you've worked with SEC filings, you've probably downloaded HTML 10-Ks or scraped PDF documents like everyone else. That approach doesn't scale. Since 2009, the SEC has required larger filers to submit data in XBRL format: eXtensible Business Reporting Language. It's XML with financial semantics baked in.
XBRL is the difference between "revenue is $500M, somewhere in this table" and "consolidated revenue: $500,000,000 (concept: us-gaap:Revenues, period: 2023-12-31, unit: USD)." For systematic traders, quant researchers, and risk managers, this distinction matters enormously.
The problem: XBRL filings are complex. The SEC publishes thousands of filings each week with subtle validation issues, concept taxonomy drift, and inconsistent tagging. Most retail investors skip XBRL entirely. That's the edge.
Understanding XBRL Instance Documents and Taxonomies
An XBRL submission has two layers:
- Instance document (.xml): The actual company data. Example: Apple's 10-K contains facts like "us-gaap:NetIncomeLoss = 96995000000" (in thousands).
- Taxonomy (.xsd, .xml): The schema defining what concepts exist. The SEC maintains the US-GAAP taxonomy and the DEI (Document and Entity Information) taxonomy.
When you file a 10-K, you don't invent tags. You pick from the taxonomy. If the concept doesn't exist, you can request an extension, but that's rare and audited. The taxonomy lives in a versioned hierarchy. XBRL GL (General Ledger) exists but isn't required for public filings yet.
The US-GAAP taxonomy for fiscal year 2023 contains roughly 15,000 concepts. Not all are used in every filing. A company tags only what's material or required by Regulation S-K Item 101, Item 7, and so on.
Accessing XBRL via the SEC EDGAR API
The SEC publishes filings through EDGAR (Electronic Data Gathering, Online Retrieval). You can fetch XBRL programmatically.
The EDGAR API is documented at https://www.sec.gov/edgar/sec-api-documentation. To find a company's filings, you need the Central Index Key (CIK). For Apple, it's 0000320193.
A basic request looks like this:
GET https://data.sec.gov/api/xbrl/companyfacts/CIK0000320193.json
This returns all facts filed by that company across all periods: revenue, net income, balance sheet items, audit status, everything. The response is substantial (Apple's file is several MB) and includes all 10-Ks, 10-Qs, and 8-Ks tagged in XBRL.
The structure is hierarchical: company > taxonomy > concept > units > time periods. For a given concept like us-gaap:NetIncomeLoss, you see all historical values, units (USD, shares, etc.), and filing dates.
Parsing Concept Values and Context
Here's where many people stumble. A single fact has metadata:
- Concept: us-gaap:NetIncomeLoss
- Value: 96995000 (in thousands)
- Unit: USD (specified in the instance document)
- Period: 2023-09-30 (end date)
- Fiscalization: Annual or quarterly
- Context: Consolidated, segment-specific, or pro-forma
The context matters. Apple files segment data for Americas, Europe, Greater China, Japan, Rest of Asia Pacific. Each has its own context ID in the instance document. If you blindly sum all revenue concepts, you'll double-count.
When fetching from the API, look at the "filed" entry. The API returns multiple entries per concept if the company restatement or amended the filing. Use the latest "filed" value, unless you're researching restatements.
Common Pitfalls and Validation Issues
XBRL compliance is mandatory, but filing quality varies. Common problems:
- Unit mismatch: A concept filed in thousands but no unit tag. You multiply by 1,000 and get garbage.
- Scale issues: Some filers report shares in actual units, others in thousands. Consistency is filer-dependent.
- Instant vs. duration contexts: Balance sheet items have an "instant" context (point in time). Income statement items span a period. Mixing them produces nonsense.
- Deprecated concepts: The taxonomy evolves. Old concepts are deprecated. A 2015 filing might use a concept that no longer exists in 2024.
- Submission errors: The filer's system may tag a number wrong. Validation happens, but not perfectly. Read the Cover Page file (cover.xml) for flags.
Always validate against the canonical instance document, not secondary aggregators. The raw .xml from EDGAR is truth.
Extracting Time-Series Data
Once you've parsed one filing correctly, scaling to 100 companies and 10 years of data is a workflow problem.
Strategy: For each company (by CIK), fetch the companyfacts JSON. For each concept you care about (e.g., us-gaap:CommonStockSharesIssued, us-gaap:Revenues), extract the time series. Filter by "filed" date and period (annual or quarterly).
A simple pipeline:
- Get a list of CIKs (from your universe).
- For each CIK, GET companyfacts JSON.
- For each concept, extract all annual entries.
- Deduplicate by filing date (handle amendments).
- Store as a time series (ticker, date, value, unit).
This takes seconds per company and scales to thousands. Unlike web scraping, it's deterministic and audit-friendly.
Concept Taxonomy Deep Dive
To understand what concepts are available, explore the US-GAAP taxonomy. The SEC publishes it as a set of schema files. Key sections:
- us-gaap.xsd: Core accounting concepts (assets, liabilities, revenue, expenses).
- ifrs-full.xsd: IFRS-compliant concepts (for foreign private issuers).
- dei.xsd: Document and entity information (company name, CIK, stock exchange).
For specific filings, the instance document references extension schemas too. A company can define custom concepts if standard ones don't fit. These are rare and tracked separately.
To map a human-readable label (e.g., "Total Revenue") to a concept, use the label extension files included in the submission. The mapping is not 1:1; a single concept may have multiple labels in different languages or contexts.
Working with Amendments and Restatements
Companies file amended 10-K/As and 10-Q/As. XBRL instance documents are versioned by filing date. When you query the API, you get all versions.
Naive approaches sum all values and overstate historical earnings. The right approach: use the latest "filed" date for any given fiscal period. If a company filed a 10-K on 2024-01-15 and an amended 10-K/A on 2024-03-20, use the amendment's values.
For research, compare the two versions. Material restatements are signals. If accounts receivable drops 20% in an amendment, investigate the driver. The 8-K filing should explain it, but the XBRL data shows the magnitude.
Validation and Quality Checks
Before loading XBRL data into your model, validate:
- Balance sheet balances: Assets = Liabilities + Stockholders' Equity.
- Cash flow statement ties to balance sheet (changes in working capital).
- Earnings per share recalculates from net income and shares outstanding.
- Segment revenue sums to total consolidated revenue (no double-counting).
These checks catch parsing errors and filer mistakes. A surprising number of filings have small discrepancies. Most are immaterial; some signal auditor concerns or restatement risk.
Tools and Automation
If you're building a data pipeline, use mature libraries. The Python ecosystem has sec_edgar and xbrl packages that handle some parsing. For production use, consider a specialized service like FilingFirehose, which vets XBRL submissions, handles deduplication, and serves clean time series via API.
For one-off analysis, the SEC's own viewer (sec.report or the EDGAR filing details page) lets you browse tagged data interactively. It's slow at scale but reliable for spot checks.
Wrapping Up
XBRL filings are the most structured financial data available for public companies. They're unforgiving of sloppy parsing but powerful once mastered. The payoff is systematic, scalable, and auditable access to quarterly earnings, balance sheets, cash flows, and segment data for thousands of companies across decades.
Start with one company. Fetch its companyfacts JSON. Pick a concept. Plot the time series. Verify it matches the 10-K text. Once you've built that intuition, automate. The edge isn't in the XBRL format itself, it's in the discipline to parse it correctly when others don't.
Start a free FilingFirehose trial →
Try it on your stack
Get an API key in 2 minutes. Self-serve via Stripe, cancel anytime.
View pricing → Read API docs