diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9a6ba43a..baad4bde 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -69,6 +69,7 @@
 - Admin
     - Grey out legacy tables in the database view
     - Checkboxes renamed to Set statuses
+    - List of sets that may need to be refreshed
 
 - Cards
     - Use macros for badge in the card header
@@ -102,6 +103,7 @@
     - Collapsible controls depending on screen size
     - Manually collapsible filters (with configuration variable for default state)
     - Manually collapsible sort (with configuration variable for default state)
+    - Clear search bar
 
 - Storage
     - Storage list
diff --git a/bricktracker/app.py b/bricktracker/app.py
index f0afe429..b4aad9eb 100644
--- a/bricktracker/app.py
+++ b/bricktracker/app.py
@@ -19,6 +19,7 @@ from bricktracker.views.admin.instructions import admin_instructions_page
 from bricktracker.views.admin.owner import admin_owner_page
 from bricktracker.views.admin.purchase_location import admin_purchase_location_page  # noqa: E501
 from bricktracker.views.admin.retired import admin_retired_page
+from bricktracker.views.admin.set import admin_set_page
 from bricktracker.views.admin.status import admin_status_page
 from bricktracker.views.admin.storage import admin_storage_page
 from bricktracker.views.admin.tag import admin_tag_page
@@ -90,6 +91,7 @@ def setup_app(app: Flask) -> None:
     app.register_blueprint(admin_retired_page)
     app.register_blueprint(admin_owner_page)
     app.register_blueprint(admin_purchase_location_page)
+    app.register_blueprint(admin_set_page)
     app.register_blueprint(admin_status_page)
     app.register_blueprint(admin_storage_page)
     app.register_blueprint(admin_tag_page)
diff --git a/bricktracker/rebrickable_set.py b/bricktracker/rebrickable_set.py
index fbf10f1a..6beffc2b 100644
--- a/bricktracker/rebrickable_set.py
+++ b/bricktracker/rebrickable_set.py
@@ -1,9 +1,9 @@
 import logging
 from sqlite3 import Row
 import traceback
-from typing import Any, TYPE_CHECKING
+from typing import Any, Self, TYPE_CHECKING
 
-from flask import current_app
+from flask import current_app, url_for
 
 from .exceptions import ErrorException, NotFoundException
 from .instructions import BrickInstructions
@@ -138,6 +138,21 @@ class RebrickableSet(BrickRecord):
 
         return False
 
+    # Select a specific set (with a set)
+    def select_specific(self, set: str, /) -> Self:
+        # Save the parameters to the fields
+        self.fields.set = set
+
+        # Load from database
+        if not self.select():
+            raise NotFoundException(
+                'Set with set {set} was not found in the database'.format(
+                    set=self.fields.set,
+                ),
+            )
+
+        return self
+
     # Return a short form of the Rebrickable set
     def short(self, /, *, from_download: bool = False) -> dict[str, Any]:
         return {
@@ -164,6 +179,10 @@ class RebrickableSet(BrickRecord):
 
         return ''
 
+    # Compute the url for the refresh button
+    def url_for_refresh(self, /) -> str:
+        return url_for('set.refresh', set=self.fields.set)
+
     # Normalize from Rebrickable
     @staticmethod
     def from_rebrickable(data: dict[str, Any], /, **_) -> dict[str, Any]:
diff --git a/bricktracker/rebrickable_set_list.py b/bricktracker/rebrickable_set_list.py
index 8fe7ee92..0db84b76 100644
--- a/bricktracker/rebrickable_set_list.py
+++ b/bricktracker/rebrickable_set_list.py
@@ -9,6 +9,7 @@ class RebrickableSetList(BrickRecordList[RebrickableSet]):
 
     # Queries
     select_query: str = 'rebrickable/set/list'
+    refresh_query: str = 'rebrickable/set/need_refresh'
 
     # All the sets
     def all(self, /) -> Self:
@@ -19,3 +20,15 @@ class RebrickableSetList(BrickRecordList[RebrickableSet]):
             self.records.append(rebrickable_set)
 
         return self
+
+    # Sets needing refresh
+    def need_refresh(self, /) -> Self:
+        # Load the sets from the database
+        for record in self.select(
+            override_query=self.refresh_query
+        ):
+            rebrickable_set = RebrickableSet(record=record)
+
+            self.records.append(rebrickable_set)
+
+        return self
diff --git a/bricktracker/sql/rebrickable/set/need_refresh.sql b/bricktracker/sql/rebrickable/set/need_refresh.sql
new file mode 100644
index 00000000..8060a60c
--- /dev/null
+++ b/bricktracker/sql/rebrickable/set/need_refresh.sql
@@ -0,0 +1,53 @@
+SELECT
+    "rebrickable_sets"."set",
+    "rebrickable_sets"."name",
+    "rebrickable_sets"."number_of_parts",
+    "rebrickable_sets"."image",
+    "rebrickable_sets"."url",
+    "null_join"."null_rgb",
+    "null_join"."null_transparent",
+    "null_join"."null_url"
+FROM "rebrickable_sets"
+
+INNER JOIN (
+    SELECT
+        "null_sums"."set",
+        "null_sums"."null_rgb",
+        "null_sums"."null_transparent",
+        "null_sums"."null_url"
+    FROM (
+        SELECT
+            "unique_set_parts"."set",
+            SUM(CASE WHEN "unique_set_parts"."color_rgb" IS NULL THEN 1 ELSE 0 END) AS "null_rgb",
+            SUM(CASE WHEN "unique_set_parts"."color_transparent" IS NULL THEN 1 ELSE 0 END) AS "null_transparent",
+            SUM(CASE WHEN "unique_set_parts"."url" IS NULL THEN 1 ELSE 0 END) AS "null_url"
+        FROM (
+            SELECT
+                "bricktracker_sets"."set",
+                "rebrickable_parts"."color_rgb",
+                "rebrickable_parts"."color_transparent",
+                "rebrickable_parts"."url"
+            FROM "bricktracker_sets"
+
+            INNER JOIN "bricktracker_parts"
+            ON "bricktracker_sets"."id" IS NOT DISTINCT FROM "bricktracker_parts"."id"
+
+            LEFT JOIN "rebrickable_parts"
+            ON "bricktracker_parts"."part" IS NOT DISTINCT FROM "rebrickable_parts"."part"
+            AND "bricktracker_parts"."color" IS NOT DISTINCT FROM "rebrickable_parts"."color_id"
+
+            GROUP BY
+                "bricktracker_sets"."set",
+                "bricktracker_parts"."part",
+                "bricktracker_parts"."color"
+        ) "unique_set_parts"
+
+        GROUP BY "unique_set_parts"."set"
+
+    ) "null_sums"
+
+    WHERE "null_rgb" > 0
+    OR "null_transparent" > 0
+    OR "null_url" > 0
+) "null_join"
+ON "rebrickable_sets"."set" IS NOT DISTINCT FROM "null_join"."set"
diff --git a/bricktracker/sql_counter.py b/bricktracker/sql_counter.py
index e5b92624..4d7a61e8 100644
--- a/bricktracker/sql_counter.py
+++ b/bricktracker/sql_counter.py
@@ -10,11 +10,12 @@ ALIASES: dict[str, Tuple[str, str]] = {
     'bricktracker_minifigures': ('Bricktracker minifigures', 'group-line'),
     'bricktracker_parts': ('Bricktracker parts', 'shapes-line'),
     'bricktracker_set_checkboxes': ('Bricktracker set checkboxes (legacy)', 'checkbox-line'),  # noqa: E501
-    'bricktracker_set_owners': ('Bricktracker set owners', 'checkbox-line'),  # noqa: E501
-    'bricktracker_set_statuses': ('Bricktracker set statuses', 'user-line'),  # noqa: E501
-    'bricktracker_set_tags': ('Bricktracker set tags', 'price-tag-2-line'),  # noqa: E501
+    'bricktracker_set_owners': ('Bricktracker set owners', 'checkbox-line'),
+    'bricktracker_set_statuses': ('Bricktracker set statuses', 'user-line'),
+    'bricktracker_set_tags': ('Bricktracker set tags', 'price-tag-2-line'),
     'bricktracker_sets': ('Bricktracker sets', 'hashtag'),
     'bricktracker_wishes': ('Bricktracker wishes', 'gift-line'),
+    'bricktracker_wish_owners': ('Bricktracker wish owners', 'checkbox-line'),
     'inventory': ('Parts', 'shapes-line'),
     'inventory_old': ('Parts (legacy)', 'shapes-line'),
     'minifigures': ('Minifigures', 'group-line'),
diff --git a/bricktracker/views/admin/set.py b/bricktracker/views/admin/set.py
new file mode 100644
index 00000000..6f00910c
--- /dev/null
+++ b/bricktracker/views/admin/set.py
@@ -0,0 +1,20 @@
+from flask import Blueprint, render_template, request
+from flask_login import login_required
+
+from ..exceptions import exception_handler
+from ...rebrickable_set_list import RebrickableSetList
+
+admin_set_page = Blueprint('admin_set',  __name__, url_prefix='/admin/set')
+
+
+# Sets that need o be refreshed
+@admin_set_page.route('/refresh', methods=['GET'])
+@login_required
+@exception_handler(__file__)
+def refresh() -> str:
+    return render_template(
+        'admin.html',
+        refresh_set=True,
+        table_collection=RebrickableSetList().need_refresh(),
+        set_error=request.args.get('set_error')
+    )
diff --git a/bricktracker/views/set.py b/bricktracker/views/set.py
index bb9e845c..1ffec550 100644
--- a/bricktracker/views/set.py
+++ b/bricktracker/views/set.py
@@ -13,8 +13,10 @@ from flask_login import login_required
 from werkzeug.wrappers.response import Response
 
 from .exceptions import exception_handler
+from ..exceptions import ErrorException
 from ..minifigure import BrickMinifigure
 from ..part import BrickPart
+from ..rebrickable_set import RebrickableSet
 from ..set import BrickSet
 from ..set_list import BrickSetList, set_metadata_lists
 from ..set_owner_list import BrickSetOwnerList
@@ -241,13 +243,22 @@ def problem_part(
 
 
 # Refresh a set
+@set_page.route('/refresh/<set>/', methods=['GET'])
 @set_page.route('/<id>/refresh', methods=['GET'])
 @login_required
 @exception_handler(__file__)
-def refresh(*, id: str) -> str:
+def refresh(*, id: str | None = None, set: str | None = None) -> str:
+    if id is not None:
+        item = BrickSet().select_specific(id)
+    elif set is not None:
+        item = RebrickableSet().select_specific(set)
+    else:
+        raise ErrorException('Could not load any set to refresh')
+
     return render_template(
         'refresh.html',
-        item=BrickSet().select_specific(id),
+        id=id,
+        item=item,
         path=current_app.config['SOCKET_PATH'],
         namespace=current_app.config['SOCKET_NAMESPACE'],
         messages=MESSAGES
diff --git a/templates/admin.html b/templates/admin.html
index 87dbdb4a..2da5000d 100644
--- a/templates/admin.html
+++ b/templates/admin.html
@@ -32,6 +32,8 @@
             {% include 'admin/database/import.html' %}
             {% elif upgrade_database %}
             {% include 'admin/database/upgrade.html' %}
+            {% elif refresh_set %}
+            {% include 'admin/set/refresh.html' %}
             {% else %}
               {% include 'admin/logout.html' %}
               {% include 'admin/instructions.html' %}
@@ -47,6 +49,7 @@
                 {% include 'admin/storage.html' %}
                 {% include 'admin/tag.html' %}
               {{ accordion.footer() }}
+              {% include 'admin/refresh.html' %}
               {% include 'admin/database.html' %}
               {% include 'admin/configuration.html' %}
             {% endif %}
diff --git a/templates/admin/refresh.html b/templates/admin/refresh.html
new file mode 100644
index 00000000..ab81cc82
--- /dev/null
+++ b/templates/admin/refresh.html
@@ -0,0 +1,5 @@
+{% import 'macro/accordion.html' as accordion %}
+
+{{ accordion.header('Set refresh', 'refresh', 'admin', icon='refresh-line') }}
+<a href="{{ url_for('admin_set.refresh') }}" class="btn btn-primary" role="button"><i class="ri-refresh-line"></i> Check for sets that may need a refresh</a>
+{{ accordion.footer() }}
diff --git a/templates/admin/set/refresh.html b/templates/admin/set/refresh.html
new file mode 100644
index 00000000..0f4befcc
--- /dev/null
+++ b/templates/admin/set/refresh.html
@@ -0,0 +1,34 @@
+{% import 'macro/table.html' as table %}
+{% import 'macro/badge.html' as badge %}
+
+<div class="alert alert-info m-2" role="alert">This page lists the sets that may need a refresh because they have some of their newer fields containing empty values.</div>
+<div class="table-responsive-sm">
+  <table data-table="true" class="table table-striped align-middle" id="wish">
+    <thead>
+      <tr>
+        <th data-table-no-sort-and-search="true" class="no-sort" scope="col"><i class="ri-image-line fw-normal"></i> Image</th>
+        <th scope="col"><i class="ri-hashtag fw-normal"></i> Set</th>
+        <th scope="col"><i class="ri-pencil-line fw-normal"></i> Name</th>
+        <th scope="col"><i class="ri-shapes-line fw-normal"></i> Parts</th>
+        <th data-table-number="true" scope="col"><i class="ri-error-warning-line fw-normal"></i> Empty RGB</th>
+        <th data-table-number="true" scope="col"><i class="ri-error-warning-line fw-normal"></i> Empty transparent</th>
+        <th data-table-number="true" scope="col"><i class="ri-error-warning-line fw-normal"></i> Empty URL</th>
+        <th data-table-no-sort-and-search="true" class="no-sort" scope="col"><i class="ri-settings-4-line fw-normal"></i> Actions</th>
+      </tr>
+    </thead>
+    <tbody>
+      {% for item in table_collection %}
+        <tr>
+          {{ table.image(item.url_for_image(), caption=item.fields.name, alt=item.fields.set) }}
+          <td>{{ item.fields.set }} {{ table.rebrickable(item) }}</td>
+          <td>{{ item.fields.name }}</td>
+          <td>{{ item.fields.number_of_parts }}</td>
+          <td>{{ item.fields.null_rgb }}</td>
+          <td>{{ item.fields.null_transparent }}</td>
+          <td>{{ item.fields.null_url }}</td>
+          <td><a href="{{ item.url_for_refresh() }}" class="btn btn-primary" role="button"><i class="ri-refresh-line"></i> Refresh</a></td>
+        </tr>
+      {% endfor %}
+    </tbody>
+  </table>
+</div>
\ No newline at end of file
diff --git a/templates/refresh.html b/templates/refresh.html
index 5add93d8..3a9804de 100644
--- a/templates/refresh.html
+++ b/templates/refresh.html
@@ -51,7 +51,11 @@
         </div>
         <div class="card-footer text-end">
           <span id="refresh-status-icon" class="me-1"></span><span id="refresh-status" class="me-1"></span>
-          <a href="{{ url_for('set.details', id=item.fields.id) }}" class="btn btn-primary" role="button"><i class="ri-hashtag"></i> Back to the set details</a>
+          {% if id %}
+            <a href="{{ url_for('set.details', id=item.fields.id) }}" class="btn btn-primary" role="button"><i class="ri-hashtag"></i> Back to the set details</a>
+            {% else %}
+            <a href="{{ url_for('admin_set.refresh') }}" class="btn btn-danger" role="button"><i class="ri-hashtag"></i> List of sets to be refreshed</a>
+          {% endif %}
           <button id="refresh" type="button" class="btn btn-primary"><i class="ri-refresh-line"></i> Refresh</button>
         </div>
       </div>