# News Scraper: GDELT Articles, Full Text & 65 Languages (`private_image_hg9/news-search-gdelt`) Actor

Search news from around the world by keyword, country, language and website through the open GDELT index (65+ languages, updated every 15 minutes). Up to 5,000 articles per search with title, URL, outlet, country, language, date and image, plus optional full text. A Google News alternative.

- **URL**: https://apify.com/private_image_hg9/news-search-gdelt.md
- **Developed by:** [Michael Shanker](https://apify.com/private_image_hg9) (community)
- **Categories:** News, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 article founds

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 Scraper: GDELT Articles, Full Text & 65 Languages

Search news from around the world by keyword and get back a clean list of articles: **title, link, outlet, country, language, the time it was published online, and the share image**. Filter by country, language and website, go back up to about 3 months, and get **up to 5,000 articles per search**. Turn on **full text** and it also visits each article and pulls out the story itself.

It searches the **[GDELT Project](https://www.gdeltproject.org/)**, an open index that monitors online news in more than 65 languages and is updated every 15 minutes. No Google pages are scraped, so it is a **Google News alternative** built on a source that is free to use and redistribute with credit.

### Who it's for

- **Media monitoring and PR**: track mentions of a brand, a person or a topic across thousands of outlets, every day.
- **Research and data teams**: build news datasets by country and language for analysis or model training.
- **Newsletters, alerts and dashboards**: schedule a run every hour and feed new articles into Sheets, Slack, Make, Zapier or n8n.
- **AI and RAG pipelines**: get the article text, not just the headline.

### How it compares

| | This Actor | Google News scrapers on the Store |
|---|---|---|
| Source | GDELT DOC 2.0 API: open data, free to use with credit | Google News pages |
| Price per 1,000 articles | **$1.50** (full text +$2.00, only when extracted) | $0.87 to $4.00 |
| Articles per search | up to 5,000 (GDELT's 250-per-request cap is paged for you) | varies by tool |
| Filters | country, 65 languages, website, date range, GDELT operators (themes, tone, proximity) | varies by tool |
| Full article text | optional; robots.txt obeyed, paywalls left alone | varies by tool |
| Empty or failed searches | free | varies by tool |

Store prices as seen in November 2026; they may change.

### Input

| Field | What it does |
|---|---|
| **Search terms** | One search per line. All words must appear. `"exact phrase"`, `(a OR b)` and `-word` work, and so do GDELT operators such as `sourcelang:spanish`, `sourcecountry:UK`, `theme:ENV_CLIMATECHANGE`, `tone<-5` and `near20:"grain exports"`. |
| **Time span** | How far back from now: `15min`, `24h`, `7d`, `2w`, `3m` (default `7d`, at most `3m`). |
| **Start date / End date** | A fixed range instead (`2026-10-01`, or `2026-10-01T08:00:00Z`). |
| **Max articles per search** | 1 to 5,000 (default 250). |
| **Sort by** | Newest first (default), oldest first, most relevant, most positive or most negative tone. |
| **Publisher country** | Country names (`Germany, United Kingdom`) or GDELT's FIPS codes (`GM, UK`). Note that FIPS codes are not ISO codes: `GB` is Gabon and `AU` is Austria in FIPS. Names are safest; the log flags codes that look like ISO codes. |
| **Language** | `Spanish, Japanese` or `es, ja` or `spa, jpn`. |
| **Only these websites** | e.g. `reuters.com`, `bbc.co.uk` (subdomains included). |
| **Fetch full article text** | Off by default. Adds `text`, `textStatus` and `wordCount`. |
| **Skip articles found by an earlier search** | On by default: an article that several searches find is saved and charged once. |
| **Use Apify Proxy for GDELT requests** | Off by default. In our tests it did not make runs faster, so leave it off unless a run keeps failing with rate-limit errors. |

Example:

```json
{
  "queries": ["\"electric vehicles\"", "inflation sourcecountry:UK", "election sourcelang:spanish"],
  "timespan": "7d",
  "maxResultsPerQuery": 500,
  "sort": "newest",
  "fetchArticleText": false
}
```

### Output

One row per article (values illustrative):

```json
{
  "query": "\"electric vehicles\"",
  "status": "found",
  "title": "EU electric vehicle sales climb for a third month",
  "url": "https://www.example-news.com/business/eu-ev-sales-climb",
  "domain": "example-news.com",
  "sourceCountry": "United Kingdom",
  "language": "English",
  "seenDate": "2026-11-03T09:15:00Z",
  "socialImage": "https://www.example-news.com/images/ev-sales.jpg",
  "mobileUrl": null,
  "text": "EU electric vehicle sales climbed for a third month in October...",
  "textStatus": "ok",
  "wordCount": 642,
  "textError": null,
  "error": null,
  "scrapedAt": "2026-11-03T09:30:12+00:00"
}
```

- `seenDate` is when GDELT first saw the article online (UTC). GDELT checks for news every 15 minutes, so this is close to, but not always the same as, the publication time.
- `text`, `textStatus`, `wordCount` and `textError` appear only when **Fetch full article text** is on. `textStatus` is one of `ok`, `paywalled`, `blocked_by_robots` (the publisher's robots.txt asks tools not to read it), `blocked` (the site refused, e.g. HTTP 403), `not_found`, `http_error`, `unreachable`, `not_html`, `no_text_found` (for example a page that needs JavaScript or a consent click) and `not_public_address`. Only `ok` rows carry text.
- A search with no articles gets one row with `status: "no_results"`, and a search GDELT rejected or could not answer gets one row with `status: "query_failed"` and GDELT's reason in `error`. Both are free.
- The run also saves a `SUMMARY` record: counts per search, the exact GDELT query each search became, articles and texts charged, GDELT requests and rate-limit waits, and whether the spending cap stopped the run.

### Pricing

Pay per event, no start fee:

- **$0.0015 per article found** ($1.50 per 1,000 unique articles).
- **$0.002 per full text extracted** ($2.00 per 1,000), charged only when text was actually extracted. Paywalled, blocked or empty pages cost nothing extra.

So 1,000 articles cost $1.50, or at most $3.50 with full text. Searches with no results and failed searches are free. Set a maximum charge per run in the run options and the Actor stops cleanly when it's reached, before fetching anything it couldn't charge for.

### Good to know

- **About 3 months back.** GDELT's search covers a rolling window of roughly the last 3 months. For older news, use a dated archive.
- **Speed.** GDELT asks for no more than one request every 5 seconds, and each request returns at most 250 articles. A 1,000-article search takes about half a minute; ten searches of 250 take about a minute. When GDELT is busy it asks callers to slow down; the Actor waits and retries (10 s, 20 s, 40 s, 60 s, 60 s) and says so in the log. These waits are common from shared cloud machines: in our tests on Apify, 3 searches with full text took about 3 minutes. Searches that still fail after the retries are saved as free `query_failed` rows.
- **Past 250 articles** the date range is walked newest to oldest (or the reverse), so results stay in order with no repeats. For the relevance and tone sorts the range is split into time windows and the windows are interleaved, so the order is "best of each window" rather than one global ranking.
- **Tone** can be used to filter (`tone<-5` in a search) and to sort, but GDELT's article list doesn't include a tone score per article, so there is no tone column.
- **Languages.** GDELT machine-translates the languages it monitors, so English search terms also find articles in other languages. Titles are kept in their original language.
- **Coverage** is what GDELT monitors: very broad, but not every outlet, and a few links may have moved or gone by the time you open them.
- **Full text** is read like a polite visitor would: one page per second per website at most, the publisher's robots.txt obeyed for every page and redirect, at most 3 MB per page, and no logins, cookies, paywall tricks or headless browser. Expect text for most open news sites and none for paywalled ones.

### Source and credit

Article data comes from **the GDELT Project** (https://www.gdeltproject.org/) through its DOC 2.0 API. GDELT's data is free for any use, including commercial use, with credit to the GDELT Project and a link to its website; please keep that credit when you publish data from this Actor. The article texts belong to their publishers: check their terms before republishing them.

This Actor isn't affiliated with or endorsed by the GDELT Project, Google or any publisher.

### More tools from the same developer

- [RSS Feed Reader: Atom & RSS to JSON with Feed Finder](https://apify.com/private_image_hg9/rss-feed-reader-finder)
- [Hacker News Scraper: Search, Stories & Comments](https://apify.com/private_image_hg9/hacker-news-scraper)
- [Google Trends Scraper: Interest Over Time, Regions & Queries](https://apify.com/private_image_hg9/google-trends-scraper)
- [OpenAlex Papers Search: Scholarly Works, Citations & Abstracts](https://apify.com/private_image_hg9/openalex-papers-search)
- [ClinicalTrials.gov Search: Studies, Phases, Sponsors & Status](https://apify.com/private_image_hg9/clinical-trials-search)
- [Federal Contracts Search: SAM.gov Opportunities & Award History](https://apify.com/private_image_hg9/federal-contracts-search)

# Actor input Schema

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

One search per line. All words must appear; put a phrase in double quotes for an exact match ("interest rates"), use (a OR b) for either, and -word to leave a word out. GDELT operators work inside a search too, e.g. sourcelang:spanish, sourcecountry:UK, theme:ENV_CLIMATECHANGE, tone<-5 or near20:"grain exports". GDELT rejects some very short or very common words; the row then says so. Each search gets its own rows; repeats run once.

## `timespan` (type: `string`):

How far back to search from now: a number and a unit, like 15min, 24h, 7d, 2w or 3m. GDELT keeps about the last 3 months, so 3m is the most. Ignored when Start date or End date is set.

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

Optional. YYYY-MM-DD or an ISO date and time (2026-10-01T08:00:00Z), in UTC unless an offset is given. With only an end date, the search starts 3 months back.

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

Optional. YYYY-MM-DD (the whole day is included) or an ISO date and time. With only a start date, the search runs up to now.

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

GDELT gives at most 250 articles per request. Above 250 the date range is walked in steps (newest or oldest sort) or split into time windows (relevance and tone sorts), and the results are merged without repeats.

## `sort` (type: `string`):

The order GDELT picks and returns articles in.

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

Only outlets based in these countries, comma separated. English country names are safest (Germany, United Kingdom, South Korea). Two-letter codes are GDELT's FIPS codes, which differ from ISO codes for many countries (UK = United Kingdom, GM = Germany, AS = Australia, JA = Japan). An ISO code that is not a FIPS code (like DE) is converted, and one that means another country in FIPS (like GB, which is Gabon) is flagged in the log.

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

Only articles in these languages, comma separated: names (Spanish, Japanese) or codes (es, spa). GDELT covers 65 languages and translates them, so English search terms also find non-English articles.

## `domains` (type: `array`):

Only articles from these news sites (and their subdomains), e.g. reuters.com or bbc.co.uk.

## `fetchArticleText` (type: `boolean`):

Visit each article page (obeying the publisher's robots.txt) and extract its main text. Adds text, textStatus and wordCount. Paywalled, blocked or empty pages get a textStatus and no text, and the text price is charged only when text was extracted. Slower: about one page per second per website.

## `dedupeAcrossQueries` (type: `boolean`):

When several searches find the same article, keep it once (under the first search). Turn off to get it under every search that found it.

## `useApifyProxy` (type: `boolean`):

Send the GDELT API requests through Apify Proxy. Useful only if the log shows many rate-limit waits, which happens when other users share the same IP address. Article pages are always fetched directly.

## Actor input object example

```json
{
  "queries": [
    "\"electric vehicles\"",
    "climate change"
  ],
  "timespan": "24h",
  "maxResultsPerQuery": 50,
  "sort": "newest",
  "fetchArticleText": false,
  "dedupeAcrossQueries": true,
  "useApifyProxy": false
}
```

# Actor output Schema

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

One row per article (title, URL, outlet, country, language, date, image and optional full text), plus one row for each search with no results or an error.

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

Counts per search, articles charged, full texts extracted, GDELT requests and rate-limit waits, and whether the spending cap was reached.

# 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": [
        "\"electric vehicles\"",
        "climate change"
    ],
    "timespan": "24h",
    "maxResultsPerQuery": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("private_image_hg9/news-search-gdelt").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": [
        "\"electric vehicles\"",
        "climate change",
    ],
    "timespan": "24h",
    "maxResultsPerQuery": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("private_image_hg9/news-search-gdelt").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": [
    "\\"electric vehicles\\"",
    "climate change"
  ],
  "timespan": "24h",
  "maxResultsPerQuery": 50
}' |
apify call private_image_hg9/news-search-gdelt --silent --output-dataset

```

## MCP server setup

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

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/PPrUSWeBJgjlLwqEz/builds/PDLiZnlY9aRuPWdzf/openapi.json
