# Package installation reference.
# Run this chunk manually only if one or more packages are missing.
install.packages(c(
"tidyverse",
"gtrendsR",
"lubridate",
"scales",
"knitr",
"kableExtra",
"writexl",
"readxl"
))# Data manipulation and visualization
library(tidyverse)
# Google Trends data collection
library(gtrendsR)
# Date handling
library(lubridate)
# Axis and number formatting
library(scales)
# Report tables
library(knitr)
library(kableExtra)
# Excel export and import
library(writexl)
library(readxl)# -------------------------------------------------------------------------
# Helper function 1: table formatting
# -------------------------------------------------------------------------
# This function creates tables that render cleanly in HTML and remain more
# stable in PDF output. The scale_down option is especially useful for
# preventing wider tables from extending beyond PDF margins.
safe_kable <- function(data, caption = NULL, digits = 3, font_size = 8) {
data %>%
kable(
caption = caption,
booktabs = TRUE,
digits = digits
) %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed"),
latex_options = c("scale_down", "hold_position"),
full_width = FALSE,
font_size = font_size
)
}
# -------------------------------------------------------------------------
# Helper function 2: shorten long text
# -------------------------------------------------------------------------
# This is used when long labels or descriptions could make tables difficult
# to read in the final report.
short_text <- function(x, width = 70) {
stringr::str_trunc(as.character(x), width = width, side = "right")
}
# -------------------------------------------------------------------------
# Helper function 3: clean Google Trends hit values
# -------------------------------------------------------------------------
# Google Trends sometimes reports very small values as "<1". Converting those
# values to 0.5 preserves them as low but nonzero observations.
clean_hits <- function(x) {
x <- as.character(x)
x <- if_else(x == "<1", "0.5", x)
as.numeric(x)
}
# -------------------------------------------------------------------------
# Helper function 4: define a reproducible five-year time window
# -------------------------------------------------------------------------
# gtrendsR accepts explicit date ranges in the structure:
# "YYYY-MM-DD YYYY-MM-DD"
#
# Using an explicit range avoids parsing issues from shortcut formats and
# allows the report to update automatically based on the knit date when live
# refresh is enabled.
trend_start <- Sys.Date() %m-% years(5)
trend_end <- Sys.Date()
trend_time_window <- paste(
format(trend_start, "%Y-%m-%d"),
format(trend_end, "%Y-%m-%d")
)
cat("Google Trends time window:", trend_time_window)## Google Trends time window: 2021-06-23 2026-06-23
# -------------------------------------------------------------------------
# Helper function 5: collect and prepare Google Trends data
# -------------------------------------------------------------------------
# This function wraps the gtrends() call so the MMORPG and MOBA analyses use
# the same collection and cleaning process.
#
# Inputs:
# terms = character vector of game titles/search terms
# genre_label = genre label assigned to the resulting data
#
# Output:
# A cleaned tibble containing date, title, genre, relative search interest,
# and derived time variables.
pull_trends <- function(terms, genre_label) {
trends_raw <- gtrends(
keyword = terms,
geo = "US",
time = trend_time_window,
gprop = "web"
)
trends_clean <- trends_raw$interest_over_time %>%
as_tibble() %>%
mutate(
hits = clean_hits(hits),
date = as.Date(date),
year = year(date),
month = month(date, label = TRUE, abbr = TRUE),
month_num = month(date),
genre = genre_label
) %>%
select(
genre,
keyword,
date,
year,
month,
month_num,
hits,
everything()
)
return(trends_clean)
}
# -------------------------------------------------------------------------
# Helper function 6: standardize cached data
# -------------------------------------------------------------------------
# When the report reads a previously exported Excel file, this function
# restores important data types so later charts and summaries work the same
# way as they do after a fresh Google Trends pull.
standardize_trends <- function(data) {
data %>%
as_tibble() %>%
mutate(
genre = as.character(genre),
keyword = as.character(keyword),
date = as.Date(date),
hits = as.numeric(hits),
year = as.integer(year),
month_num = as.integer(month_num),
month = month(date, label = TRUE, abbr = TRUE)
)
}
# -------------------------------------------------------------------------
# Helper function 7: safe live pull with retries
# -------------------------------------------------------------------------
# Google Trends can temporarily reject or throttle automated requests.
# This function attempts a small number of retries before failing with a clear
# message. The preferred report workflow is still to use the cached Excel file
# after the first successful scrape.
safe_pull_trends <- function(terms, genre_label, tries = 3, wait_seconds = 10) {
for (attempt in seq_len(tries)) {
result <- tryCatch(
{
pull_trends(terms, genre_label)
},
error = function(e) {
message(
"Google Trends pull failed for ",
genre_label,
" on attempt ",
attempt,
" of ",
tries,
". Error: ",
e$message
)
NULL
}
)
if (!is.null(result) && nrow(result) > 0) {
return(result)
}
if (attempt < tries) {
Sys.sleep(wait_seconds)
}
}
stop(
"Google Trends data could not be collected for ",
genre_label,
". If a prior Excel export exists, set refresh_trends_data <- FALSE ",
"and knit again using the cached workbook."
)
}Video games increasingly operate as long-running entertainment ecosystems rather than one-time product releases. Major MMORPGs and MOBAs compete not only through core gameplay, but also through expansions, esports visibility, community momentum, streamer attention, patch cycles, franchise loyalty, and broader online discourse.
This report uses Google Trends data to compare U.S. web search interest for selected MMORPG and MOBA titles over the past five years. Search interest is interpreted as an attention signal: it is not a direct measure of player population, revenue, or product quality, but it can help identify when a title becomes more visible in the broader gaming conversation.
The analysis separates MMORPGs and MOBAs into two genre groups because these genres tend to generate attention through different mechanisms. MMORPGs often spike around expansions, major content updates, relaunches, or franchise announcements. MOBAs may show attention shifts around esports events, balance updates, new playable characters, competitive seasons, or community controversies.
This analysis addresses three guiding questions:
Together, these questions compare both peak visibility and longer-term search-interest patterns within each genre.
The MMORPG comparison includes World of Warcraft, Star Wars: The Old Republic, Final Fantasy XIV, Guild Wars 2, and The Elder Scrolls Online. These titles represent a mix of legacy dominance, licensed universes, subscription-based ecosystems, and long-running live-service fantasy worlds.
The MOBA comparison includes Dota 2, League of Legends, Heroes of the Storm, Smite, and Pokemon Unite. This group captures several versions of the MOBA market: traditional lane-based competitive design, action-oriented third-person combat, Blizzard’s genre entry, and a more contemporary franchise-driven title.
# -------------------------------------------------------------------------
# MMORPG search terms
# -------------------------------------------------------------------------
# Full titles are used where possible to reduce ambiguity in search behavior.
# For example, "Star Wars: The Old Republic" is preferable to "SWTOR" because
# it is more explicit and less dependent on acronym usage.
mmorpg_terms <- c(
"World of Warcraft",
"Star Wars: The Old Republic",
"Final Fantasy XIV",
"Guild Wars 2",
"The Elder Scrolls Online"
)
# -------------------------------------------------------------------------
# MOBA search terms
# -------------------------------------------------------------------------
# Pokemon Unite is included as a contemporary MOBA comparison title.
# The plain ASCII spelling "Pokemon Unite" is used for coding stability.
moba_terms <- c(
"Dota 2",
"League of Legends",
"Heroes of the Storm",
"Smite",
"Pokemon Unite"
)
terms_tbl <- tibble(
Genre = c(rep("MMORPG", length(mmorpg_terms)), rep("MOBA", length(moba_terms))),
Search_Term = c(mmorpg_terms, moba_terms)
)
terms_tbl %>%
safe_kable(caption = "Google Trends Search Terms by Genre")| Genre | Search_Term |
|---|---|
| MMORPG | World of Warcraft |
| MMORPG | Star Wars: The Old Republic |
| MMORPG | Final Fantasy XIV |
| MMORPG | Guild Wars 2 |
| MMORPG | The Elder Scrolls Online |
| MOBA | Dota 2 |
| MOBA | League of Legends |
| MOBA | Heroes of the Storm |
| MOBA | Smite |
| MOBA | Pokemon Unite |
Google Trends data were collected using the gtrendsR
package. The analysis uses U.S. web search interest over a five-year
period ending on the report generation date.
Google Trends reports relative search interest rather than absolute search volume. A score of 100 represents the highest point of relative search interest within the selected query group, geography, and time range. Therefore, the MMORPG and MOBA results should be interpreted primarily within their own genre-specific comparison groups.
This distinction is important because a normalized score does not reveal the exact number of searches. Instead, it shows how search interest changed relative to the strongest observed point in that specific comparison.
For reproducibility, the report uses a local Excel cache after the first successful data collection. This prevents temporary Google Trends access issues from breaking the report during later knitting.
# -------------------------------------------------------------------------
# Data collection and cache control
# -------------------------------------------------------------------------
# Set refresh_trends_data to TRUE only when you want to request new data from
# Google Trends. Keep it FALSE for normal knitting after a successful scrape.
#
# If the Excel workbook exists and refresh_trends_data is FALSE, the report
# reads the cached data instead of sending new requests to Google Trends.
refresh_trends_data <- FALSE
cache_file <- "google_trends_mmorpg_moba_brand_tracker.xlsx"
if (file.exists(cache_file) && refresh_trends_data == FALSE) {
cat("Using cached Google Trends workbook:", cache_file)
all_trends <- read_excel(cache_file, sheet = "all_trends") %>%
standardize_trends()
mmorpg_trends <- read_excel(cache_file, sheet = "mmorpg_trends") %>%
standardize_trends()
moba_trends <- read_excel(cache_file, sheet = "moba_trends") %>%
standardize_trends()
terms_tbl <- read_excel(cache_file, sheet = "search_terms") %>%
as_tibble()
} else {
cat("Collecting fresh Google Trends data.")
mmorpg_trends <- safe_pull_trends(mmorpg_terms, "MMORPG")
moba_trends <- safe_pull_trends(moba_terms, "MOBA")
all_trends <- bind_rows(mmorpg_trends, moba_trends)
}## Using cached Google Trends workbook: google_trends_mmorpg_moba_brand_tracker.xlsx
all_trends %>%
select(genre, keyword, date, hits) %>%
head(12) %>%
safe_kable(caption = "Sample of Collected Google Trends Data")| genre | keyword | date | hits |
|---|---|---|---|
| MMORPG | World of Warcraft | 2021-06-20 | 44 |
| MMORPG | World of Warcraft | 2021-06-27 | 45 |
| MMORPG | World of Warcraft | 2021-07-04 | 45 |
| MMORPG | World of Warcraft | 2021-07-11 | 51 |
| MMORPG | World of Warcraft | 2021-07-18 | 47 |
| MMORPG | World of Warcraft | 2021-07-25 | 54 |
| MMORPG | World of Warcraft | 2021-08-01 | 41 |
| MMORPG | World of Warcraft | 2021-08-08 | 40 |
| MMORPG | World of Warcraft | 2021-08-15 | 36 |
| MMORPG | World of Warcraft | 2021-08-22 | 36 |
| MMORPG | World of Warcraft | 2021-08-29 | 31 |
| MMORPG | World of Warcraft | 2021-09-05 | 30 |
# -------------------------------------------------------------------------
# Export collected data
# -------------------------------------------------------------------------
# The Excel workbook supports reproducibility and external review. It includes
# the combined dataset, genre-specific datasets, and the search-term reference
# table used in the analysis.
write_xlsx(
list(
all_trends = all_trends,
mmorpg_trends = mmorpg_trends,
moba_trends = moba_trends,
search_terms = terms_tbl
),
path = cache_file
)
cat("Excel export complete:", cache_file)## Excel export complete: google_trends_mmorpg_moba_brand_tracker.xlsx
The MMORPG trend line compares relative search interest across five major online role-playing games. Peaks in this genre may reflect expansion launches, major content patches, franchise announcements, community controversy, or renewed interest driven by streaming and social discussion.
Rather than treating every spike as a direct measure of active players, this section interprets search interest as evidence of public attention. A high peak indicates that a title became unusually visible during a specific moment in the five-year window.
# -------------------------------------------------------------------------
# Core trend visualization: MMORPG titles
# -------------------------------------------------------------------------
mmorpg_trends %>%
ggplot(aes(x = date, y = hits, color = keyword)) +
geom_line(linewidth = 0.8) +
labs(
title = "U.S. Google Search Interest for MMORPG Titles",
subtitle = "Five-year Google Trends comparison",
x = NULL,
y = "Relative Search Interest",
color = "Game",
caption = "Source: Google Trends via gtrendsR"
) +
scale_x_date(date_breaks = "6 months", date_labels = "%b %Y") +
scale_y_continuous(limits = c(0, 100)) +
theme_minimal(base_size = 12) +
theme(
legend.position = "bottom",
axis.text.x = element_text(angle = 45, hjust = 1)
)# -------------------------------------------------------------------------
# Highest observed search-interest point for each MMORPG
# -------------------------------------------------------------------------
# If multiple dates tie for the maximum value, with_ties = FALSE returns one
# representative observation to keep the summary table concise.
mmorpg_peaks <- mmorpg_trends %>%
group_by(keyword) %>%
slice_max(order_by = hits, n = 1, with_ties = FALSE) %>%
ungroup() %>%
arrange(desc(hits)) %>%
select(
Game = keyword,
Peak_Date = date,
Peak_Search_Interest = hits
)
mmorpg_peaks %>%
mutate(Peak_Date = format(as.Date(Peak_Date), "%B %d, %Y")) %>%
safe_kable(caption = "Highest Google Trends Peak by MMORPG")| Game | Peak_Date | Peak_Search_Interest |
|---|---|---|
| World of Warcraft | April 17, 2022 | 100 |
| Star Wars: The Old Republic | December 07, 2025 | 69 |
| Guild Wars 2 | June 07, 2026 | 45 |
| Final Fantasy XIV | November 28, 2021 | 31 |
| The Elder Scrolls Online | July 16, 2023 | 6 |
# -------------------------------------------------------------------------
# Peak marker visualization: MMORPG titles
# -------------------------------------------------------------------------
# This chart overlays each game's highest observed point onto the trend line.
# The marked peaks provide a starting point for follow-up interpretation.
mmorpg_trends %>%
ggplot(aes(x = date, y = hits, color = keyword)) +
geom_line(linewidth = 0.7, alpha = 0.85) +
geom_point(
data = mmorpg_peaks %>%
rename(keyword = Game, date = Peak_Date, hits = Peak_Search_Interest),
aes(x = date, y = hits, color = keyword),
size = 3
) +
labs(
title = "MMORPG Search Interest with Peak Moments Highlighted",
subtitle = "Dots indicate each title's highest observed point in the five-year window",
x = NULL,
y = "Relative Search Interest",
color = "Game",
caption = "Source: Google Trends via gtrendsR"
) +
scale_x_date(date_breaks = "6 months", date_labels = "%b %Y") +
scale_y_continuous(limits = c(0, 100)) +
theme_minimal(base_size = 12) +
theme(
legend.position = "bottom",
axis.text.x = element_text(angle = 45, hjust = 1)
)The MOBA trend line compares relative search interest across five competitive multiplayer titles. Search behavior in this genre may be shaped by esports calendars, patch cycles, balance changes, hero or champion releases, competitive seasons, and major community conversations.
Because MOBAs depend heavily on active communities and recurring competitive engagement, volatility can be especially informative. A title with high volatility may be more event-driven, while a title with steadier search interest may have more consistent baseline visibility.
# -------------------------------------------------------------------------
# Core trend visualization: MOBA titles
# -------------------------------------------------------------------------
moba_trends %>%
ggplot(aes(x = date, y = hits, color = keyword)) +
geom_line(linewidth = 0.8) +
labs(
title = "U.S. Google Search Interest for MOBA Titles",
subtitle = "Five-year Google Trends comparison",
x = NULL,
y = "Relative Search Interest",
color = "Game",
caption = "Source: Google Trends via gtrendsR"
) +
scale_x_date(date_breaks = "6 months", date_labels = "%b %Y") +
scale_y_continuous(limits = c(0, 100)) +
theme_minimal(base_size = 12) +
theme(
legend.position = "bottom",
axis.text.x = element_text(angle = 45, hjust = 1)
)# -------------------------------------------------------------------------
# Highest observed search-interest point for each MOBA
# -------------------------------------------------------------------------
moba_peaks <- moba_trends %>%
group_by(keyword) %>%
slice_max(order_by = hits, n = 1, with_ties = FALSE) %>%
ungroup() %>%
arrange(desc(hits)) %>%
select(
Game = keyword,
Peak_Date = date,
Peak_Search_Interest = hits
)
moba_peaks %>%
mutate(Peak_Date = format(as.Date(Peak_Date), "%B %d, %Y")) %>%
safe_kable(caption = "Highest Google Trends Peak by MOBA")| Game | Peak_Date | Peak_Search_Interest |
|---|---|---|
| Pokemon Unite | July 25, 2021 | 100 |
| League of Legends | November 24, 2024 | 98 |
| Smite | June 19, 2022 | 83 |
| Dota 2 | October 10, 2021 | 19 |
| Heroes of the Storm | July 03, 2022 | 2 |
# -------------------------------------------------------------------------
# Peak marker visualization: MOBA titles
# -------------------------------------------------------------------------
moba_trends %>%
ggplot(aes(x = date, y = hits, color = keyword)) +
geom_line(linewidth = 0.7, alpha = 0.85) +
geom_point(
data = moba_peaks %>%
rename(keyword = Game, date = Peak_Date, hits = Peak_Search_Interest),
aes(x = date, y = hits, color = keyword),
size = 3
) +
labs(
title = "MOBA Search Interest with Peak Moments Highlighted",
subtitle = "Dots indicate each title's highest observed point in the five-year window",
x = NULL,
y = "Relative Search Interest",
color = "Game",
caption = "Source: Google Trends via gtrendsR"
) +
scale_x_date(date_breaks = "6 months", date_labels = "%b %Y") +
scale_y_continuous(limits = c(0, 100)) +
theme_minimal(base_size = 12) +
theme(
legend.position = "bottom",
axis.text.x = element_text(angle = 45, hjust = 1)
)The monthly heatmap provides a broader view of how search interest varies across months and years. This visualization helps distinguish between concentrated attention spikes and more sustained visibility.
For live-service games, this distinction matters. A title with repeated seasonal or annual spikes may be maintaining a recurring attention cycle, while a title with one isolated peak may have experienced a single major event that temporarily increased visibility.
# -------------------------------------------------------------------------
# Monthly aggregation
# -------------------------------------------------------------------------
# Google Trends often returns weekly observations over multi-year windows.
# Aggregating to monthly averages makes broader attention patterns easier to
# compare across titles.
monthly_trends <- all_trends %>%
group_by(genre, keyword, year, month, month_num) %>%
summarise(
avg_hits = mean(hits, na.rm = TRUE),
.groups = "drop"
)# -------------------------------------------------------------------------
# Monthly attention heatmap: MMORPG titles
# -------------------------------------------------------------------------
monthly_trends %>%
filter(genre == "MMORPG") %>%
ggplot(aes(x = month, y = factor(year), fill = avg_hits)) +
geom_tile(color = "white") +
facet_wrap(~ keyword, ncol = 1) +
scale_fill_gradient(low = "gray95", high = "steelblue") +
labs(
title = "MMORPG Monthly Search Interest Heatmap",
subtitle = "Average relative search interest by month and year",
x = "Month",
y = "Year",
fill = "Avg. Interest",
caption = "Source: Google Trends via gtrendsR"
) +
theme_minimal(base_size = 11) +
theme(
strip.text = element_text(face = "bold"),
legend.position = "bottom"
)# -------------------------------------------------------------------------
# Monthly attention heatmap: MOBA titles
# -------------------------------------------------------------------------
monthly_trends %>%
filter(genre == "MOBA") %>%
ggplot(aes(x = month, y = factor(year), fill = avg_hits)) +
geom_tile(color = "white") +
facet_wrap(~ keyword, ncol = 1) +
scale_fill_gradient(low = "gray95", high = "darkorange") +
labs(
title = "MOBA Monthly Search Interest Heatmap",
subtitle = "Average relative search interest by month and year",
x = "Month",
y = "Year",
fill = "Avg. Interest",
caption = "Source: Google Trends via gtrendsR"
) +
theme_minimal(base_size = 11) +
theme(
strip.text = element_text(face = "bold"),
legend.position = "bottom"
)Search interest is not only about the single highest peak. A title can generate one large spike and then fade, or it can maintain steady attention over time. To account for this difference, this section compares each game’s average interest and volatility.
Average search interest provides a rough indicator of sustained visibility. Volatility, measured using the standard deviation of search interest, helps identify games with more event-driven attention patterns.
# -------------------------------------------------------------------------
# Average attention and volatility summary
# -------------------------------------------------------------------------
# mean_hits = average relative attention across the five-year period
# sd_hits = volatility in search interest
# max_hits = highest observed peak
# min_hits = lowest observed level
# range_hits = difference between maximum and minimum interest
volatility_tbl <- all_trends %>%
group_by(genre, keyword) %>%
summarise(
mean_hits = round(mean(hits, na.rm = TRUE), 2),
sd_hits = round(sd(hits, na.rm = TRUE), 2),
min_hits = min(hits, na.rm = TRUE),
max_hits = max(hits, na.rm = TRUE),
range_hits = max_hits - min_hits,
.groups = "drop"
) %>%
arrange(genre, desc(mean_hits))
volatility_tbl %>%
rename(
Genre = genre,
Game = keyword,
`Average Interest` = mean_hits,
`Volatility SD` = sd_hits,
`Minimum Interest` = min_hits,
`Maximum Interest` = max_hits,
`Range` = range_hits
) %>%
safe_kable(caption = "Average Search Interest and Volatility by Game")| Genre | Game | Average Interest | Volatility SD | Minimum Interest | Maximum Interest | Range |
|---|---|---|---|---|---|---|
| MMORPG | World of Warcraft | 50.82 | 12.53 | 27.0 | 100 | 73.0 |
| MMORPG | Guild Wars 2 | 16.74 | 5.63 | 9.0 | 45 | 36.0 |
| MMORPG | Final Fantasy XIV | 9.17 | 4.14 | 5.0 | 31 | 26.0 |
| MMORPG | Star Wars: The Old Republic | 8.39 | 5.51 | 4.0 | 69 | 65.0 |
| MMORPG | The Elder Scrolls Online | 2.61 | 0.97 | 1.0 | 6 | 5.0 |
| MOBA | League of Legends | 33.26 | 12.01 | 18.0 | 98 | 80.0 |
| MOBA | Smite | 14.97 | 7.10 | 7.0 | 83 | 76.0 |
| MOBA | Dota 2 | 7.91 | 2.58 | 4.0 | 19 | 15.0 |
| MOBA | Pokemon Unite | 6.01 | 9.23 | 2.0 | 100 | 98.0 |
| MOBA | Heroes of the Storm | 0.96 | 0.15 | 0.5 | 2 | 1.5 |
# -------------------------------------------------------------------------
# Average search-interest comparison
# -------------------------------------------------------------------------
volatility_tbl %>%
ggplot(aes(x = reorder(keyword, mean_hits), y = mean_hits, fill = genre)) +
geom_col(show.legend = FALSE) +
coord_flip() +
facet_wrap(~ genre, scales = "free_y") +
labs(
title = "Average Google Search Interest by Game",
subtitle = "Average relative interest over the five-year period",
x = NULL,
y = "Average Relative Search Interest",
caption = "Source: Google Trends via gtrendsR"
) +
theme_minimal(base_size = 12)# -------------------------------------------------------------------------
# Volatility comparison
# -------------------------------------------------------------------------
# Higher standard deviation suggests more uneven or event-driven attention.
# Lower standard deviation suggests a steadier attention profile.
volatility_tbl %>%
ggplot(aes(x = reorder(keyword, sd_hits), y = sd_hits, fill = genre)) +
geom_col(show.legend = FALSE) +
coord_flip() +
facet_wrap(~ genre, scales = "free_y") +
labs(
title = "Search Interest Volatility by Game",
subtitle = "Higher values suggest more event-driven attention patterns",
x = NULL,
y = "Standard Deviation of Relative Interest",
caption = "Source: Google Trends via gtrendsR"
) +
theme_minimal(base_size = 12)The peak summary identifies the highest observed search-interest point for each game and the top peak within each genre. These peaks should be interpreted as attention moments that deserve contextual follow-up rather than complete explanations on their own.
Possible explanations include expansion releases, esports tournaments, patch cycles, content updates, franchise news, or broader gaming-community discussion. A deeper follow-up analysis could pair each peak date with release notes, esports calendars, Steam player data, Twitch viewership, or official announcement timelines.
# -------------------------------------------------------------------------
# Combined peak table by genre
# -------------------------------------------------------------------------
combined_peaks <- bind_rows(
mmorpg_peaks %>% mutate(Genre = "MMORPG"),
moba_peaks %>% mutate(Genre = "MOBA")
) %>%
select(Genre, Game, Peak_Date, Peak_Search_Interest) %>%
arrange(Genre, desc(Peak_Search_Interest))
combined_peaks %>%
mutate(Peak_Date = format(as.Date(Peak_Date), "%B %d, %Y")) %>%
safe_kable(caption = "Highest Observed Peak by Game and Genre")| Genre | Game | Peak_Date | Peak_Search_Interest |
|---|---|---|---|
| MMORPG | World of Warcraft | April 17, 2022 | 100 |
| MMORPG | Star Wars: The Old Republic | December 07, 2025 | 69 |
| MMORPG | Guild Wars 2 | June 07, 2026 | 45 |
| MMORPG | Final Fantasy XIV | November 28, 2021 | 31 |
| MMORPG | The Elder Scrolls Online | July 16, 2023 | 6 |
| MOBA | Pokemon Unite | July 25, 2021 | 100 |
| MOBA | League of Legends | November 24, 2024 | 98 |
| MOBA | Smite | June 19, 2022 | 83 |
| MOBA | Dota 2 | October 10, 2021 | 19 |
| MOBA | Heroes of the Storm | July 03, 2022 | 2 |
# -------------------------------------------------------------------------
# Highest peak winner within each genre
# -------------------------------------------------------------------------
genre_winners <- combined_peaks %>%
group_by(Genre) %>%
slice_max(order_by = Peak_Search_Interest, n = 1, with_ties = FALSE) %>%
ungroup()
genre_winners %>%
mutate(Peak_Date = format(as.Date(Peak_Date), "%B %d, %Y")) %>%
safe_kable(caption = "Highest Peak Winner by Genre")| Genre | Game | Peak_Date | Peak_Search_Interest |
|---|---|---|---|
| MMORPG | World of Warcraft | April 17, 2022 | 100 |
| MOBA | Pokemon Unite | July 25, 2021 | 100 |
# -------------------------------------------------------------------------
# Data-driven preliminary findings
# -------------------------------------------------------------------------
# This section generates a written interpretation from the observed peak values.
# It also ranks all games within each genre from highest to lowest observed peak.
# Dates are explicitly formatted so they print as readable calendar dates rather
# than R's internal numeric Date representation.
peak_rankings <- combined_peaks %>%
mutate(
Peak_Date = as.Date(Peak_Date),
Peak_Date_Display = format(Peak_Date, "%B %d, %Y"),
Peak_Search_Interest = as.numeric(Peak_Search_Interest)
) %>%
arrange(
Genre,
desc(Peak_Search_Interest),
Peak_Date
)
mmorpg_rankings <- peak_rankings %>%
filter(Genre == "MMORPG")
moba_rankings <- peak_rankings %>%
filter(Genre == "MOBA")
mmorpg_winner <- mmorpg_rankings %>%
slice(1)
moba_winner <- moba_rankings %>%
slice(1)
cat("Based on the five-year U.S. Google Trends comparison, **",
mmorpg_winner$Game,
"** had the highest observed MMORPG search-interest peak, reaching a relative score of **",
mmorpg_winner$Peak_Search_Interest,
"** on **",
mmorpg_winner$Peak_Date_Display,
"**. ",
sep = "")Based on the five-year U.S. Google Trends comparison, World of Warcraft had the highest observed MMORPG search-interest peak, reaching a relative score of 100 on April 17, 2022.
cat("Within the MOBA comparison, **",
moba_winner$Game,
"** had the highest observed search-interest peak, reaching a relative score of **",
moba_winner$Peak_Search_Interest,
"** on **",
moba_winner$Peak_Date_Display,
"**. ",
sep = "")Within the MOBA comparison, Pokemon Unite had the highest observed search-interest peak, reaching a relative score of 100 on July 25, 2021.
cat("These peaks should be interpreted as relative attention spikes within each genre comparison rather than absolute measures of popularity. Plausible explanations may include expansion releases, major updates, esports events, streaming or media attention, franchise announcements, community controversy, or shifts in live-service engagement.")These peaks should be interpreted as relative attention spikes within each genre comparison rather than absolute measures of popularity. Plausible explanations may include expansion releases, major updates, esports events, streaming or media attention, franchise announcements, community controversy, or shifts in live-service engagement.
mmorpg_rankings %>%
mutate(Rank = row_number()) %>%
select(
Rank,
Game,
`Peak Date` = Peak_Date_Display,
`Peak Search Interest` = Peak_Search_Interest
) %>%
safe_kable(caption = "MMORPG Titles Ranked by Highest Observed Search-Interest Peak") %>%
print()| Rank | Game | Peak Date | Peak Search Interest |
|---|---|---|---|
| 1 | World of Warcraft | April 17, 2022 | 100 |
| 2 | Star Wars: The Old Republic | December 07, 2025 | 69 |
| 3 | Guild Wars 2 | June 07, 2026 | 45 |
| 4 | Final Fantasy XIV | November 28, 2021 | 31 |
| 5 | The Elder Scrolls Online | July 16, 2023 | 6 |
moba_rankings %>%
mutate(Rank = row_number()) %>%
select(
Rank,
Game,
`Peak Date` = Peak_Date_Display,
`Peak Search Interest` = Peak_Search_Interest
) %>%
safe_kable(caption = "MOBA Titles Ranked by Highest Observed Search-Interest Peak") %>%
print()| Rank | Game | Peak Date | Peak Search Interest |
|---|---|---|---|
| 1 | Pokemon Unite | July 25, 2021 | 100 |
| 2 | League of Legends | November 24, 2024 | 98 |
| 3 | Smite | June 19, 2022 | 83 |
| 4 | Dota 2 | October 10, 2021 | 19 |
| 5 | Heroes of the Storm | July 03, 2022 | 2 |
cat("\n\nThe ranking tables show that peak attention is unevenly distributed across titles. A game with the highest peak may have benefited from a major event or announcement, while games with lower peaks may still maintain meaningful baseline attention over time. For that reason, the peak rankings should be read alongside the average-interest and volatility results rather than as a complete measure of each game's overall health or popularity.")The ranking tables show that peak attention is unevenly distributed across titles. A game with the highest peak may have benefited from a major event or announcement, while games with lower peaks may still maintain meaningful baseline attention over time. For that reason, the peak rankings should be read alongside the average-interest and volatility results rather than as a complete measure of each game’s overall health or popularity.
The results suggest that search interest in MMORPGs and MOBAs is highly sensitive to events and community attention cycles. Some titles appear to maintain steadier baseline visibility, while others generate sharper spikes around specific moments.
For MMORPGs, this pattern likely reflects the importance of expansions, major patches, franchise loyalty, and long-term community investment. For MOBAs, attention may be more closely tied to esports visibility, competitive seasons, hero or champion updates, and community discourse.
Overall, Google Trends provides a useful attention signal, but it should be interpreted alongside other gaming metrics such as active player counts, revenue estimates, Twitch viewership, patch history, esports calendars, and official announcement timelines.
Google Trends data measures relative search interest, not absolute popularity. A score of 100 represents the highest point within a specific comparison group and time range, not a fixed number of searches.
The MMORPG and MOBA groups were queried separately, so results are best interpreted within each genre rather than directly across genres. Search behavior also varies by naming conventions, abbreviations, expansions, esports events, and player habits. For example, players may search for patch notes, expansion names, build guides, competitive events, or community tools rather than the game title itself.
Despite these limitations, Google Trends is valuable for identifying moments when a game becomes more visible to the broader public and for comparing attention patterns among competing titles in the same genre.
Gaming search interest is not simply a popularity contest. It reflects the rhythm of live-service entertainment: announcements, expansions, patches, esports moments, nostalgia cycles, streamer visibility, and community reaction.
The most useful insight from this analysis is not only which game reached the highest peak, but how differently each title generates attention. Some games operate like stable genre institutions, while others appear more dependent on major events to re-enter public conversation.
For a follow-up analysis, the most valuable next step would be to annotate the largest search-interest spikes with release dates, esports events, major patch notes, Twitch viewership data, or platform player-count trends. That would help separate routine attention from true inflection points in each game’s public visibility.
gtrendsR package. Used to collect Google Trends data in
R.tidyverse: R packages for data
science.writexl package. Used to export collected data for
reproducibility and external review.