diff --git a/CHANGES.md b/CHANGES.md
index 3340b4a071a9b3863b269075c0c1ae33bcb1fd43..9abb343c108ec35fbaa428e3feb183ee2d9b51ce 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -12,6 +12,10 @@
 
 - System notification popups are now used instead of own implementation.
 
+- Item rows in main window and tray menu are now indexed from one instead of
+  zero by default (#1085). This can be reverted to the old behavior using
+  command `copyq row_index_from_one false`.
+
 - A tag can be marked as "locked" in configuration. Items with such tags cannot
   be removed until the tag is removed or "unlocked".
 
diff --git a/docs/scripting-api.rst b/docs/scripting-api.rst
index 07185a42525653cf2703ae64d0766b9b3e7f236d..42ba1ca26d85c5174fc8c9aac582a3668a1862e8 100644
--- a/docs/scripting-api.rst
+++ b/docs/scripting-api.rst
@@ -73,6 +73,9 @@ Functions
 Argument list parts ``...`` and ``[...]`` are optional and can be
 omitted.
 
+Item **row** values in scripts always **start from 0** (like array index),
+unlike in GUI, where row numbers start from 1 by default.
+
 .. js:function:: String version()
 
    Returns version string.
diff --git a/src/app/clipboardserver.cpp b/src/app/clipboardserver.cpp
index e6fde889193568768ec89197ce5a5045b994a289..c94bade1d548871efaaa617f6851f194117d82ec 100644
--- a/src/app/clipboardserver.cpp
+++ b/src/app/clipboardserver.cpp
@@ -688,6 +688,7 @@ void ClipboardServer::loadSettings()
     m_sharedData->saveDelayMsOnItemRemoved = appConfig.option<Config::save_delay_ms_on_item_removed>();
     m_sharedData->saveDelayMsOnItemMoved = appConfig.option<Config::save_delay_ms_on_item_moved>();
     m_sharedData->saveDelayMsOnItemEdited = appConfig.option<Config::save_delay_ms_on_item_edited>();
+    m_sharedData->rowIndexFromOne = appConfig.option<Config::row_index_from_one>();
 
     m_wnd->loadSettings(settings, appConfig);
 
diff --git a/src/common/appconfig.h b/src/common/appconfig.h
index 94c0ec4b0f5de8befa5478ebc06be93378ced7f8..61f49c8c833d341de56587239d367cc8699dc84b 100644
--- a/src/common/appconfig.h
+++ b/src/common/appconfig.h
@@ -403,6 +403,11 @@ struct window_wait_for_modifiers_released_ms : Config<int> {
     static Value defaultValue() { return 50; }
 };
 
+struct row_index_from_one : Config<bool> {
+    static QString name() { return "row_index_from_one"; }
+    static Value defaultValue() { return true; }
+};
+
 struct style : Config<QString> {
     static QString name() { return "style"; }
 };
diff --git a/src/gui/clipboardbrowser.cpp b/src/gui/clipboardbrowser.cpp
index b16f2f52f2c874cc44f6217ef44d7b67057fef30..edcdd27a1d1aaf3849f10648e5ada2ef25a30994 100644
--- a/src/gui/clipboardbrowser.cpp
+++ b/src/gui/clipboardbrowser.cpp
@@ -1332,8 +1332,11 @@ void ClipboardBrowser::filterItems(const ItemFilterPtr &filter)
 
     // If search string is a number, highlight item in that row.
     bool filterByRowNumber = !m_sharedData->numberSearch;
-    if (filterByRowNumber)
+    if (filterByRowNumber) {
         m_filterRow = newSearch.toInt(&filterByRowNumber);
+        if (m_filterRow > 0 && m_sharedData->rowIndexFromOne)
+            --m_filterRow;
+    }
     if (!filterByRowNumber)
         m_filterRow = -1;
 
diff --git a/src/gui/clipboardbrowsershared.h b/src/gui/clipboardbrowsershared.h
index e1ee67f41408d7c697c115aa8be88a770a9dec3b..89e33cd94ed590257ea4370b1f54de82a7747f22 100644
--- a/src/gui/clipboardbrowsershared.h
+++ b/src/gui/clipboardbrowsershared.h
@@ -44,6 +44,7 @@ struct ClipboardBrowserShared {
     int saveDelayMsOnItemRemoved = 0;
     int saveDelayMsOnItemMoved = 0;
     int saveDelayMsOnItemEdited = 0;
+    bool rowIndexFromOne = true;
     ItemFactory *itemFactory = nullptr;
     ActionHandler *actions = nullptr;
     NotificationDaemon *notifications = nullptr;
diff --git a/src/gui/configurationmanager.cpp b/src/gui/configurationmanager.cpp
index ca9a90244059f14f1d371f213218ab4c3a305a6b..9fb574e0eca68801f9b04db4b1a0ba2f642df9bd 100644
--- a/src/gui/configurationmanager.cpp
+++ b/src/gui/configurationmanager.cpp
@@ -346,6 +346,8 @@ void ConfigurationManager::initOptions()
     bind<Config::window_wait_for_modifiers_released_ms>();
 
     bind<Config::style>();
+
+    bind<Config::row_index_from_one>();
 }
 
 template <typename Config, typename Widget>
diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp
index d0789bc463941b83d85b3e01e0528ba5959064a1..486a7c2a206115d1d0a74d48a7f88ead02fb5e42 100644
--- a/src/gui/mainwindow.cpp
+++ b/src/gui/mainwindow.cpp
@@ -2509,6 +2509,9 @@ void MainWindow::loadSettings(QSettings &settings, AppConfig &appConfig)
     m_trayMenu->setNumberSearchEnabled(m_sharedData->numberSearch);
     m_menu->setNumberSearchEnabled(m_sharedData->numberSearch);
 
+    m_trayMenu->setRowIndexFromOne(m_sharedData->rowIndexFromOne);
+    m_menu->setRowIndexFromOne(m_sharedData->rowIndexFromOne);
+
     m_options.transparency = appConfig.option<Config::transparency>();
     m_options.transparencyFocused = appConfig.option<Config::transparency_focused>();
     updateWindowTransparency();
diff --git a/src/gui/traymenu.cpp b/src/gui/traymenu.cpp
index a248e7eae86cf65ee238f86218cd2ccbd02f5451..0b52b6da2f711c09a7e1ebb1a48edec25959a305 100644
--- a/src/gui/traymenu.cpp
+++ b/src/gui/traymenu.cpp
@@ -101,10 +101,11 @@ void TrayMenu::addClipboardItemAction(const QVariantMap &data, bool showImages)
     QString format;
 
     // Add number key hint.
-    if (m_clipboardItemActionCount < 10) {
+    const int rowNumber = m_clipboardItemActionCount + static_cast<int>(m_rowIndexFromOne);
+    if (rowNumber < 10) {
         format = tr("&%1. %2",
                     "Key hint (number shortcut) for items in tray menu (%1 is number, %2 is item label)")
-                .arg(m_clipboardItemActionCount);
+                .arg(rowNumber);
     }
 
     m_clipboardItemActionCount++;
diff --git a/src/gui/traymenu.h b/src/gui/traymenu.h
index 6f58701b51c6db4455257e8f38a72f3f608758d7..2560eb4369009d7c22e1590263f22a6d77406db3 100644
--- a/src/gui/traymenu.h
+++ b/src/gui/traymenu.h
@@ -61,6 +61,9 @@ public:
 
     void markItemInClipboard(const QVariantMap &clipboardData);
 
+    /** Row numbers start from one instead of zero? */
+    void setRowIndexFromOne(bool rowIndexFromOne) { m_rowIndexFromOne = rowIndexFromOne; }
+
 signals:
     /** Emitted if numbered action triggered. */
     void clipboardItemActionTriggered(const QVariantMap &itemData, bool omitPaste);
@@ -100,6 +103,8 @@ private:
     QString m_searchText;
 
     QTimer m_timerUpdateActiveAction;
+
+    bool m_rowIndexFromOne = true;
 };
 
 #endif // TRAYMENU_H
diff --git a/src/item/itemdelegate.cpp b/src/item/itemdelegate.cpp
index cda64cd2a57cf79e873eaa052b6001944f9950a0..0f52b8e4992cc964810c1011902a14c3dd2b34e9 100644
--- a/src/item/itemdelegate.cpp
+++ b/src/item/itemdelegate.cpp
@@ -482,7 +482,7 @@ void ItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
 
     // Render number.
     if ( m_sharedData->theme.showRowNumber() ) {
-        const QString num = QString::number(row);
+        const QString num = QString::number(row + static_cast<int>(m_sharedData->rowIndexFromOne));
         QPalette::ColorRole role = isSelected ? QPalette::HighlightedText : QPalette::Text;
         painter->save();
         painter->setFont( m_sharedData->theme.rowNumberFont() );
diff --git a/src/scriptable/scriptableproxy.cpp b/src/scriptable/scriptableproxy.cpp
index 48ebaf1d23b75964a6195d9e83441fa3e4b5f975..7f77b00f428a285514749f43462e3fa29ff560a0 100644
--- a/src/scriptable/scriptableproxy.cpp
+++ b/src/scriptable/scriptableproxy.cpp
@@ -1398,6 +1398,7 @@ int ScriptableProxy::menuItems(const QVector<QVariantMap> &items)
 
     TrayMenu menu;
     menu.setObjectName("CustomMenu");
+    menu.setRowIndexFromOne( AppConfig().option<Config::row_index_from_one>() );
 
     const auto addMenuItems = [&](const QString &searchText) {
         menu.clearClipboardItems();
diff --git a/src/tests/tests.cpp b/src/tests/tests.cpp
index 6d373f4805882a547b921150b0d0de77507a9cca..13b253284b56a03c78c3a8910d326f6310018a9b 100644
--- a/src/tests/tests.cpp
+++ b/src/tests/tests.cpp
@@ -2288,6 +2288,13 @@ void Tests::searchItemsAndSelect()
 void Tests::searchRowNumber()
 {
     RUN("add" << "d2" << "c" << "b2" << "a", "");
+
+    RUN("keys" << ":2" << "TAB", "");
+    RUN("testSelected", QString(clipboardTabName) + " 1 1\n");
+    RUN("keys" << "CTRL+A", "");
+    RUN("testSelected", QString(clipboardTabName) + " 1 1 3\n");
+
+    RUN("config" << "row_index_from_one" << "false", "false\n");
     RUN("keys" << ":2" << "TAB", "");
     RUN("testSelected", QString(clipboardTabName) + " 2 2\n");
     RUN("keys" << "CTRL+A", "");
@@ -2869,6 +2876,23 @@ void Tests::menu()
     RUN("menu" << tab << "2", "");
     RUN("keys" << menuId << "END", "");
     ACTIVATE_MENU_ITEM(menuId, clipboardBrowserId, "B");
+
+#ifdef Q_OS_MAC
+    SKIP("Number keys don't seem to work in the tray menu on macOS.");
+#endif
+
+    // Select item by row number.
+    RUN("tab" << tab << "add(3,2,1,0)", "");
+    RUN("menu" << tab, "");
+    RUN("keys" << menuId << "3" << clipboardBrowserId, "");
+    WAIT_FOR_CLIPBOARD("2");
+
+    // Select item by index.
+    RUN("config" << "row_index_from_one" << "false", "false\n");
+    RUN("tab" << tab << "add(3,2,1,0)", "");
+    RUN("menu" << tab, "");
+    RUN("keys" << menuId << "3" << clipboardBrowserId, "");
+    WAIT_FOR_CLIPBOARD("3");
 }
 
 void Tests::traySearch()