diff --git a/lms/djangoapps/discussion/django_comment_client/base/tests.py b/lms/djangoapps/discussion/django_comment_client/base/tests.py
index d450998a60c6..6ad1c8bb4a9a 100644
--- a/lms/djangoapps/discussion/django_comment_client/base/tests.py
+++ b/lms/djangoapps/discussion/django_comment_client/base/tests.py
@@ -1859,6 +1859,34 @@ def test_thread_voted_event(self, view_name, obj_id_name, obj_type, mock_request
         assert event['undo_vote'] == undo
         assert event['vote_value'] == 'up'
 
+    @ddt.data('follow_thread', 'unfollow_thread',)
+    @patch('eventtracking.tracker.emit')
+    @patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True)
+    def test_thread_followed_event(self, view_name, mock_request, mock_emit):
+        self._set_mock_request_data(mock_request, {
+            'closed': False,
+            'commentable_id': 'test_commentable_id',
+            'username': 'test_user',
+        })
+        request = RequestFactory().post('dummy_url', {})
+        request.user = self.student
+        request.view_name = view_name
+        view_function = getattr(views, view_name)
+        kwargs = dict(course_id=str(self.course.id))
+        kwargs['thread_id'] = 'thread_id'
+        view_function(request, **kwargs)
+
+        assert mock_emit.called
+        event_name, event_data = mock_emit.call_args[0]
+        action_name = 'followed' if view_name == 'follow_thread' else 'unfollowed'
+        expected_action_value = True if view_name == 'follow_thread' else False
+        assert event_name == f'edx.forum.thread.{action_name}'
+        assert event_data['commentable_id'] == 'test_commentable_id'
+        assert event_data['id'] == 'thread_id'
+        assert event_data['followed'] == expected_action_value
+        assert event_data['user_forums_roles'] == ['Student']
+        assert event_data['user_course_roles'] == ['Wizard']
+
 
 class UsersEndpointTestCase(ForumsEnableMixin, SharedModuleStoreTestCase, MockRequestSetupMixin):
 
diff --git a/lms/djangoapps/discussion/django_comment_client/base/views.py b/lms/djangoapps/discussion/django_comment_client/base/views.py
index 5ad3dae8992b..1ec41e31551e 100644
--- a/lms/djangoapps/discussion/django_comment_client/base/views.py
+++ b/lms/djangoapps/discussion/django_comment_client/base/views.py
@@ -134,6 +134,20 @@ def track_thread_created_event(request, course, thread, followed, from_mfe_sideb
     track_created_event(request, event_name, course, thread, event_data)
 
 
+def track_thread_followed_event(request, course, thread, followed):
+    """
+    Send analytics event for a newly followed/unfollowed thread.
+    """
+    action_name = 'followed' if followed else 'unfollowed'
+    event_name = _EVENT_NAME_TEMPLATE.format(obj_type='thread', action_name=action_name)
+    event_data = {
+        'commentable_id': thread.commentable_id,
+        'id': thread.id,
+        'followed': followed,
+    }
+    track_forum_event(request, event_name, course, thread, event_data)
+
+
 def track_comment_created_event(request, course, comment, commentable_id, followed, from_mfe_sidebar=False):
     """
     Send analytics event for a newly created response or comment.
@@ -938,9 +952,12 @@ def un_pin_thread(request, course_id, thread_id):
 @permitted
 def follow_thread(request, course_id, thread_id):  # lint-amnesty, pylint: disable=missing-function-docstring, unused-argument
     user = cc.User.from_django_user(request.user)
+    course_key = CourseKey.from_string(course_id)
+    course = get_course_by_id(course_key)
     thread = cc.Thread.find(thread_id)
     user.follow(thread)
     thread_followed.send(sender=None, user=request.user, post=thread)
+    track_thread_followed_event(request, course, thread, True)
     return JsonResponse({})
 
 
@@ -966,10 +983,13 @@ def unfollow_thread(request, course_id, thread_id):  # lint-amnesty, pylint: dis
     given a course id and thread id, stop following this thread
     ajax only
     """
+    course_key = CourseKey.from_string(course_id)
+    course = get_course_by_id(course_key)
     user = cc.User.from_django_user(request.user)
     thread = cc.Thread.find(thread_id)
     user.unfollow(thread)
     thread_unfollowed.send(sender=None, user=request.user, post=thread)
+    track_thread_followed_event(request, course, thread, False)
     return JsonResponse({})
 
 
diff --git a/lms/djangoapps/discussion/rest_api/api.py b/lms/djangoapps/discussion/rest_api/api.py
index f79cd663718b..54878d69ca37 100644
--- a/lms/djangoapps/discussion/rest_api/api.py
+++ b/lms/djangoapps/discussion/rest_api/api.py
@@ -93,7 +93,7 @@
     track_voted_event,
     track_discussion_reported_event,
     track_discussion_unreported_event,
-    track_forum_search_event
+    track_forum_search_event, track_thread_followed_event
 )
 from ..django_comment_client.utils import (
     get_group_id_for_user,
@@ -1333,7 +1333,7 @@ def _do_extra_actions(api_content, cc_content, request_fields, actions_form, con
         if field in request_fields and field in api_content and form_value != api_content[field]:
             api_content[field] = form_value
             if field == "following":
-                _handle_following_field(form_value, context["cc_requester"], cc_content)
+                _handle_following_field(form_value, context["cc_requester"], cc_content, request)
             elif field == "abuse_flagged":
                 _handle_abuse_flagged_field(form_value, context["cc_requester"], cc_content, request)
             elif field == "voted":
@@ -1346,12 +1346,15 @@ def _do_extra_actions(api_content, cc_content, request_fields, actions_form, con
                 raise ValidationError({field: ["Invalid Key"]})
 
 
-def _handle_following_field(form_value, user, cc_content):
+def _handle_following_field(form_value, user, cc_content, request):
     """follow/unfollow thread for the user"""
+    course_key = CourseKey.from_string(cc_content.course_id)
+    course = get_course_with_access(request.user, 'load', course_key)
     if form_value:
         user.follow(cc_content)
     else:
         user.unfollow(cc_content)
+    track_thread_followed_event(request, course, cc_content, form_value)
 
 
 def _handle_abuse_flagged_field(form_value, user, cc_content, request):
diff --git a/lms/djangoapps/discussion/rest_api/tests/test_api.py b/lms/djangoapps/discussion/rest_api/tests/test_api.py
index 1193384bfbd0..98c27feb58c1 100644
--- a/lms/djangoapps/discussion/rest_api/tests/test_api.py
+++ b/lms/djangoapps/discussion/rest_api/tests/test_api.py
@@ -2709,7 +2709,8 @@ def test_author_only_fields(self, role_name):
 
     @ddt.data(*itertools.product([True, False], [True, False]))
     @ddt.unpack
-    def test_following(self, old_following, new_following):
+    @mock.patch("eventtracking.tracker.emit")
+    def test_following(self, old_following, new_following, mock_emit):
         """
         Test attempts to edit the "following" field.
 
@@ -2739,6 +2740,13 @@ def test_following(self, old_following, new_following):
             )
             request_data.pop("request_id", None)
             assert request_data == {'source_type': ['thread'], 'source_id': ['test_thread']}
+            event_name, event_data = mock_emit.call_args[0]
+            expected_event_action = 'followed' if new_following else 'unfollowed'
+            assert event_name == f'edx.forum.thread.{expected_event_action}'
+            assert event_data['commentable_id'] == 'original_topic'
+            assert event_data['id'] == 'test_thread'
+            assert event_data['followed'] == new_following
+            assert event_data['user_forums_roles'] == ['Student']
 
     @ddt.data(*itertools.product([True, False], [True, False]))
     @ddt.unpack