# Google News Scraper & AI Company Signals (`steadywren/google-news-signals-scraper`) Actor

Google News scraper with AI company signals: articles for any company, keyword or topic with publisher URLs, AI event type and sentiment, stories across outlets, momentum. $3 per 1,000 articles. Add-ons: trigger events with facts (funding, M\&A), full text, AI briefs, share of voice, Slack alerts.

- **URL**: https://apify.com/steadywren/google-news-signals-scraper.md
- **Developed by:** [Steadywren](https://apify.com/steadywren) (community)
- **Categories:** AI, News, Lead generation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 articles

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

## Google News Scraper & AI Company Signals

Google News articles for a company watchlist, keywords or topics, with real publisher URLs and AI company signals:
event type (funding, acquisition, earnings, layoffs...), sentiment toward your company, stories grouped across outlets
and what changed since your last run. $3 per 1,000 articles, URL decoding and AI included.

![Google News Scraper & AI Company Signals - example output](https://steadywren.com/assets/screens/google-news-signals-scraper.png)

### What you get

Three tables in the **Output** tab:

| Table | One row per | Price |
|---|---|---|
| **Articles** (default dataset) | article | $0.003 |
| **Stories** | story with at least one delivered article | free |
| **Company digests** | company or search query per run | $0.005 |

- **Articles**: `articleId`, `title` (headline without the outlet), `source`, `sourceDomain`, `publisherUrl`
  (decoded), `googleUrl`, `url` (publisher URL, or the Google link when it could not be decoded), `publishedAt`,
  `snippet`, `feedType` (`company`, `query`, `topic`), `company`, `query`, `eventType`, `targetRole` (`main`,
  `mentioned`, `unrelated`), `targetIsMain`, `sentimentTowardTarget` (-1..1), `sentimentLabel` (`negative`,
  `neutral`, `positive`), `entities` (other organisations in the headline), `storyId`, `isNew`, `firstSeenAt`,
  `edition` (`US:en`), `titleEnglish`, `scrapedAt`; with the text add-on also `body`, `markdown`, `author`,
  `wordCount`, `bodyStatus`.
- **AI event type + sentiment toward the company**: each headline gets an `eventType` from a fixed list of 12
  (`funding`, `acquisition`, `earnings`, `stock-analyst`, `layoffs`, `legal-regulatory`, `product`, `executive`,
  `partnership`, `security-incident`, `expansion`, `other`), a `targetRole` (is the company the subject, only
  mentioned, or is the name about something else - a person called "Stripe", a cycling "peloton") and a
  `sentimentTowardTarget` that judges the effect on *your* company, not the tone of the writing. A falling stock is
  negative, a raised price target positive.
- **Stories for search results**: Google groups related coverage only on its topic pages; a search returns a flat
  list where one earnings release can be 40 articles. The Actor groups search results into stories (the same
  real-world event across outlets) with an AI pass, so you see 1 story with 22 outlets instead of 40 rows. Story
  fields: `storyId`, `company` / `query`, `headline` (the earliest article), `eventType` (most common among its
  articles), `articles`, `outlets`, `outletDomains`, `firstSeenAt`, `lastSeenAt`, `isNewStory`,
  `outletsAddedSinceLastRun`, `isBreaking`, `sentimentTowardTarget`, `articleUrls`, `edition`, `brief` (add-on).
- **Momentum and a company digest**: on a schedule every story carries `isNewStory`, `outletsAddedSinceLastRun` and
  `isBreaking`; every company gets one digest row per run: `company`, `timeRange`, `articles`, `mainArticles` (the
  company is the subject), `eventCounts` (every event type, counted over `main` articles), `netSentiment`,
  `positiveArticles`, `negativeArticles`, `stories`, `newStories`, `breakingStories` and `topStories` (top 3 each),
  a 0-100 `signalScore`, `signalWindow`, `previousRunAt`, `edition`, `briefing` (add-on).
- **Past the 100-result cap**: Google News returns at most 100 articles per search. When you ask for more, the Actor
  splits the time range into date windows (up to 500 articles per company).

Use it for B2B sales triggers (funding, expansion and new executives at your target accounts, every morning),
investor and analyst research (company news by event type and tone, with earnings and stock chatter told apart from
real events), PR (how far a story spreads, which outlets picked it up since yesterday) and AI agents or dashboards
(clean, pre-labelled news rows instead of raw headlines).

### Sample output

Duolingo, captured 2026-11-04 (AI labels from gpt-5-mini, trimmed):

```json
{
    "articleId": "CBMidEFVX3lxTE5jNDZtS1JfUUhIa0VMQXJ4VVNPODlibW5kTDg2cDNzNG1uVlRoUEFtOHRPUFVCOGhvcVUwMzJlcEptdVdVZ2NLUFZLMFcwa2dfQ2Z6aklXV09xNVBpOWs3MFZIcldMb2pnTHhXblRLWVNGR1Q0",
    "title": "Small Business Spotlight: Duolingo",
    "source": "PA Department of Community & Economic Development (.gov)",
    "sourceDomain": "dced.pa.gov",
    "publisherUrl": "https://dced.pa.gov/paproudblog/small-business-spotlight-duolingo/",
    "url": "https://dced.pa.gov/paproudblog/small-business-spotlight-duolingo/",
    "publishedAt": "2026-10-30T07:00:00.000Z",
    "snippet": null,
    "feedType": "company",
    "company": "Duolingo",
    "query": null,
    "eventType": "other",
    "targetRole": "main",
    "targetIsMain": true,
    "sentimentTowardTarget": 0,
    "sentimentLabel": "neutral",
    "entities": [],
    "storyId": "s-5ea6909d05fa",
    "isNew": true
}
```

More labels from the same test set: "Duolingo, Inc. (DUOL) Q3 Earnings Miss Estimates" -> `earnings`, -0.6; "Nvidia's
$12.9 billion Hugging Face deal draws DOJ scrutiny" -> `legal-regulatory`, -0.6, entities `Hugging Face`, `DOJ`;
"Why Is DUOL Stock Surging Over 11% Overnight Today?" -> `stock-analyst`, +0.6.

#### Story

Shopify, 7 days to 2026-11-04 (trimmed): the AI put 40 of the 100 search results into one story.

```json
{
    "company": "Shopify",
    "headline": "Watch Shopify Revenue Miss; Yum Brands Jumps on Taco Bell Sales | Stock Movers",
    "articles": 40,
    "outlets": 22,
    "outletDomains": ["cnbc.com", "investors.com", "bloomberg.com", "finance.yahoo.com", "barrons.com", "qz.com"],
    "firstSeenAt": "2026-11-03T00:00:00.000Z",
    "lastSeenAt": "2026-11-03T21:08:23.000Z",
    "isNewStory": true,
    "outletsAddedSinceLastRun": null
}
```

### How much does it cost?

**$3 per 1,000 articles.** Example: a daily run for 5 companies with 50 articles each = 250 articles x $0.003 + 5
company digests x $0.005 = $0.75 + $0.025 = $0.775 per run.

- $0.003 per article; publisher URL decoding, AI labels and story grouping are included.
- $0.005 per company digest: one per company or search query per run, only when it has articles.
- Stories are free. No start fee; platform compute is included.
- Paid add-ons cost extra only when switched on and only for what they deliver - **free until 19 November 2026**
  (prices in "Paid add-ons" below).
- **Max articles in total** and your spending limit cap the cost. The Actor never decodes or sends to the AI more
  articles than your limit lets it deliver, and articles it cannot deliver are never charged.

### How to use

1. Enter **Companies (watchlist)**, **Search queries** or **Topic URLs** (empty = Duolingo as an example).
2. Set the **Time range** (or **From date** / **To date**) and **Max articles per company / query / topic**.
3. Click **Start**, then download JSON, CSV or Excel from the Output tab.

Main filters: time range or dates, country and language (or several countries), max articles, only new articles.

Example input: `{"companies": ["Shopify", "Nvidia"], "timeRange": "7d", "maxArticlesPerCompany": 30}`.

### Use with AI assistants (MCP)

Connect this Actor to Claude, ChatGPT or any MCP client: `https://mcp.apify.com?tools=steadywren/google-news-signals-scraper`

Try:

- "Get this week's Google News for Stripe, Adyen and Klarna and list every funding, acquisition or layoff story with its sentiment."
- "Which of Shopify, Wix and BigCommerce had the most negative news in the last 7 days, and why?"

### How it compares

Checked against the READMEs of 16 Google News Actors in Apify Store on 2026-11-03.

| | This Actor | Other Google News scrapers in Apify Store |
|---|---|---|
| AI event type per article (funding, M\&A, earnings, layoffs...) | yes | not claimed |
| Sentiment toward the company you watch | yes | not claimed (some call their data "ready for" sentiment) |
| Story grouping for search results | yes | not claimed (some group topic feeds only) |
| Story momentum between runs + one signal row per company | yes | not claimed |
| Publisher URL decoded | yes, included | several, some for +$0.50 - $1 per 1,000 |
| Price per 1,000 articles | $3, no start fee | $1.50 - $5 (several add a start fee) |

### Paid add-ons

Each add-on is an input switch, **off by default**, and is charged only for what it delivers. The base features
above stay included in the article price. **Launch offer: the add-on prices below start on 19 November 2026 - until
then every add-on is free.**

| Add-on (input) | What you get | Price |
|---|---|---|
| **Trigger events** (`extractTriggers`) | Sales triggers with facts in the **Trigger events** table: funding (amount, currency, round, lead investors, valuation), acquisitions (acquirer, acquired company, deal value), expansion (location), layoffs (count, share of staff), partnerships (partner), product launches (product), executive changes (role, appointed/departed) | $0.01 per trigger |
| **Full article text** (`fetchBodies`) | `body` (plain text), `markdown` (RAG-ready), `author`, `wordCount`, `bodyStatus` on each article, from the publisher page | $0.001 per article with text |
| **AI story briefs** (`storyBriefs`) | `brief`: 2-3 sentences per story - what happened, key numbers, why it matters. Stories with 2+ articles or a fetched text; with `trackChanges` on (default), a story an earlier run already delivered is briefed again only when new outlets picked it up | $0.01 per brief |
| **AI company briefing** (`companyBriefing`) | `briefing` on the company digest: top events, tone and how it changed since the last run, risks | $0.02 per company per run |
| **Share of voice** (`shareOfVoice`, 2+ companies) | **Share of voice** table + `SHARE_OF_VOICE` record: each company's share of coverage, tier-1 outlet share, tone, event mix, change since the last run | $0.02 per run |
| **Alerts** (`alertWebhookUrl`) | One Slack or webhook message per run when a company's `signalScore` reaches your threshold or a trigger event of the chosen types appears | free |
| **Several countries** (`countries`) | The same watchlist in up to 10 Google News editions (US, GB, DE, FR, JP...), each with its own articles, stories and digest; non-English titles get an English `titleEnglish` (with AI signals on) | normal prices |

**Max story briefs per company / query / topic** caps the briefs; your spending limit caps everything - an add-on
output that no longer fits is left out, never charged. Example: the 5-company run above with 4 new trigger events
and a company briefing each costs + $0.04 + $0.10 = $0.915 per run.

#### Trigger events

`triggerId`, `type` (`funding`, `acquisition`, `expansion`, `layoffs`, `partnership`, `product-launch`,
`executive-change`), `company` / `query`, `edition`, `summary` (one sentence), `facts` (`amount`, `currency`,
`round`, `leadInvestors`, `valuation`, `acquirer`, `acquiredCompany`, `dealValue`, `location`, `layoffCount`,
`layoffSharePct`, `partner`, `product`, `executiveRole`, `executiveName`, `executiveChange` - only the facts of its
type, null when the text does not state them), `confidence` (0-1), `storyId`, `headline`, `url`, `publishedAt`,
`sources` (outlet, url, date of each article). One row per new story: with `trackChanges` on (default), a story
already delivered by an earlier run of the same watchlist is not extracted (and charged) again. When two stories of
one run report the same event (same type and main fact: amount, acquired company, location, partner, product,
executive), only the widest-covered one is delivered and charged.

**What counts as a trigger event?** Only stories whose AI event type is funding, acquisition, expansion, layoffs,
partnership, product or executive, where your company is the subject, are sent to the extraction step. The model then
keeps only real events in which your company itself takes part and states only facts written in the headlines (and
the article text when `fetchBodies` is on): rumours, stock moves, analyst notes, and governments, counties, schools
or charities "acquiring" or "appointing" are rejected. Executive names are kept only together with the company role
the article names. How accurate is it? We checked every trigger the final prompt delivered for 18 companies it had
never been tuned on (HSBC, Toyota, Samsung, Sony, CrowdStrike, Monzo and others, one week of news, one annotator): 30
of 35 (86%) were real events of the right type, and in all 30 the facts matched the headlines. The misses were
sponsorships, a pricing announcement, motorsport team news and a vague "plans" story. Expect roughly one trigger in 7
to be a weaker signal than you want; `confidence` and `sources` help you check fast.

#### Full article text

With `fetchBodies` the Actor opens each decoded publisher URL once (at most 4 pages at a time, one request per outlet
per second, no cookies, no proxies, no login) and reads the article from the page's structured data (JSON-LD
`articleBody`) or its main paragraphs. `bodyStatus` says what happened: `ok` (text delivered and charged), `paywall`
(the page's structured data says the article is not free - even when the text is hidden in the page for search
engines - or it shows only a teaser behind paywall markup), `blocked` (the site refused, asked for consent or served
a bot check), `no-text` (no article text on the page), `error`, `no-url` (the publisher URL could not be decoded),
`skipped` (your spending limit). Only `ok` is charged. Texts longer than 50,000 characters are cut. How many articles
get a text depends on the outlets: in our test run (Shopify, Wix, BigCommerce, US and German editions, 62 articles)
29 got a text (47%); finance portals that block bots or show quote pages (Investing.com, Yahoo Finance quote pages,
Seeking Alpha) gave `blocked`, `error` or `paywall` and were not charged.

#### Share of voice

`company`, `edition`, `timeRange`, `articles`, `sharePct`, `atCap`, `mainArticles`, `netSentiment`, `eventCounts`,
`tier1Articles`, `tier1SharePct`, `stories`, `previousSharePct`, `shareChangePct`. Tier-1 outlets: Reuters,
Bloomberg, FT, WSJ, CNBC, New York Times, Washington Post, AP, BBC, The Guardian, The Economist, Forbes, Fortune,
Business Insider, MarketWatch, Barron's, Axios, TechCrunch, The Verge, Wired, The Information, CNN, Nikkei,
Handelsblatt, Les Echos.

Shares count the articles the run delivered. When a company reaches **Max articles per company / query / topic**,
its real coverage is larger than counted: such rows have `atCap: true` and the report has a warning. Raise it (up to
500\) for a fair comparison.

#### Alerts and several countries

At the end of the run the Actor sends **one** POST with all alerts: a Slack message for `hooks.slack.com` URLs,
otherwise JSON (`{"source", "runId", "scrapedAt", "alerts": [{"kind", "company", "edition", "signalScore",
"triggerType", "text", "url"}]}`). It retries 3 times on 5xx/429/network errors; a failed webhook never fails the run
and is reported in `RUN_SUMMARY`. The URL is a secret input, and only its host appears in logs.

With `countries` (e.g. `["US", "GB", "DE"]`) every company, query and topic runs once per edition, with that
edition's language. Each edition has its own history, stories, digest (`edition` field on every row) and
share-of-voice comparison. With AI signals on, titles of non-English editions get an English translation in
`titleEnglish` (the AI labels read the original title).

Example with add-ons: `{"companies": ["Stripe", "Adyen", "Klarna"], "timeRange": "7d", "maxArticlesPerCompany": 50, "extractTriggers": true, "storyBriefs": true, "shareOfVoice": true, "alertWebhookUrl": "https://hooks.slack.com/services/..."}`.

### Monitor daily

Schedule the Actor (Apify **Schedules**) with the same watchlist and keep **Track changes between runs** on; turn on
**Only new articles** to receive (and pay for) only articles an earlier run did not deliver.

With tracking on, the Actor saves the watchlist's articles and stories in a key-value store named
`google-news-signals-state` in your account, under a key computed from your companies, queries, topics, country and
language (the order and case of names do not matter; the key is in `RUN_SUMMARY.stateKey`). A story keeps its
`storyId` across runs when it contains an article seen before. `outletsAddedSinceLastRun` counts outlets that were
not in the story last time; a story is `isBreaking` when it gained 3 or more outlets, or is new with 3 or more (on
the first run only when its latest article is from the last 24 hours). History older than 30 days is dropped. Change
the watchlist and you start a fresh history.

**How is `signalScore` computed?** Each story gets a weight by its event type: funding, acquisition, layoffs,
security incident 3; legal/regulatory 2.5; executive, expansion 2; partnership, earnings 1.5; product 1;
stock/analyst 0.5; other 0. `raw` = the sum over the company's stories that are new since the last run of
`weight x log2(1 + outlets)`. On the first run (or with tracking off) there is no last run, so only stories with an
article in the last 24 hours count; `signalWindow` says which rule was used (`since-last-run` or `last-24h`), and
`signalScore = round(100 x (1 - e^(-raw / 10)))`. One funding story covered by 3 outlets gives 45; quiet weeks with
only stock chatter stay near 0. It is null when the AI was off.

### FAQ

**Is it legal?** The Actor collects publicly available data only, without login and without personal data of
private individuals. Check the site's terms for your use case. With `fetchBodies` it reads publicly available
article pages and returns the byline (`author`) as the publisher prints it; nothing behind a login or paywall is
fetched.

**What if Google News changes or a run fails?** The run fails with a clear error instead of returning empty results,
and you are not charged for results it did not deliver. An empty search (no Google News articles for the names in the
range) finishes green with a message and nothing charged; 0 articles because of a block or a broken feed fails the
run. If Google rate-limits the run (403/429/503), the Actor waits and retries up to 3 times (1, 2, 4 s, or Google's
Retry-After up to 30 s); if Google keeps refusing, it stops making Google requests and delivers what it already has
(undecoded articles get `publisherUrl: null`). If the very first request is refused, the run fails and nothing is
charged. The run never fails because of the AI: unlabelled articles keep null AI fields and stories are grouped by
title similarity. Each run's summary (articles, stories, digests, Google requests, decoded URLs, AI cost, add-on
counts, messages) is in the Storage tab -> Key-value store -> `RUN_SUMMARY`.

**Do I need proxies? Are there limits?** No proxies are used. The Actor is polite: one feed at a time, at most 2 URL
decodes in parallel, and Google requests start at least 0.5 s apart. It never solves captchas or changes its
identity. Up to 500 articles per company (date windows past Google's 100 per search; a single day with more than 100
articles still stops at 100) and 10,000 per run.

**How fresh is the data?** Live at run time, from Google News of the chosen time range. The default input (Duolingo,
100 articles) took 94 s on Apify in our test run (2026-11-04).

**How are the AI labels made, and how accurate are they?** The model (OpenAI gpt-5-mini) reads only the headline with
its outlet - not the article text - in batches of 20, with a fixed prompt and a fixed list of event types. On 136
reference-labelled headlines of 20 companies (one annotator) the event type agreed with the reference label in about
87% of cases and the sentiment label in about 82%; on the 38 of them that were labelled before the model saw them the
numbers were 81% and 77%. Expect roughly one label in 8 to differ from what you would pick, most often `other` vs
`partnership`/`expansion` when the company is only mentioned, and `earnings` vs `stock-analyst` for stock moves after
results. Story groups were checked one by one on 3 companies: about 96% of the article pairs the AI put in one story
really report the same event.

**What is `targetRole` for?** Name searches are noisy: "Peloton" also finds cycling races, "Zoom" generic video-call
stories. `unrelated` marks articles where the name means something else (their event type is always `other`),
`mentioned` marks articles where the company only appears. The digest counts events and sentiment over `main`
articles only.

**Why is `publisherUrl` sometimes null?** Google links to its own redirect page; the Actor asks Google for the real
URL (2 requests per article, cached between runs). In our tests about 2% of articles got no URL from Google. Those
keep `publisherUrl: null` and `url` = the Google link.

**Do topics work like searches?** Topic feeds (`https://news.google.com/topics/...`) return Google's current stories
for a section; the time range does not apply. Stories come from Google's own related coverage, and their outlets
include the related links. The AI labels the event type; sentiment and `targetRole` are null because there is no
target company, and there is no company digest for topics.

### More from Steadywren

- [Startup Funding Rounds Scraper - Global News](https://apify.com/steadywren/startup-funding-rounds-scraper) - fresh funding rounds from news in many countries, merged across outlets, in USD.
- [Substack Scraper & Newsletter Revenue Estimate](https://apify.com/steadywren/substack-revenue-scraper) - Substack leaderboards with an estimated revenue range per newsletter.
- [Goodreads Scraper & Series Read-Through](https://apify.com/steadywren/goodreads-series-scraper) - Goodreads book series with ratings and read-through.
- [All Steadywren Actors](https://apify.com/steadywren) - small tools, steady results. Custom builds: [steadywren.com](https://steadywren.com).

### Input reference

| Field | Type | Default | Description |
|---|---|---|---|
| `companies` | array | - (form prefilled with Duolingo) | **Companies (watchlist).** Company names. Each is searched on Google News as an exact phrase ("Shopify"); the AI judges every headline against this name. With companies, queries and topics all empty the run watches Duolingo as an example. |
| `queries` | array | - | **Search queries.** Free Google News searches (any keywords and Google operators, e.g. AI chips OR semiconductors). The AI judges headlines against the query text. |
| `topicUrls` | array | - | **Topic URLs.** Google News topic or section URLs (https://news.google.com/topics/...). Stories come from Google's own related coverage; timeRange does not apply; no sentiment (there is no target company). |
| `timeRange` | string | `7d` | **Time range.** How far back to search (`1h`, `1d`, `7d`, `30d`, `1y`). Ignored when dateFrom or dateTo is set. |
| `dateFrom` | string | - | **From date.** Optional first day (YYYY-MM-DD). Overrides the time range. Without To date: until today. |
| `dateTo` | string | - | **To date.** Optional last day (YYYY-MM-DD), included. Without From date: the 7 days up to this day. |
| `country` | string | `US` | **Country.** Two-letter country code of the Google News edition (US, GB, DE, IN...). |
| `language` | string | `en` | **Language.** Two-letter language code of the edition (en, de, fr...). The AI prompts are written for English headlines. |
| `countries` | array | - | **Several countries (editions).** Run the same watchlist in several Google News editions, e.g. US, GB, DE, FR or DE:de / BE:nl (country:language). Each edition gets its own articles, stories and digest (normal prices); titles of non-English editions get an English translation in titleEnglish (with AI signals on). Up to 10. Empty = the Country and Language above. |
| `maxArticlesPerCompany` | integer | 100 | **Max articles per company / query / topic.** Newest articles kept per entry (1-500). Google gives at most 100 per search; above that the Actor splits the time range into date windows. |
| `maxItems` | integer | 1000 | **Max articles in total.** Stop after this many articles in the whole run (1-10,000). You pay per article, so this also caps your cost. |
| `resolveUrls` | boolean | true | **Decode publisher URLs.** Turn Google's news.google.com links into the real publisher URL (2 extra requests per article, cached between runs). Included in the price. |
| `ai` | boolean | true | **AI signals.** AI event type (funding, acquisition, earnings, layoffs, lawsuits...), sentiment toward the company, entities and story grouping. Included in the price. |
| `maxAiCostUsd` | number | 0.5 | **Max AI cost per run (USD).** Safety cap of the AI work per run (paid by us, not added to your bill; 0.05-2). When reached, the rest of the articles have empty AI fields. |
| `trackChanges` | boolean | true | **Track changes between runs.** Remember articles and stories of this watchlist: new articles, new stories, outlets added since the last run, breaking stories. Best with a schedule. |
| `onlyNewArticles` | boolean | false | **Only new articles.** Deliver only articles that an earlier run with the same watchlist did not deliver. |
| `extractTriggers` | boolean | false | **Trigger events with facts ($0.01 per trigger).** Sales trigger events of the watched companies with their facts: funding (amount, currency, round, lead investors, valuation), acquisitions (acquirer, acquired company, deal value), expansion (location), layoffs (count, share), partnerships (partner), product launches (product), executive changes (role; the person's name only when the article names them in that role). One row per new story in the `triggers` dataset, event trigger-event, $0.01 each. |
| `fetchBodies` | boolean | false | **Full article text ($0.001 per article).** Fetch each publisher page and add the article text, clean Markdown (RAG-ready), author and word count. Paywalled or blocked pages get bodyStatus paywall/blocked and are not charged. Needs Decode publisher URLs on. Event article-text, $0.001 per article with text. Adds about 1 s per article. |
| `storyBriefs` | boolean | false | **AI story briefs ($0.01 per brief).** A 2-3 sentence AI brief per story (what happened, key numbers, why it matters) in the `stories` dataset. Only stories with 2+ articles or a fetched article text, widest coverage first; with Track changes on, a story an earlier run already delivered is briefed again only when new outlets picked it up. Event story-brief, $0.01 each. |
| `maxBriefsPerTarget` | integer | 10 | **Max story briefs per company / query / topic.** Caps the story-brief cost: at most this many briefs per watchlist entry per run (1-50). |
| `companyBriefing` | boolean | false | **AI company briefing ($0.02 per company).** A short written briefing per company per run (top events, tone and how it changed since the last run, risks) in the `briefing` field of the company digest. Event company-briefing, $0.02 each. |
| `shareOfVoice` | boolean | false | **Share of voice report ($0.02 per run).** Compare 2+ watched companies: share of coverage, tier-1 outlet share (Reuters, Bloomberg, FT, WSJ, CNBC...), tone, event mix and change since the last run. Dataset `sov` + record SHARE_OF_VOICE. Event sov-report, $0.02 per run. |
| `alertWebhookUrl` | string | - | **Alert webhook URL (free).** Slack incoming-webhook URL (hooks.slack.com) or any https webhook. One POST per run when a company's signal score reaches the threshold or a trigger event of the chosen types appears. Free. |
| `alertMinSignalScore` | integer | 60 | **Alert when signal score is at least.** Signal score (0-100) that triggers a company alert. |
| `alertTriggerTypes` | array | every type | **Alert on trigger types.** Trigger events (needs Trigger events on) that send an alert. Empty = every type. |

Search keywords: google news scraper, google news, news monitoring, company news, news sentiment

# Actor input Schema

## `companies` (type: `array`):

Company names. Each is searched on Google News as an exact phrase ("Shopify"); the AI judges every headline against this name.

## `queries` (type: `array`):

Free Google News searches (any keywords and Google operators, e.g. AI chips OR semiconductors). The AI judges headlines against the query text.

## `topicUrls` (type: `array`):

Google News topic or section URLs (https://news.google.com/topics/...). Stories come from Google's own related coverage; timeRange does not apply; no sentiment (there is no target company).

## `timeRange` (type: `string`):

How far back to search. Ignored when dateFrom or dateTo is set.

## `dateFrom` (type: `string`):

Optional first day (YYYY-MM-DD). Overrides the time range. Without To date: until today.

## `dateTo` (type: `string`):

Optional last day (YYYY-MM-DD), included. Without From date: the 7 days up to this day.

## `country` (type: `string`):

Two-letter country code of the Google News edition (US, GB, DE, IN...).

## `language` (type: `string`):

Two-letter language code of the edition (en, de, fr...). The AI prompts are written for English headlines.

## `countries` (type: `array`):

Run the same watchlist in several Google News editions, e.g. US, GB, DE, FR or DE:de / BE:nl (country:language). Each edition gets its own articles, stories and digest (normal prices); titles of non-English editions get an English translation in titleEnglish (with AI signals on). Up to 10. Empty = the Country and Language above.

## `maxArticlesPerCompany` (type: `integer`):

Newest articles kept per entry. Google gives at most 100 per search; above that the Actor splits the time range into date windows.

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

Stop after this many articles in the whole run. You pay per article, so this also caps your cost.

## `resolveUrls` (type: `boolean`):

Turn Google's news.google.com links into the real publisher URL (2 extra requests per article, cached between runs). Included in the price.

## `ai` (type: `boolean`):

AI event type (funding, acquisition, earnings, layoffs, lawsuits...), sentiment toward the company, entities and story grouping. Included in the price.

## `maxAiCostUsd` (type: `number`):

Safety cap of the AI work per run (paid by us, not added to your bill). When reached, the rest of the articles have empty AI fields.

## `trackChanges` (type: `boolean`):

Remember articles and stories of this watchlist: new articles, new stories, outlets added since the last run, breaking stories. Best with a schedule.

## `onlyNewArticles` (type: `boolean`):

Deliver only articles that an earlier run with the same watchlist did not deliver.

## `extractTriggers` (type: `boolean`):

Sales trigger events of the watched companies with their facts: funding (amount, currency, round, lead investors, valuation), acquisitions (acquirer, acquired company, deal value), expansion (location), layoffs (count, share), partnerships (partner), product launches (product), executive changes (role; the person's name only when the article names them in that role). One row per new story in the `triggers` dataset, event trigger-event, $0.01 each.

## `fetchBodies` (type: `boolean`):

Fetch each publisher page and add the article text, clean Markdown (RAG-ready), author and word count. Paywalled or blocked pages get bodyStatus paywall/blocked and are not charged. Needs Decode publisher URLs on. Event article-text, $0.001 per article with text. Adds about 1 s per article.

## `storyBriefs` (type: `boolean`):

A 2-3 sentence AI brief per story (what happened, key numbers, why it matters) in the `stories` dataset. Only stories with 2+ articles or a fetched article text, widest coverage first; with Track changes on, a story an earlier run already delivered is briefed again only when new outlets picked it up. Event story-brief, $0.01 each.

## `maxBriefsPerTarget` (type: `integer`):

Caps the story-brief cost: at most this many briefs per watchlist entry per run.

## `companyBriefing` (type: `boolean`):

A short written briefing per company per run (top events, tone and how it changed since the last run, risks) in the `briefing` field of the company digest. Event company-briefing, $0.02 each.

## `shareOfVoice` (type: `boolean`):

Compare 2+ watched companies: share of coverage, tier-1 outlet share (Reuters, Bloomberg, FT, WSJ, CNBC...), tone, event mix and change since the last run. Dataset `sov` + record SHARE_OF_VOICE. Event sov-report, $0.02 per run.

## `alertWebhookUrl` (type: `string`):

Slack incoming-webhook URL (hooks.slack.com) or any https webhook. One POST per run when a company's signal score reaches the threshold or a trigger event of the chosen types appears. Free.

## `alertMinSignalScore` (type: `integer`):

Signal score (0-100) that triggers a company alert.

## `alertTriggerTypes` (type: `array`):

Trigger events (needs Trigger events on) that send an alert. Empty = every type.

## Actor input object example

```json
{
  "companies": [
    "Duolingo"
  ],
  "timeRange": "7d",
  "country": "US",
  "language": "en",
  "maxArticlesPerCompany": 100,
  "maxItems": 1000,
  "resolveUrls": true,
  "ai": true,
  "maxAiCostUsd": 0.5,
  "trackChanges": true,
  "onlyNewArticles": false,
  "extractTriggers": false,
  "fetchBodies": false,
  "storyBriefs": false,
  "maxBriefsPerTarget": 10,
  "companyBriefing": false,
  "shareOfVoice": false,
  "alertMinSignalScore": 60
}
```

# Actor output Schema

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

One item per article with publisher URL, AI event type, sentiment toward the company and story id. Add ?format=csv or ?format=xlsx for other formats.

## `stories` (type: `string`):

One item per story (the same event across outlets) with outlet count and momentum since the last run. Free.

## `companies` (type: `string`):

One row per company or search query: event counts, net sentiment, new and breaking stories, signal score.

## `triggers` (type: `string`):

Funding, acquisitions, expansion, layoffs, partnerships, product launches and executive changes with their facts (amount, round, investors, acquirer, location, partner...). Only with extractTriggers.

## `sov` (type: `string`):

One row per company and edition: share of coverage, tier-1 outlet share, tone, change since the last run. Only with shareOfVoice.

## `shareOfVoice` (type: `string`):

The whole share-of-voice comparison as one JSON record, with a warning when a company hit the article cap.

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

Articles, stories and digests per target, feeds, URL decoding counts, whether Google blocked the run, AI cost and messages, and why the run failed if it did.

# 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 = {
    "companies": [
        "Duolingo"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("steadywren/google-news-signals-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 = { "companies": ["Duolingo"] }

# Run the Actor and wait for it to finish
run = client.actor("steadywren/google-news-signals-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 '{
  "companies": [
    "Duolingo"
  ]
}' |
apify call steadywren/google-news-signals-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,steadywren/google-news-signals-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/B0CFiGOElOC5YjSiS/builds/8aTzHAt3uUfoZ2Cpm/openapi.json
