diff --git a/src/frontend-common/cheevos.cpp b/src/frontend-common/cheevos.cpp
index 34ac35a22..0a76163e4 100644
--- a/src/frontend-common/cheevos.cpp
+++ b/src/frontend-common/cheevos.cpp
@@ -45,6 +45,7 @@ static bool ActivateAchievement(Achievement* achievement);
 static void DeactivateAchievement(Achievement* achievement);
 static void SendPing();
 static void SendPlaying();
+static void UpdateRichPresence();
 
 /// Uses a temporarily (second) CD image to resolve the hash.
 static void GameChanged();
@@ -287,6 +288,8 @@ void Update()
 
     if (!s_test_mode)
     {
+      UpdateRichPresence();
+
       const s32 ping_frequency =
         s_rich_presence_enabled ? RICH_PRESENCE_PING_FREQUENCY : NO_RICH_PRESENCE_PING_FREQUENCY;
       if (static_cast<s32>(s_last_ping_time.GetTimeSeconds()) >= ping_frequency)
@@ -614,6 +617,7 @@ static void GetUserUnlocksCallback(s32 status_code, const FrontendCommon::HTTPDo
   ActivateLockedAchievements();
   DisplayAchievementSummary();
   SendPlaying();
+  UpdateRichPresence();
   SendPing();
   GetHostInterface()->OnAchievementsRefreshed();
 }
@@ -1022,6 +1026,9 @@ void SendPlaying()
 
 static void UpdateRichPresence()
 {
+  if (!s_has_rich_presence)
+    return;
+
   char buffer[512];
   int res = rc_runtime_get_richpresence(&s_rcheevos_runtime, buffer, sizeof(buffer), CheevosPeek, nullptr, nullptr);
   if (res <= 0)
@@ -1053,9 +1060,6 @@ void SendPing()
   if (!HasActiveGame())
     return;
 
-  if (s_has_rich_presence)
-    UpdateRichPresence();
-
   char url[512];
   char post_data[512];
   int res = rc_url_ping(url, sizeof(url), post_data, sizeof(post_data), s_username.c_str(), s_login_token.c_str(),
diff --git a/src/frontend-common/common_host_interface.cpp b/src/frontend-common/common_host_interface.cpp
index f0e178346..58b0e5666 100644
--- a/src/frontend-common/common_host_interface.cpp
+++ b/src/frontend-common/common_host_interface.cpp
@@ -1028,7 +1028,7 @@ void CommonHostInterface::OnRunningGameChanged(const std::string& path, CDImage*
   }
 
 #ifdef WITH_DISCORD_PRESENCE
-  UpdateDiscordPresence();
+  UpdateDiscordPresence(false);
 #endif
 
 #ifdef WITH_CHEEVOS
@@ -3763,7 +3763,7 @@ void CommonHostInterface::InitializeDiscordPresence()
   Discord_Initialize("705325712680288296", &handlers, 0, nullptr);
   m_discord_presence_active = true;
 
-  UpdateDiscordPresence();
+  UpdateDiscordPresence(false);
 }
 
 void CommonHostInterface::ShutdownDiscordPresence()
@@ -3774,13 +3774,31 @@ void CommonHostInterface::ShutdownDiscordPresence()
   Discord_ClearPresence();
   Discord_Shutdown();
   m_discord_presence_active = false;
+#ifdef WITH_CHEEVOS
+  m_discord_presence_cheevos_string.clear();
+#endif
 }
 
-void CommonHostInterface::UpdateDiscordPresence()
+void CommonHostInterface::UpdateDiscordPresence(bool rich_presence_only)
 {
   if (!m_discord_presence_active)
     return;
 
+#ifdef WITH_CHEEVOS
+  // Update only if RetroAchievements rich presence has changed
+  const std::string& new_rich_presence = Cheevos::GetRichPresenceString();
+  if (new_rich_presence == m_discord_presence_cheevos_string && rich_presence_only)
+  {
+    return;
+  }
+  m_discord_presence_cheevos_string = new_rich_presence;
+#else
+  if (rich_presence_only)
+  {
+    return;
+  }
+#endif
+
   // https://discord.com/developers/docs/rich-presence/how-to#updating-presence-update-presence-payload-fields
   DiscordRichPresence rp = {};
   rp.largeImageKey = "duckstation_logo";
@@ -3798,6 +3816,22 @@ void CommonHostInterface::UpdateDiscordPresence()
     details_string.AppendString("No Game Running");
   }
 
+#ifdef WITH_CHEEVOS
+  SmallString state_string;
+  // Trim to 128 bytes as per Discord-RPC requirements
+  if (m_discord_presence_cheevos_string.length() >= 128)
+  {
+    // 124 characters + 3 dots + null terminator
+    state_string = m_discord_presence_cheevos_string.substr(0, 124);
+    state_string.AppendString("...");
+  }
+  else
+  {
+    state_string = m_discord_presence_cheevos_string;
+  }
+
+  rp.state = state_string;
+#endif
   rp.details = details_string;
 
   Discord_UpdatePresence(&rp);
@@ -3808,6 +3842,8 @@ void CommonHostInterface::PollDiscordPresence()
   if (!m_discord_presence_active)
     return;
 
+  UpdateDiscordPresence(true);
+
   Discord_RunCallbacks();
 }
 
diff --git a/src/frontend-common/common_host_interface.h b/src/frontend-common/common_host_interface.h
index fea38c842..e85d6df05 100644
--- a/src/frontend-common/common_host_interface.h
+++ b/src/frontend-common/common_host_interface.h
@@ -502,7 +502,7 @@ private:
   void SetDiscordPresenceEnabled(bool enabled);
   void InitializeDiscordPresence();
   void ShutdownDiscordPresence();
-  void UpdateDiscordPresence();
+  void UpdateDiscordPresence(bool rich_presence_only);
   void PollDiscordPresence();
 #endif
 
@@ -551,5 +551,8 @@ private:
   // discord rich presence
   bool m_discord_presence_enabled = false;
   bool m_discord_presence_active = false;
+#ifdef WITH_CHEEVOS
+  std::string m_discord_presence_cheevos_string;
+#endif
 #endif
 };