diff --git a/scipost/managers.py b/scipost/managers.py
index 8d698f4011d692b77452d0de652db8e234fe704f..c37902f85314e43c552eaf1285004f84a561b2fb 100644
--- a/scipost/managers.py
+++ b/scipost/managers.py
@@ -4,7 +4,7 @@ __license__ = "AGPL v3"
 
 from django.db import models
 from django.db.models import Count, Q
-from django.db.models.functions import Lower
+from django.db.models.functions import Concat, Lower
 from django.utils import timezone
 
 from .constants import NORMAL_CONTRIBUTOR, NEWLY_REGISTERED, AUTHORSHIP_CLAIM_PENDING
@@ -54,6 +54,15 @@ class ContributorQuerySet(models.QuerySet):
         """TODO: NEEDS UPDATE TO NEW FELLOWSHIP RELATIONS."""
         return self.filter(fellowships__isnull=False).distinct()
 
+    def potential_duplicates(self):
+        """
+        Returns only potential duplicate Contributors (as identified by first and
+        last names).
+        """
+        contribs = self.annotate(full_name=Concat('user__last_name', 'user__first_name')
+        ).values('full_name').annotate(nr_count=Count('full_name')).filter(nr_count__gt=1)
+        return contribs.order_by('user__last_name', 'user__first_name', '-id')
+
 
 class UnavailabilityPeriodManager(models.Manager):
     def today(self):
diff --git a/scipost/templates/scipost/contributor_duplicate_list.html b/scipost/templates/scipost/contributor_duplicate_list.html
new file mode 100644
index 0000000000000000000000000000000000000000..d348fbadcfc83e2034c763e9d4cd8384d1f6afe2
--- /dev/null
+++ b/scipost/templates/scipost/contributor_duplicate_list.html
@@ -0,0 +1,44 @@
+{% extends 'scipost/base.html' %}
+
+{% load bootstrap %}
+
+{% block breadcrumb_items %}
+    {{ block.super }}
+<span class="breadcrumb-item">Duplicates</span>
+{% endblock %}
+
+{% load scipost_extras %}
+
+{% block pagetitle %}: Contributor duplicates{% endblock pagetitle %}
+
+{% block content %}
+<div class="row">
+  <div class="col-12">
+    <h1 class="highlight">Potentially duplicate Contributors</h1>
+    {% if merge_form %}
+        <form action="{% url 'profiles:merge' %}" method="get">
+          {{ merge_form|bootstrap }}
+          <input class="btn btn-outline-secondary" type="submit" value="Check">
+        </form>
+    {% endif %}
+
+    <br>
+    <h3>All found duplicates</h3>
+    <ul>
+      {% for contrib_dup in object_list %}
+          <li>{{ contrib_dup }} (<em>id={{ contrib_dup.id }}</em>)</li>
+      {% empty %}
+          <li<em>No duplicates found</em></li>
+      {% endfor %}
+    </ul>
+
+    {% if is_paginated %}
+    <div class="col-12">
+      {% include 'partials/pagination.html' with page_obj=page_obj %}
+    </div>
+    {% endif %}
+
+  </div>
+</div>
+
+{% endblock content %}
diff --git a/scipost/urls.py b/scipost/urls.py
index e9c1f7f5742b1b7fda3a2739d85d2694d58bcb8c..94d958866a960a094e45ebf0f455c9850f4a4f84 100644
--- a/scipost/urls.py
+++ b/scipost/urls.py
@@ -158,6 +158,10 @@ urlpatterns = [
     url(r'^vet_authorship_claim/(?P<claim_id>[0-9]+)/(?P<claim>[0-1])$',
         views.vet_authorship_claim, name='vet_authorship_claim'),
 
+    # Potential duplicates
+    url(r'contributor_duplicates/$',
+        views.ContributorDuplicateListView.as_view(),
+        name='duplicates'),
 
     ####################
     # Email facilities #
diff --git a/scipost/views.py b/scipost/views.py
index f399522d10c023b8f955b3a33d7947329d5575f4..b9ad9f9abfb08211942aa8db500cbad7bc09382f 100644
--- a/scipost/views.py
+++ b/scipost/views.py
@@ -40,6 +40,7 @@ from .forms import (
     AuthenticationForm, UnavailabilityPeriodForm, RegistrationForm, AuthorshipClaimForm,
     SearchForm, VetRegistrationForm, reg_ref_dict, UpdatePersonalDataForm, UpdateUserDataForm,
     PasswordChangeForm, EmailGroupMembersForm, EmailParticularForm, SendPrecookedEmailForm)
+from .mixins import PermissionsMixin, PaginationMixin
 from .utils import Utils, EMAIL_FOOTER, SCIPOST_SUMMARY_FOOTER, SCIPOST_SUMMARY_FOOTER_HTML
 
 from affiliations.forms import AffiliationsFormset
@@ -958,6 +959,18 @@ def contributor_info(request, contributor_id):
     return render(request, 'scipost/contributor_info.html', context)
 
 
+class ContributorDuplicateListView(PermissionsMixin, PaginationMixin, ListView):
+    """
+    List Contributors with potential duplicates.
+    """
+    permission_required = 'scipost.can_vet_registration_requests'
+    model = Contributor
+    template_name = 'scipost/contributor_duplicate_list.html'
+
+    def get_queryset(self):
+        return Contributor.objects.potential_duplicates()
+
+
 ####################
 # Email facilities #
 ####################