edgar-geo-revenue

edgar-geo-revenue

A Python tool for geographic revenue from SEC EDGAR.

Give it a ticker. Get the revenue-by-country split the company actually disclosed in its 10-K — resolved to ISO country codes. No API key, no account, no database. Two dependencies: requests and beautifulsoup4.

import edgar_geo_revenue as egr

egr.set_user_agent("Your Name your@email.com")   # SEC requires a real contact
egr.fetch_geo_revenue("AAPL")
# {'fiscal_year': 2025, 'total_revenue_usd': 416161000000,
#  'segments': [['US', 36.47], ['CN', 15.47]],
#  'region_segments': [['INTL', 48.06]], 'pct_coverage': 100.0}

Install & code → · PyPI · File an issue · Open a PR


Why this tool exists

Fetching a 10-K is easy. Finding the geographic revenue note and reading it correctly is not.

Reality in EDGAR What breaks naive parsers
XBRL geo tags are incomplete XBRL-only tools return “no data” when the HTML note clearly discloses a split
Note sits in an arbitrary R*.htm Stopping the scan early misses the table entirely
Labels are free-form “U.S.”, “US and Canada”, “EMEA”, “Greater China”, “Rest of world”…
Neighbour tables look identical Assets / deposits / pensions by geography share the same row labels

The selection and resolution rules here survived a production audit of 463 SEC filers. 262 had a usable geographic disclosure. Much of the rest genuinely do not disclose one — that is a valid result, not a tool failure.


Install

pip install edgar-geo-revenue
# or from source:
git clone https://github.com/Metricshour/edgar-geo-revenue.git
cd edgar-geo-revenue && pip install -e .
import edgar_geo_revenue as egr
egr.set_user_agent("YourApp your@email.com")
# or: export EDGAR_GEO_USER_AGENT="YourApp your@email.com"

result = egr.fetch_geo_revenue("MSFT")

See examples/ for a multi-ticker walkthrough.

What you get back

Field Meaning
fiscal_year Fiscal year from the filing’s own period metadata
total_revenue_usd Total revenue for that year, USD
segments [[ISO2, percent], …] country-level rows
region_segments [[REGION, percent], …] genuinely region-level rows
pct_coverage Share of total revenue the rows account for

None means no geographic disclosure was found — normal, not an error.


What it deliberately refuses to do

Each of these looked reasonable, shipped wrong numbers in production, and was removed:

Combined place labels resolve on the set of places, not the string: {EUROPE, MEA} → EMEA, {US, CA} → North America, across punctuation variants.


SEC fair-access compliance

Built to stay inside the SEC fair-access rules for automated tools:

Filing content is public domain as a US government work. This tool is MIT-licensed and is not affiliated with or endorsed by the SEC.


Contribute

Wrong geographic numbers are worse than missing ones. Help keep the tool honest.

Highest-value contributions

  1. False positives — assets, deposits, or pensions tables mistaken for revenue
  2. Missed notes — filer discloses geo revenue, tool returns None
  3. Label gaps — a place string that should resolve to a known ISO/region and does not
  4. Partition rejects — cases where a valid split is thrown out, or an invalid one is kept

How to ship a fix

  1. Open an issue with ticker, filing period, and what you expected vs what you got
  2. Prefer a minimal failing example over a vague report
  3. PRs that add a regression case alongside the fix land fastest

Browse issues · New issue · Pull requests · Source


Live data (optional)

This extractor is the layer behind MetricsHour. If you want the parsed universe with screening rather than running the parser yourself, use metricshour.com/screener.