# GDELT News Scraper: Worldwide News in 65 Languages (`glitchbound/gdelt-scraper`) Actor

Search worldwide news coverage through GDELT, updated every 15 minutes across 65 languages and every country. Filter by language, source country and tone. Returns title, URL, outlet domain, language, source country and publication time, with syndicated duplicates removed.

- **URL**: https://apify.com/glitchbound/gdelt-scraper.md
- **Developed by:** [Daniel Meshulam](https://apify.com/glitchbound) (community)
- **Categories:** News, AI, SEO tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## GDELT News Scraper: Worldwide News in 65 Languages

Search worldwide news coverage in 65 languages and every country, what the whole
world is saying about something, not what five RSS feeds said.

```json
{ "queries": ["artificial intelligence regulation"], "timespan": "24h" }
```

GDELT indexes news from every country in **65 languages** and refreshes every
**15 minutes**. Free, no key.

### How this differs from a news scraper

A normal news Actor reads the feeds you point it at. GDELT is the index of
essentially everything, so the useful filters are the opposite way round:

```json
{
  "queries": ["\"supply chain\" shortage"],
  "language": "spanish",
  "sourceCountry": "MX",
  "timespan": "1w"
}
```

That is Spanish-language coverage from Mexican outlets, a question you cannot
ask a feed list at all.

`sortBy` also exposes GDELT's tone scoring: `tonedesc` gives the most positive
coverage first, `toneasc` the most negative. Useful for finding the sharpest
criticism of a company or policy in one pass.

### Three GDELT behaviours that are handled

**It 429s cold, then works.** GDELT rate-limits unpredictably, the same request
that fails often succeeds seconds later. Measured while building this: a first
probe got `429`, an identical retry got `200`. Proxy rotation plus staged backoff
handles it, so a run does not die on the first rejection.

**An over-narrow query returns HTTP 200 and an empty body**, not an error. That
is turned into an explicit `error` row saying the query matched nothing and to
widen it, instead of an empty dataset you have to interpret yourself.

**Timespan and absolute dates are mutually exclusive.** GDELT honours one and
silently ignores the other without telling you which. Set both and the log says
plainly that the date range won.

### Deduplication

One wire story appears on dozens of syndicating domains. Articles are
deduplicated by URL across every query in the run, and the log reports how many
duplicates were dropped, so a five-query run does not bill you five times for the
same coverage.

### Use cases

- **Global brand monitoring**: every language, not just yours
- **Geopolitical and risk tracking**: filter by source country to see how a story is framed locally
- **Narrative analysis**: sort by tone to find the most positive and most negative framing
- **Market research**: coverage volume for a product or category across regions
- **Journalism**: find non-English reporting that never reaches English feeds

### Pricing

Charged per article returned. A query that matches nothing, or a GDELT rate-limit
that survives every retry, produces an `error` row and costs **$0.00**.

### Worldwide news monitoring, in 65 languages

Most news scrapers read a handful of English feeds. GDELT indexes broadcast,
print and web news worldwide and updates every 15 minutes, which makes it the
one free source that answers "what is the whole world saying about this" rather
than "what did these five outlets say".

**Time windows.** Either a relative `timespan`, one of `1h`, `6h`, `12h`, `24h`,
`3d`, `1w`, `2w`, `1m`, `3m`, or an absolute `startDateTime` / `endDateTime`
pair. Never both: GDELT accepts one or the other and sending both is a silent
precedence bug, so the input schema makes them exclusive.

**Filter by language** with `language`, and by publishing country with
`sourceCountry`. That combination is what the source is actually for: the same
story as covered in Spanish-language Mexican media versus German media is two
runs and a diff, not a translation project.

**Sort** by `datedesc`, `dateasc`, `hybridrel` for relevance, or `tonedesc` /
`toneasc` to surface the most positively or negatively toned coverage first.
Tone sorting is how you find the outliers in a wave of coverage.

**Per article**: headline, URL, outlet domain, language, source country,
timestamp and the social share image. Body text is not part of GDELT's document
API, which is a property of the source rather than of this Actor.

**No key and no quota page.** GDELT rate-limits by IP unpredictably, sometimes
429ing a first request and serving the identical one seconds later, so this
rotates and backs off rather than failing the run.

### Notes

- GDELT caps any single response at **250 articles**. For more, split the run by narrower timespans.
- Returned fields are metadata: headline, outlet, language, country, timestamp, URL. Article body text is not part of GDELT's document API.
- `language` takes GDELT's own names (`english`, `spanish`, `hebrew`), not ISO codes.

### FAQ

#### Do I need a GDELT API key?

No. GDELT's document API is open and key-free.

#### How fresh is the data, and how far back does it go?

GDELT re-indexes every 15 minutes, so `timespan: "15min"` genuinely returns news
from the last quarter hour. The document API covers roughly the last few months;
for older material use absolute `startDate` and `endDate` rather than a timespan.

#### Can I search news in languages other than English?

That is the main reason to use GDELT. Set `language` to GDELT's own name for it,
so `spanish`, `hebrew`, `arabic` rather than ISO codes, and optionally `sourceCountry` to
restrict to outlets based in one country. Spanish-language coverage from Mexican
outlets is a query you cannot ask a feed list at all.

#### Does it return the article text?

No. GDELT's document API is a metadata index: headline, outlet domain, language,
source country, timestamp and URL. Fetch the body from the URL if you need it.

#### My query returned nothing. Why?

Almost always an over-narrow query. GDELT answers those with HTTP 200 and an
empty body rather than an error, so this Actor turns that into an explicit
`error` row telling you to widen it. Quoted phrases are exact, so drop the quotes
or shorten the phrase.

#### Why do I get fewer articles than I asked for?

GDELT caps any single response at 250 articles. Split the run into narrower
timespans to go past that. Syndicated duplicates are also removed by URL across
every query in the run, and the log reports how many were dropped.

#### Can I find the most negative coverage of something?

Set `sortBy` to `toneasc` for the most negative first, `tonedesc` for the most
positive. That surfaces the sharpest criticism of a company or policy in one pass.

# Actor input Schema

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

What to search worldwide news for, one per line. Quote a phrase to match it exactly: "supply chain".

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

How far back to search, relative to now: 1h, 24h, 3d, 1w, 1m. Ignored if you set an absolute date range below.

## `startDateTime` (type: `string`):

Absolute start, YYYYMMDD or YYYYMMDDHHMMSS. Must be given together with To. Overrides Look back.

## `endDateTime` (type: `string`):

Absolute end, YYYYMMDD or YYYYMMDDHHMMSS.

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

Restrict to one language, e.g. english, spanish, hebrew, arabic. Leave empty for all 65 GDELT indexes.

## `sourceCountry` (type: `string`):

Restrict to outlets based in one country, e.g. US, GB, IL, IN.

## `sortBy` (type: `string`):

Ordering of the articles returned.

## `maxArticlesPerQuery` (type: `integer`):

GDELT itself caps a single response at 250.

## `proxyConfiguration` (type: `object`):

Proxy settings. Rotation matters: GDELT rate-limits unpredictably and a fresh IP clears it.

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

A hard ceiling on rows for the entire run, across every target. The per-target limits above cap each one separately, so fifty targets at twenty each is still a thousand rows; this caps the total. The run stops cleanly when it is reached and nothing beyond that point is fetched or charged. Leave empty for no ceiling.

## Actor input object example

```json
{
  "queries": [
    "artificial intelligence regulation"
  ],
  "timespan": "24h",
  "sortBy": "datedesc",
  "maxArticlesPerQuery": 100,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Headline, outlet, language, source country and publication time.

# 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"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("glitchbound/gdelt-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 = { "queries": ["artificial intelligence regulation"] }

# Run the Actor and wait for it to finish
run = client.actor("glitchbound/gdelt-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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"
  ]
}' |
apify call glitchbound/gdelt-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=glitchbound/gdelt-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/gVp3JsvaB4h3YOdq7/builds/wIOwjmcfc5Kop58ui/openapi.json
