diff --git a/Configuration/UserConfig.cs b/Configuration/UserConfig.cs
index d14320eb..1344818d 100644
--- a/Configuration/UserConfig.cs
+++ b/Configuration/UserConfig.cs
@@ -26,6 +26,7 @@ sealed class UserConfig : BaseConfig<UserConfig>, IAppUserConfiguration {
 		public bool KeepLikeFollowDialogsOpen { get; set; } = true;
 		public bool BestImageQuality          { get; set; } = true;
 		public bool EnableAnimatedImages      { get; set; } = true;
+		public bool HideTweetsByNftUsers      { get; set; } = false;
 
 		private bool _enableSmoothScrolling = true;
 		private string _customCefArgs       = null;
diff --git a/Dialogs/FormSettings.cs b/Dialogs/FormSettings.cs
index 368eab3d..a651a263 100644
--- a/Dialogs/FormSettings.cs
+++ b/Dialogs/FormSettings.cs
@@ -40,7 +40,7 @@ public FormSettings(FormBrowser browser, PluginManager plugins, UpdateChecker up
 
 			PrepareLoad();
 
-			AddButton("General", () => new TabSettingsGeneral(tweetDeckFunctions.ReloadColumns, updates));
+			AddButton("General", () => new TabSettingsGeneral(this.browser.ReloadToTweetDeck, tweetDeckFunctions.ReloadColumns, updates));
 			AddButton("Notifications", () => new TabSettingsNotifications(this.browser.CreateExampleNotification()));
 			AddButton("Sounds", () => new TabSettingsSounds(() => tweetDeckFunctions.PlaySoundNotification(true)));
 			AddButton("Tray", () => new TabSettingsTray());
diff --git a/Dialogs/Settings/TabSettingsGeneral.Designer.cs b/Dialogs/Settings/TabSettingsGeneral.Designer.cs
index 92f64a0b..a6a4f01f 100644
--- a/Dialogs/Settings/TabSettingsGeneral.Designer.cs
+++ b/Dialogs/Settings/TabSettingsGeneral.Designer.cs
@@ -42,6 +42,8 @@ private void InitializeComponent() {
             this.checkFocusDmInput = new System.Windows.Forms.CheckBox();
             this.checkKeepLikeFollowDialogsOpen = new System.Windows.Forms.CheckBox();
             this.checkSmoothScrolling = new System.Windows.Forms.CheckBox();
+            this.labelTweetDeckSettings = new System.Windows.Forms.Label();
+            this.checkHideTweetsByNftUsers = new System.Windows.Forms.CheckBox();
             this.labelBrowserPath = new System.Windows.Forms.Label();
             this.comboBoxCustomBrowser = new System.Windows.Forms.ComboBox();
             this.labelSearchEngine = new System.Windows.Forms.Label();
@@ -87,11 +89,11 @@ private void InitializeComponent() {
             // 
             this.checkUpdateNotifications.AutoSize = true;
             this.checkUpdateNotifications.Font = new System.Drawing.Font("Segoe UI", 9F);
-            this.checkUpdateNotifications.Location = new System.Drawing.Point(6, 307);
+            this.checkUpdateNotifications.Location = new System.Drawing.Point(6, 381);
             this.checkUpdateNotifications.Margin = new System.Windows.Forms.Padding(6, 6, 3, 2);
             this.checkUpdateNotifications.Name = "checkUpdateNotifications";
             this.checkUpdateNotifications.Size = new System.Drawing.Size(182, 19);
-            this.checkUpdateNotifications.TabIndex = 11;
+            this.checkUpdateNotifications.TabIndex = 13;
             this.checkUpdateNotifications.Text = "Check Updates Automatically";
             this.checkUpdateNotifications.UseVisualStyleBackColor = true;
             // 
@@ -99,12 +101,12 @@ private void InitializeComponent() {
             // 
             this.btnCheckUpdates.AutoSize = true;
             this.btnCheckUpdates.Font = new System.Drawing.Font("Segoe UI", 9F);
-            this.btnCheckUpdates.Location = new System.Drawing.Point(5, 331);
+            this.btnCheckUpdates.Location = new System.Drawing.Point(5, 405);
             this.btnCheckUpdates.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3);
             this.btnCheckUpdates.Name = "btnCheckUpdates";
             this.btnCheckUpdates.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
             this.btnCheckUpdates.Size = new System.Drawing.Size(128, 25);
-            this.btnCheckUpdates.TabIndex = 12;
+            this.btnCheckUpdates.TabIndex = 14;
             this.btnCheckUpdates.Text = "Check Updates Now";
             this.btnCheckUpdates.UseVisualStyleBackColor = true;
             // 
@@ -124,12 +126,12 @@ private void InitializeComponent() {
             // 
             this.checkBestImageQuality.AutoSize = true;
             this.checkBestImageQuality.Font = new System.Drawing.Font("Segoe UI", 9F);
-            this.checkBestImageQuality.Location = new System.Drawing.Point(6, 122);
-            this.checkBestImageQuality.Margin = new System.Windows.Forms.Padding(6, 3, 3, 2);
+            this.checkBestImageQuality.Location = new System.Drawing.Point(6, 259);
+            this.checkBestImageQuality.Margin = new System.Windows.Forms.Padding(6, 6, 3, 2);
             this.checkBestImageQuality.Name = "checkBestImageQuality";
-            this.checkBestImageQuality.Size = new System.Drawing.Size(125, 19);
-            this.checkBestImageQuality.TabIndex = 5;
-            this.checkBestImageQuality.Text = "Best Image Quality";
+            this.checkBestImageQuality.Size = new System.Drawing.Size(182, 19);
+            this.checkBestImageQuality.TabIndex = 9;
+            this.checkBestImageQuality.Text = "Download Best Image Quality";
             this.checkBestImageQuality.UseVisualStyleBackColor = true;
             // 
             // checkOpenSearchInFirstColumn
@@ -163,11 +165,11 @@ private void InitializeComponent() {
             // 
             this.labelZoom.AutoSize = true;
             this.labelZoom.Font = new System.Drawing.Font("Segoe UI Semibold", 9F, System.Drawing.FontStyle.Bold);
-            this.labelZoom.Location = new System.Drawing.Point(3, 203);
+            this.labelZoom.Location = new System.Drawing.Point(3, 155);
             this.labelZoom.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
             this.labelZoom.Name = "labelZoom";
             this.labelZoom.Size = new System.Drawing.Size(39, 15);
-            this.labelZoom.TabIndex = 8;
+            this.labelZoom.TabIndex = 6;
             this.labelZoom.Text = "Zoom";
             // 
             // zoomUpdateTimer
@@ -179,21 +181,21 @@ private void InitializeComponent() {
             // 
             this.panelZoom.Controls.Add(this.trackBarZoom);
             this.panelZoom.Controls.Add(this.labelZoomValue);
-            this.panelZoom.Location = new System.Drawing.Point(0, 219);
+            this.panelZoom.Location = new System.Drawing.Point(0, 171);
             this.panelZoom.Margin = new System.Windows.Forms.Padding(0, 1, 0, 0);
             this.panelZoom.Name = "panelZoom";
             this.panelZoom.Size = new System.Drawing.Size(300, 35);
-            this.panelZoom.TabIndex = 9;
+            this.panelZoom.TabIndex = 7;
             // 
             // checkAnimatedAvatars
             // 
             this.checkAnimatedAvatars.AutoSize = true;
             this.checkAnimatedAvatars.Font = new System.Drawing.Font("Segoe UI", 9F);
-            this.checkAnimatedAvatars.Location = new System.Drawing.Point(6, 146);
+            this.checkAnimatedAvatars.Location = new System.Drawing.Point(6, 307);
             this.checkAnimatedAvatars.Margin = new System.Windows.Forms.Padding(6, 3, 3, 2);
             this.checkAnimatedAvatars.Name = "checkAnimatedAvatars";
             this.checkAnimatedAvatars.Size = new System.Drawing.Size(158, 19);
-            this.checkAnimatedAvatars.TabIndex = 6;
+            this.checkAnimatedAvatars.TabIndex = 11;
             this.checkAnimatedAvatars.Text = "Enable Animated Avatars";
             this.checkAnimatedAvatars.UseVisualStyleBackColor = true;
             // 
@@ -201,11 +203,11 @@ private void InitializeComponent() {
             // 
             this.labelUpdates.AutoSize = true;
             this.labelUpdates.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
-            this.labelUpdates.Location = new System.Drawing.Point(0, 281);
+            this.labelUpdates.Location = new System.Drawing.Point(0, 355);
             this.labelUpdates.Margin = new System.Windows.Forms.Padding(0, 27, 0, 1);
             this.labelUpdates.Name = "labelUpdates";
             this.labelUpdates.Size = new System.Drawing.Size(69, 19);
-            this.labelUpdates.TabIndex = 10;
+            this.labelUpdates.TabIndex = 12;
             this.labelUpdates.Text = "UPDATES";
             // 
             // flowPanelLeft
@@ -217,11 +219,13 @@ private void InitializeComponent() {
             this.flowPanelLeft.Controls.Add(this.checkFocusDmInput);
             this.flowPanelLeft.Controls.Add(this.checkOpenSearchInFirstColumn);
             this.flowPanelLeft.Controls.Add(this.checkKeepLikeFollowDialogsOpen);
-            this.flowPanelLeft.Controls.Add(this.checkBestImageQuality);
-            this.flowPanelLeft.Controls.Add(this.checkAnimatedAvatars);
             this.flowPanelLeft.Controls.Add(this.checkSmoothScrolling);
             this.flowPanelLeft.Controls.Add(this.labelZoom);
             this.flowPanelLeft.Controls.Add(this.panelZoom);
+            this.flowPanelLeft.Controls.Add(this.labelTweetDeckSettings);
+            this.flowPanelLeft.Controls.Add(this.checkBestImageQuality);
+            this.flowPanelLeft.Controls.Add(this.checkHideTweetsByNftUsers);
+            this.flowPanelLeft.Controls.Add(this.checkAnimatedAvatars);
             this.flowPanelLeft.Controls.Add(this.labelUpdates);
             this.flowPanelLeft.Controls.Add(this.checkUpdateNotifications);
             this.flowPanelLeft.Controls.Add(this.btnCheckUpdates);
@@ -271,14 +275,37 @@ private void InitializeComponent() {
             // 
             this.checkSmoothScrolling.AutoSize = true;
             this.checkSmoothScrolling.Font = new System.Drawing.Font("Segoe UI", 9F);
-            this.checkSmoothScrolling.Location = new System.Drawing.Point(6, 170);
+            this.checkSmoothScrolling.Location = new System.Drawing.Point(6, 122);
             this.checkSmoothScrolling.Margin = new System.Windows.Forms.Padding(6, 3, 3, 2);
             this.checkSmoothScrolling.Name = "checkSmoothScrolling";
             this.checkSmoothScrolling.Size = new System.Drawing.Size(117, 19);
-            this.checkSmoothScrolling.TabIndex = 7;
+            this.checkSmoothScrolling.TabIndex = 5;
             this.checkSmoothScrolling.Text = "Smooth Scrolling";
             this.checkSmoothScrolling.UseVisualStyleBackColor = true;
             // 
+            // labelTweetDeckSettings
+            // 
+            this.labelTweetDeckSettings.AutoSize = true;
+            this.labelTweetDeckSettings.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
+            this.labelTweetDeckSettings.Location = new System.Drawing.Point(0, 233);
+            this.labelTweetDeckSettings.Margin = new System.Windows.Forms.Padding(0, 27, 0, 1);
+            this.labelTweetDeckSettings.Name = "labelTweetDeckSettings";
+            this.labelTweetDeckSettings.Size = new System.Drawing.Size(67, 19);
+            this.labelTweetDeckSettings.TabIndex = 8;
+            this.labelTweetDeckSettings.Text = "TWITTER";
+            // 
+            // checkHideTweetsByNftUsers
+            // 
+            this.checkHideTweetsByNftUsers.AutoSize = true;
+            this.checkHideTweetsByNftUsers.Font = new System.Drawing.Font("Segoe UI", 9F);
+            this.checkHideTweetsByNftUsers.Location = new System.Drawing.Point(6, 283);
+            this.checkHideTweetsByNftUsers.Margin = new System.Windows.Forms.Padding(6, 3, 3, 2);
+            this.checkHideTweetsByNftUsers.Name = "checkHideTweetsByNftUsers";
+            this.checkHideTweetsByNftUsers.Size = new System.Drawing.Size(231, 19);
+            this.checkHideTweetsByNftUsers.TabIndex = 10;
+            this.checkHideTweetsByNftUsers.Text = "Hide Tweets by Users with NFT Avatars";
+            this.checkHideTweetsByNftUsers.UseVisualStyleBackColor = true;
+            // 
             // labelBrowserPath
             // 
             this.labelBrowserPath.AutoSize = true;
@@ -594,5 +621,7 @@ private void InitializeComponent() {
         private System.Windows.Forms.Label labelFirstDayOfWeek;
         private System.Windows.Forms.ComboBox comboBoxFirstDayOfWeek;
         private System.Windows.Forms.Label labelUI;
+        private System.Windows.Forms.CheckBox checkHideTweetsByNftUsers;
+        private System.Windows.Forms.Label labelTweetDeckSettings;
     }
 }
diff --git a/Dialogs/Settings/TabSettingsGeneral.cs b/Dialogs/Settings/TabSettingsGeneral.cs
index 7f608e2d..d2687e21 100644
--- a/Dialogs/Settings/TabSettingsGeneral.cs
+++ b/Dialogs/Settings/TabSettingsGeneral.cs
@@ -13,6 +13,7 @@
 
 namespace TweetDuck.Dialogs.Settings {
 	sealed partial class TabSettingsGeneral : FormSettings.BaseTab {
+		private readonly Action reloadTweetDeck;
 		private readonly Action reloadColumns;
 
 		private readonly UpdateChecker updates;
@@ -27,9 +28,10 @@ sealed partial class TabSettingsGeneral : FormSettings.BaseTab {
 		private readonly int searchEngineIndexDefault;
 		private readonly int searchEngineIndexCustom;
 
-		public TabSettingsGeneral(Action reloadColumns, UpdateChecker updates) {
+		public TabSettingsGeneral(Action reloadTweetDeck, Action reloadColumns, UpdateChecker updates) {
 			InitializeComponent();
 
+			this.reloadTweetDeck = reloadTweetDeck;
 			this.reloadColumns = reloadColumns;
 
 			this.updates = updates;
@@ -43,8 +45,6 @@ public TabSettingsGeneral(Action reloadColumns, UpdateChecker updates) {
 			toolTip.SetToolTip(checkFocusDmInput, "Places cursor into Direct Message input\r\nfield when opening a conversation.");
 			toolTip.SetToolTip(checkOpenSearchInFirstColumn, "By default, TweetDeck adds Search columns at the end.\r\nThis option makes them appear before the first column instead.");
 			toolTip.SetToolTip(checkKeepLikeFollowDialogsOpen, "Allows liking and following from multiple accounts at once,\r\ninstead of automatically closing the dialog after taking an action.");
-			toolTip.SetToolTip(checkBestImageQuality, "When right-clicking a tweet image, the context menu options\r\nwill use links to the original image size (:orig in the URL).");
-			toolTip.SetToolTip(checkAnimatedAvatars, "Some old Twitter avatars could be uploaded as animated GIFs.");
 			toolTip.SetToolTip(checkSmoothScrolling, "Toggles smooth mouse wheel scrolling.");
 			toolTip.SetToolTip(labelZoomValue, "Changes the zoom level.\r\nAlso affects notifications and screenshots.");
 			toolTip.SetToolTip(trackBarZoom, toolTip.GetToolTip(labelZoomValue));
@@ -53,13 +53,21 @@ public TabSettingsGeneral(Action reloadColumns, UpdateChecker updates) {
 			checkFocusDmInput.Checked = Config.FocusDmInput;
 			checkOpenSearchInFirstColumn.Checked = Config.OpenSearchInFirstColumn;
 			checkKeepLikeFollowDialogsOpen.Checked = Config.KeepLikeFollowDialogsOpen;
-			checkBestImageQuality.Checked = Config.BestImageQuality;
-			checkAnimatedAvatars.Checked = Config.EnableAnimatedImages;
 			checkSmoothScrolling.Checked = Config.EnableSmoothScrolling;
 
 			trackBarZoom.SetValueSafe(Config.ZoomLevel);
 			labelZoomValue.Text = trackBarZoom.Value + "%";
 
+			// twitter
+
+			toolTip.SetToolTip(checkBestImageQuality, "When right-clicking a tweet image, the context menu options\r\nwill use links to the original image size (:orig in the URL).");
+			toolTip.SetToolTip(checkHideTweetsByNftUsers, "Hides tweets created by users who use Twitter's NFT avatar integration.\r\nThis feature is somewhat experimental, some accounts might not be detected immediately.");
+			toolTip.SetToolTip(checkAnimatedAvatars, "Some old Twitter avatars could be uploaded as animated GIFs.");
+
+			checkBestImageQuality.Checked = Config.BestImageQuality;
+			checkHideTweetsByNftUsers.Checked = Config.HideTweetsByNftUsers;
+			checkAnimatedAvatars.Checked = Config.EnableAnimatedImages;
+
 			// updates
 
 			toolTip.SetToolTip(checkUpdateNotifications, "Checks for updates every hour.\r\nIf an update is dismissed, it will not appear again.");
@@ -135,11 +143,13 @@ public override void OnReady() {
 			checkFocusDmInput.CheckedChanged += checkFocusDmInput_CheckedChanged;
 			checkOpenSearchInFirstColumn.CheckedChanged += checkOpenSearchInFirstColumn_CheckedChanged;
 			checkKeepLikeFollowDialogsOpen.CheckedChanged += checkKeepLikeFollowDialogsOpen_CheckedChanged;
-			checkBestImageQuality.CheckedChanged += checkBestImageQuality_CheckedChanged;
-			checkAnimatedAvatars.CheckedChanged += checkAnimatedAvatars_CheckedChanged;
 			checkSmoothScrolling.CheckedChanged += checkSmoothScrolling_CheckedChanged;
 			trackBarZoom.ValueChanged += trackBarZoom_ValueChanged;
 
+			checkBestImageQuality.CheckedChanged += checkBestImageQuality_CheckedChanged;
+			checkHideTweetsByNftUsers.CheckedChanged += checkHideTweetsByNftUsers_CheckedChanged;
+			checkAnimatedAvatars.CheckedChanged += checkAnimatedAvatars_CheckedChanged;
+
 			checkUpdateNotifications.CheckedChanged += checkUpdateNotifications_CheckedChanged;
 			btnCheckUpdates.Click += btnCheckUpdates_Click;
 
@@ -177,15 +187,6 @@ private void checkKeepLikeFollowDialogsOpen_CheckedChanged(object sender, EventA
 			Config.KeepLikeFollowDialogsOpen = checkKeepLikeFollowDialogsOpen.Checked;
 		}
 
-		private void checkBestImageQuality_CheckedChanged(object sender, EventArgs e) {
-			Config.BestImageQuality = checkBestImageQuality.Checked;
-		}
-
-		private void checkAnimatedAvatars_CheckedChanged(object sender, EventArgs e) {
-			Config.EnableAnimatedImages = checkAnimatedAvatars.Checked;
-			BrowserProcessHandler.UpdatePrefs().ContinueWith(task => reloadColumns());
-		}
-
 		private void checkSmoothScrolling_CheckedChanged(object sender, EventArgs e) {
 			Config.EnableSmoothScrolling = checkSmoothScrolling.Checked;
 		}
@@ -205,6 +206,24 @@ private void zoomUpdateTimer_Tick(object sender, EventArgs e) {
 
 		#endregion
 
+		#region Twitter
+
+		private void checkBestImageQuality_CheckedChanged(object sender, EventArgs e) {
+			Config.BestImageQuality = checkBestImageQuality.Checked;
+		}
+
+		private void checkHideTweetsByNftUsers_CheckedChanged(object sender, EventArgs e) {
+			Config.HideTweetsByNftUsers = checkHideTweetsByNftUsers.Checked;
+			BeginInvoke(reloadTweetDeck);
+		}
+
+		private void checkAnimatedAvatars_CheckedChanged(object sender, EventArgs e) {
+			Config.EnableAnimatedImages = checkAnimatedAvatars.Checked;
+			BrowserProcessHandler.UpdatePrefs().ContinueWith(task => reloadColumns());
+		}
+
+		#endregion
+
 		#region Updates
 
 		private void checkUpdateNotifications_CheckedChanged(object sender, EventArgs e) {
diff --git a/Resources/Content/.all.js b/Resources/Content/.all.js
index 5747e563..5b73041d 100644
--- a/Resources/Content/.all.js
+++ b/Resources/Content/.all.js
@@ -45,6 +45,7 @@ import limit_loaded_dm_count from "./tweetdeck/limit_loaded_dm_count.js";
 import make_retweets_lowercase from "./tweetdeck/make_retweets_lowercase.js";
 import middle_click_tweet_icon_actions from "./tweetdeck/middle_click_tweet_icon_actions.js";
 import move_accounts_above_hashtags_in_search from "./tweetdeck/move_accounts_above_hashtags_in_search.js";
+import mute_accounts_with_nft_avatars from "./tweetdeck/mute_accounts_with_nft_avatars.js";
 import offline_notification from "./tweetdeck/offline_notification.js";
 import open_search_externally from "./tweetdeck/open_search_externally.js";
 import open_search_in_first_column from "./tweetdeck/open_search_in_first_column.js";
diff --git a/Resources/Content/api/bridge.js b/Resources/Content/api/bridge.js
index 93cdfa99..a7aedf28 100644
--- a/Resources/Content/api/bridge.js
+++ b/Resources/Content/api/bridge.js
@@ -37,6 +37,7 @@ if (!("$TDX" in window)) {
  * @property {boolean} [expandLinksOnHover]
  * @property {number} [firstDayOfWeek]
  * @property {boolean} [focusDmInput]
+ * @property {boolean} [hideTweetsByNftUsers]
  * @property {boolean} [keepLikeFollowDialogsOpen]
  * @property {boolean} [muteNotifications]
  * @property {boolean} [notificationMediaPreviews]
diff --git a/Resources/Content/api/td.js b/Resources/Content/api/td.js
index 0ff2757a..791e6853 100644
--- a/Resources/Content/api/td.js
+++ b/Resources/Content/api/td.js
@@ -40,6 +40,7 @@ if (!("TD" in window)) {
  * @property {TD_Column_Model} model
  * @property {boolean} notificationsDisabled
  * @property {function} reloadTweets
+ * @property {ChirpBase[]} updateArray
  * @property {{ columnWidth: number }} visibility
  */
 
@@ -272,10 +273,14 @@ if (!("TD" in window)) {
  * @typedef TwitterClient
  * @type {Object}
  *
+ * @property {string} API_BASE_URL
+ * @property {function(id: string)} addIdToMuteList
  * @property {function(chirp: ChirpBase)} callback
  * @property {string} chirpId
  * @property {TwitterConversations} conversations
  * @property {function(ids: string[], onSuccess: function(users: TwitterUser[]), onError: function)} getUsersByIds
+ * @property {function(url: string, data: object, method: "GET"|"POST", responseProcessor: function, onSuccess: function, onError: function)} makeTwitterCall
+ * @property {function(json: string[]): TwitterUser[]} processUsers
  */
 
 /**
@@ -360,6 +365,7 @@ if (!("TD" in window)) {
  * @typedef TwitterUserJSON
  * @type {Object}
  *
+ * @property {boolean} [ext_has_nft_avatar]
  * @property {string} id
  * @property {string} id_str
  * @property {string} name
diff --git a/Resources/Content/tweetdeck/globals/user_nft_status.js b/Resources/Content/tweetdeck/globals/user_nft_status.js
new file mode 100644
index 00000000..f71f0675
--- /dev/null
+++ b/Resources/Content/tweetdeck/globals/user_nft_status.js
@@ -0,0 +1,210 @@
+import { TD } from "../../api/td.js";
+import { checkPropertyExists, noop } from "../../api/utils.js";
+
+function isSupported() {
+	return checkPropertyExists(TD, "controller", "clients", "getPreferredClient") &&
+	       checkPropertyExists(TD, "services", "TwitterClient", "prototype", "API_BASE_URL") &&
+	       checkPropertyExists(TD, "services", "TwitterClient", "prototype", "makeTwitterCall") &&
+	       checkPropertyExists(TD, "services", "TwitterClient", "prototype", "processUsers") &&
+	       checkPropertyExists(TD, "services", "TwitterUser", "prototype");
+}
+
+/**
+ * @type {function(id: string)[]}
+ */
+const nftUserListeners = [];
+
+/**
+ * @type {Map<string, boolean>}
+ */
+const knownStatus = new Map();
+
+/**
+ * @type {Map<string, function(result: boolean)[]>}
+ */
+const deferredCallbacks = new Map();
+
+/**
+ * @type {Set<string>}
+ */
+const usersInQueue = new Set();
+
+/**
+ * @type {Set<string>}
+ */
+const usersPending = new Set();
+
+let checkTimer = -1;
+
+function requestQueuedUserInfo() {
+	if (usersInQueue.size === 0) {
+		return;
+	}
+	
+	const ids = [];
+	
+	for (const id of usersInQueue) {
+		if (ids.length === 100) {
+			break;
+		}
+		
+		ids.push(id);
+		usersInQueue.delete(id);
+	}
+	
+	// noinspection JSUnusedGlobalSymbols
+	const data = {
+		user_id: ids.join(",")
+	};
+	
+	/**
+	 * @param {TwitterUserJSON[]} users
+	 */
+	const processUserData = function(users) {
+		for (const user of users) {
+			setUserNftStatus(user.id_str, user.ext_has_nft_avatar === true);
+		}
+	};
+	
+	const client = TD.controller.clients.getPreferredClient();
+	
+	client.makeTwitterCall(client.API_BASE_URL + "users/lookup.json?include_ext_has_nft_avatar=1", data, "POST", processUserData, noop, function() {
+		// In case of API error, assume the users are not associated with NFTs so that callbacks can fire.
+		for (const id of ids) {
+			setUserNftStatus(id, false);
+		}
+	});
+	
+	if (usersInQueue.size === 0) {
+		checkTimer = -1;
+	}
+	else {
+		checkTimer = window.setTimeout(requestQueuedUserInfo, 400);
+	}
+}
+
+/**
+ * Calls the provided callback function with the result of whether a user id is associated with NFTs.
+ * If the user id is null, it will be presumed as not associated with NFTs.
+ * @param {string|null} id
+ * @param {function(nft: boolean)} [callback]
+ */
+function checkUserNftStatusCallback(id, callback) {
+	if (id === null) {
+		callback && callback(false);
+		return;
+	}
+	
+	const status = knownStatus.get(id);
+	
+	if (status !== undefined) {
+		callback && callback(status);
+		return;
+	}
+	
+	if (callback) {
+		let callbackList = deferredCallbacks.get(id);
+		if (callbackList === undefined) {
+			deferredCallbacks.set(id, callbackList = []);
+		}
+		
+		callbackList.push(callback);
+	}
+	
+	if (usersPending.has(id)) {
+		return;
+	}
+	
+	usersInQueue.add(id);
+	usersPending.add(id);
+	
+	window.clearTimeout(checkTimer);
+	checkTimer = window.setTimeout(requestQueuedUserInfo, 400);
+}
+
+/**
+ * Checks whether a user id is associated with NFTs, but only using already known results.
+ * If the user id is null or has not been checked yet, it will be presumed as not associated with NFTs.
+ * @param {string|null} id
+ * @return {boolean}
+ */
+export function checkUserNftStatusImmediately(id) {
+	return id !== null && knownStatus.get(id) === true;
+}
+
+/**
+ * Adds a listener that gets called when a user is added to the list of users associated with NFTs.
+ * If some users were already known to be associated with NFTs before registering the listener, the listener will be called for every user.
+ * @param {function(id: string)} listener
+ */
+export function addNftUserListener(listener) {
+	nftUserListeners.push(listener);
+	
+	for (const entry of knownStatus.entries()) {
+		if (entry[1]) {
+			listener(entry[0]);
+		}
+	}
+}
+
+/**
+ * Sets whether a user id is associated with NFTs.
+ * @param {string} id
+ * @param {boolean} status
+ */
+export function setUserNftStatus(id, status) {
+	usersInQueue.delete(id);
+	usersPending.delete(id);
+	
+	if (knownStatus.get(id) !== status) {
+		knownStatus.set(id, status);
+		
+		if (status) {
+			for (const listener of nftUserListeners) {
+				try {
+					listener(id);
+				} catch (e) {
+					console.error("Error in NFT user listener: " + e);
+				}
+			}
+		}
+	}
+	
+	if (deferredCallbacks.has(id)) {
+		for (const callback of deferredCallbacks.get(id)) {
+			callback(status);
+		}
+		
+		deferredCallbacks.delete(id);
+	}
+}
+
+/**
+ * Calls the provided callback function with the result of whether a user id is associated with NFTs.
+ * @param {string} id
+ * @param {function(nft: boolean)} [callback]
+ */
+export const checkUserNftStatus = isSupported() ? checkUserNftStatusCallback : function(id, callback) {
+	callback && callback(false);
+};
+
+/**
+ * Utility function that returns the user id from a tweet.
+ * @param {ChirpBase} tweet
+ * @returns {string|null}
+ */
+export function getTweetUserId(tweet) {
+	const user = tweet.user;
+	return typeof user === "object" && typeof user.id === "string" ? user.id : null;
+}
+
+/**
+ * Clears known status of users who are not associated with NFTs, in case they became associated with NFTs in the meantime.
+ */
+window.setInterval(function() {
+	for (const entry of knownStatus.entries()) {
+		if (!entry[1]) {
+			knownStatus.delete(entry[0]);
+		}
+	}
+}, 1000 * 60 * 60);
diff --git a/Resources/Content/tweetdeck/mute_accounts_with_nft_avatars.js b/Resources/Content/tweetdeck/mute_accounts_with_nft_avatars.js
new file mode 100644
index 00000000..73ac777f
--- /dev/null
+++ b/Resources/Content/tweetdeck/mute_accounts_with_nft_avatars.js
@@ -0,0 +1,54 @@
+import { $TDX } from "../api/bridge.js";
+import { replaceFunction } from "../api/patch.js";
+import { TD } from "../api/td.js";
+import { ensurePropertyExists } from "../api/utils.js";
+import { addNftUserListener, checkUserNftStatus, checkUserNftStatusImmediately, getTweetUserId, setUserNftStatus } from "./globals/user_nft_status.js";
+
+export default function() {
+	if (!$TDX.hideTweetsByNftUsers) {
+		return;
+	}
+	
+	ensurePropertyExists(TD, "controller", "clients", "getPreferredClient");
+	ensurePropertyExists(TD, "services", "TwitterClient", "prototype", "addIdToMuteList");
+	ensurePropertyExists(TD, "services", "TwitterUser", "prototype");
+	ensurePropertyExists(TD, "vo", "Column", "prototype", "addItemsToIndex");
+	
+	addNftUserListener(function(id) {
+		TD.controller.clients.getPreferredClient().addIdToMuteList(id);
+	});
+	
+	replaceFunction(TD.services.TwitterUser.prototype, "fromJSONObject", function(func, args) {
+		/** @type {TwitterUser} */
+		const user = func.apply(this, args);
+		
+		if (args.length > 0 && typeof args[0] === "object") {
+			const id = user.id;
+			const json = args[0];
+			
+			if ("ext_has_nft_avatar" in json) {
+				setUserNftStatus(id, json.ext_has_nft_avatar === true);
+			}
+			else {
+				checkUserNftStatus(id);
+			}
+		}
+		
+		return user;
+	});
+	
+	replaceFunction(TD.vo.Column.prototype, "mergeAndRenderChirps", function(func, args) {
+		/** @type ChirpBase[] */
+		const tweets = args[0];
+		
+		if (Array.isArray(tweets)) {
+			for (let i = tweets.length - 1; i >= 0; i--) {
+				if (checkUserNftStatusImmediately(getTweetUserId(tweets[i]))) {
+					tweets.splice(i, 1);
+				}
+			}
+		}
+		
+		return func.apply(this, args);
+	});
+};
diff --git a/Resources/Content/tweetdeck/setup_desktop_notifications.js b/Resources/Content/tweetdeck/setup_desktop_notifications.js
index fb5c558c..e8e2b0dc 100644
--- a/Resources/Content/tweetdeck/setup_desktop_notifications.js
+++ b/Resources/Content/tweetdeck/setup_desktop_notifications.js
@@ -4,6 +4,7 @@ import { replaceFunction } from "../api/patch.js";
 import { TD } from "../api/td.js";
 import { checkPropertyExists, ensurePropertyExists } from "../api/utils.js";
 import { getColumnName } from "./globals/get_column_name.js";
+import { checkUserNftStatus, getTweetUserId } from "./globals/user_nft_status.js";
 
 /**
  * Event callback for a new tweet.
@@ -67,20 +68,7 @@ const onNewTweet = (function() {
 	 * @param {TD_Column} column
 	 * @param {ChirpBase} tweet
 	 */
-	return function(column, tweet) {
-		if (tweet instanceof TD.services.TwitterConversation || tweet instanceof TD.services.TwitterConversationMessageEvent) {
-			if (checkTweetCache(recentMessages, tweet.id)) {
-				return;
-			}
-		}
-		else {
-			if (checkTweetCache(recentTweets, tweet.id)) {
-				return;
-			}
-		}
-		
-		startRecentTweetTimer();
-		
+	const showTweetNotification = function(column, tweet) {
 		if (column.model.getHasNotification()) {
 			const sensitive = isSensitive(tweet);
 			const previews = $TDX.notificationMediaPreviews && (!sensitive || TD.settings.getDisplaySensitiveMedia());
@@ -184,6 +172,36 @@ const onNewTweet = (function() {
 			$TD.onTweetSound();
 		}
 	};
+	
+	/**
+	 * @param {TD_Column} column
+	 * @param {ChirpBase} tweet
+	 */
+	return function(column, tweet) {
+		if (tweet instanceof TD.services.TwitterConversation || tweet instanceof TD.services.TwitterConversationMessageEvent) {
+			if (checkTweetCache(recentMessages, tweet.id)) {
+				return;
+			}
+		}
+		else {
+			if (checkTweetCache(recentTweets, tweet.id)) {
+				return;
+			}
+		}
+		
+		startRecentTweetTimer();
+		
+		if (!$TDX.hideTweetsByNftUsers) {
+			showTweetNotification(column, tweet);
+		}
+		else {
+			checkUserNftStatus(getTweetUserId(tweet), function(nft) {
+				if (!nft) {
+					showTweetNotification(column, tweet);
+				}
+			});
+		}
+	};
 })();
 
 /**
diff --git a/TweetDuck.csproj b/TweetDuck.csproj
index 3ff80c8e..6a5fa797 100644
--- a/TweetDuck.csproj
+++ b/TweetDuck.csproj
@@ -402,6 +402,7 @@
     <None Include="Resources\Content\tweetdeck\globals\reload_columns.js" />
     <None Include="Resources\Content\tweetdeck\globals\retrieve_tweet.js" />
     <None Include="Resources\Content\tweetdeck\globals\show_tweet_detail.js" />
+    <None Include="Resources\Content\tweetdeck\globals\user_nft_status.js" />
     <None Include="Resources\Content\tweetdeck\handle_extra_mouse_buttons.js" />
     <None Include="Resources\Content\tweetdeck\hook_theme_settings.js" />
     <None Include="Resources\Content\tweetdeck\inject_css.js" />
@@ -410,6 +411,7 @@
     <None Include="Resources\Content\tweetdeck\make_retweets_lowercase.js" />
     <None Include="Resources\Content\tweetdeck\middle_click_tweet_icon_actions.js" />
     <None Include="Resources\Content\tweetdeck\move_accounts_above_hashtags_in_search.js" />
+    <None Include="Resources\Content\tweetdeck\mute_accounts_with_nft_avatars.js" />
     <None Include="Resources\Content\tweetdeck\offline_notification.js" />
     <None Include="Resources\Content\tweetdeck\open_search_externally.js" />
     <None Include="Resources\Content\tweetdeck\open_search_in_first_column.js" />
diff --git a/lib/TweetLib.Core/Application/IAppUserConfiguration.cs b/lib/TweetLib.Core/Application/IAppUserConfiguration.cs
index c65e68da..c9c4ae93 100644
--- a/lib/TweetLib.Core/Application/IAppUserConfiguration.cs
+++ b/lib/TweetLib.Core/Application/IAppUserConfiguration.cs
@@ -9,6 +9,7 @@ public interface IAppUserConfiguration {
 		bool ExpandLinksOnHover { get; }
 		bool FirstRun { get; }
 		bool FocusDmInput { get; }
+		bool HideTweetsByNftUsers { get; }
 		bool IsCustomSoundNotificationSet { get; }
 		bool KeepLikeFollowDialogsOpen { get; }
 		bool MuteNotifications { get; }
diff --git a/lib/TweetLib.Core/Features/PropertyObjectScript.cs b/lib/TweetLib.Core/Features/PropertyObjectScript.cs
index 5ac6186e..946145f4 100644
--- a/lib/TweetLib.Core/Features/PropertyObjectScript.cs
+++ b/lib/TweetLib.Core/Features/PropertyObjectScript.cs
@@ -13,7 +13,7 @@ internal static string Generate(IAppUserConfiguration config, Environment enviro
 			static string Bool(bool value) => value ? "true;" : "false;";
 			static string Str(string value) => $"\"{value}\";";
 
-			StringBuilder build = new StringBuilder(384).Append("(function(x){");
+			StringBuilder build = new StringBuilder(414).Append("(function(x){");
 
 			build.Append("x.expandLinksOnHover=").Append(Bool(config.ExpandLinksOnHover));
 
@@ -24,6 +24,7 @@ internal static string Generate(IAppUserConfiguration config, Environment enviro
 				build.Append("x.muteNotifications=").Append(Bool(config.MuteNotifications));
 				build.Append("x.notificationMediaPreviews=").Append(Bool(config.NotificationMediaPreviews));
 				build.Append("x.translationTarget=").Append(Str(config.TranslationTarget));
+				build.Append("x.hideTweetsByNftUsers=").Append(Bool(config.HideTweetsByNftUsers));
 				build.Append("x.firstDayOfWeek=").Append(config.CalendarFirstDay == -1 ? JQuery.GetDatePickerDayOfWeek(Lib.Culture.DateTimeFormat.FirstDayOfWeek) : config.CalendarFirstDay);
 			}
 
diff --git a/lib/TweetLib.Core/Features/TweetDeck/TweetDeckBrowser.cs b/lib/TweetLib.Core/Features/TweetDeck/TweetDeckBrowser.cs
index d20b19a5..71c1c838 100644
--- a/lib/TweetLib.Core/Features/TweetDeck/TweetDeckBrowser.cs
+++ b/lib/TweetLib.Core/Features/TweetDeck/TweetDeckBrowser.cs
@@ -249,6 +249,9 @@ private sealed class ResourceRequestHandler : BaseResourceRequestHandler {
 					case ResourceType.Xhr when url.Contains(UrlVersionCheck):
 						return RequestHandleResult.Cancel.Instance;
 
+					case ResourceType.Xhr when url.Contains("://api.twitter.com/") && url.Contains("include_entities=1") && !url.Contains("&include_ext_has_nft_avatar=1"):
+						return new RequestHandleResult.Redirect(url.Replace("include_entities=1", "include_entities=1&include_ext_has_nft_avatar=1"));
+
 					default:
 						return base.Handle(url, resourceType);
 				}