# Earnings Release Extractor: EPS, Revenue, Guidance & CEO Quote (`chaucerlabs/earnings-release-extractor`) Actor

Earnings press releases to structured data, by ticker, date range or URL: GAAP and adjusted EPS, revenue, net income, EBITDA, guidance ranges, one-line outlook summaries and the CEO quote, each with source text and SEC link.

- **URL**: https://apify.com/chaucerlabs/earnings-release-extractor.md
- **Developed by:** [Chaucer Labs](https://apify.com/chaucerlabs) (community)
- **Categories:** Developer tools, Business, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$30.00 / 1,000 release extracteds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Earnings Release Extractor: EPS, Revenue, Guidance & CEO Quote

Turn quarterly earnings press releases into clean, structured JSON. You give it tickers, a date range or release URLs. For each release it returns:

- **EPS**: GAAP diluted and adjusted/non-GAAP ("core", "operating", "as adjusted")
- **Revenue** (plus adjusted/managed revenue where reported), **net income** and **EBITDA / adjusted EBITDA**
- **Guidance**: metric, period (Q4 2026, FY 2026…), low/high or point value, qualifier ("approximately", "at least"), and whether it was **raised, lowered, narrowed or maintained**, with the prior range when the release gives it
- **Outlook summaries**: every long written outlook/guidance paragraph, kept word for word, plus a **one-sentence summary (≤25 words)** you can scan in seconds
- **The CEO quote**, with speaker, title, the full quote and a ≤280-character version

Every number comes with the **exact sentence or table row it was read from** and the **source URL**, so you can audit any value in one click. If a value is ambiguous or not in the release, the field is `null`. Nothing is guessed.

### How it finds releases

- **Tickers**: the Actor looks up the company on SEC EDGAR, finds its earnings 8-K (Item 2.02, "Results of Operations") and reads the press release exhibit (EX-99.1). When a filing carries several exhibits, it picks the actual press release over supplemental decks.
- **Date range** (no tickers): sweeps **every** Item 2.02 8-K filed in the window. In peak earnings season that is 100+ releases a week.
- **URLs**: SEC exhibit links work best. Company IR and newswire pages (e.g. PR Newswire) are tried too. Short "stub" pages that only link to the full release come back as `partial`.

SEC fair-access rules are respected: an identified User-Agent, ≤5 requests/second and backoff on throttling.

### Input examples

Latest quarter for a watchlist:

```json
{ "tickers": ["JPM", "DAL", "PEP", "JNJ"] }
```

Everything that reported this week:

```json
{ "startDate": "2026-10-13", "endDate": "2026-10-17", "maxReleases": 200 }
```

Last 4 quarters for one name:

```json
{ "tickers": ["UNH"], "startDate": "2025-10-01", "maxReleasesPerTicker": 4 }
```

### Output (one item per release, abbreviated)

```json
{
  "ticker": "CLF", "companyName": "CLEVELAND-CLIFFS INC.", "periodLabel": "Q3 2026", "filingDate": "2026-10-19",
  "epsGaapValue": 0.26, "epsAdjustedValue": 0.28, "revenueValue": 5612000000, "netIncomeValue": 165000000, "ebitdaValue": 612000000,
  "epsAdjusted": { "value": 0.28, "unit": "USD/share", "asStated": "$0.28", "method": "narrative",
    "snippet": "For the third quarter of 2026, the Company recorded GAAP net income of $165 million, or $0.26 per diluted share, with an adjusted net income of $0.28 per diluted share.",
    "sourceUrl": "https://www.sec.gov/Archives/edgar/data/764065/000076406526000112/clf-202609308xkex991.htm" },
  "guidance": [
    { "metric": "ebitda_adjusted", "period": "Q4 2026", "low": 715000000, "high": 715000000, "unit": "USD",
      "qualifier": "approximately", "direction": null, "snippet": "The Company expects fourth-quarter 2026 adjusted EBITDA to be approximately $715 million…" }
  ],
  "guidanceSummary": "FY 2027 adjusted EBITDA: exceed $4.00B; Q4 2026 adjusted EBITDA: approximately $715M",
  "outlook": [
    { "section": "Outlook",
      "text": "The Company expects fourth-quarter 2026 adjusted EBITDA2 to be approximately $715 million, an increase from the third quarter as a result of increased pricing, partially offset by seasonality, increased maintenance outages, input costs and incentive compensation accruals.",
      "summary": "The Company expects fourth-quarter 2026 adjusted EBITDA to be approximately $715 million, an increase from the third quarter as a result of increased pricing.",
      "summaryMethod": "extractive", "sourceUrl": "https://www.sec.gov/Archives/edgar/data/764065/000076406526000112/clf-202609308xkex991.htm" }
  ],
  "outlookSummary": "We would expect our 2027 adjusted EBITDA to exceed $4 billion. | The Company expects fourth-quarter 2026 adjusted EBITDA to be approximately $715 million, …",
  "ceoQuote": { "speaker": "Lourenco Goncalves", "title": "Cliffs' Chairman and CEO", "quoteShort": "Third quarter was our strongest quarter in three years…" },
  "status": "ok", "releaseType": "earnings"
}
```

Each financial field (`epsDilutedGaap`, `epsAdjusted`, `revenue`, `revenueAdjusted`, `netIncome`, `ebitda`) is an object with `value`, `unit`, `asStated`, `label`, `method` (`narrative`, `table` or `table+narrative`), `snippet`, `confirmingSnippet` and `sourceUrl`. The flat `…Value` columns make CSV/Excel export easy.

#### Outlook summaries

`outlook` lists the long (200+ character) written outlook and guidance paragraphs: paragraphs under an "Outlook" / "Guidance" heading, plus any narrative paragraph a `guidance` item was read from. Each entry has:

| Field | Meaning |
|---|---|
| `section` | The heading the paragraph sits under |
| `text` | The paragraph exactly as written in the release (unchanged) |
| `summary` | One sentence, at most 25 words, or `null` |
| `summaryMethod` | `extractive` when a summary is given |
| `sourceUrl` | The release (SEC exhibit) link |

How the summary is made: it is **extractive and rule-based, not AI-generated**. The Actor picks the most guidance-like sentence in the paragraph and only *deletes* words from it: lead-ins ("Looking ahead,"), footnote markers, parentheses, side clauses and trailing explanations ("…, partially offset by …"). It never adds words, never rewrites, and never computes a number. Before a summary is returned it is checked automatically: its words must appear in the paragraph in the same order, and every number in it must appear in the paragraph. If a paragraph can't be shortened that way to 25 words, `summary` is `null` and you still get the full text. The flat `outlookSummary` column joins all summaries with `|` for spreadsheets.

`status`: `ok` = EPS or revenue found (charged); `partial` = a release was read but no headline figures were found, e.g. a dividend notice or a newswire stub (**not charged**); `error` = could not fetch (**not charged**).

### Accuracy

Hand-checked against the source text on Q3 2026 releases from banks, brokers, airlines, pharma, consumer staples, metals, staffing, trucking and REITs:

- **29 named releases**: 103 headline figures extracted (GAAP EPS, adjusted EPS, revenue, net income, EBITDA), **0 wrong values** after review, and 1 figure missed (left `null`). The CEO/executive quote was found in every release that has one.
- **Outlook summaries**: on the same releases, every summary was checked against its paragraph: no added numbers and no added words.
- **Blind sweep of 20 filings** (every Item 2.02 8-K on Oct 15–16, 2026): all regular earnings releases were correct. Restatements, preliminary-range announcements and stubs are now marked `partial` and not charged.

### Pricing

**$0.03 per successfully extracted release.** Partial and failed rows are free. A 100-release earnings-week sweep costs about $3.

### Known limits

- Reads the press release only: no consensus estimates, no beat/miss vs. Street, and no transcript.
- Banks often report no single "total revenue" line under that name; then `revenue` may be `null` or the FTE/managed figure appears as `revenueAdjusted`.
- REITs: FFO/Core FFO per share is returned as `epsAdjusted` (its label says so).
- Guidance written as long narrative paragraphs is captured less completely as structured `guidance` items than guidance tables; the `outlook` field gives you the full paragraph and a one-line summary.
- Outlook summaries are a single sentence taken from the paragraph, so a paragraph that covers several topics is summarized by its most guidance-like sentence only.
- Non-US filers (6-K) and image-only releases are not supported yet.

### Use cases

Earnings-season dashboards, guidance-revision tracking, quant/LLM pipelines that need audited inputs, IR and competitive monitoring, newsletter and journalism research.

*Data comes from public SEC EDGAR filings and public press releases. Not investment advice.*

# Actor input Schema

## `tickers` (type: `array`):

US-listed tickers (e.g. JPM, DAL, PEP). For each one the Actor finds its latest earnings 8-K (Item 2.02) on SEC EDGAR and extracts the press release (Exhibit 99.1). Combine with a date range to get several quarters per ticker.

## `urls` (type: `array`):

Optional direct links to earnings releases: SEC exhibit/filing-index URLs work best; company investor-relations or newswire pages are attempted too (some sites block automated access).

## `startDate` (type: `string`):

YYYY-MM-DD. With no tickers, the Actor scans ALL Item 2.02 8-Ks filed in the range (earnings-season sweep). With tickers, limits which quarters are returned. Empty input defaults to the last 2 days.

## `endDate` (type: `string`):

YYYY-MM-DD. Defaults to today.

## `maxReleases` (type: `integer`):

Hard cap on releases processed in one run (cost control).

## `maxReleasesPerTicker` (type: `integer`):

How many quarters to return per ticker. Defaults to 1 (latest) without dates and 8 with a date range.

## `contactEmail` (type: `string`):

SEC asks automated clients to identify themselves. Leave empty to use the Actor's default contact.

## Actor input object example

```json
{
  "tickers": [
    "JPM",
    "DAL",
    "PEP"
  ],
  "maxReleases": 25
}
```

# Actor output Schema

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

Structured fields per release with source snippets.

## `runStats` (type: `string`):

Releases requested, extracted (ok), partial and errors.

## `outlook` (type: `string`):

Verbatim outlook/guidance paragraphs, each with a one-sentence extractive summary and its source link.

# 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 = {
    "tickers": [
        "JPM",
        "DAL",
        "PEP"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("chaucerlabs/earnings-release-extractor").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 = { "tickers": [
        "JPM",
        "DAL",
        "PEP",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("chaucerlabs/earnings-release-extractor").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 '{
  "tickers": [
    "JPM",
    "DAL",
    "PEP"
  ]
}' |
apify call chaucerlabs/earnings-release-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,chaucerlabs/earnings-release-extractor"
        }
    }
}
```

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/GC4KmnbMBNEWPDuwi/builds/fah0I4ifeav2pg9dk/openapi.json
