Google News API: Search News Articles as JSON
To search Google News as JSON, send a GET request to /v1/google-news/news with a search term in q. Each result comes back with a title, link, snippet, source name and an ISO 8601 publish date. A successful call costs 1 credit, a failed one costs nothing, and the free tier covers 1,000 calls a month.
Is there an official Google News API?
Google's News help pages are written for publishers, and we found no keyword search API among them. What Google documents is a publisher-side tool: Publisher Center, where news publishers manage how their own content appears. That's the opposite direction from what a developer wants, which is a query in and articles out.
Publisher Center feeds don't fill the gap either. In an announcement dated March 2025, Google said it was moving to automatically generated publication pages and that "Google News will no longer use RSS feeds or web locations that were submitted in Publisher Center" (Google News Publisher Center announcement, 2025). Those feeds were about publishers submitting content, never about searching it. Nothing in that announcement describes a search feed you could build on.
So the practical options are scraping the results page yourself, paying each publisher's own API, or calling an endpoint that already returns the results as JSON. If you only need one publisher's articles, that publisher's own feed or API is simpler and you should use it. If you need a cross-publisher search, the Google News API here gives you one request and a stable shape. For the maintenance side of the scraping option, see what maintaining a scraper really involves.
How do you search Google News with one request?
Send a GET request to https://api.perceptlayer.com/v1/google-news/news with your key in the X-API-Key header and a query in q. The response is JSON with a news_results array, each item numbered by position. The whole call is one HTTP request and costs 1 credit when it succeeds.
curl "https://api.perceptlayer.com/v1/google-news/news?q=technology" \
-H "X-API-Key: $API_KEY"
Replace $API_KEY with a key from a free sign-up. Where headers aren't possible, the key also works as the api_key query parameter. The authentication docs cover both, and the Requests section explains the general call format.
You can also run the same call without writing code. The News endpoint page links to the playground, where you pick the endpoint, fill in the parameters and run it with your key.
What does the response look like?
Each item in news_results describes one article. Below is an excerpt from a recorded response to the request above, trimmed with …: position 1 is omitted, and the thumbnail fields, the source icon and the publication link are cut. It shows the fields you'll use most: the headline, the link, the publish time in three forms, and the source.
{
"news_results": [
…
{
"position": 2,
"title": "How did AI discover the internet's massive cyber-security risk?",
"link": "https://www.bbc.com/news/videos/cq0ld7e0jg2eo",
"type": "article",
"snippet": "The BBC's technology correspondent Joe Tidy explains how it happened, and what it means for you.",
"iso_date": "2026-10-22T12:17:44+00:00",
"published_at": "2026-10-22 12:17:44 UTC",
"date": "today",
…
"source": {
"name": "BBC",
…
"title": "BBC"
},
"story_token": "CBMiWEFVX3lxTFBkQ0VLSmdYNkk0TzVBZGtlU3piaFlGejFNemlncTZRTWR2MjFlNDhpWWNiVnJMYk5PRUo3eHJ2YlppUmtoLW5FbERMTFNBZ2xkMVhzNmpFWXU",
"related_publications": [
{
"title": "BBC",
…
"publication_token": "CAAqIAgKIhpDQklTRFFnTWFna0tCMkppWXk1amIyMG9BQVAB"
}
]
},
…
],
"menu_links": [
…
]
}
The table below lists what each field is for. These are the fields shown in the excerpt; the full items also carry thumbnail URLs, a source icon and a publication link.
| Field | What it holds | Use it for |
|---|---|---|
position |
Number of the result in the response | Preserving the order you received |
title, snippet |
Headline and a short text excerpt | Display, keyword filters |
link |
URL of the article on the publisher's site | Deduplication, fetching the full text |
iso_date |
Publish time in ISO 8601 with offset | Sorting and date windows |
published_at |
The same time as 2026-10-22 12:17:44 UTC |
Human-readable logs |
date |
Relative label such as today or 2 days ago |
Display only; don't parse it |
source.name |
The publisher's name | Grouping by outlet |
story_token |
Token for the story | The story_token parameter |
related_publications[].publication_token |
Token for the publisher | The publication_token parameter |
Store iso_date, not date. The relative label changes depending on when you call, while iso_date is the same tomorrow as today.
Which parameters does the News endpoint take?
The endpoint has no required parameters and eleven optional ones. q is the free-text search, up to 500 characters. The four *_token parameters and kgmid are strings; token values appear in responses, and the playground shows what each one does.
| Parameter | Type | Notes |
|---|---|---|
q |
string | Search query, up to 500 characters |
gl |
string | Up to 2 characters |
hl |
string | Up to 2 characters |
topic_token |
string | Up to 200 characters |
kgmid |
string | Up to 100 characters |
publication_token |
string | Up to 200 characters; matches related_publications[].publication_token in a response |
section_token |
string | Up to 200 characters |
story_token |
string | Up to 2,000 characters; matches story_token on a result |
so |
integer | One of 0, 1 |
start |
integer | Optional |
page |
integer | Optional |
gl and hl are two-character values, which is the shape of country and language codes. The endpoint documentation doesn't spell out defaults, page sizes or what each value of so does, so test them in the playground before you build on them. Our guide to paginating a web data API in Python covers the loop pattern for start and page style parameters.
How do you use the tokens in a response?
Responses include story_token and related_publications[].publication_token, and the endpoint accepts parameters of the same names. Copy a token from a result into the matching parameter in the playground to try it; we haven't recorded those calls, so we don't describe what they return. A successful call costs 1 credit like any other.
How much does a daily news monitor cost?
A news monitor costs 1 credit per query per run. Multiply queries by runs per day by days: 20 queries checked twice a day for 30 days is 20 × 2 × 30 = 1,200 credits. The Starter pack's 10,000 credits would cover that for more than eight months (10,000 ÷ 1,200 ≈ 8.3), and pricing shows what credits cost.
| Monitor | Calls per month | Credits | Notes |
|---|---|---|---|
| 10 queries, once a day | 10 × 30 = 300 | 300 | Inside the 1,000 free credits |
| 20 queries, twice a day | 20 × 2 × 30 = 1,200 | 1,200 | 1,200 ÷ 10,000 of a Starter pack |
| 100 queries, once a day | 100 × 30 = 3,000 | 3,000 | 3,000 ÷ 10,000 of a Starter pack |
Packs: Starter is 10,000 credits, Build 50,000, Growth 200,000, Pro 500,000, Scale 1,000,000 and Volume 5,000,000. Purchased credits last 12 months, and there's no subscription. See pricing for what each pack costs and its request rate, and the credits docs.
A monitor that asks the same query often can skip repeat calls; caching API responses in Python shows how TTLs save credits.
Failed calls cost nothing. Every successful response carries X-Credits-Used and X-Credits-Remaining, so a monitor can log its own balance. The service is prepaid, so when credits run out calls return insufficient_credits (402) and nothing more is debited.
How do you run it on a schedule?
Run the query list from a cron job or scheduled function, keep the link of every article you've seen and store only new ones. The script below does that with the fields from the recorded response: news_results, title, link, iso_date and source.name.
import os
import requests
API = "https://api.perceptlayer.com/v1/google-news/news"
HEADERS = {"X-API-Key": os.environ["API_KEY"]}
QUERIES = ["technology", "cybersecurity"]
seen = set() # load from your database in a real job
for q in QUERIES:
r = requests.get(API, params={"q": q}, headers=HEADERS, timeout=30)
if r.status_code != 200:
print(q, r.status_code, r.json()["error"]["code"])
continue
for item in r.json()["news_results"]:
if item["link"] in seen:
continue
seen.add(item["link"])
print(item["iso_date"], item["source"]["name"], item["title"])
print("credits left:", r.headers["X-Credits-Remaining"])
Two points about errors. A 429 or 503 response carries a Retry-After header with the seconds to wait, and the rate limit docs cover the details. Requests have no idempotency key, so a call that timed out on your side may have succeeded and been billed; the article on retrying without paying twice shows how to handle that. The error reference lists every code.
If an agent rather than a cron job needs the news, the same endpoint is available through the MCP server at https://api.perceptlayer.com/mcp. Its call_endpoint tool takes the endpoint ID and the same parameters; see the MCP docs and giving a Claude agent live search results. The sibling guide for web results is Google Search API: Get Search Results as JSON.
Next step: get a free API key, then run the first cURL call above for q=technology and look at iso_date and source.name in your own response. Data is collected from publicly available sources and returned as found at the time of the call.
APIs in this post
Frequently asked questions
Does Google have an official news search API?
Google's Publisher Center help is aimed at publishers managing their own content, and we found no keyword search API for news results there. In March 2025 Google also said it would stop using feeds submitted in Publisher Center. A JSON endpoint such as /v1/google-news/news fills the gap for developers who need to search across publishers.
How much does one News API call cost?
A successful call to /v1/google-news/news costs 1 credit. The free tier includes 1,000 credits every month after you verify an email address, which covers 1,000 calls, and pricing shows what credits cost beyond that. Failed calls cost nothing and return X-Credits-Used: 0, so errors don't reduce your balance.
How do I get only new articles on each run?
Store the link of every article you've processed and skip items whose link you've seen. Sort by iso_date, which is ISO 8601 with an offset, rather than the relative date label such as 2 days ago. Don't use position for this, because it numbers the results in the response you received, so the link is the safer identity.
Which token parameters does the endpoint accept?
The endpoint accepts publication_token, topic_token, section_token, story_token and kgmid as string parameters. Publisher and story tokens appear in responses as related_publications[].publication_token and story_token. We haven't recorded what each returns, so try them in the playground. q takes free text up to 500 characters.
What happens if a call fails or the balance runs out?
Errors return an HTTP status and a JSON body with error.code, error.message and request_id. Rate-limited (429) and unavailable (503) responses include Retry-After. When credits run out, calls return insufficient_credits (402) and nothing is debited; there's no automatic top-up.