diff --git a/data/dock.gschema.xml b/data/dock.gschema.xml
index 96664d1c3..8ecc90868 100644
--- a/data/dock.gschema.xml
+++ b/data/dock.gschema.xml
@@ -27,4 +27,51 @@
       <description>An ordered array of app id's to show as launchers</description>
     </key>
   </schema>
+  <schema path="/io/elementary/dock/keybindings/" id="io.elementary.dock.keybindings">
+    <key type="as" name="launch-dock-1">
+      <default><![CDATA[['<Super>1']]]></default>
+      <summary>Launch the first dock item</summary>
+      <description></description>
+    </key>
+    <key type="as" name="launch-dock-2">
+      <default><![CDATA[['<Super>2']]]></default>
+      <summary>Launch the second dock item</summary>
+      <description></description>
+    </key>
+    <key type="as" name="launch-dock-3">
+      <default><![CDATA[['<Super>3']]]></default>
+      <summary>Launch the third dock item</summary>
+      <description></description>
+    </key>
+    <key type="as" name="launch-dock-4">
+      <default><![CDATA[['<Super>4']]]></default>
+      <summary>Launch the fourth dock item</summary>
+      <description></description>
+    </key>
+    <key type="as" name="launch-dock-5">
+      <default><![CDATA[['<Super>5']]]></default>
+      <summary>Launch the fith dock item</summary>
+      <description></description>
+    </key>
+    <key type="as" name="launch-dock-6">
+      <default><![CDATA[['<Super>6']]]></default>
+      <summary>Launch the sixth dock item</summary>
+      <description></description>
+    </key>
+    <key type="as" name="launch-dock-7">
+      <default><![CDATA[['<Super>7']]]></default>
+      <summary>Launch the seventh dock item</summary>
+      <description></description>
+    </key>
+    <key type="as" name="launch-dock-8">
+      <default><![CDATA[['<Super>8']]]></default>
+      <summary>Launch the eigth dock item</summary>
+      <description></description>
+    </key>
+    <key type="as" name="launch-dock-9">
+      <default><![CDATA[['<Super>9']]]></default>
+      <summary>Launch the nineth dock item</summary>
+      <description></description>
+    </key>
+  </schema>
 </schemalist>
diff --git a/src/Application.vala b/src/Application.vala
index 85eb5a61a..207ed5fb8 100644
--- a/src/Application.vala
+++ b/src/Application.vala
@@ -12,6 +12,7 @@ public class Dock.Application : Gtk.Application {
         base.startup ();
 
         Granite.init ();
+        ShellKeyGrabber.init ();
 
         unowned var granite_settings = Granite.Settings.get_default ();
         unowned var gtk_settings = Gtk.Settings.get_default ();
diff --git a/src/DBus/ShellKeyGrabber.vala b/src/DBus/ShellKeyGrabber.vala
new file mode 100644
index 000000000..52fc228f1
--- /dev/null
+++ b/src/DBus/ShellKeyGrabber.vala
@@ -0,0 +1,124 @@
+/*
+ * SPDX-License-Identifier: GPL-3.0
+ * SPDX-FileCopyrightText: 2024 elementary, Inc. (https://elementary.io)
+ */
+
+/**
+ * ActionMode:
+ * @NONE: block action
+ * @NORMAL: allow action when in window mode, e.g. when the focus is in an application window
+ * @OVERVIEW: allow action while the overview is active
+ * @LOCK_SCREEN: allow action when the screen is locked, e.g. when the screen shield is shown
+ * @UNLOCK_SCREEN: allow action in the unlock dialog
+ * @LOGIN_SCREEN: allow action in the login screen
+ * @SYSTEM_MODAL: allow action when a system modal dialog (e.g. authentification or session dialogs) is open
+ * @LOOKING_GLASS: allow action in looking glass
+ * @POPUP: allow action while a shell menu is open
+ */
+
+[Flags]
+public enum ActionMode {
+    NONE = 0,
+    NORMAL = 1 << 0,
+    OVERVIEW = 1 << 1,
+    LOCK_SCREEN = 1 << 2,
+    UNLOCK_SCREEN = 1 << 3,
+    LOGIN_SCREEN = 1 << 4,
+    SYSTEM_MODAL = 1 << 5,
+    LOOKING_GLASS = 1 << 6,
+    POPUP = 1 << 7,
+}
+
+[Flags]
+public enum Meta.KeyBindingFlags {
+    NONE = 0,
+    PER_WINDOW = 1 << 0,
+    BUILTIN = 1 << 1,
+    IS_REVERSED = 1 << 2,
+    NON_MASKABLE = 1 << 3,
+    IGNORE_AUTOREPEAT = 1 << 4,
+}
+
+public struct Accelerator {
+    public string name;
+    public ActionMode mode_flags;
+    public Meta.KeyBindingFlags grab_flags;
+}
+
+[DBus (name = "org.gnome.Shell")]
+public interface ShellKeyGrabber : GLib.Object {
+    public abstract signal void accelerator_activated (uint action, GLib.HashTable<string, GLib.Variant> parameters_dict);
+
+    public abstract uint grab_accelerator (string accelerator, ActionMode mode_flags, Meta.KeyBindingFlags grab_flags) throws GLib.DBusError, GLib.IOError;
+    public abstract uint[] grab_accelerators (Accelerator[] accelerators) throws GLib.DBusError, GLib.IOError;
+    public abstract bool ungrab_accelerator (uint action) throws GLib.DBusError, GLib.IOError;
+    public abstract bool ungrab_accelerators (uint[] actions) throws GLib.DBusError, GLib.IOError;
+
+    private static Settings settings;
+    private static ShellKeyGrabber? instance;
+
+    private static HashTable<uint, int> saved_action_ids;
+
+    public static void init () {
+        settings = new Settings ("io.elementary.dock.keybindings");
+        saved_action_ids = new HashTable<uint, int> (null, null);
+
+        settings.changed.connect (() => {
+            ungrab_keybindings ();
+            setup_grabs ();
+        });
+
+        Bus.watch_name (BusType.SESSION, "org.gnome.Shell", BusNameWatcherFlags.NONE, () => on_watch.begin (), () => instance = null);
+    }
+
+    private static async void on_watch () {
+        try {
+            instance = yield Bus.get_proxy (SESSION, "org.gnome.Shell", "/org/gnome/Shell");
+            setup_grabs ();
+        } catch (Error e) {
+            warning ("Failed to connect to bus for keyboard shortcut grabs: %s", e.message);
+        }
+    }
+
+    private static void setup_grabs () requires (instance != null) {
+        for (int i = 1; i <= 9; i++) {
+            var keybindings = settings.get_strv ("launch-dock-%d".printf (i));
+            Accelerator[] accelerators = {};
+            for (int j = 0; j < keybindings.length; j++) {
+                accelerators += Accelerator () {
+                    name = keybindings[j],
+                    mode_flags = ActionMode.NONE,
+                    grab_flags = Meta.KeyBindingFlags.NONE
+                };
+
+                try {
+                    foreach (var id in instance.grab_accelerators (accelerators)) {
+                        saved_action_ids[id] = i;
+                    }
+                } catch (Error e) {
+                    critical ("Couldn't grab accelerators: %s", e.message);
+                }
+            }
+        }
+
+        instance.accelerator_activated.connect (on_accelerator_activated);
+    }
+
+    private static void on_accelerator_activated (uint action, GLib.HashTable<string, GLib.Variant> parameters_dict) {
+        if (!(action in saved_action_ids)) {
+            return;
+        }
+
+        Dock.LauncherManager.get_default ().launch (saved_action_ids[action]);
+    }
+
+    private static void ungrab_keybindings () requires (instance != null) {
+        var actions = saved_action_ids.get_keys_as_array ();
+
+        try {
+            instance.ungrab_accelerators (actions);
+        } catch (Error e) {
+            critical ("Couldn't ungrab accelerators: %s", e.message);
+        }
+    }
+}
diff --git a/src/LauncherManager.vala b/src/LauncherManager.vala
index 68502793e..94dd638bf 100644
--- a/src/LauncherManager.vala
+++ b/src/LauncherManager.vala
@@ -313,6 +313,15 @@
         settings.set_strv ("launchers", new_pinned_ids);
     }
 
+    public void launch (uint index) {
+        if (index < 1 || index > launchers.length ()) {
+            return;
+        }
+
+        var context = Gdk.Display.get_default ().get_app_launch_context ();
+        launchers.nth (index - 1).data.app.launch (context);
+    }
+
     public void add_launcher_for_id (string app_id) {
         if (app_id in id_to_app) {
             id_to_app[app_id].pinned = true;
diff --git a/src/meson.build b/src/meson.build
index 0ed8fe590..30e3413d8 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -8,6 +8,7 @@ sources = [
     'MainWindow.vala',
     'PoofPopover.vala',
     'DBus' / 'ItemInterface.vala',
+    'DBus' / 'ShellKeyGrabber.vala',
     'DBus' / 'SwitcherooControl.vala',
     'DBus' / 'Unity.vala'
 ]
