# Stock News Sentiment Scraper (`khadinakbar/stock-news-sentiment-scraper`) Actor

Scrape stock ticker headlines from Yahoo Finance, Google News, and Finviz, score each with local VADER sentiment, and return per-item plus ticker summary rows. Reddit optional (off by default). MCP-ready.

- **URL**: https://apify.com/khadinakbar/stock-news-sentiment-scraper.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (community)
- **Categories:** News, AI, MCP servers
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 sentiment items

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

### What is Stock News Sentiment Scraper?

For quants, research desks, and MCP agents that need ticker news sentiment, this Actor returns dataset rows of scored public headlines. Paste tickers and receive sentiment-item records with title, URL, source, publisher, VADER compound score, and sentimentLabel, plus optional ticker-sentiment-summary roll-ups. Primary sources are Yahoo Finance news, Google News finance RSS, and Finviz. Sentiment uses local VADER (no paid NLP). Reddit is optional and off by default.

### What data can you extract?

| Field | Description |
|---|---|
| `ticker` | Uppercase symbol (AAPL, TSLA, …) |
| `title` / `url` / `publisher` / `publishedAt` | Headline identity and provenance |
| `source` | `yahoo`, `google-news`, `finviz`, or optional `reddit` |
| `sentimentLabel` / `compound` | VADER label + compound score (−1…+1) |
| `positiveScore` / `negativeScore` / `neutralScore` | VADER intensity mix |
| `itemCount` / `avgCompound` / `bullishRatio` | Ticker summary aggregates |
| `topPositiveTitles` / `topNegativeTitles` | Extreme headlines in the window |
| `sourceUrl` / `scrapedAt` | Feed URL and ISO freshness |

### Best fit

Use this Actor when a quant, trader, or AI agent needs a fast multi-source news-sentiment snapshot for US tickers without standing up an NLP vendor. Prefer it over raw news scrapers when you need a comparable compound score and a ticker-level summary in one run.

### Scope and routing

This Actor is strongest for public headline triage with local VADER scores. Pair this Actor with specialist tools when you need full article bodies, licensed terminals, or paid transformer NLP. For live quotes and multi-asset prices after a sentiment pass, continue with [Stock Price Tracker](https://apify.com/khadinakbar/stock-price-tracker). For broader Yahoo Finance modes such as statements or options, route to [Yahoo Finance Scraper](https://apify.com/khadinakbar/yahoo-finance-scraper). For Google Finance page coverage beyond news sentiment, use [Google Finance Stock News Scraper](https://apify.com/khadinakbar/google-finance-stock-news-scraper).

### Workflow story

A portfolio agent watches AAPL and TSLA each morning. It calls this Actor with both tickers, the three primary sources, `maxItemsPerTicker: 15`, and `includeSummary: true`. Each headline becomes a billed `sentiment-item` with a VADER compound score. One `ticker-sentiment-summary` per symbol rolls up counts, average compound, and bullish ratio so the agent can gate alerts without reading every row.

### How it works

1. Normalizes tickers and resolves the source list (Reddit stays off unless enabled)
2. Fetches Yahoo Finance RSS, Google News finance RSS, and Finviz news-table HTML over HTTPS
3. Deduplicates headlines, scores title (+ snippet) with local VADER, validates rows
4. Charges `sentiment-item` then writes each row; optionally charges `ticker-sentiment-summary` then writes roll-ups
5. Writes `OUTPUT` and `RUN_SUMMARY` with outcome, source attempts, and charged event counts

### Input example

```json
{
  "tickers": ["AAPL"],
  "sources": ["yahoo", "google-news", "finviz"],
  "includeReddit": false,
  "maxItemsPerTicker": 10,
  "maxItemsPerSource": 10,
  "lookbackDays": 7,
  "includeSummary": true
}
```

### Example output (sentiment item)

```json
{
  "recordType": "sentiment-item",
  "itemId": "a1b2c3d4e5f6789012345678",
  "ticker": "AAPL",
  "title": "Apple stock climbs after strong iPhone demand",
  "url": "https://finance.yahoo.com/news/example.html",
  "source": "yahoo",
  "publisher": "Yahoo Finance",
  "publishedAt": "2026-09-30T12:00:00.000Z",
  "sentimentLabel": "positive",
  "compound": 0.4215,
  "positiveScore": 0.258,
  "negativeScore": 0.117,
  "neutralScore": 0.625,
  "sourceUrl": "https://finance.yahoo.com/rss/headline?s=AAPL",
  "scrapedAt": "2026-09-30T12:05:00.000Z"
}
```

You can download the dataset as JSON, CSV, Excel, or HTML.

### Pricing

This Actor uses **Pay per event** with **platform usage** passed through to the caller (`isPPEPlatformUsagePaidByUser: true`). Current event prices:

- `apify-actor-start`: $0.00005 per run
- `sentiment-item`: $0.005 per scored headline written
- `ticker-sentiment-summary`: $0.015 per ticker summary written

For example, 10 scored headlines plus one ticker summary cost about $0.065 plus small platform usage. Invalid inputs and valid-empty runs leave the named result events uncharged. Treat the **live Pricing tab** on the Actor page as the current source of truth for event prices and platform usage before budgeting a production run.

### Outcomes

Every run writes `OUTPUT` and `RUN_SUMMARY` with one of:

`COMPLETE` | `PARTIAL` | `VALID_EMPTY` | `INVALID_INPUT` | `UPSTREAM_FAILED` | `CONFIG_ERROR`

- `VALID_EMPTY`: sources responded, but no scored headline matched (for example an unknown ticker symbol)
- `INVALID_INPUT`: no usable tickers after normalization
- `PARTIAL`: useful rows were saved while an optional source such as Reddit was unavailable
- `UPSTREAM_FAILED`: every required source was unavailable and nothing was saved

### API example

```bash
curl "https://api.apify.com/v2/acts/khadinakbar~stock-news-sentiment-scraper/runs?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "tickers": ["AAPL"],
    "sources": ["yahoo", "google-news", "finviz"],
    "maxItemsPerTicker": 10,
    "includeSummary": true,
    "includeReddit": false
  }'
```

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('khadinakbar/stock-news-sentiment-scraper').call({
  tickers: ['AAPL'],
  sources: ['yahoo', 'google-news', 'finviz'],
  maxItemsPerTicker: 10,
  includeSummary: true,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.slice(0, 3));
```

### MCP / agent prompt card

> Use Stock News Sentiment Scraper to score the last week of AAPL headlines from Yahoo Finance, Google News, and Finviz. Keep Reddit off. Return compound scores, sentiment labels, and one ticker summary. Read the dataset for rows and OUTPUT for itemsPushed and chargedEventCounts.

### Tips for best results

- Start with the three primary sources and `includeReddit: false`
- Use `maxItemsPerTicker` to bound cost before widening lookback
- Prefer ticker summaries for agent gating; drill into items when polarity is mixed
- Treat VADER as a triage signal for research workflows

### FAQ

**Which sources are on by default?** Yahoo Finance, Google News finance RSS, and Finviz. Reddit stays off until you set `includeReddit: true` or include `reddit` in `sources`.

**Is this investment advice?** No. Local VADER scores help triage headlines; they are not trading recommendations.

**Do I need an NLP API key?** No. Sentiment uses local VADER inside the Actor.

### Builder's note

I built this Actor after probing the three public primary feeds and choosing local VADER so every FREE-tier caller gets the same scoring path with no owner NLP key. I collect every selected source before applying `maxItemsPerTicker`, so dense Yahoo feeds still leave room for Finviz and Google News rows. Reddit stays optional because public search from datacenter IPs is less reliable than the primary news feeds, and the Actor can still finish with useful news rows as an honest `PARTIAL`.

### Legal / responsible use

This Actor collects publicly reachable finance headlines for research and automation. Output is not investment advice. You remain responsible for complying with applicable terms and laws. Yahoo and Yahoo Finance are trademarks of their respective owners. This independent Actor is not affiliated with, associated with, or endorsed by Yahoo. Google and Google News are trademarks of their respective owners. This independent Actor is not affiliated with, associated with, or endorsed by Google. Finviz is a trademark of its respective owner. This independent Actor is not affiliated with, associated with, or endorsed by Finviz. Reddit is a trademark of its respective owner. This independent Actor is not affiliated with, associated with, or endorsed by Reddit.

# Changelog

This Actor's version history is a separate document: https://apify.com/khadinakbar/stock-news-sentiment-scraper/changelog.md

# Actor input Schema

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

One or more stock tickers to score, such as AAPL, TSLA, or MSFT. Leading $ is stripped. Duplicates are removed. Required for a useful run. Maximum 50 tickers per run.

## `sources` (type: `array`):

Sources to query. Default primary set is yahoo, google-news, and finviz. Include reddit only when you explicitly want optional social posts; Reddit stays off unless includeReddit is true or reddit is listed here.

## `includeReddit` (type: `boolean`):

When true, also search public Reddit posts mentioning each ticker. Default false — Reddit is optional and often rate-limited from datacenter IPs.

## `maxItemsPerTicker` (type: `integer`):

Hard cap on scored sentiment-item rows kept per ticker across all sources. Defaults to 20. Accepts 1 through 200. Each item costs $0.005.

## `maxItemsPerSource` (type: `integer`):

Cap headlines pulled from each source before dedupe and sentiment scoring. Defaults to 15. Accepts 1 through 100.

## `lookbackDays` (type: `integer`):

How many days of news to request where the source supports a window (Google News when:Nd; Reddit t=day/week/month). Yahoo and Finviz return their live recent feeds. Defaults to 7. Accepts 1 through 90.

## `includeSummary` (type: `boolean`):

When true (default), write one ticker-sentiment-summary row per ticker that produced items. Each summary costs $0.015.

## `minCompound` (type: `number`):

Optional filter that keeps only headlines whose absolute VADER compound score is at least this value (0–1). Leave empty to keep all scored items including neutrals.

## Actor input object example

```json
{
  "tickers": [
    "AAPL",
    "TSLA"
  ],
  "sources": [
    "yahoo",
    "google-news",
    "finviz"
  ],
  "includeReddit": false,
  "maxItemsPerTicker": 10,
  "maxItemsPerSource": 10,
  "lookbackDays": 7,
  "includeSummary": true,
  "minCompound": 0.2
}
```

# Actor output Schema

## `records` (type: `string`):

Validated sentiment-item and ticker-sentiment-summary rows returned by this run.

## `output` (type: `string`):

Compact outcome, item counts, warnings, and charged event totals.

## `runSummary` (type: `string`):

Source attempt log, per-ticker totals, and Pay per event billing counts.

# 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": [
        "AAPL"
    ],
    "sources": [
        "yahoo",
        "google-news",
        "finviz"
    ],
    "maxItemsPerTicker": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/stock-news-sentiment-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 = {
    "tickers": ["AAPL"],
    "sources": [
        "yahoo",
        "google-news",
        "finviz",
    ],
    "maxItemsPerTicker": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/stock-news-sentiment-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 '{
  "tickers": [
    "AAPL"
  ],
  "sources": [
    "yahoo",
    "google-news",
    "finviz"
  ],
  "maxItemsPerTicker": 10
}' |
apify call khadinakbar/stock-news-sentiment-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,khadinakbar/stock-news-sentiment-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/VwcqW9HgAeg5qa1VD/builds/Nd0KguTHJCinju62W/openapi.json
