diff --git a/hypha/apply/activity/context_processors.py b/hypha/apply/activity/context_processors.py
new file mode 100644
index 0000000000000000000000000000000000000000..975680a3c1a58d4bec894d1d395eb519410fe01c
--- /dev/null
+++ b/hypha/apply/activity/context_processors.py
@@ -0,0 +1,9 @@
+from .models import Activity
+
+
+def notification_context(request):
+    context_data = dict()
+    if hasattr(request, 'user'):
+        if request.user.is_authenticated and request.user.is_apply_staff:
+            context_data['latest_notifications'] = Activity.objects.latest().order_by('-timestamp')[:5]
+    return context_data
diff --git a/hypha/apply/activity/filters.py b/hypha/apply/activity/filters.py
new file mode 100644
index 0000000000000000000000000000000000000000..899c5d5f533e0a77f8afca289760c49f2cbfcba6
--- /dev/null
+++ b/hypha/apply/activity/filters.py
@@ -0,0 +1,43 @@
+from datetime import timedelta
+
+import django_filters
+from django.utils.timezone import now
+from django.utils.translation import gettext_lazy as _
+from django_filters.filters import DateRangeFilter, _truncate
+
+from .models import Activity
+
+
+class NotificationFilter(django_filters.FilterSet):
+    timestamp_choices = [
+        ('today', _('Today')),
+        ('yesterday', _('Yesterday')),
+        ('week', _('Past 7 days')),
+        ('month', _('This month'))
+    ]
+    timestamp_filters = {
+        'today': lambda qs, name: qs.filter(**{
+            '%s__year' % name: now().year,
+            '%s__month' % name: now().month,
+            '%s__day' % name: now().day
+        }),
+        'yesterday': lambda qs, name: qs.filter(**{
+            '%s__year' % name: (now() - timedelta(days=1)).year,
+            '%s__month' % name: (now() - timedelta(days=1)).month,
+            '%s__day' % name: (now() - timedelta(days=1)).day,
+        }),
+        'week': lambda qs, name: qs.filter(**{
+            '%s__gte' % name: _truncate(now() - timedelta(days=7)),
+            '%s__lt' % name: _truncate(now() + timedelta(days=1)),
+        }),
+        'month': lambda qs, name: qs.filter(**{
+            '%s__year' % name: now().year,
+            '%s__month' % name: now().month
+        })
+    }
+
+    date = DateRangeFilter(field_name='timestamp', choices=timestamp_choices, filters=timestamp_filters)
+
+    class Meta:
+        model = Activity
+        fields = {}
diff --git a/hypha/apply/activity/models.py b/hypha/apply/activity/models.py
index 2b6c99ff21cfe71e350242cb2ac4637f180fc20a..99a4010044e866db751d13ca0cb5314fb4a382b3 100644
--- a/hypha/apply/activity/models.py
+++ b/hypha/apply/activity/models.py
@@ -4,6 +4,7 @@ from django.contrib.contenttypes.models import ContentType
 from django.db import models
 from django.db.models import Case, Value, When
 from django.db.models.functions import Concat
+from django.utils import timezone
 
 from .options import MESSAGES
 
@@ -54,6 +55,9 @@ class ActivityQuerySet(BaseActivityQuerySet):
     def actions(self):
         return self.filter(type=ACTION)
 
+    def latest(self):
+        return self.filter(timestamp__gte=(timezone.now() - timezone.timedelta(days=30)))
+
 
 class ActivityBaseManager(models.Manager):
     def create(self, **kwargs):
diff --git a/hypha/apply/activity/templates/activity/include/notifications_dropdown.html b/hypha/apply/activity/templates/activity/include/notifications_dropdown.html
new file mode 100644
index 0000000000000000000000000000000000000000..b6212ab5db6c3c7ca63196ff53007a25f0a64aa8
--- /dev/null
+++ b/hypha/apply/activity/templates/activity/include/notifications_dropdown.html
@@ -0,0 +1,19 @@
+{% load i18n activity_tags bleach_tags markdown_tags submission_tags apply_tags %}
+
+<div class="notifications notifications--dropdown">
+    <a href="#" class="button button--contains-icons notifications__bell" aria-label="{% trans "Notifications" %}" aria-haspopup="activity" aria-expanded="false" role="button">
+        <svg class="icon"><use xlink:href="#bell-icon"></use></svg>
+    </a>
+    <div class="notifications__content zeta hidden" role="activity">
+        <h5>Notifications</h5>
+        {% for activity in latest_notifications %}
+        <p class="notifications__item">
+            <strong>{{ activity.source_content_type.name|source_type }} </strong>
+            <a href="{{ activity.source.get_absolute_url }}{% ifequal activity.type 'comment' %}#communications{% endifequal %}">{{ activity.source.title|capfirst|truncatechars:15 }}</a>
+            : {{ activity.user.get_full_name }} {% ifequal activity.type 'comment' %}{% trans "made a comment" %}{% else %} {{ activity|display_for:request.user }}{% endifequal %}
+            {% if activity.related_object %}<a href="{{ activity.related_object.get_absolute_url }}">{{ activity.related_object|model_verbose_name }}</a>{% endif %}
+        </p>
+        {% endfor %}
+        <p class="notifications__more"><a href="{% url "activity:notifications" %}">Show All</a></p>
+    </div>
+</div>
diff --git a/hypha/apply/activity/templates/activity/notifications.html b/hypha/apply/activity/templates/activity/notifications.html
new file mode 100644
index 0000000000000000000000000000000000000000..1b9f19f82253ded4721e1016ba938cbd32c16bb5
--- /dev/null
+++ b/hypha/apply/activity/templates/activity/notifications.html
@@ -0,0 +1,72 @@
+{% extends "base-apply.html" %}
+{% load i18n static activity_tags apply_tags bleach_tags markdown_tags submission_tags %}
+
+{% block content %}
+<div class="admin-bar">
+    <div class="admin-bar__inner">
+        <div class="admin-bar__inner--with-button">
+            <h1 class="gamma heading heading--no-margin heading--bold">{% trans "Notifications" %}</h1>
+            <form class="form notifications__filters" method="get">
+                {{ filter.form }}
+                <button class="button button--primary" type="submit" value="Filter">{% trans "Filter" %}</button>
+            </form>
+        </div>
+
+        <div class="tabs js-tabs">
+            <div class="tabs__container">
+                <a class="tab__item" href="#comments" data-tab="tab-1">
+                    {% trans "Communications" %}
+                </a>
+
+                <a class="tab__item" href="#actions" data-tab="tab-2">
+                    {% trans "Activity Feed" %}
+                </a>
+            </div>
+        </div>
+    </div>
+</div>
+
+<div class="wrapper wrapper--large wrapper--tabs js-tabs-content">
+    {# Tab 1 #}
+    <div class="tabs__content" id="tab-1">
+        {% for activity in object_list %}
+            {% if activity.type == 'comment' %}
+                <div class="feed__item feed__item--{{ activity.type }}">
+                    <div class="feed__pre-content">
+                        <p class="feed__label feed__label--{{ activity.source_content_type.name|source_type|lower }}">{{ activity.source_content_type.name|source_type }}</p>
+                    </div>
+                    <div class="feed__content js-feed-content">
+                        <div class="feed__meta js-feed-meta">
+                            <p class="feed__meta-item"><a href="{{ activity.source.get_absolute_url }}#communications">{{ activity.source.title|capfirst }}</a>
+                                : {{ activity.user.get_full_name }} {% trans "made a comment" %} – {{ activity.timestamp|date:"SHORT_DATE_FORMAT" }}</p>
+                        </div>
+                    </div>
+                </div>
+            {% endif %}
+        {% endfor %}
+    </div>
+    {# Tab 2 #}
+    <div class="tabs__content" id="tab-2">
+        {% for activity in object_list %}
+            {% if activity.type == 'action' %}
+                <div class="feed__item feed__item--{{ activity.type }}">
+                    <div class="feed__pre-content">
+                        <p class="feed__label feed__label--{{ activity.source_content_type.name|source_type|lower }}">{{ activity.source_content_type.name|source_type }}</p>
+                    </div>
+                    <div class="feed__content js-feed-content">
+                        <div class="feed__meta js-feed-meta">
+                            <p class="feed__meta-item"><a href="{{ activity.source.get_absolute_url }}">{{ activity.source.title|capfirst }}</a>
+                                : {{ activity.user.get_full_name }} – {{ activity.timestamp|date:"SHORT_DATE_FORMAT" }} – {{ activity|display_for:request.user }} {% if activity.related_object %}<a href="{{ activity.related_object.get_absolute_url }}" class="feed__related-item">{{ activity.related_object|model_verbose_name }} <svg><use xlink:href="#arrow-head-pixels--solid"></use></svg></a>{% endif %}</p>
+                        </div>
+                    </div>
+                </div>
+            {% endif %}
+        {% endfor %}
+    </div>
+</div>
+
+{% endblock %}
+
+{% block extra_js %}
+    <script src="{% static 'js/apply/tabs.js' %}"></script>
+{% endblock %}
diff --git a/hypha/apply/activity/templatetags/activity_tags.py b/hypha/apply/activity/templatetags/activity_tags.py
index 2df2a15d1c8c19f9020ff1f86e0bc93ac3e36fff..5b0dc4b115d4c15938af7ca91326b02de096ec16 100644
--- a/hypha/apply/activity/templatetags/activity_tags.py
+++ b/hypha/apply/activity/templatetags/activity_tags.py
@@ -55,3 +55,10 @@ def display_for(activity, user):
 def visibility_options(activity, user):
     choices = activity.visibility_choices_for(user)
     return json.dumps(choices)
+
+
+@register.filter
+def source_type(value):
+    if value and "submission" in value:
+        return "Submission"
+    return str(value).capitalize()
diff --git a/hypha/apply/activity/urls.py b/hypha/apply/activity/urls.py
index 19c0855275d45f3e4ee2837471121ea044a2d764..4ba4a55f802e7aea772d0985530b43e7576a69ee 100644
--- a/hypha/apply/activity/urls.py
+++ b/hypha/apply/activity/urls.py
@@ -1,8 +1,11 @@
 from django.urls import include, path
 
+from .views import NotificationsView
+
 app_name = 'activity'
 
 
 urlpatterns = [
     path('anymail/', include('anymail.urls')),
+    path('notifications/', NotificationsView.as_view(), name='notifications')
 ]
diff --git a/hypha/apply/activity/views.py b/hypha/apply/activity/views.py
index 7b75221f084be8092a1fbf1062a7b649c4cf138e..0af55e2b554adbd9aa64bce00b9415388a0cdf3c 100644
--- a/hypha/apply/activity/views.py
+++ b/hypha/apply/activity/views.py
@@ -1,8 +1,11 @@
 from django.utils import timezone
-from django.views.generic import CreateView
+from django.utils.decorators import method_decorator
+from django.views.generic import CreateView, ListView
 
+from hypha.apply.users.decorators import staff_required
 from hypha.apply.utils.views import DelegatedViewMixin
 
+from .filters import NotificationFilter
 from .forms import CommentForm
 from .messaging import MESSAGES, messenger
 from .models import COMMENT, Activity
@@ -57,3 +60,21 @@ class CommentFormView(DelegatedViewMixin, CreateView):
         kwargs = super().get_form_kwargs()
         kwargs.pop('instance')
         return kwargs
+
+
+@method_decorator(staff_required, name='dispatch')
+class NotificationsView(ListView):
+    model = Activity
+    template_name = 'activity/notifications.html'
+    filterset_class = NotificationFilter
+
+    def get_queryset(self):
+        # List only last 30 days' activities
+        queryset = Activity.objects.latest()
+        self.filterset = self.filterset_class(self.request.GET, queryset=queryset)
+        return self.filterset.qs.distinct().order_by('-timestamp')
+
+    def get_context_data(self, *, object_list=None, **kwargs):
+        context = super(NotificationsView, self).get_context_data()
+        context['filter'] = self.filterset
+        return context
diff --git a/hypha/settings/base.py b/hypha/settings/base.py
index 07e5af2b9dc97fad7fbfc133c753e5d03903e143..7524adc3ed3fff2b1c147312881f99f6209d6386 100644
--- a/hypha/settings/base.py
+++ b/hypha/settings/base.py
@@ -179,6 +179,7 @@ TEMPLATES = [
                 'social_django.context_processors.login_redirect',
                 'hypha.apply.projects.context_processors.projects_enabled',
                 'hypha.cookieconsent.context_processors.cookies_accepted',
+                'hypha.apply.activity.context_processors.notification_context',
             ],
         },
     },
diff --git a/hypha/static_src/src/javascript/apply/notifications.js b/hypha/static_src/src/javascript/apply/notifications.js
new file mode 100644
index 0000000000000000000000000000000000000000..a24bcd16282a16723886992f228f7b78a8189d96
--- /dev/null
+++ b/hypha/static_src/src/javascript/apply/notifications.js
@@ -0,0 +1,21 @@
+(function () {
+
+    'use strict';
+
+    // Open/close dropdown when users clicks the bell.
+    document.querySelector('.notifications__bell').addEventListener('click', function () {
+        document.querySelector('.notifications__content').classList.toggle('hidden');
+    });
+
+    // Close the dropdown menu if the user clicks outside of it.
+    window.onclick = function (event) {
+        if (!event.target.matches('.notifications--dropdown, .notifications--dropdown *')) {
+            const dropdown = document.querySelector('.notifications__content');
+            if (!dropdown.classList.contains('hidden')) {
+                dropdown.classList.add('hidden');
+            }
+        }
+    };
+
+
+})();
diff --git a/hypha/static_src/src/sass/apply/components/_activity-notifications.scss b/hypha/static_src/src/sass/apply/components/_activity-notifications.scss
new file mode 100644
index 0000000000000000000000000000000000000000..132a6f3739624909f37c61c1aec06c40cf12ff5c
--- /dev/null
+++ b/hypha/static_src/src/sass/apply/components/_activity-notifications.scss
@@ -0,0 +1,54 @@
+.notifications {
+    &--dropdown {
+        position: relative;
+        display: inline-block;
+        z-index: 200;
+    }
+
+    &__bell {
+        padding: 7px 12px;
+        cursor: pointer;
+    }
+
+    &__content {
+        position: absolute;
+        right: 1em;
+        padding: 1em;
+        margin-top: .5em;
+        background-color: $color--light-grey;
+        min-width: 400px;
+        box-shadow: 2px 2px 6px 1px $color--dark-grey;
+    }
+
+    &__item {
+        padding-bottom: 1em;
+        border-bottom: 1px solid $color--dark-grey;
+    }
+
+    &__more {
+        text-align: center;
+        font-weight: $weight--semibold;
+    }
+
+    &__filters {
+        display: flex;
+        align-items: center;
+        padding: 4px;
+        justify-content: space-between;
+
+        label {
+            font-weight: $weight--semibold;
+            padding-right: 1em;
+        }
+
+        select {
+            padding-right: 1em;
+        }
+
+        .form {
+            &__select {
+                margin-right: 1em;
+            }
+        }
+    }
+}
diff --git a/hypha/static_src/src/sass/apply/components/_feed.scss b/hypha/static_src/src/sass/apply/components/_feed.scss
index 881f1f7366ca0fe62684aed28299d765d4ca500e..83d342d4b649be9649f3864790c004b368c1cb52 100644
--- a/hypha/static_src/src/sass/apply/components/_feed.scss
+++ b/hypha/static_src/src/sass/apply/components/_feed.scss
@@ -52,6 +52,14 @@
             background-color: $color--mint;
         }
 
+        &--submission {
+            background-color: $color--green;
+        }
+
+        &--project {
+            background-color: $color--mint;
+        }
+
         &--mobile {
             display: block;
             margin-right: 10px;
@@ -152,6 +160,8 @@
     }
 
     &__related-item {
+        white-space: nowrap;
+
         svg {
             width: 10px;
             height: 14px;
diff --git a/hypha/static_src/src/sass/apply/main.scss b/hypha/static_src/src/sass/apply/main.scss
index 150d659960e74af3bfc4b8da72db452846c236db..c0a9ee4695a03f7b752a13e6e2885f2ef8a5329e 100644
--- a/hypha/static_src/src/sass/apply/main.scss
+++ b/hypha/static_src/src/sass/apply/main.scss
@@ -68,6 +68,7 @@
 @import 'components/reminder-sidebar';
 @import 'components/two-factor';
 @import 'components/determination';
+@import 'components/activity-notifications';
 
 // Layout
 @import 'layout/header';
diff --git a/hypha/templates/base-apply.html b/hypha/templates/base-apply.html
index 33f22e725619cd2612d509ed6b8ef55fdaa7d3b1..ce30affbfe32ab0159909b4e437e530651f3c3f1 100644
--- a/hypha/templates/base-apply.html
+++ b/hypha/templates/base-apply.html
@@ -30,6 +30,9 @@
         <script src="{% static 'js/jquery.min.js' %}"></script>
         <script src="{% static 'js/js.cookie.min.js' %}"></script>
         <script src="{% static 'js/main-top.js' %}"></script>
+        {% if latest_notifications %}
+        <script defer src="{% static 'js/apply/notifications.js' %}"></script>
+        {% endif %}
         {% if COOKIES_ACCEPTED and MATOMO_URL and MATOMO_SITEID %}
         {# we are only expecting strings, so make sure we escape the values #}
         <script>
@@ -104,6 +107,9 @@
                 </section>
 
                 <div class="header__button-container">
+                    {% if latest_notifications %}
+                        {% include "activity/include/notifications_dropdown.html" %}
+                    {% endif %}
                     <a href="{% url 'users:account' %}" class="button button--transparent button--narrow button--contains-icons">
                         <svg class="icon icon--person"><use xlink:href="#person-icon"></use></svg>
                         {{ request.user }}
diff --git a/hypha/templates/includes/sprites.html b/hypha/templates/includes/sprites.html
index dbd3555ac3bc152ae8e659e76d767b12d7d20373..ed6584bc88c0f78eb1e250d10e41e6fb3f2cb877 100644
--- a/hypha/templates/includes/sprites.html
+++ b/hypha/templates/includes/sprites.html
@@ -119,6 +119,10 @@
         <path d="M17 9.81V16h-3.644v-5.776c0-1.45-.527-2.441-1.846-2.441-1.006 0-1.605.667-1.87 1.313-.095.23-.12.552-.12.875V16H5.875s.05-9.782 0-10.796H9.52v1.53l-.024.035h.024v-.035c.484-.734 1.349-1.783 3.284-1.783C15.202 4.95 17 6.494 17 9.81zM2.062 0C.816 0 0 .806 0 1.865 0 2.9.792 3.73 2.014 3.73h.024c1.272 0 2.062-.83 2.062-1.866C4.076.805 3.31 0 2.062 0zM.216 16H3.86V5.204H.216V16z" fill-rule="nonzero" />
     </symbol>
 
+    <symbol id="bell-icon" viewBox="0 0 16 16">
+        <path d="M8 16a2 2 0 0 0 2-2H6a2 2 0 0 0 2 2zm.995-14.901a1 1 0 1 0-1.99 0A5.002 5.002 0 0 0 3 6c0 1.098-.5 6-2 7h14c-1.5-1-2-5.902-2-7 0-2.42-1.72-4.44-4.005-4.901z"/>
+    </symbol>
+
     <symbol id="arrow-head-pixels--transparent" viewBox="0 0 50 75">
         <g fill="#25AAE1" fill-rule="evenodd">
             <path opacity=".2" d="M0 50h25v25H0z" />