Narrative Intelligence
Neuvia is a narrative intelligence API with two main features:
- An entity-concept time series. For a person, company or place, and a specific storyline around it, you get a daily series of how each news channel portrays it. We track three channels: Google News headlines, Finnhub financial news and local news.
- A balanced reference. For the same pairs, we build Balanced Discoverable Media Sentiment (BDMS) from the coverage Google News search turns up. Articles are sampled across outlet types and political perspectives, and scores are averaged within each publisher first, so high-volume outlets can't dominate. Each reference comes with a confidence interval.
Each is useful on its own. Side by side, they show where a channel runs warmer or cooler than the reference, a gap we call Channel Narrative Divergence (CND).
We've been collecting since March 2026: about 550,000 articles so far, roughly 3,000 a day, yielding about 2 million entity-concept scores.
This post explains both features and how they combine, then walks through two examples of the analysis they make possible.
Feature 1: the entity-concept time series
The first feature is a daily record of how each channel portrays an entity on a specific concept. It rests on three terms:
- Entity: a person, company, place or institution, such as "palantir" or "donald trump".
- Concept: the specific development being discussed about that entity, such as "revenue growth" or "sanctions waiver". Concepts are deliberately narrow: we track "palantir + revenue growth", not "palantir + finance".
- Channel: a path by which news reaches readers. We currently ingest three:
- Google News headlines: stories featured in Google News's headline sections
- Finnhub: financial news for the companies we track
- Local news: RSS feeds from local newspapers, TV and radio stations across the US
For each entity in an article we ingest, an LLM identifies up to five specific concepts the article connects it to. It scores each entity-concept pair from −1 (very negative) to +1 (very positive).
The score describes how the article portrays the entity with respect to that concept, not the article's overall tone. A bearish stock call can still score positively on "revenue growth" if it describes the growth favorably.
Each day, a channel's value for a pair is the plain average of that day's article scores, which is what a reader of that channel saw, along with the number of mentions. Strung together, those days show how a storyline's coverage develops in each channel.
Feature 2: the balanced reference (BDMS)
The second feature is a standardized reference for the same pairs: Balanced Discoverable Media Sentiment (BDMS). It's built from discoverable news coverage by averaging scores within publishers, then across publishers within each outlet type, and finally equally across the types represented.
To compute it:
- Search Google News (US English edition) for the entity and concept, asking for articles from the past seven days. Keep up to 60 results, excluding social platforms.
- Classify each publisher by outlet type: wire, broadcast, print, independent or local.
- Take up to four articles per outlet type. When a type has more candidates than that, alternate between left-, center- and right-leaning publishers.
- Fetch each article's full text where possible. If it's paywalled or blocked, use the Google News snippet instead. An LLM scores how the article portrays the entity with respect to the concept, on the same −1 to +1 scale.
- Average the scores within each publisher, then across publishers within each outlet type, then equally across the outlet types present.
So a reference uses at most 20 articles. If we find fewer than five, we don't compute one.
Step 4 scores every article the search returns, including ones that mention the concept only in passing. That's deliberate: a passing mention still expresses a view, and counting it gives a denser reference.
The averaging in step 5 does two things. A publisher that runs several stories on a topic counts once. And a heavily covered outlet type can't drown out a thinly covered one.
For the confidence interval, we resample publishers with replacement within each outlet type and recompute the estimate, 1,000 times. The interval runs from the 2.5th to the 97.5th percentile. We resample publishers rather than articles because articles from the same publisher share an editorial line, so they aren't independent observations.
Every computation is stored with its timestamp, so each pair builds up a reference history. So far there are about 15,000 references across roughly 10,800 pairs. Scheduled jobs recompute references for pairs that are getting fresh coverage in our channels, most-covered first. Otherwise, the latest reference carries forward.
BDMS is not consensus, and it isn't ground truth. It's a transparent, repeatable reference built from the coverage anyone can find.
Combining the two: Channel Narrative Divergence (CND)
Put the time series next to the reference and you get the divergence. For a channel c:
CND_c = S_c − BDMS
S_c is the channel's value from the time series on a given day, and BDMS is the reference in effect that day.
Each day is compared with the most recent reference computed before that day. If none exists yet, it uses the earliest reference. The API reports which reference it used.
A positive CND means the channel portrays the entity more favorably on that concept than the reference does. A negative CND means less favorably. Why the gap exists is a separate question.
The two examples below show two ways to work on that question:
- Following a divergence over time.
- Tracing a divergence back to the outlets and stories behind it.
They're illustrations of the method, not definitive findings. Both use our production data as of November 3, 2026.
Example 1: Palantir's revenue growth, followed over time
From July 6 to September 20, our Finnhub channel picked up 43 articles about Palantir's revenue growth, mostly from Yahoo Finance and Seeking Alpha. They averaged +0.93, and 36 of them scored the maximum +1.0.
That includes bearish pieces like "Palantir Technologies Likely To Plunge After Its Historic Run Higher". The score is about how an article portrays the growth, not the stock.
The channel barely moved, but the reference moved a lot. Selected days:
| Day | Finnhub channel (articles) | Reference in effect (computed) | CND |
|---|---|---|---|
| Jul 31 | +1.00 (4) | +0.44 (Jul 26) | +0.56 |
| Aug 3 | +1.00 (4) | +0.17 (Aug 2) | +0.83 |
| Aug 4 | +1.00 (1) | +0.06 (Aug 3) | +0.94 |
| Aug 7 | +1.00 (1) | +0.67 (Aug 6) | +0.33 |
| Aug 9 | +1.00 (1) | +0.94 (Aug 8) | +0.06 |
| Aug 10 | +0.50 (1) | +0.94 (Aug 8) | −0.44 |
| Aug 14 | +0.85 (2) | +0.67 (Aug 10) | +0.18 |
| Aug 21 | +1.00 (2) | +0.17 (Aug 19) | +0.83 |
| Aug 28 – Sep 5 | +1.00 (4) | +0.38 (Aug 24) | +0.63 |
| Sep 9 – 20 | +1.00 (3) | −0.13 (Sep 7) | +1.13 |
| Oct 17 – 19 | +0.80 (2) | −0.13 (Sep 7) | +0.93 |
| Oct 30 – Nov 2 | +1.00 (2) | −0.13 (Sep 7) | +1.13 |
Values are rounded to two decimals; CND is computed before rounding.
The reference moved with the news cycle and with which outlets were covering the story:
- Before earnings (July 8 to August 3): every reference came from print and independent outlets only. Each had 5 to 8 articles, and the value sat between +0.06 and +0.44.
- Earnings week (August 4 to 10): Palantir reported Q2 results on August 3.
- Wire services and broadcasters joined the coverage, mostly scoring the growth at +1.0. Print outlets turned more positive too.
- The reference grew to 11 or 12 articles across four outlet types and peaked at +0.94 on August 8.
- Because each outlet type counts equally, the three or four wire and broadcast articles carried half its weight.
- For a few days the channel and the reference agreed: CND was +0.06 on August 9.
- After earnings (from August 19): wire and broadcast coverage dropped out of the search results, and the reference fell back to print and independent outlets. The September 7 reference came in at −0.13, and CND reached +1.13.
The September 7 reference drew on 7 articles from five publishers: The Globe and Mail, Trefis and TradingKey (print), and Yahoo Finance and Seeking Alpha (independent).
The articles closest to its value were valuation and forecast pieces, such as "Where Will Palantir Stock Be in 1 Year?" and "Is Palantir's AI Growth Worth the Premium Valuation of its Stock?". They discussed the growth alongside the stock's valuation and scored neutral on it.
One reading: after earnings week, the wider conversation about Palantir's growth turned into a debate about valuation, while the financial channel kept running upbeat growth stories.
Q3 so far. Palantir reported third-quarter results after the close on November 2, with revenue up 96% year over year according to its press release. Our Finnhub channel scored the growth coverage at +1.0, including Yahoo's "Palantir's U.S. Revenue Soars 119% as Commercial Revenue Surpasses Government Revenue for the First Time". The next morning, CNBC reported Palantir shares sliding in premarket trading.
There's no fresh reference to compare against yet. Our refresh jobs prioritize the most-covered pairs, and this one hasn't come up since September 7, so the API still measures this week's coverage against −0.13. In Q2, a reference computed during earnings week closed most of the gap.
An aside on price. We also snapshot Palantir's share price, and over this period it moved more like the reference than like the channel. The reference computed hours before the Q2 report stood at +0.06; by August 8 it was +0.94. Over the same week the shares rose 37%, from $125.65 at the August 3 close to $172.01 on August 7. The Finnhub channel stayed at or near +1.0 throughout.
The match isn't consistent. Between August 10 and 19 the reference fell from +0.67 to +0.17 while the shares held around $175. They peaked near $187 on August 28 and had slipped about 7% by September 7, when the reference came in at −0.13. After the Q3 report, the channel scored +1.0 again while the shares slid.
Two earnings cycles can't establish a pattern, and coverage reacts to price moves too, so this may be coincidence. But it's the kind of question you can ask once you have both the time series and the reference.
Example 2: Trump's Russia sanctions waiver, traced to its sources
The Washington Post reported on October 17 that Donald Trump had signed an executive order waiving sanctions against Russia.
The reference for "donald trump + sanctions waiver" was computed on October 20 from a search covering the previous seven days. It's the earliest reference for this pair, so the API uses it for October 18 and 19 even though it was computed afterwards. Its seven-day window includes both days.
It came in at −0.07, with a 95% interval of −0.24 to +0.10. It drew on 17 articles from 12 publishers:
| Outlet type | Publishers | Articles | Article average |
|---|---|---|---|
| Wire | Reuters, Associated Press | 4 | 0.00 |
| Broadcast | CNN, NBC News, CNBC | 4 | −0.13 |
| The Guardian, Newsweek, Radio Free Europe/Radio Liberty, LiveNOW from FOX | 4 | −0.50 | |
| Independent | The Hill, Axios | 4 | −0.20 |
| Local | ABC7 Los Angeles | 1 | +0.50 |
The reference averages each publisher's articles before averaging within a type, so it doesn't exactly equal the mean of the last column. LiveNOW from FOX was classified as print when this reference was computed; we've since reclassified it as broadcast.
A second reference, computed on November 1, came in at −0.10 from 11 articles. By then the coverage had moved on to Russian diesel exports and possible sanctions relief for Russia's sovereign wealth fund, and no wire or local outlets turned up.
The five articles closest to the October 20 reference value were:
- Two Reuters oil-market stories, scored 0
- The Hill's "Wright defends waiving sanctions: 'It's not an economic lifeline for Russia'", scored 0
- AP's "Trump's decision to waive Russian sanctions outrages Congress, but no quick counter seen", scored −0.5
- CNN's "Trump waives Russia-related sanctions before they kick in, prompting backlash from Ukraine and US lawmakers", scored −0.5
On October 18 and 19, our local channel picked up five articles on this pair from three outlets. They averaged −0.76, well outside the reference's interval:
| Day | Outlet | Score | Headline |
|---|---|---|---|
| Oct 18 | Philadelphia Inquirer (PA) | −0.5 | St Petersburg oil facilities ablaze as Ukraine launches more than 1,000 drones at Russia |
| Oct 18 | WBAL Radio Baltimore (MD) | −0.8 | Jeffries likes Democrats' chances in race for the House as he campaigns in Ohio |
| Oct 19 | Seattle Times (WA) | −1.0 | Asian shares are mixed with tech stocks volatile, and oil falls on Trump's Russian sanctions waiver |
| Oct 19 | WBAL Radio Baltimore (MD) | −0.5 | Asian shares are mixed with tech stocks volatile, and oil falls on Trump's Russian sanctions waiver |
| Oct 19 | Seattle Times (WA) | −1.0 | U.S. ties with Ukraine hit new low as Trump slights Zelenskyy, eases up on Russia |
Pooled over the two days, the local channel's CND was −0.69: −0.58 on October 18 and −0.76 on October 19.
Which outlets drove it. The Seattle Times contributed two of the five articles, both scored −1.0: the markets story and the story on US–Ukraine ties. Without the Seattle Times, the local average would be −0.60.
WBAL's story on House Democratic leader Hakeem Jeffries isn't mainly about the waiver, but it took a view on it (−0.8). Without that story, the average would be −0.75.
Why local outlets carry a Russia sanctions story. All five articles appear to be Associated Press stories republished by the local sites; the Inquirer's sits in its /wires/ap/ section. Syndicated copy still reflects an editorial choice. Each outlet decides which wire stories to carry and whether they appear in its main feed, and that choice is what the local channel measures.
The three outlets chose differently:
- The Seattle Times ran the markets story and the US–Ukraine story.
- WBAL ran the same markets story and the Jeffries piece.
- The Inquirer ran a story on Ukraine's drone strikes.
How the other channel compares. On the same two days, our Google News channel had six articles on this pair: Al Jazeera, NBC News, CBS News (two), the Wall Street Journal and Yahoo Finance. They averaged −0.50, a CND of −0.43. Both channels sat well below the reference, and local news sat further below it.
What the gap shows.
- The channels led with the fallout. Near the reference's center sat two Reuters oil-market stories and The Hill's "Wright defends waiving sanctions", all scored 0, plus AP and CNN reports on the backlash at −0.5. In the channels, three of the four −1.0 scores went to the diplomatic fallout: Zelenskyy's warning that siding with Putin would be a "historic mistake", the slump in US–Ukraine ties, and the bipartisan backlash. Readers of these channels saw the waiver mainly through its fallout with Ukraine and in Congress; the wider coverage gave more room to oil markets and the administration's case.
- The channels caught the reaction phase. The reference's seven-day window reaches back before the October 17 decision, into anticipation coverage such as Reuters' "Oil eases as markets assess potential waiver on Russian energy, Middle East supply risks". By October 18 and 19, both channels were carrying reaction pieces. Part of the gap is the story moving from anticipation to backlash, which a week-long reference blends together.
- Market coverage explains the gap between the channels. Google News mixed in two market pieces scored 0: the Wall Street Journal on oil prices and Yahoo Finance's "Morning Bid: Wavering waiver?". Without them, Google News would average −0.75, level with local news at −0.76.
That's what the method is for: it shows which publishers formed the reference, and which outlets, stories and angles moved each channel.
What BDMS is not, and other limitations
- Discoverable, not complete. BDMS reflects what Google News returns for a keyword search in its US English edition. That isn't all coverage. It inherits Google's ranking, and Google's date filter sometimes lets older articles through.
- Classification comes from our own source table. Publishers we haven't classified default to print, and publishers without a lean rating count as center. We fix entries as we find them.
- References can go stale. Sometimes there's no fresh reference when there is no new coverage. The last one then carries forward, sometimes for weeks, as with Palantir. The API tells you when the reference you're comparing against was computed.
Using it
Both features come from one call. For any entity-concept pair, GET /api/v1/narratives returns the daily series with the reference alongside. Each day includes:
- the channel's score and mention count (the time series)
- the BDMS reference in effect, with its confidence interval, sample size and the date it was computed (the reference)
- the CND between them
You can filter to one channel (google-news, financial or local) or combine them. Here's what a free key returned for Palantir's revenue growth on November 3. Free keys cover the last seven days:
GET https://neuvianews.com/api/v1/narratives?entity=palantir&concept=revenue+growth&channel=financial
{
"entity": "palantir",
"concept": "revenue growth",
"channel": "financial",
"series": [
{
"mentions": 1,
"date": "2026-10-30",
"sentiment": 1,
"bdms": -0.125,
"bdmsCiLow": -0.25,
"bdmsCiHigh": 0,
"bdmsSampleSize": 7,
"bdmsComputedAt": "2026-09-07",
"cnd": 1.125
},
{
"mentions": 1,
"date": "2026-11-02",
"sentiment": 1,
"bdms": -0.125,
"bdmsCiLow": -0.25,
"bdmsCiHigh": 0,
"bdmsSampleSize": 7,
"bdmsComputedAt": "2026-09-07",
"cnd": 1.125
}
]
}
A free key gets 1,000 calls a month. Starter ($49/month) extends history to 90 days, and Professional ($199/month) covers everything since March 2026. Other endpoints cover search, trending pairs, the articles behind a pair, the most-covered stocks, state-level local news and analysis of your own article text, some of them on paid plans. The docs list them all, and the Explorer lets you browse any tracked entity's concepts without a key.
Stack: Next.js API routes, MongoDB, and OpenAI's gpt-4o-mini for extraction and scoring.
Feedback I'm looking for
- Which channels would you want compared next?
- What would you use this for, and what's missing from the API to do it?
Neuvia: neuvianews.com