# SEC Financials Scraper (`normdata/sec-financials-scraper`) Actor

Get clean, normalised financial statements for US public companies from the SEC EDGAR XBRL API by ticker or CIK: revenue, net income, EPS, assets, cash flow, plus margins, ROE, ROA and YoY growth. Batch a whole watchlist, or screen one metric across every filer. No API key.

- **URL**: https://apify.com/normdata/sec-financials-scraper.md
- **Developed by:** [Norm Data](https://apify.com/normdata) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.10 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

![Norm Data](https://i.ibb.co/rGbhM5Y8/Chat-GPT-Image-Sep-8-2026-02-20-50-PM.png)

## 🏛️ SEC Financials Scraper

Pull **clean, normalised financial statements** for US public companies straight from the
official **SEC EDGAR XBRL API** by ticker or CIK. Revenue, net income, EPS, assets, equity and
cash flow as one flat row per company per fiscal period, with **computed margins, ROE, ROA and
year-over-year growth** already worked out. Batch a whole watchlist, or run the market-wide
**screener** for one metric across every filer. No API key, no login.

Here is one real row (trimmed), for Apple FY2024:

```json
{
  "ticker": "AAPL",
  "cik": "320193",
  "company_name": "Apple Inc.",
  "sic_description": "Electronic Computers",
  "exchange": "Nasdaq",
  "fiscal_year": 2024,
  "fiscal_period": "FY",
  "period_end": "2024-09-28",
  "form": "10-K",
  "filed_date": "2024-11-01",
  "revenue": 391035000000,
  "gross_profit": 180683000000,
  "operating_income": 123216000000,
  "net_income": 93736000000,
  "eps_diluted": 6.08,
  "total_assets": 364980000000,
  "total_equity": 56950000000,
  "operating_cash_flow": 118254000000,
  "capex": 9447000000,
  "free_cash_flow": 108807000000,
  "gross_margin": 0.4621,
  "operating_margin": 0.3151,
  "net_margin": 0.2397,
  "return_on_equity": 1.6459,
  "revenue_growth_yoy": 0.0202,
  "source_url": "https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&CIK=320193&type=10-K",
  "scraped_at": "2026-09-08T20:00:00.000Z"
}
```

### What it does

Reads the SEC's XBRL company-facts API (`data.sec.gov`), which the SEC publishes for public
programmatic use. Three modes:

- **Companies** - paste a list of tickers or CIKs and get a full, normalised statement for every
  fiscal period: 20+ income-statement, balance-sheet and cash-flow line items, plus ratios and
  YoY growth. One row per company per period.
- **Concept** - one metric (e.g. `revenue`) as a clean time series for a list of companies.
- **Frame (screener)** - one metric for **every company that reported it** in a calendar period.
  "Revenue for all US filers in CY2024" comes back as ~3,000 rows.

**The normalisation is the point.** Filers report the same line item under different XBRL tags
depending on the year and the company (Apple's revenue lives under
`RevenueFromContractWithCustomerExcludingAssessedTax`, `Revenues` and `SalesRevenueNet` across
different filings). This Actor maps every variant to one clean `revenue` column, dedupes
re-stated values to the latest filing, and drops 8-K and proxy re-statements that would
otherwise corrupt the series.

### Why this scraper

- **Clean columns, not raw tags.** Every other SEC financials Actor hands you the messy XBRL
  tag and leaves the normalisation to you. This one gives you `revenue`, `net_income`, `eps_diluted`
  ready to use.
- **Batch input with ticker to CIK auto-resolution.** Paste `AAPL, MSFT, NVDA`; most Actors make
  you look up and supply the 10-digit CIK yourself.
- **Ratios and growth built in.** Margins, ROE, ROA, current ratio, debt-to-equity, free cash
  flow, and YoY revenue / net income / EPS growth on every row.
- **Screener mode.** One metric across the whole market in a single period - a bulk dataset no
  other Actor offers.
- **One row per input.** Tickers that do not resolve come back as an `error` row so your output
  lines up with your list.
- **No API key, no login.** The SEC data is free; so is a well-packaged version of it.

### How it compares

| Capability | This actor | Other SEC financials scrapers on Apify |
|---|:--:|:--:|
| Financial line items by ticker or CIK | yes | yes |
| **Normalised metrics (one clean column per line item)** | **yes** | **raw XBRL tags** |
| **Batch multi-ticker input + ticker to CIK resolution** | **yes** | **often CIK only, one at a time** |
| Computed margins, ROE, ROA, ratios | yes | rare |
| Year-over-year growth | yes | rare |
| **Market-wide screener (one metric, every filer)** | **yes** | **no** |
| Restatement de-duplication + 8-K noise filtering | yes | rare |
| One row per input (error rows for bad tickers) | yes | no |
| Declared dataset schema + free-plan preview | yes | rare |

### Use cases

- **Fundamentals database.** Load revenue, margins and growth for a universe of tickers into a
  factor model or a screener.
- **Sales and market intelligence.** Filter B2B prospects by revenue, growth or profitability.
- **Investment diligence.** Pull 5-10 years of financials for a company and its public comps
  before a deal.
- **Benchmarking.** Use Frame mode to rank an entire industry (by SIC) on one metric.
- **Monitoring.** Re-run a watchlist on a schedule; the `filed_date` and `accession_number`
  fields make restatements easy to spot.

### Quickstart

```json
{
  "mode": "companies",
  "identifiers": ["AAPL", "MSFT", "NVDA"],
  "period": "annual",
  "fiscalYearFrom": 2020,
  "maxItems": 50
}
```

Revenue time series for two companies:

```json
{ "mode": "concept", "identifiers": ["AAPL", "TSLA"], "metric": "revenue", "period": "annual" }
```

Every US filer's revenue for calendar year 2024:

```json
{ "mode": "frame", "metric": "revenue", "framePeriod": "CY2024", "maxItems": 5000 }
```

### Input reference

| Field | Applies to | Description |
|---|---|---|
| `maxItems` | all | Ceiling on rows written. |
| `mode` | all | `companies`, `concept` or `frame`. |
| `identifiers` | companies, concept | Tickers or CIKs. Tickers resolve automatically. |
| `period` | companies, concept | `annual` (10-K), `quarterly` (10-Q) or `both`. |
| `fiscalYearFrom` / `fiscalYearTo` | companies, concept | Filter by the calendar year the period ends in. |
| `includeRatios` | companies | Add margins, ROE, ROA, ratios and YoY growth. |
| `metric` | concept, frame | Which line item to pull (`revenue`, `net_income`, `total_assets`, ...). |
| `framePeriod` | frame | `CY2024` (year), `CY2024Q1` (quarter), `CY2024Q1I` (balance-sheet instant). |

### Output reference (selected)

One row per company per fiscal period (companies mode). Values are `null` when the filer did not
report that item, never invented.

| Field | Description |
|---|---|
| `ticker` / `cik` / `company_name` | Identity. `cik` is the SEC key. |
| `sic` / `sic_description` / `exchange` / `state_of_incorporation` | Company metadata. |
| `fiscal_year` / `fiscal_period` | Year the period ends in, and `FY` / `Q1` / `Q2` / `Q3`. |
| `period_start` / `period_end` / `form` / `filed_date` / `accession_number` | Filing provenance. |
| `revenue` ... `eps_diluted` | Income statement, normalised across XBRL tag variants. |
| `total_assets` ... `shares_outstanding` | Balance sheet. |
| `operating_cash_flow` / `capex` / `dividends_paid` / `free_cash_flow` | Cash flow. |
| `gross_margin` / `operating_margin` / `net_margin` / `rd_intensity` | Margins (with `includeRatios`). |
| `return_on_equity` / `return_on_assets` / `current_ratio` / `debt_to_equity` | Ratios. |
| `revenue_growth_yoy` / `net_income_growth_yoy` / `eps_diluted_growth_yoy` | YoY change vs the prior same period. |
| `metric` / `value` / `period` | Concept and Frame mode rows. |
| `query` / `error` | Set on an unresolved-identifier row. |
| `source_url` | EDGAR filing history for the company. |
| `scraped_at` | ISO 8601 collection timestamp. |

### Run via API and CLI

```bash
curl -X POST "https://api.apify.com/v2/acts/USERNAME~sec-financials-scraper/run-sync-get-dataset-items?token=<TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"mode":"companies","identifiers":["AAPL","MSFT"],"period":"annual","fiscalYearFrom":2020}'
```

```bash
apify call USERNAME/sec-financials-scraper --input '{"mode":"frame","metric":"revenue","framePeriod":"CY2024","maxItems":5000}'
```

### Fetch results

```bash
curl "https://api.apify.com/v2/datasets/<DATASET_ID>/items?token=<TOKEN>&clean=true&format=csv"
```

`<DATASET_ID>` is `defaultDatasetId` on the run object.

### Billing and limits

- **Pay per result.** Billed per row written. The current rate is on the Actor's Pricing tab.
- **No charge on failure.** A run that produces zero rows fails with a message and is not billed.
- An unresolved ticker still writes one `error: "not found"` row and is billed as a base row.
- **Free Apify plans** run the built-in 10-row sample only. Upgrade to run your own settings.
- The SEC API allows about 10 requests per second; this Actor stays well under it.

### FAQ and troubleshooting

**Do I need an API key or login?** No. `data.sec.gov` is a US government open-data host with no
key, no login and no captcha. The Actor sends a descriptive `User-Agent` as the SEC asks.

**Why is a metric `null`?** The filer did not report that XBRL line item for that period. Banks,
for example, rarely report `capex` the standard way. Missing values are `null`, never guessed.

**Why does `fiscal_year` differ from what the company calls its fiscal year?** It is the
calendar year the period ends in - the convention most data vendors use. A company with a June
year-end has its "FY2025" period end in June 2025.

**How does it handle restatements?** For each period it keeps the value from the most recent
10-K / 10-Q, and ignores 8-K earnings releases and DEF 14A proxies that re-quote the same
numbers without a proper period tag.

**What is Frame mode for?** Screening. `{"mode":"frame","metric":"net_income","framePeriod":"CY2024"}`
returns every US filer's 2024 net income in one run - a market-wide dataset.

**Is this an official SEC tool?** No. Independent, not affiliated with the SEC. It reads only
data the SEC publishes as open data.

### Local development

```bash
bun install
bun test              # offline: normalisation and input logic against synthetic fixtures
bun run src/main.ts   # reads storage/key_value_stores/default/INPUT.json
```

# Actor input Schema

## `maxItems` (type: `integer`):

Caps how many rows this run writes. Starts at 10 for a quick sample; raise it for a full run.

## `mode` (type: `string`):

Companies gives a full normalised statement per fiscal period. Concept gives one metric over time. Frame gives one metric for the whole US market in a single period.

## `identifiers` (type: `array`):

Stock tickers (AAPL, MSFT) or SEC CIK numbers. Tickers are resolved to CIKs automatically. Unresolved entries come back as an error row.

## `period` (type: `string`):

Annual pulls from 10-K filings, quarterly from 10-Q.

## `fiscalYearFrom` (type: `integer`):

Only periods whose end falls in this calendar year or later.

## `fiscalYearTo` (type: `integer`):

Only periods whose end falls in this calendar year or earlier.

## `includeRatios` (type: `boolean`):

Adds margins, ROE, ROA, current ratio, debt-to-equity, free cash flow, and year-over-year growth to each row.

## `metric` (type: `string`):

Which line item to pull in Concept and Frame modes.

## `framePeriod` (type: `string`):

Calendar period for Frame mode: CY2024 for a full year, CY2024Q1 for a quarter. Instant metrics (balance sheet) use CY2024Q1I.

## Actor input object example

```json
{
  "maxItems": 10,
  "mode": "companies",
  "identifiers": [
    "AAPL",
    "MSFT"
  ],
  "period": "annual",
  "includeRatios": true,
  "metric": "revenue",
  "framePeriod": "CY2024"
}
```

# Actor output Schema

## `results` (type: `string`):

One dataset row per company (or sub-unit, or change-feed entry).

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "maxItems": 10,
    "mode": "companies",
    "identifiers": [
        "AAPL",
        "MSFT"
    ],
    "period": "annual",
    "includeRatios": true,
    "metric": "revenue",
    "framePeriod": "CY2024"
};

// Run the Actor and wait for it to finish
const run = await client.actor("normdata/sec-financials-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "maxItems": 10,
    "mode": "companies",
    "identifiers": [
        "AAPL",
        "MSFT",
    ],
    "period": "annual",
    "includeRatios": True,
    "metric": "revenue",
    "framePeriod": "CY2024",
}

# Run the Actor and wait for it to finish
run = client.actor("normdata/sec-financials-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "maxItems": 10,
  "mode": "companies",
  "identifiers": [
    "AAPL",
    "MSFT"
  ],
  "period": "annual",
  "includeRatios": true,
  "metric": "revenue",
  "framePeriod": "CY2024"
}' |
apify call normdata/sec-financials-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,normdata/sec-financials-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/OpHbUAZmgrgoNye0e/builds/JJZfEcgvEE0FhVCdC/openapi.json
