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

Monitoring competitors with Google News RSS

October 22, 20269 min readFeedmarkdown#competitor-monitoring#google-news#rss#media-monitoring

A Google News RSS query for a company name returns a feed that is mostly not company news, and the mix changes from pull to pull. In one test, the same Snowflake query returned 8 company-news headlines out of 100, then 3 out of 78 two minutes later. For competitor monitoring, the fix is to filter after the fetch, not to find a cleverer operator.

We ran 31 requests on 2026-10-22 for three companies: Snowflake, Databricks and MongoDB. We picked them for the test. They are not each other's stated competitors, and we did not check anyone's own list. Our media monitoring post builds a monitor for one company and cuts one kind of noise, the name clash. This post counts the other kinds. We did not test Google Alerts, any paid tool or Feedmarkdown on these queries.

What we watched and how we counted

The endpoint is the one from our Google News RSS feed guide. Here is the first request:

curl -s -A "Mozilla/5.0" \
  "https://news.google.com/rss/search?hl=en-US&gl=US&ceid=US:en&q=Snowflake+when%3A7d"

We used a Python equivalent. The requests were 5 seconds apart, one attempt each, from a home connection in the Netherlands, US edition, with no cookies. Every response was 200. No rate limit or consent redirect showed up.

We gave every item one label by rule, then read the doubtful ones. That is not a double-blind count, so read every number below as "about".

  • On-topic: the headline names the company and reports its news or a partner or vendor announcement. It does not mean the story matters.
  • First-party: the company's own site is the publisher.
  • Stock/market pages: quote, chart, options, filing, rating and "stocks moving" pages. We define this by page type, not value. Some of these pages carry real company news.
  • Namesake, jobs and social, and other: the name means something else, the item is a job or social post, or the headline is about another party's news.

The same query gave 100 items, then 78

Terminal output for the Snowflake query on 2026-10-22: 100 items from 48 publishers, labelled by category, then a repeat of the same query two minutes later returning 78 items

Feed, when:7d, 2026-10-22 Items Publishers On-topic First-party Stock/market pages Namesake Other
Snowflake 100 48 8 25 40 24 3
Snowflake, about 2 min later 78 39 3 13 41 16 5
Databricks 58 37 29 21 3 0 5
MongoDB 35 25 5 0 28 0 2

The two Snowflake pulls share 52 headlines, but only 1 of the on-topic headlines. Treat every per-query count here as a single pull with a swing of that size. A feed also stops at about 100 items, so 100 means "at least".

Databricks was mostly company news and its own posts. MongoDB was 28 of 35 stock/market pages. That is not a noise score. A competitor watcher may want some of those pages, and we did not judge any item.

The noise comes in more kinds than a name clash

Kind Snowflake pull (100 items) What removes it
Namesake 24 Context words or a rule in code. The pillar covers this.
Stock/market pages 40 A -word list, or a publisher list in code
The company's own posts 25, many in other languages Your code, if you want only third-party news
Other subject 3 (a lease of a former office, a webinar title) Only reading them
Jobs 0 Appear only after -site:, below

The MongoDB feed also had one law-firm notice, and Databricks had one listicle. We count them and leave it there.

What each operator removed

Stacked bars of item categories for seven Snowflake queries on 2026-10-22, showing noise moving between categories

Each change moved the noise instead of removing it. Quoting the legal name returned 60 items, 0 of them on-topic, and 42 were stock/market pages. Adding finance -words removed those pages, and namesakes took their place: 33 of 51. Adding context words with OR removed the namesakes, but 51 of 95 were stock/market pages. The best on-topic share we saw for Snowflake was 9 of 58, against 8 of 100 for the bare name. No query got above about one in six.

Adding the finance -words to the OR query left 60 items: 5 on-topic and 36 in "other", 20 of them from one publisher with generic infrastructure headlines. These are single pulls, so we would not rank the queries.

What -site: did to the feed

-site: is the operator people reach for to drop a publisher. We saw it do something else. Nine of our feeds with -site: returned exactly 100 items, and 53 to 91 of them were jobs or social pages: Facebook, LinkedIn, Instagram, YouTube, job boards and retail pages. It did remove its target: the company's own posts went from 25 to 0.

That could have been an artefact of how we sent it, so we ran six more requests on 2026-10-22 between 20:08 and 20:09 UTC.

# Query Items Publishers Jobs and social
T1 Snowflake -site:snowflake.com when:7d (repeat) 100 48 57
T2 Snowflake -site:example.com when:7d 100 45 51
T3 T1 with : sent unencoded 100 48 57
T4 Snowflake -site:snowflake.com, no when: 100 42 67
T5 Snowflake -intitle:snowflakes when:7d 100 49 0
T6 Databricks -site:example.com when:7d 100 41 74

What the rows show:

  • It repeats. T1 shares 97 of its 100 items with the same query pulled earlier in the run.
  • It is not the encoding. T3 returned the same 100 items as T1.
  • It does not depend on when:. T4 widened too, and returned three items older than seven days.
  • It does not need a real target. example.com appears nowhere in these feeds, and T2 and T6 still came back full of jobs and social pages. The 9 first-party items in T2 were not removed.
  • It is not every negative operator. T5 looked like the plain query, with 95 items in common with it.
  • On Databricks, the plain query had 58 items. T6 had 100, and only 12 of them were in the plain feed.

So any -site: we sent widened the feed. We do not know why, and we only tested these two names. Snowflake's plain feed was already at 100 items, so there the change shows up in what the items are. Don't use -site: to drop a publisher. Do it after the fetch. Our test of the other operators is in Google News RSS search operators.

Two panels comparing the Snowflake feed with and without -site:snowflake.com on 2026-10-22: category counts and the five most frequent publishers for each

Use one feed per company

An OR feed looks like a shortcut for a competitor set. We ran Snowflake OR Databricks OR MongoDB. It returned 100 items, and the headlines named Snowflake 60 times, Databricks 34 and MongoDB 7. MongoDB alone returned 35 items in the same window. The cap hides the quieter names.

A list of event words (acquires, raises, launches, partnership) gave Databricks 24 items, 13 on-topic. The plain feed had 29 of 58. These are different sets and too small to compare as percentages. Snowflake Databricks returned 18 items, 2 of them on-topic, so a head-to-head feed is thin.

One story under ten headlines

The plain Databricks pull had one story, a New York office expansion, in 10 headlines from 10 publishers, one of them Databricks itself. We ran the stage-1 headline check from our dedup post on the feed. It flagged 2 duplicates in 58 items, and they were other stories. Headline matching only catches near-identical wording, and a press release carried by many outlets still counts as many items. If you run several queries per company, dedupe by guid first.

A filter that works after the fetch

We moved the rules into code and ran them on the saved feeds. Save a feed with the curl above, then run the script with the company name. The third argument is an optional context regex for ambiguous names. The deny-list is ours and needs upkeep.

import re, sys
import xml.etree.ElementTree as ET

# usage: python3 filter.py feed.xml Snowflake '\b(data|cloud|AI)\b'   (third argument optional)
# Rules are ours and need upkeep. Publishers are matched as substrings.
DENY_SOURCES = re.compile(
    r"Facebook|Instagram|YouTube|Reddit|LinkedIn|Pinterest|Dice|Indeed|Glassdoor|"
    r"TradingView|MarketBeat|Seeking Alpha|Investing\.com|Yahoo.?Finance|Moomoo|Zacks|"
    r"Benzinga|TipRanks|Barchart|Trefis|GuruFocus|TradingKey|Quiver|Binance|CoinMarketCap|"
    r"CoinGecko|Insider Monkey|Simply Wall|Stock Titan|Kalkine|Traders Union|TIKR|"
    r"marketscreener|24/7 Wall|Motley Fool|NewsBreak", re.I)
MARKET_TITLE = re.compile(
    r"\b(stocks?|shares|options chain|price target|bStocks|Form 4|Form 144)\b|\((SNOW|MDB)\)", re.I)

def tokens(title):
    return set(re.findall(r"[a-z0-9]+", title.lower()))

def jaccard(a, b):
    return len(a & b) / len(a | b) if a | b else 0.0

def main(path, company, context=None):
    items = []
    for it in ET.parse(path).iter("item"):
        src = it.find("source")
        items.append({"title": it.findtext("title") or "",
                      "source": src.text if src is not None else "",
                      "guid": it.findtext("guid") or ""})
    kept, seen_guid, seen_tok = [], set(), []
    for it in items:
        t = it["title"]
        if it["source"].lower() == company.lower():
            continue                       # the company's own site
        if DENY_SOURCES.search(it["source"]) or MARKET_TITLE.search(t):
            continue                       # social, job and market pages
        if company.lower() not in t.lower():
            continue                       # the headline must name the company
        if context and not re.search(context, t, re.I):
            continue                       # ambiguous name: need a context word
        if it["guid"] in seen_guid:
            continue
        tok = tokens(t)
        if any(jaccard(tok, s) >= 0.6 for s in seen_tok):
            continue                       # near-identical headline already kept
        seen_guid.add(it["guid"]); seen_tok.append(tok); kept.append(it)
    print(f"{len(items)} items in, {len(kept)} kept")
    for it in kept:
        print("-", it["title"])

if __name__ == "__main__":
    main(*sys.argv[1:4])
python3 filter.py feed.xml Snowflake '\b(data|cloud|AI|Cortex|database)\b'
python3 filter.py feed.xml Databricks
Saved feed (2026-10-22) Items in Kept On-topic kept On-topic dropped
Snowflake, context regex 100 8 5 3 of 8
Snowflake, context regex, 2 min later 78 5 3 0 of 3
Snowflake, no context regex 100 34 7 1 of 8
Databricks 58 31 28 1 of 29
MongoDB 35 3 3 2 of 5

It keeps most of the on-topic items, and the drops are the price. Without the context regex, 21 namesakes got through. For MongoDB it dropped two on-topic items. One came from a publisher on the deny-list and one matched a market word in its headline, and a rule list tuned on one name will need retuning for the next.

What we did not test

Where Feedmarkdown fits

A Feedmarkdown Google News source takes a query string and passes it to Google. We have not run these queries through it, so we promise nothing about what comes back, and it does not filter job posts, market pages or namesakes. It does fetch and resolve publisher URLs, drop duplicates across sources before scraping, and return full-text Markdown by HMAC-signed webhook or as a JSON Feed 1.1 or Atom pull. Starter is $19 a month for 10 sources checked every 6 hours, Pro is $49 for 50 sources checked hourly, and Agency is $149 for 200 sources checked every 15 minutes. See the home page and the pricing section.