diff --git a/app/graphql/mutations/user_preferences/update.rb b/app/graphql/mutations/user_preferences/update.rb
index 111bd2587757e78ad55bbd457249a23b0e959f50..8c4c545aa18291bc9a27012d9494a00efc4da55d 100644
--- a/app/graphql/mutations/user_preferences/update.rb
+++ b/app/graphql/mutations/user_preferences/update.rb
@@ -6,24 +6,28 @@ class Update < BaseMutation
       graphql_name 'UserPreferencesUpdate'
 
       NON_NULLABLE_ARGS = [
+        :extensions_marketplace_opt_in_status,
         :use_web_ide_extension_marketplace,
         :visibility_pipeline_id_type
       ].freeze
 
+      argument :extensions_marketplace_opt_in_status, Types::ExtensionsMarketplaceOptInStatusEnum,
+        required: false,
+        description: 'Status of the Web IDE Extension Marketplace opt-in for the user.'
       argument :issues_sort, Types::IssueSortEnum,
-               required: false,
-               description: 'Sort order for issue lists.'
+        required: false,
+        description: 'Sort order for issue lists.'
       argument :use_web_ide_extension_marketplace, GraphQL::Types::Boolean,
-               required: false,
-               description: 'Whether Web IDE Extension Marketplace is enabled for the user.'
+        required: false,
+        description: 'Whether Web IDE Extension Marketplace is enabled for the user.'
       argument :visibility_pipeline_id_type, Types::VisibilityPipelineIdTypeEnum,
-               required: false,
-               description: 'Determines whether the pipeline list shows ID or IID.'
+        required: false,
+        description: 'Determines whether the pipeline list shows ID or IID.'
 
       field :user_preferences,
-            Types::UserPreferencesType,
-            null: true,
-            description: 'User preferences after mutation.'
+        Types::UserPreferencesType,
+        null: true,
+        description: 'User preferences after mutation.'
 
       def resolve(**attributes)
         attributes.delete_if { |key, value| NON_NULLABLE_ARGS.include?(key) && value.nil? }
diff --git a/app/graphql/types/extensions_marketplace_opt_in_status_enum.rb b/app/graphql/types/extensions_marketplace_opt_in_status_enum.rb
new file mode 100644
index 0000000000000000000000000000000000000000..4ea4b55a9923d03897350ba1600e61655b7307c9
--- /dev/null
+++ b/app/graphql/types/extensions_marketplace_opt_in_status_enum.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+module Types
+  class ExtensionsMarketplaceOptInStatusEnum < BaseEnum
+    graphql_name 'ExtensionsMarketplaceOptInStatus'
+    description 'Values for status of the Web IDE Extension Marketplace opt-in for the user'
+
+    UserPreference.extensions_marketplace_opt_in_statuses.each_key do |field|
+      value field.upcase, value: field, description: "Web IDE Extension Marketplace opt-in status: #{field.upcase}."
+    end
+  end
+end
diff --git a/app/graphql/types/user_preferences_type.rb b/app/graphql/types/user_preferences_type.rb
index e9ac3a28a5303c6a60996bcddcffcba2dd9becce..4d695a6e967cc9e2d616cbff48e63c9f23f66773 100644
--- a/app/graphql/types/user_preferences_type.rb
+++ b/app/graphql/types/user_preferences_type.rb
@@ -6,6 +6,10 @@ module Types
   class UserPreferencesType < BaseObject
     graphql_name 'UserPreferences'
 
+    field :extensions_marketplace_opt_in_status, Types::ExtensionsMarketplaceOptInStatusEnum,
+      description: 'Status of the Web IDE Extension Marketplace opt-in for the user.',
+      null: false
+
     field :issues_sort, Types::IssueSortEnum,
       description: 'Sort order for issue lists.',
       null: true
@@ -16,7 +20,8 @@ class UserPreferencesType < BaseObject
 
     field :use_web_ide_extension_marketplace, GraphQL::Types::Boolean,
       description: 'Whether Web IDE Extension Marketplace is enabled for the user.',
-      null: false
+      null: false,
+      deprecated: { reason: 'Use `extensions_marketplace_opt_in_status` instead', milestone: '16.11' }
 
     def issues_sort
       object.issues_sort.to_sym
diff --git a/app/models/concerns/enums/web_ide/extensions_marketplace_opt_in_status.rb b/app/models/concerns/enums/web_ide/extensions_marketplace_opt_in_status.rb
new file mode 100644
index 0000000000000000000000000000000000000000..44e63dcaa27f7baaac8916fc80f2a5ab7ff3e355
--- /dev/null
+++ b/app/models/concerns/enums/web_ide/extensions_marketplace_opt_in_status.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Enums
+  module WebIde
+    module ExtensionsMarketplaceOptInStatus
+      def self.statuses
+        { unset: 0, enabled: 1, disabled: 2 }
+      end
+    end
+  end
+end
diff --git a/app/models/user.rb b/app/models/user.rb
index 35b0a73049ee74c9a978528a87906b150799ef6c..acda8cd88e741bc779619477a11ac9b50f4572f7 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -408,6 +408,7 @@ def update_tracked_fields!(request)
     :sourcegraph_enabled, :sourcegraph_enabled=,
     :gitpod_enabled, :gitpod_enabled=,
     :use_web_ide_extension_marketplace, :use_web_ide_extension_marketplace=,
+    :extensions_marketplace_opt_in_status, :extensions_marketplace_opt_in_status=,
     :setup_for_company, :setup_for_company=,
     :project_shortcut_buttons, :project_shortcut_buttons=,
     :keyboard_shortcuts_enabled, :keyboard_shortcuts_enabled=,
diff --git a/app/models/user_preference.rb b/app/models/user_preference.rb
index caedf08fa44a52e7a96b0882aac78268cd42241a..19a7601be32783d02b083a6e8b695194737831dd 100644
--- a/app/models/user_preference.rb
+++ b/app/models/user_preference.rb
@@ -42,6 +42,7 @@ class UserPreference < MainClusterwide::ApplicationRecord
   attribute :use_web_ide_extension_marketplace, default: false
 
   enum visibility_pipeline_id_type: { id: 0, iid: 1 }
+  enum extensions_marketplace_opt_in_status: Enums::WebIde::ExtensionsMarketplaceOptInStatus.statuses
 
   class << self
     def notes_filters
diff --git a/db/migrate/20240410000000_add_extensions_marketplace_opt_in_status_to_user_preferences.rb b/db/migrate/20240410000000_add_extensions_marketplace_opt_in_status_to_user_preferences.rb
new file mode 100644
index 0000000000000000000000000000000000000000..d81193d2a5da89eb3516da496c04309af3b06cfe
--- /dev/null
+++ b/db/migrate/20240410000000_add_extensions_marketplace_opt_in_status_to_user_preferences.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddExtensionsMarketplaceOptInStatusToUserPreferences < Gitlab::Database::Migration[2.2]
+  milestone '16.11'
+
+  def change
+    add_column :user_preferences, :extensions_marketplace_opt_in_status, :smallint, default: 0, null: false
+  end
+end
diff --git a/db/schema_migrations/20240410000000 b/db/schema_migrations/20240410000000
new file mode 100644
index 0000000000000000000000000000000000000000..48b31e3a3bcf3ba828ac2d63f709f69b86b2557e
--- /dev/null
+++ b/db/schema_migrations/20240410000000
@@ -0,0 +1 @@
+2f045332b7600514f8adeea441afca3c5cd8eddd5a7fab261e48fc373046ead1
\ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index b5a3dc574b0ef50c5ad19c7bcf16561d99d6954d..b983ebe6d448f81a0efa5c5bf6ca253f935414fc 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -17109,6 +17109,7 @@ CREATE TABLE user_preferences (
     time_display_format smallint DEFAULT 0 NOT NULL,
     home_organization_id bigint,
     use_web_ide_extension_marketplace boolean DEFAULT false NOT NULL,
+    extensions_marketplace_opt_in_status smallint DEFAULT 0 NOT NULL,
     CONSTRAINT check_1d670edc68 CHECK ((time_display_relative IS NOT NULL)),
     CONSTRAINT check_89bf269f41 CHECK ((char_length(diffs_deletion_color) <= 7)),
     CONSTRAINT check_b22446f91a CHECK ((render_whitespace_in_code IS NOT NULL)),
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 8d7b5069dea77cbd2974dab769c5e1ee2f4f9ffd..8b880d584deffefed82fc109b1b3eb18d19a31c7 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -8953,6 +8953,7 @@ Input type: `UserPreferencesUpdateInput`
 | Name | Type | Description |
 | ---- | ---- | ----------- |
 | <a id="mutationuserpreferencesupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationuserpreferencesupdateextensionsmarketplaceoptinstatus"></a>`extensionsMarketplaceOptInStatus` | [`ExtensionsMarketplaceOptInStatus`](#extensionsmarketplaceoptinstatus) | Status of the Web IDE Extension Marketplace opt-in for the user. |
 | <a id="mutationuserpreferencesupdateissuessort"></a>`issuesSort` | [`IssueSort`](#issuesort) | Sort order for issue lists. |
 | <a id="mutationuserpreferencesupdateusewebideextensionmarketplace"></a>`useWebIdeExtensionMarketplace` | [`Boolean`](#boolean) | Whether Web IDE Extension Marketplace is enabled for the user. |
 | <a id="mutationuserpreferencesupdatevisibilitypipelineidtype"></a>`visibilityPipelineIdType` | [`VisibilityPipelineIdType`](#visibilitypipelineidtype) | Determines whether the pipeline list shows ID or IID. |
@@ -30228,8 +30229,9 @@ fields relate to interactions between the two entities.
 
 | Name | Type | Description |
 | ---- | ---- | ----------- |
+| <a id="userpreferencesextensionsmarketplaceoptinstatus"></a>`extensionsMarketplaceOptInStatus` | [`ExtensionsMarketplaceOptInStatus!`](#extensionsmarketplaceoptinstatus) | Status of the Web IDE Extension Marketplace opt-in for the user. |
 | <a id="userpreferencesissuessort"></a>`issuesSort` | [`IssueSort`](#issuesort) | Sort order for issue lists. |
-| <a id="userpreferencesusewebideextensionmarketplace"></a>`useWebIdeExtensionMarketplace` | [`Boolean!`](#boolean) | Whether Web IDE Extension Marketplace is enabled for the user. |
+| <a id="userpreferencesusewebideextensionmarketplace"></a>`useWebIdeExtensionMarketplace` **{warning-solid}** | [`Boolean!`](#boolean) | **Deprecated** in GitLab 16.11. Use `extensions_marketplace_opt_in_status` instead. |
 | <a id="userpreferencesvisibilitypipelineidtype"></a>`visibilityPipelineIdType` | [`VisibilityPipelineIdType`](#visibilitypipelineidtype) | Determines whether the pipeline list shows ID or IID. |
 
 ### `UserStatus`
@@ -32671,6 +32673,16 @@ Event action.
 | <a id="eventactionreopened"></a>`REOPENED` | Reopened action. |
 | <a id="eventactionupdated"></a>`UPDATED` | Updated action. |
 
+### `ExtensionsMarketplaceOptInStatus`
+
+Values for status of the Web IDE Extension Marketplace opt-in for the user.
+
+| Value | Description |
+| ----- | ----------- |
+| <a id="extensionsmarketplaceoptinstatusdisabled"></a>`DISABLED` | Web IDE Extension Marketplace opt-in status: DISABLED. |
+| <a id="extensionsmarketplaceoptinstatusenabled"></a>`ENABLED` | Web IDE Extension Marketplace opt-in status: ENABLED. |
+| <a id="extensionsmarketplaceoptinstatusunset"></a>`UNSET` | Web IDE Extension Marketplace opt-in status: UNSET. |
+
 ### `FindingReportsComparerStatus`
 
 Report comparison status.
diff --git a/spec/graphql/types/extensions_marketplace_opt_in_status_enum_spec.rb b/spec/graphql/types/extensions_marketplace_opt_in_status_enum_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..84199f443b21e6a99640a5899e95f81ee1a03102
--- /dev/null
+++ b/spec/graphql/types/extensions_marketplace_opt_in_status_enum_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::ExtensionsMarketplaceOptInStatusEnum, feature_category: :web_ide do
+  specify { expect(described_class.graphql_name).to eq('ExtensionsMarketplaceOptInStatus') }
+
+  it 'exposes all the existing extensions_marketplace_opt_in_status values' do
+    expect(described_class.values.keys).to contain_exactly('UNSET', 'ENABLED', 'DISABLED')
+  end
+end
diff --git a/spec/graphql/types/user_preferences_type_spec.rb b/spec/graphql/types/user_preferences_type_spec.rb
index 87fac17a5ba6b7d21457950f8645009716152b18..1db51d27b221dd9abc891a93cb513405d4dffada 100644
--- a/spec/graphql/types/user_preferences_type_spec.rb
+++ b/spec/graphql/types/user_preferences_type_spec.rb
@@ -10,6 +10,7 @@
       issues_sort
       visibility_pipeline_id_type
       use_web_ide_extension_marketplace
+      extensions_marketplace_opt_in_status
     ]
 
     expect(described_class).to have_graphql_fields(*expected_fields)
diff --git a/spec/models/user_preference_spec.rb b/spec/models/user_preference_spec.rb
index 8852c14c1aadb3cb3795b09edbee4310e5d6a2fb..efcd1b620e1bc1bb38d3adb32c87b6a0358e2590 100644
--- a/spec/models/user_preference_spec.rb
+++ b/spec/models/user_preference_spec.rb
@@ -73,6 +73,19 @@
       it { is_expected.to define_enum_for(:visibility_pipeline_id_type).with_values(id: 0, iid: 1) }
     end
 
+    describe 'extensions_marketplace_opt_in_status' do
+      it 'is set to 0 by default' do
+        pref = described_class.new
+
+        expect(pref.extensions_marketplace_opt_in_status).to eq('unset')
+      end
+
+      it do
+        is_expected
+          .to define_enum_for(:extensions_marketplace_opt_in_status).with_values(unset: 0, enabled: 1, disabled: 2)
+      end
+    end
+
     describe 'user belongs to the home organization' do
       let_it_be(:organization) { create(:organization) }
 
diff --git a/spec/requests/api/graphql/mutations/user_preferences/update_spec.rb b/spec/requests/api/graphql/mutations/user_preferences/update_spec.rb
index b1cd3259eebe8ffab06e127dde36ccaf61ad45af..63a3a48fbd60deafff8d3951526b92ddd9061462 100644
--- a/spec/requests/api/graphql/mutations/user_preferences/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/user_preferences/update_spec.rb
@@ -11,6 +11,7 @@
 
   let(:input) do
     {
+      'extensionsMarketplaceOptInStatus' => 'ENABLED',
       'issuesSort' => sort_value,
       'visibilityPipelineIdType' => 'IID',
       'useWebIdeExtensionMarketplace' => true
@@ -25,11 +26,13 @@
       post_graphql_mutation(mutation, current_user: current_user)
 
       expect(response).to have_gitlab_http_status(:success)
+      expect(mutation_response['userPreferences']['extensionsMarketplaceOptInStatus']).to eq('ENABLED')
       expect(mutation_response['userPreferences']['issuesSort']).to eq(sort_value)
       expect(mutation_response['userPreferences']['visibilityPipelineIdType']).to eq('IID')
       expect(mutation_response['userPreferences']['useWebIdeExtensionMarketplace']).to eq(true)
 
       expect(current_user.user_preference.persisted?).to eq(true)
+      expect(current_user.user_preference.extensions_marketplace_opt_in_status).to eq('enabled')
       expect(current_user.user_preference.issues_sort).to eq(Types::IssueSortEnum.values[sort_value].value.to_s)
       expect(current_user.user_preference.visibility_pipeline_id_type).to eq('iid')
       expect(current_user.user_preference.use_web_ide_extension_marketplace).to eq(true)
@@ -39,6 +42,7 @@
   context 'when user has existing preference' do
     let(:init_user_preference) do
       {
+        extensions_marketplace_opt_in_status: 'enabled',
         issues_sort: Types::IssueSortEnum.values['TITLE_DESC'].value,
         visibility_pipeline_id_type: 'id',
         use_web_ide_extension_marketplace: true
@@ -65,6 +69,7 @@
     context 'when input has nil attributes' do
       let(:input) do
         {
+          'extensionsMarketplaceOptInStatus' => nil,
           'issuesSort' => nil,
           'visibilityPipelineIdType' => nil,
           'useWebIdeExtensionMarketplace' => nil
@@ -80,6 +85,7 @@
           # These are nullable and are exepcted to change
           issues_sort: nil,
           # These should not have changed
+          extensions_marketplace_opt_in_status: init_user_preference[:extensions_marketplace_opt_in_status],
           visibility_pipeline_id_type: init_user_preference[:visibility_pipeline_id_type],
           use_web_ide_extension_marketplace: init_user_preference[:use_web_ide_extension_marketplace]
         })