diff --git a/src/metabase/api/card.clj b/src/metabase/api/card.clj
index f08c958f891f39c38c1c5aacf6e996c77723be57..f2321d912a0895f5d5cc1b854705d728b5e45038 100644
--- a/src/metabase/api/card.clj
+++ b/src/metabase/api/card.clj
@@ -757,7 +757,10 @@ saved later when it is ready."
 
   (let [card (t2/select-one Card :id id)]
     (delete-alerts-if-needed! card-before-update card)
-    (events/publish-event! :event/card-update {:object card :user-id api/*current-user-id*})
+    ;; skip publishing the event if it's just a change in its collection position
+    (when-not (= #{:collection_position}
+                 (set (keys card-updates)))
+      (events/publish-event! :event/card-update {:object card :user-id api/*current-user-id*}))
     ;; include same information returned by GET /api/card/:id since frontend replaces the Card it currently
     ;; has with returned one -- See #4142
     (-> card
diff --git a/src/metabase/api/dashboard.clj b/src/metabase/api/dashboard.clj
index 21d4c6928c2c35ee691bd6f637a2e9efbd0eb289..33ad8abb906fc27155c61a0b5d9a799cc4275b07 100644
--- a/src/metabase/api/dashboard.clj
+++ b/src/metabase/api/dashboard.clj
@@ -607,7 +607,10 @@
                       (select-keys dashcards-changes-stats [:created-dashcards :deleted-dashcards]))))))
        true))
     (let [dashboard (t2/select-one :model/Dashboard id)]
-      (events/publish-event! :event/dashboard-update {:object dashboard :user-id api/*current-user-id*})
+      ;; skip publishing the event if it's just a change in its collection position
+      (when-not (= #{:collection_position}
+                   (set (keys dash-updates)))
+        (events/publish-event! :event/dashboard-update {:object dashboard :user-id api/*current-user-id*}))
       (track-dashcard-and-tab-events! dashboard @changes-stats)
       (-> (t2/hydrate dashboard [:collection :is_personal] [:dashcards :series] :tabs)
           (assoc :last-edit-info (last-edit/edit-information-for-user @api/*current-user*))))))