Founding customers get 50% off the first year. Claim it →
← all posts

Google News RSS feed: URLs that work, and what they leave out

October 6, 20269 min readFeedmarkdown#google-news#rss

Google News gives you an RSS feed for any search or topic. Below are the URLs that work, then the three places the feed falls short: redirect links, no article body, and duplicate stories.

I tested every URL and script here on 2026-10-08. Google does not document these endpoints as a public API, so re-test before you rely on them.

The Google News RSS URL formats

Type URL pattern Notes
Top stories https://news.google.com/rss?hl=en-US&gl=US&ceid=US:en The front page for that edition.
Search https://news.google.com/rss/search?q=QUERY&hl=en-US&gl=US&ceid=US:en The workhorse. QUERY is URL-encoded.
One site .../rss/search?q=site:reuters.com&... site: works inside q.
Time window .../rss/search?q=openai+when:1d&... when:1h, when:1d, when:7d and so on.
Topic https://news.google.com/rss/topics/TOPIC_ID?hl=en-US&gl=US&ceid=US:en Needs a topic ID, see below.
Section https://news.google.com/rss/headlines/section/topic/TECHNOLOGY?... Redirects to a topic ID URL.

Search feeds

Search feeds are the most useful because you control the query. Spaces become + or %20. Quote phrases with %22. Operators such as site: and when: go inside q.

# "interest rates" from the last 7 days, German edition
curl -s "https://news.google.com/rss/search?q=%22interest+rates%22+when:7d&hl=de&gl=DE&ceid=DE:de"

# Everything from one publisher in the last day
curl -s "https://news.google.com/rss/search?q=site:reuters.com+when:1d&hl=en-US&gl=US&ceid=US:en"

Search feeds returned 100 to 103 items. Top stories returned 38. Narrow queries return fewer: openai+when:1h gave 15. We tested each operator in the feed, with counts, in Google News RSS search operators.

Topic and section feeds

For the standard sections you do not need an ID. /rss/headlines/section/topic/TECHNOLOGY returns a 302 to the matching /rss/topics/<ID> URL, so use curl -L. That feed returned 68 items. For other topics, the ID is the long string in the topic page URL on news.google.com; I first confirmed the /rss/topics/<ID> form only with the ID the redirect returned. We later tested IDs copied from topic pages too, and found that some return a 200 with no items. See Google News topic IDs that still work.

Country and language editions

hl, gl and ceid describe one edition and should agree:

  • hl is the interface language, such as en-US or de.
  • gl is the country, such as US or DE.
  • ceid is country:language, such as US:en or DE:de.

Leave some out and Google answers with a 302 to a URL with all three filled in. hl=de, gl=DE or ceid=DE:de alone each redirected to the German edition. With none, I got en-US, which may depend on where you request from. Plain curl does not follow redirects, so use curl -L.

When they disagree, ceid won: hl=de&gl=US&ceid=US:en returned the US English edition. Set all three and keep them consistent.

What an item actually contains

Here is one <item> from q=openai+when:1d, trimmed. The link and ID are shortened.

<item>
  <title>OpenAI used AI to help write email warning Australian government AI had hacked its websites - The Guardian</title>
  <link>https://news.google.com/rss/articles/CBMi3wFBVV95cUxOUkM3NTBLW...</link>
  <guid isPermaLink="false">CBMi3wFBVV95cUxOUkM3NTBLW...</guid>
  <pubDate>Thu, 08 Oct 2026 13:30:00 GMT</pubDate>
  <description>&lt;a href="https://news.google.com/rss/articles/CBMi3w..."&gt;OpenAI used AI to help write email ...&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;font color="#6f6f6f"&gt;The Guardian&lt;/font&gt;</description>
  <source url="https://www.theguardian.com">The Guardian</source>
</item>

The fields of one Google News RSS item printed from a curl request: title, a news.google.com redirect link, pubDate and source

What you get:

  • A title with the publisher appended after -.
  • A publish date.
  • A source element with the publisher name and its home page.
  • A description that is an HTML fragment. In this item it is the headline link plus the publisher name. For some stories it is an ordered list of related headlines instead: the first item of q=openai on 2026-10-08 came back that way.

What you do not get: the article text, an author, or the publisher's article URL.

The three problems you hit next

The link points at news.google.com/rss/articles/<encoded id>, not at the publisher. I fetched four with curl -L. Each took three hops (one through consent.google.com, from my location) and ended on a news.google.com HTML page with a 200. No hop went to the publisher.

curl -s -L -A "Mozilla/5.0" -o /dev/null \
  -w "code=%{http_code} hops=%{num_redirects} final=%{url_effective}\n" \
  "https://news.google.com/rss/articles/CBMi..."

The IDs do not help either: base64-decoding all four gave opaque bytes, not a URL.

What worked was calling the endpoint the Google News page itself uses. The article page carries two attributes, data-n-a-sg and data-n-a-ts. Send them with the article ID to batchexecute and the response contains the publisher URL. The script at the end of this post does it in about 20 lines of standard-library Python. It resolved every link I tried (4 by hand, 3 more in the pipeline script). It is an undocumented internal call: expect it to break, and rate-limit it, since you call Google once per item.

Dedup, canonical links and scraping all key on the URL, so you need a resolver first.

2. Headline and snippet only

The feed has no body. For an LLM, a search index or a digest, you must fetch each publisher page yourself. News pages are full of JavaScript, navigation, cookie banners and related-article rails, so extracting the article takes a renderer plus a content extractor. Markdown is a good target format for the result.

3. Same story, many outlets

One event produces dozens of items: wire copy on many sites, and rewritten headlines over the same body. Scrape first and dedup later and you pay for every copy. Dedup in layers, cheapest first:

Check Catches Needs the body?
Exact URL or ID repeat The same item seen on the previous poll No
Headline clustering Same story, similar headline No
Content similarity Same text under a rewritten headline Yes

The first two should run before you fetch anything. The third is a clean-up pass after scraping. For counts from real feeds, see why a Google News RSS feed repeats the same story.

Limits and gotchas

  • Item count. Feeds are capped, around 100 for searches. A busy query can push stories out between polls, so poll often enough.
  • Polling hard. I did not stress-test rate limits. Poll modestly and cache.
  • No stability promise. These URLs are not a documented API. Parameters and behaviour can change without notice.
  • Is there a Google News API? I know of no official public one for this. You have three options: these feeds, a third-party SERP or news API, or your own pipeline. I have not compared vendors.

Google Alerts as an RSS source

Google Alerts can also deliver to a feed.

  • Create an alert and set Deliver to to RSS feed. You get a feed URL per alert instead of an email.
  • I did not test Alerts feeds for this post, and options may differ by account.
  • Expect the same limits: redirect-style links and no article body.
  • It suits narrow, low-volume queries, not broad topics.
  • For other tools that can watch a query, see Google Alerts alternatives for news monitoring.

Doing it yourself: minimal pipeline

Pipeline diagram: Google News RSS item, redirect link, publisher URL, full-text Markdown, with headline dedup before scraping and content dedup after

The steps are the same in any language:

  1. Poll the feed.
  2. Resolve each redirect to the publisher URL.
  3. Dedup on metadata.
  4. Scrape the survivors.
  5. Convert to Markdown.
  6. Store, and mark the item as seen.
Step Cost Where it breaks
Poll Free Item cap, rate limits, URL changes
Resolve redirect Cheap, but rate-limited The undocumented call changes
Metadata dedup Free Thresholds: too loose merges different stories
Scrape Paid or heavy JavaScript, paywalls, blocked requests
Markdown conversion Cheap Boilerplate leaking into the text
Store Cheap Retention and replay

Dedup runs before the scrape on purpose. On q=openai+when:1d the feed held 100 items and a token-overlap check at 0.6 left 93. Each dropped item is a scrape you do not pay for. This is the whole of step 3.

import re

def tokens(title):
    title = title.rsplit(" - ", 1)[0].lower()  # drop the " - Publisher" suffix
    return set(re.findall(r"[a-z0-9]+", title))

def similar(a, b, threshold=0.6):
    return len(a & b) / max(1, len(a | b)) >= threshold

kept = []  # (title, tokens)
for title in titles:  # titles from the feed, oldest first
    toks = tokens(title)
    if not any(similar(toks, t) for _, t in kept):
        kept.append((title, toks))

Tune the threshold on your own topics. Too low and you merge different stories. Too high and rewrites slip through to the scraper.

My full pipeline.py adds the resolver, the scrape and the store. It reads a scraper key from WEBCRAWLERAPI_KEY; any service that returns Markdown for a URL works.

export WEBCRAWLERAPI_KEY=...   # your own key
python3 pipeline.py "openai when:1d" 3

That printed 93 unique items, scraping 3 and wrote three Markdown files (19,542, 7,942 and 10,578 characters) from openai.com, mashable.com and theguardian.com. The scraper left some &#x20; entities in the Markdown, so budget a clean-up pass.

The resolver, the part the feed docs do not cover:

import json, re, urllib.parse, urllib.request

UA = "Mozilla/5.0"
COOKIE = "CONSENT=YES+cb; SOCS=CAI"  # skips the EU consent redirect

def resolve(link):
    gid = urllib.parse.urlparse(link).path.rstrip("/").split("/")[-1]
    req = urllib.request.Request(f"https://news.google.com/rss/articles/{gid}",
                                 headers={"User-Agent": UA, "Cookie": COOKIE})
    html = urllib.request.urlopen(req, timeout=20).read().decode()
    sg = re.search(r'data-n-a-sg="([^"]+)"', html).group(1)
    ts = re.search(r'data-n-a-ts="([^"]+)"', html).group(1)
    inner = ('["garturlreq",[["X","X",["X","X"],null,null,1,1,"US:en",null,1,'
             'null,null,null,null,null,0,1],"X","X",1,[1,1,1],1,1,null,0,0,null,0],'
             f'"{gid}",{ts},"{sg}"]')
    body = urllib.parse.urlencode(
        {"f.req": json.dumps([[["Fbv4je", inner, None, "generic"]]])}).encode()
    req = urllib.request.Request(
        "https://news.google.com/_/DotsSplashUi/data/batchexecute", data=body,
        headers={"User-Agent": UA, "Cookie": COOKIE,
                 "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"})
    raw = urllib.request.urlopen(req, timeout=20).read().decode()
    return json.loads(json.loads(raw.split("\n\n", 1)[1])[0][2])[1]

The same pipeline in n8n

I also built it in n8n: an RSS Read node, two Code nodes (headline dedup, then the resolver above), an HTTP Request node that calls the scraper, and a Set node that shapes title, url and markdown. It ran green end to end and returned 3 articles. The dedup node keeps the first 3 headlines per run to keep the test cheap and does not remember earlier runs, so a production version needs somewhere to store seen IDs.

n8n canvas showing six green nodes: Run manually, Poll Google News RSS (100 items), Dedup headlines (3 items), Resolve publisher URL, Scrape to Markdown and Shape article (3 items)

It uses only built-in n8n nodes. To end that pipeline in Slack, see n8n RSS feed to Slack with full article text.

Skip the plumbing

If you are weighing a paid news API instead of the feed, see Is there a Google News API? and Newscatcher vs NewsData.io.

Feedmarkdown runs this pipeline for you. Today it supports Google News and Google Alerts as sources. Direct site sources and plain RSS are on the roadmap, not live. It resolves redirects to publisher URLs, dedups across sources before scraping, and returns each article as full-text Markdown. You receive it by HMAC-signed webhook (X-Feedmarkdown-Signature) or pull it as JSON Feed 1.1 or Atom. Plans start at $19 a month for 10 sources checked every 6 hours; the rest are in the pricing section. To skip the setup, start on the home page.