๐ŸŽ‰ Premium Proxies ยท 3-Day Free TrialClaim Now โ†’
Guides

How to Scrape Google News: RSS, Headlines, and Feeds

Scrape Google News with its free RSS feeds: pull headlines and articles, decode the redirected article links, and geo-target editions with hl, gl, and ceid.

S SparkProxy 2 18 min read
Share
How to Scrape Google News: RSS, Headlines, and Feeds

To scrape Google News you don't fight a rendered single-page app, you read a set of RSS feeds Google publishes for free, then solve the one hard problem those feeds create: every article link is an encrypted redirect that no longer decodes the way the old tutorials show. This guide covers the four feed types (top stories, topic sections, geo sections, and full-text search), the hl, gl, and ceid parameters that pick an edition, how to turn a news.google.com/rss/articles/CBMi... link back into a real publisher URL in 2026, and how proxies keep a high-frequency poller from getting rate-limited or fed the wrong country's edition. Every code sample uses SparkProxy's Scraping API, so geo-targeting and IP rotation are one request parameter instead of an infrastructure project.

Key Takeaways

  • Google News exposes four RSS endpoints (top stories, topic, geo, and search) that return clean XML, so you rarely need a headless browser to collect headlines.
  • The in every RSS item is an encrypted Google redirect, and the base64 trick that decoded it before 2024 is dead. The working method today extracts a signature and timestamp from the article page, then calls Google's batchexecute RPC.
  • Editions are selected by hl, gl, and ceid, but the request IP still matters: EU exits hit a consent wall, and a mismatched IP can skew which stories rank, so pair the params with a matching country_code proxy exit.

What you can pull from Google News

Google News is an aggregator, not a publisher. A feed hands you metadata that points at other people's articles. Here is the field set that comes out of a single RSS item.

FieldRSS elementExample valueNotes
Headline`title``Fed holds rates steady - Reuters`Search and topic feeds append ` - Publisher`
Article link`link``https://news.google.com/rss/articles/CBMiV...`Encrypted redirect, not the real URL
Item id`guid``CBMiV...`Same encoded id, `isPermaLink="false"`
Published`pubDate``Wed, 30 Jul 2026 12:04:00 GMT`RFC 822 timestamp in UTC
Snippet`description`CDATA HTMLSearch feeds pack a list of related links here
Publisher`source``Reuters` with `url="https://www.reuters.com"`Cleanest way to read the outlet name

The important detail is that link never points at the publisher directly. It points at a Google redirect that resolves in the browser. Getting from that redirect to https://www.reuters.com/markets/... is the part most tutorials get wrong, and it has its own section below.

Free trial

Scraping at scale? Skip the blocks.

Fast, unblockable datacentre proxies with unlimited bandwidth.

The four RSS endpoints

Every feed lives under https://news.google.com/rss and takes the same three edition parameters. The path selects the feed type.

Feed typeURL pattern
Top stories`https://news.google.com/rss?hl=en-US&gl=US&ceid=US:en`
Topic section`https://news.google.com/rss/headlines/section/topic/TECHNOLOGY?hl=en-US&gl=US&ceid=US:en`
Geo section`https://news.google.com/rss/headlines/section/geo/Chicago?hl=en-US&gl=US&ceid=US:en`
Full-text search`https://news.google.com/rss/search?q=YOUR+QUERY&hl=en-US&gl=US&ceid=US:en`

The topic path accepts a fixed set of section names: WORLD, NATION, BUSINESS, TECHNOLOGY, ENTERTAINMENT, SPORTS, SCIENCE, and HEALTH. Pass any of those in uppercase. There is also a numeric variant, .../rss/topics/, where the id is the long base64 string you see in a topic page's own URL; that is how you follow a niche topic Google curates but does not expose by name.

The geo path takes a place name (Chicago, London, Mumbai) or a Google location id. Every feed caps at roughly 100 items, and none of them paginate. When 100 headlines is not enough coverage, you narrow the query rather than ask for page two, which is exactly what the search operators in the next section are for.

hl, gl, and ceid: picking an edition

These three parameters decide which country and language edition Google serves. Get one wrong and you get an empty feed or the wrong country's stories.

  • hl is the interface language as a language-region tag: en-US, en-GB, de, fr, pt-BR.
  • gl is the country as an uppercase ISO 3166 code: US, GB, DE, FR, IN.
  • ceid is the edition id in COUNTRY:language form: US:en, GB:en, DE:de. It must agree with hl and gl.

The ceid is the one people forget, and it is the one that silently breaks feeds. If gl=DE but ceid=US:en, Google resolves the mismatch in ways that are not documented and often returns thin or empty results. Keep all three consistent.

Editionhlglceid
United States (English)`en-US``US``US:en`
United Kingdom`en-GB``GB``GB:en`
Germany`de``DE``DE:de`
France`fr``FR``FR:fr`
India (English)`en-IN``IN``IN:en`
Japan`ja``JP``JP:ja`

Setting these parameters tells Google which edition you want. It does not fully control which edition you get, because the request IP still weighs in. That gap is why the geo section pairs these params with a proxy exit in the same country.

Set up the SparkProxy Scraping API

You can hit an RSS feed with a plain HTTP client, and for a handful of requests that is fine. The moment you poll many feeds every few minutes, or you start decoding article links at volume, Google starts returning 429s and the occasional consent redirect. Routing through the SparkProxy Scraping API turns IP rotation, geo-targeting, and optional browser rendering into request parameters.

The base URL is https://scrape.sparkproxy.io/api/v1, and it authenticates with an X-API-Key header. RSS is static XML, so turn rendering off with render_js=false to keep each call at the 1-credit tier instead of paying for a browser you don't need.

curl -G "https://scrape.sparkproxy.io/api/v1" \
  --data-urlencode "url=https://news.google.com/rss?hl=en-US&gl=US&ceid=US:en" \
  --data-urlencode "render_js=false" \
  -H "X-API-Key: YOUR_API_KEY"

A thin Python wrapper keeps the rest of the guide readable:

import requests

API = "https://scrape.sparkproxy.io/api/v1"
KEY = "YOUR_API_KEY"

def fetch(url, **params):
    """GET a URL through the SparkProxy Scraping API and return the body."""
    params["url"] = url
    r = requests.get(API, params=params,
                     headers={"X-API-Key": KEY}, timeout=120)
    r.raise_for_status()
    return r.text

Every later snippet calls fetch(...). The parameters that matter for Google News are render_js (leave it false for RSS, true only when you resolve an article link in a browser), premium_proxy=true to route through residential IPs, and country_code to pick the exit country. All three are documented in the Scraping API reference.

Fetch and parse an RSS feed

Grab the top-stories feed and parse it with feedparser, which handles the RSS namespaces and the element for you.

import feedparser

def get_feed(url):
    xml = fetch(url, render_js="false", premium_proxy="true", country_code="US")
    return feedparser.parse(xml)

feed = get_feed("https://news.google.com/rss?hl=en-US&gl=US&ceid=US:en")

for entry in feed.entries[:5]:
    # Search and topic feeds format the title as "Headline - Publisher".
    headline, _, from_title = entry.title.rpartition(" - ")
    publisher = getattr(entry, "source", {}).get("title") or from_title
    print({
        "headline":  headline or entry.title,
        "publisher": publisher,
        "published": entry.get("published"),
        "gnews_link": entry.link,          # still encoded at this stage
        "gnews_id":   entry.id,            # the encoded article id
    })

Two parsing notes save you time. First, read the publisher from entry.source.title when it exists; the - Publisher suffix on the headline is a fallback because some items omit it. Second, do not try to read a clean summary out of entry.summary on search feeds. Google packs an HTML list of related links in there, not a readable snippet, so treat description as structured navigation rather than article text.

Search feeds and query operators

The search feed is where Google News gets useful for monitoring, because the q parameter accepts the same operators as the Google News search box. Recency is the big one: news queries without a time window return stale, high-authority pages instead of what broke this hour.

OperatorExampleEffect
`when:``when:1h`, `when:24h`, `when:7d`Restrict to a recency window
`intitle:``intitle:tesla`Term must appear in the headline
`"..."``"interest rate cut"`Exact phrase match
`OR``tesla OR rivian`Either term
`-``tesla -stock`Exclude a term
`site:``site:reuters.com`Limit to one source domain
`after:` / `before:``after:2026-07-01`Explicit date range (yyyy-mm-dd)

Because the query goes in a URL, encode it. Here is a builder that assembles a search feed and pulls the last hour of headlines for a brand:

from urllib.parse import quote_plus

def search_feed_url(query, hl="en-US", gl="US", ceid="US:en"):
    return (f"https://news.google.com/rss/search?"
            f"q={quote_plus(query)}&hl={hl}&gl={gl}&ceid={ceid}")

url  = search_feed_url('intitle:"rate cut" OR "rate hike" when:1h')
feed = get_feed(url)
print(f"{len(feed.entries)} fresh items")

Two behaviors worth knowing. There is no page two: if when:1h returns 100 items you are already at the cap, so tighten the query or poll more often rather than trying to paginate. And site: filters by the source Google attributes the story to, which is a fast way to watch a single outlet without scraping that outlet directly.

Decode the redirected article URLs

This is the section every other Google News tutorial fumbles. The link and guid in each item look like https://news.google.com/rss/articles/CBMiV..., and they are encrypted redirects, not publisher URLs.

For years the fix was to base64-decode the string after articles/. When it started with CBMi the decoded bytes were a small protobuf that contained the real URL in plain text. That method broke in 2024. Google changed the encoding so the decoded blob no longer carries the destination, and every scraper that relied on the base64 shortcut now returns garbage. If a guide you are reading tells you to base64-decode the id, it is out of date.

There are two working approaches in 2026.

Approach B: the batchexecute RPC (no browser, faster, rate-limited)

If you need to resolve thousands of links and don't want the article body, call Google's internal batchexecute endpoint the way the maintained decoder libraries do. Two moving parts live on the article page: a signature and a timestamp, exposed as data-n-a-sg and data-n-a-ts on a > div, alongside the id in data-n-a-id.

import json
from bs4 import BeautifulSoup

def get_decode_params(encoded_id):
    html = fetch(f"https://news.google.com/rss/articles/{encoded_id}",
                 render_js="false", premium_proxy="true", country_code="US")
    div = BeautifulSoup(html, "html.parser").select_one("c-wiz > div")
    return {"id":  div["data-n-a-id"],
            "sig": div["data-n-a-sg"],
            "ts":  div["data-n-a-ts"]}

def batch_decode(p, proxies=None):
    art = json.dumps([
        "garturlreq",
        [["en-US", "US", ["FINANCE_TOP_INDICES", "WEB_TEST_1_0_0"],
          None, None, 1, 1, "US:en", None, 1, None, None,
          None, None, None, 0, 1],
         p["id"], int(p["ts"]), p["sig"]],
    ], separators=(",", ":"))
    freq = json.dumps([[["Fbv4je", art, None, "generic"]]],
                      separators=(",", ":"))
    r = requests.post(
        "https://news.google.com/_/DotsSplashUi/data/batchexecute",
        data={"f.req": freq},
        headers={"content-type":
                 "application/x-www-form-urlencoded;charset=UTF-8"},
        proxies=proxies,   # rotate residential IPs; this is the 429 hotspot
        timeout=60,
    )
    body = json.loads(r.text.split("\n\n")[1])
    return json.loads(body[0][2])[1]

The Fbv4je RPC id and the garturlreq payload shape are what the open-source googlenewsdecoder (Python) and google-news-url-decoder (Node) packages construct, so track those repos when Google adjusts the envelope. The catch is throughput: that endpoint returns 429 fast when many requests come from one IP, which is precisely why the POST above takes a rotating proxy. For most projects, Approach A is less fragile; reach for B only when link volume makes rendered requests too slow.

Scale without hitting 429

A single feed pull is trivial. A monitoring system polling dozens of queries across several editions every few minutes is a different animal, and it fails in three predictable ways: 429s from over-polling one IP, the consent wall on EU exits, and duplicate stories from wire copy that AP or Reuters syndicate to hundreds of outlets.

Dedupe on the resolved publisher URL, not the Google link, because the same story arrives under different encoded ids across feeds. Normalize the URL (drop tracking query params) before hashing.

import time
from urllib.parse import urlsplit, urlunsplit

seen = set()

def canonical(url):
    parts = urlsplit(url)
    return urlunsplit((parts.scheme, parts.netloc, parts.path, "", ""))

def poll(feed_urls, delay=1.5):
    for url in feed_urls:
        feed = get_feed(url)
        for entry in feed.entries:
            resolved = resolve_via_browser(entry.link)
            if not resolved:
                continue
            key = canonical(resolved)
            if key in seen:
                continue          # wire copy already collected elsewhere
            seen.add(key)
            yield {"url": key, "headline": entry.title,
                   "published": entry.get("published")}
        time.sleep(delay)         # polite pacing between feeds

Three rules keep this alive in production. Poll each query no faster than the news actually moves; when:1h queries every 10 to 15 minutes catch everything without hammering. Let the proxy layer rotate IPs so no single address carries the whole load, and retry a 429 with exponential backoff plus jitter rather than an immediate re-hit. The general pattern for staying under rate limits is worth reading in full: How to Scrape High-Volume Data Without Rate Limiting. If a feed exit gets blocked despite pacing, the checklist in How to Avoid Getting Your Proxy Blocked applies directly.

Frequently asked questions

FAQ

No. Google retired the Google News API years ago, and the current product has no official developer API. The supported public interface is the RSS feed set under news.google.com/rss (top stories, topic, geo, and search), which returns clean XML. Anything beyond those feeds, such as decoding article links or reading article bodies, means scraping.

Because the link in each item is an encrypted Google redirect (news.google.com/rss/articles/CBMi...), not the publisher URL. Google resolves it in the browser to track clicks. To get the real URL you either load the redirect in a headless browser and read the canonical link, or call Google's batchexecute RPC with the signature and timestamp from the article page.

The base64 decode that worked before 2024 no longer returns the destination. The current method fetches the article page, reads data-n-a-sg (signature), data-n-a-ts (timestamp), and data-n-a-id (id) from the c-wiz > div element, then POSTs them to news.google.com/_/DotsSplashUi/data/batchexecute using the Fbv4je RPC. Rendering the link in a browser and reading its canonical URL is the simpler, more durable alternative.

They select the Google News edition. hl sets the interface language (en-US, de), gl sets the country (US, DE), and ceid is the edition id in COUNTRY:language form (US:en, DE:de). All three must agree, or the feed returns thin or empty results. A DE:de edition needs hl=de and gl=DE.

Requests to Google News from an EU IP without a consent cookie redirect to consent.google.com, so your parser receives a cookie page instead of RSS. Fix it by exiting from a non-EU country with country_code=US, or by injecting a Google consent cookie (SOCS or CONSENT) when you specifically need an EU edition from a local IP.

For light, occasional pulls a datacenter IP is usually enough since RSS is a supported feed. At scale it changes: polling many queries and decoding links at volume triggers 429s, and the batchexecute endpoint is especially strict. Rotating residential IPs, targeted by country to match the edition you want, keep both the feeds and the decode step flowing.

Limited-time ยท 50% off

Get 50% off your first purchase

Premium datacentre proxies with unlimited bandwidth. Use the code at checkout.

Offer ends soon โ€” claim it before it's gone

Claim Discount

About the Author

This guide was written by the SparkProxy Technical Team. SparkProxy builds datacenter proxies, residential proxies, and a Scraping API that handles JavaScript rendering, geo-targeting, and IP rotation from a single endpoint. We publish these guides from hands-on work running large collection pipelines against aggregators, search engines, and marketplaces, and every code sample here uses SparkProxy's own documented API. Full parameter reference: SparkProxy Scraping API docs.

Keep reading

Related articles

How to Scrape Craigslist Listings

How to Scrape Craigslist Listings

Learn how to scrape Craigslist listings across city subdomains: search results, categories, and posting details, plus the RSS trick and rate-limit fixes.

SparkProxyยทGuides