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
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.
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.
| 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.
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.
Built to stay inside the SEC fair-access rules for automated tools:
UserAgentNotSetFiling content is public domain as a US government work. This tool is MIT-licensed and is not affiliated with or endorsed by the SEC.
Wrong geographic numbers are worse than missing ones. Help keep the tool honest.
Highest-value contributions
NoneHow to ship a fix
Browse issues · New issue · Pull requests · Source
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.