# News Search API: Multi-Source Headlines (`spider355/news-search-google-bing`) Actor

Search news by keyword and get headlines, publisher, article link and date from the free GDELT DOC 2.0 API, plus NewsAPI with your own optional key. Merged and deduplicated. Language, country and time filters. No full article text.

- **URL**: https://apify.com/spider355/news-search-google-bing.md
- **Developed by:** [Mitchell](https://apify.com/spider355) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 75.9% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 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.

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

## News Search API: Multi-Source Headlines

Search the news by keyword and get a clean, deduplicated list of **headlines with the publisher's article link, outlet and date**. The default source is the free, open **GDELT DOC 2.0 API** (no key needed). You can add **NewsAPI** with your own API key. Export as JSON, CSV or Excel, or call it as an API.

This Actor returns search results only: headline, link, outlet, date and, from NewsAPI, a short description. It does not copy article text or images. Open the link to read the story on the publisher's site.

### What you can do with it

- **Monitor a brand, competitor or topic.** Schedule a run every hour or day and send new headlines to Slack, email or a spreadsheet.
- **Feed AI agents and alert bots** with fresh, linked headlines on any subject.
- **Track coverage** with publisher URLs you can open or archive.
- **Research markets** across many languages and publisher countries.

### Sources

| Source | Key | What it gives | Notes |
|---|---|---|---|
| `gdelt` (default) | none | headline, link, outlet domain, first-seen time | GDELT DOC 2.0 covers about the **last 3 months**. Allows one request every 5 seconds, so each query takes at least 5.5 seconds. |
| `newsapi` (optional) | **your own** newsapi.org key | headline, link, outlet name, publish time, short description | Your NewsAPI plan's terms and limits apply. The free Developer plan is for development and testing only. |

Leave `sources` empty to use GDELT, plus NewsAPI when you enter a key. An article found by both is merged into one item, and `alsoOn` names the other source.

### Input

```json
{
    "queries": ["\"electric vehicles\" battery", "(Tesla OR Rivian) -stock"],
    "timeRange": "day",
    "language": "en",
    "country": "",
    "maxResultsPerQuery": 100
}
```

- `queries`: one search per line. `"exact phrase"`, `-exclude` and `(a OR b)` with brackets work. `site:example.com` is sent to GDELT as `domain:example.com`. GDELT rejects very short single words (under 3 letters).
- `timeRange`: `hour`, `day`, `week` (default), `month`, `year` or `any`. For GDELT, `year` and `any` mean the last 3 months.
- `language`: two-letter code of the article language (default `en`).
- `country`: optional two-letter code of the publisher's country, for example `US`, `GB`, `NZ`. Leave empty for all countries. GDELT only; NewsAPI search has no country filter.
- `sources`: `gdelt`, `newsapi` or both.
- `newsApiKey`: optional, your own NewsAPI key. It is a secret input: it is sent only in the `X-Api-Key` request header to newsapi.org, and is never logged or written to the output.
- `maxResultsPerQuery`: up to 200 (default 100).

#### Input validation

The run stops before any search if the input is invalid, and the error names the field:

- `queries` is required: 1 to 50 strings, each up to 500 characters.
- `timeRange` must be one of `any`, `hour`, `day`, `week`, `month`, `year`. The default is `week`.
- `language` must be a two-letter code. `country` must be a two-letter code or empty.
- `sources` must be drawn from `gdelt` and `newsapi`. `newsapi` without a `newsApiKey` fails the run.
- `maxResultsPerQuery` must be a whole number from 1 to 200.

#### Upgrading from version 1

Version 2 changed the sources. The old `engines` input was removed: a run that still sends `engines` fails with a message asking you to delete it and use `sources`. The old `resolveUrls` input is ignored with a warning, because both sources return the publisher's own link. `country` no longer defaults to `US`; it is empty (all countries) unless you set it.

#### Redaction in snippets

NewsAPI descriptions are free text, and press-release coverage often ends with a media contact. Each `snippet` is passed through the shared redaction module (`src/redact.js`) and cut to 300 characters. Emails and phone numbers become `[redacted]`, and so does a personal name after a label or sign-off (`Media contact: Jane Roe` becomes `Media contact: [redacted]`). Headlines, outlets, prices and dates are not changed. Names in the running text of a story are not removed; they are part of the news. Article authors are not output.

### Output

```json
{
    "query": "electric vehicles",
    "title": "Example Motors opens battery plant",
    "publisher": "news.example.com",
    "url": "https://news.example.com/2026/10/20/example-motors-battery-plant",
    "publishedAt": "2026-10-20T09:15:00.000Z",
    "snippet": null,
    "source": "gdelt",
    "alsoOn": []
}
```

Illustrative values. `publisher` is the site domain for GDELT and the outlet name for NewsAPI. `publishedAt` is the time GDELT first saw the article, or NewsAPI's publish time. `snippet` is filled only from NewsAPI.

A `SUMMARY` record in the key-value store shows, for each query, how many articles each source found and how many were returned.

### Pricing

You pay per article returned. Duplicates merged across sources and queries are free. NewsAPI usage counts against your own NewsAPI plan.

### Limits worth knowing

- GDELT searches about the last 3 months and returns up to 250 articles per query; this Actor returns up to 200.
- GDELT allows one request every 5 seconds. Queries run one after another, at least 5.5 seconds apart, and a rate-limit reply (HTTP 429) or dropped connection is retried. GDELT counts requests per IP address, and Apify's outgoing IPs are shared, so on Apify the retries go out through Apify Proxy (a fresh datacenter IP each time) when your account has proxy access; otherwise they wait and retry directly. A run with 50 queries takes about 5 minutes or more.
- Headlines come from the publishers. GDELT's headline text is lightly tidied (spacing around punctuation); words are not changed.
- No full article text and no images. Pass the URLs to an article extractor if you need the body, subject to the publisher's terms.

### Credits and terms

- Data from the [GDELT Project](https://www.gdeltproject.org/), which makes its datasets available for unlimited and unrestricted use, including commercial use, without fee. Please credit GDELT when you publish results.
- [NewsAPI](https://newsapi.org/) results are fetched with your own key under your agreement with NewsAPI.
- Headlines and linked articles belong to their publishers.
- Not affiliated with, or endorsed by, the GDELT Project, NewsAPI or any publisher.

### Questions and requests

Open an issue on the Issues tab and it will be looked at quickly.

# Actor input Schema

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

One search per line. Exact phrases in "quotes", -exclude, and (a OR b) with brackets work; site:example.com is sent to GDELT as domain:example.com. 1 to 50 queries, each up to 500 characters. GDELT rejects very short single words (under 3 letters).

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

Keep only articles published in this period. GDELT covers about the last 3 months, so "Past year" and "Any time" return GDELT articles from that window only.

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

Two-letter language code of the article, for example en, de, fr, es, pt, ja.

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

Optional two-letter country code of the news outlet, for example US, GB, DE, AU, NZ. Leave empty for all countries. Applies to GDELT only.

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

GDELT is free and needs no key. NewsAPI needs your own key (below). Leave empty for GDELT, plus NewsAPI when a key is given.

## `newsApiKey` (type: `string`):

Optional. Your own key from newsapi.org. It is sent only in the X-Api-Key request header to newsapi.org and is never logged or saved in the output. Your NewsAPI plan's terms apply (the free Developer plan is for development only).

## `maxResultsPerQuery` (type: `integer`):

Upper limit of articles returned for each query, newest first.

## Actor input object example

```json
{
  "queries": [
    "artificial intelligence regulation"
  ],
  "timeRange": "week",
  "language": "en",
  "maxResultsPerQuery": 20
}
```

# Actor output Schema

## `articles` (type: `string`):

One item per news article, newest first within each query.

## `summary` (type: `string`):

Per query: articles found on each source and articles returned.

# 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 = {
    "queries": [
        "artificial intelligence regulation"
    ],
    "maxResultsPerQuery": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("spider355/news-search-google-bing").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 = {
    "queries": ["artificial intelligence regulation"],
    "maxResultsPerQuery": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("spider355/news-search-google-bing").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 '{
  "queries": [
    "artificial intelligence regulation"
  ],
  "maxResultsPerQuery": 20
}' |
apify call spider355/news-search-google-bing --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,spider355/news-search-google-bing"
        }
    }
}
```

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/Umn1N56JE4sHWuulX/builds/DsRRPW9pNuYPZO2Iu/openapi.json
