install.packages(c("tidyverse", "tidytext", "textdata", "lubridate", "knitr", "kableExtra", "httr", "jsonlite"))
## Installing packages into '/cloud/lib/x86_64-pc-linux-gnu-library/4.6'
## (as 'lib' is unspecified)
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.2.1     ✔ readr     2.2.0
## ✔ forcats   1.0.1     ✔ stringr   1.6.0
## ✔ ggplot2   4.0.3     ✔ tibble    3.3.1
## ✔ lubridate 1.9.5     ✔ tidyr     1.3.2
## ✔ purrr     1.2.2     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(tidytext)
library(textdata)
library(lubridate)
library(knitr)
library(kableExtra)
## 
## Attaching package: 'kableExtra'
## 
## The following object is masked from 'package:dplyr':
## 
##     group_rows
library(httr)
## 
## Attaching package: 'httr'
## 
## The following object is masked from 'package:textdata':
## 
##     cache_info
library(jsonlite)
## 
## Attaching package: 'jsonlite'
## 
## The following object is masked from 'package:purrr':
## 
##     flatten
api_key <- "83bf3c013b054d6db1c87a8e1c103f31"

response <- GET(
  url = "https://newsapi.org/v2/everything",
  query = list(q = "CoreWeave", language = "en", sortBy = "publishedAt",
               pageSize = 30, apiKey = api_key)
)
parsed <- content(response, as = "text", encoding = "UTF-8")
news_raw <- as_tibble(fromJSON(parsed, flatten = TRUE)$articles)
news_clean <- news_raw %>%
  filter(!is.na(title)) %>%
  mutate(
    title_clean = str_remove(title, "\\s*-\\s*[^-]+$"),
    title_clean = str_squish(str_replace_all(title_clean, "[^[:alnum:][:space:]]", " ")),
    title_clean = str_to_lower(title_clean)
  ) %>%
  distinct(title_clean, .keep_all = TRUE)

write.csv(news_clean, "coreweave_news_raw.csv", row.names = FALSE)
news_clean %>% select(title, publishedAt) %>% head(10) %>%
  kable(caption = "CoreWeave Headlines") %>%
  kable_styling(bootstrap_options = "striped", full_width = FALSE)
CoreWeave Headlines
title publishedAt
Inference chip startup Groq raises $650M to grow its cloud platform 2026-06-22T20:06:25Z
CoreWeave Insiders Have Sold $2.3 Billion. The Stock Is Dropping Again 2026-06-22T19:07:59Z
Micron, Anthropic sign AI infrastructure supply agreement 2026-06-22T18:38:55Z
CoreWeave Sinks 5%, Nebius Dips as AI Cloud Stocks Sell the News on Their NASDAQ 100 Debut 2026-06-22T18:34:39Z
NASDAQ adds CoreWeave to the NASDAQ 100. In case you’re playing at home, this company is a money laundering facility for Nvidia [Scary] 2026-06-22T14:15:00Z
Google is spending billions to turn its TPU chips into a real challenger to Nvidia 2026-06-22T11:15:00Z
The AI Arms Race Isn’t About Technology – It’s About Electricity 2026-06-22T00:00:00Z
CoreWeave is Joining the Nasdaq-100. Is the Stock a Buy? 2026-06-21T23:02:13Z
Jane Street’s private company portfolio reaches $20B as trading firm outearns major banks 2026-06-21T16:24:57Z
How OpenAI and Anthropic IPOs could affect your retirement savings 2026-06-21T11:34:50Z
tokens <- news_clean %>%
  select(title) %>%
  unnest_tokens(word, title) %>%
  anti_join(stop_words, by = "word")

sentiment_counts <- tokens %>%
  inner_join(get_sentiments("bing"), by = "word") %>%
  count(sentiment)

sentiment_counts %>%
  kable(caption = "Sentiment Word Counts") %>%
  kable_styling(bootstrap_options = "striped", full_width = FALSE)
Sentiment Word Counts
sentiment n
negative 9
positive 3
ggplot(sentiment_counts, aes(x = sentiment, y = n, fill = sentiment)) +
  geom_col() +
  scale_fill_manual(values = c("positive" = "#2ecc71", "negative" = "#e74c3c")) +
  labs(title = "CoreWeave News Sentiment", x = "", y = "Word Count") +
  theme_minimal()

Summary

Of the CoreWeave headlines pulled from NewsAPI, 3 words matched a positive sentiment and 9 words matched a negative sentiment this is a notably negative skew. I believe this likely reflects recent coverage of CoreWeave’s debt levels and insider selling outweighing positive stories like its Nasdaq-100 inclusion in the headlines pulled.