diff --git a/modules/game_containers/container.otui b/modules/game_containers/container.otui
index 7615e4e4..ccf7920c 100644
--- a/modules/game_containers/container.otui
+++ b/modules/game_containers/container.otui
@@ -1,3 +1,8 @@
+PageButton < Button
+  size: 30 18
+  margin: 1
+
+
 ContainerWindow < MiniWindow
   height: 150
 
@@ -25,6 +30,35 @@ ContainerWindow < MiniWindow
     $pressed:
       image-clip: 42 28 14 14
 
+  Panel
+    id: pagePanel
+    anchors.left: parent.left
+    anchors.right: parent.right
+    anchors.top: miniwindowTopBar.bottom
+    height: 20
+    margin: 2 3 0 3
+    background: #00000066
+    visible: false
+
+    Label
+      id: pageLabel
+      anchors.top: parent.top
+      anchors.horizontalCenter: parent.horizontalCenter
+      margin-top: 2
+      text-auto-resize: true
+
+    PageButton
+      id: prevPageButton
+      text: <
+      anchors.top: parent.top
+      anchors.left: parent.left
+
+    PageButton
+      id: nextPageButton
+      text: >
+      anchors.top: parent.top
+      anchors.right: parent.right
+
   MiniWindowContents
     padding-right: 0
     layout:
diff --git a/modules/game_containers/containers.lua b/modules/game_containers/containers.lua
index 7f2aed5d..9265942d 100644
--- a/modules/game_containers/containers.lua
+++ b/modules/game_containers/containers.lua
@@ -3,9 +3,8 @@ function init()
 
   connect(Container, { onOpen = onContainerOpen,
                        onClose = onContainerClose,
-                       onAddItem = onContainerAddItem,
-                       onUpdateItem = onContainerUpdateItem,
-                       onRemoveItem = onContainerRemoveItem })
+                       onSizeChange = onContainerChangeSize,
+                       onUpdateItem = onContainerUpdateItem })
   connect(Game, { onGameEnd = clean() })
 
   reloadContainers()
@@ -14,9 +13,8 @@ end
 function terminate()
   disconnect(Container, { onOpen = onContainerOpen,
                           onClose = onContainerClose,
-                          onAddItem = onContainerAddItem,
-                          onUpdateItem = onContainerUpdateItem,
-                          onRemoveItem = onContainerRemoveItem })
+                          onSizeChange = onContainerChangeSize,
+                          onUpdateItem = onContainerUpdateItem })
   disconnect(Game, { onGameEnd = clean() })
 end
 
@@ -46,6 +44,38 @@ function refreshContainerItems(container)
     local itemWidget = container.itemsPanel:getChildById('item' .. slot)
     itemWidget:setItem(container:getItem(slot))
   end
+
+  if container:hasPages() then
+    refreshContainerPages(container)
+  end
+end
+
+function toggleContainerPages(containerWindow, pages)
+  containerWindow:getChildById('miniwindowScrollBar'):setMarginTop(pages and 42 or 22)
+  containerWindow:getChildById('contentsPanel'):setMarginTop(pages and 42 or 22)
+  containerWindow:getChildById('pagePanel'):setVisible(pages)
+end
+
+function refreshContainerPages(container)
+  local currentPage = 1 + math.floor(container:getFirstIndex() / container:getCapacity())
+  local pages = 1 + math.floor(math.max(0, (container:getSize() - 1)) / container:getCapacity())
+  container.window:recursiveGetChildById('pageLabel'):setText(string.format('Page %i of %i', currentPage, pages))
+
+  local prevPageButton = container.window:recursiveGetChildById('prevPageButton')
+  if currentPage == 1 then
+    prevPageButton:setEnabled(false)
+  else
+    prevPageButton:setEnabled(true)
+    prevPageButton.onClick = function() g_game.seekInContainer(container:getId(), container:getFirstIndex() - container:getCapacity()) end
+  end
+
+  local nextPageButton = container.window:recursiveGetChildById('nextPageButton')
+  if currentPage >= pages then
+    nextPageButton:setEnabled(false)
+  else
+    nextPageButton:setEnabled(true)
+    nextPageButton.onClick = function() g_game.seekInContainer(container:getId(), container:getFirstIndex() + container:getCapacity()) end
+  end
 end
 
 function onContainerOpen(container, previousContainer)
@@ -88,11 +118,18 @@ function onContainerOpen(container, previousContainer)
     itemWidget:setItem(container:getItem(slot))
     itemWidget:setMargin(0)
     itemWidget.position = container:getSlotPosition(slot)
+
+    if not container:isUnlocked() then
+      itemWidget:setBorderColor('red')
+    end
   end
 
   container.window = containerWindow
   container.itemsPanel = containerPanel
 
+  toggleContainerPages(containerWindow, container:hasPages())
+  refreshContainerPages(container)
+
   local layout = containerPanel:getLayout()
   local cellSize = layout:getCellSize()
   containerWindow:setContentMinimumHeight(cellSize.height)
@@ -110,7 +147,7 @@ function onContainerClose(container)
   destroy(container)
 end
 
-function onContainerAddItem(container, slot, item)
+function onContainerChangeSize(container, size)
   if not container.window then return end
   refreshContainerItems(container)
 end
@@ -120,8 +157,3 @@ function onContainerUpdateItem(container, slot, item, oldItem)
   local itemWidget = container.itemsPanel:getChildById('item' .. slot)
   itemWidget:setItem(item)
 end
-
-function onContainerRemoveItem(container, slot, item)
-  if not container.window then return end
-  refreshContainerItems(container)
-end
diff --git a/modules/game_interface/gameinterface.lua b/modules/game_interface/gameinterface.lua
index 85ef18b7..8cbeca96 100644
--- a/modules/game_interface/gameinterface.lua
+++ b/modules/game_interface/gameinterface.lua
@@ -467,6 +467,10 @@ function createThingMenu(menuPosition, lookThing, useThing, creatureThing)
     if useThing:isRotateable() then
       menu:addOption(tr('Rotate'), function() g_game.rotate(useThing) end)
     end
+
+    if g_game.getFeature(GameBrowseField) and useThing:getPosition().x ~= 0xffff then
+      menu:addOption(tr('Browse Field'), function() g_game.browseField(useThing:getPosition()) end)
+    end
   end
 
   if lookThing and not lookThing:isCreature() and not lookThing:isNotMoveable() and lookThing:isPickupable() then
diff --git a/modules/gamelib/const.lua b/modules/gamelib/const.lua
index 3588cac0..7c5695d6 100644
--- a/modules/gamelib/const.lua
+++ b/modules/gamelib/const.lua
@@ -117,6 +117,8 @@ GamePVPMode = 50
 GameWritableDate = 51
 GameAdditionalVipInfo = 52
 GameSpritesAlphaChannel = 56
+GamePremiumExpiration = 57
+GameBrowseField = 58
 
 TextColors = {
   red       = '#f55e5e', --'#c83200'
diff --git a/src/client/const.h b/src/client/const.h
index 268af7f4..2914199c 100644
--- a/src/client/const.h
+++ b/src/client/const.h
@@ -389,6 +389,7 @@ namespace Otc
         GameHideNpcNames = 55,
         GameSpritesAlphaChannel = 56,
         GamePremiumExpiration = 57,
+        GameBrowseField = 58,
 
         LastGameFeature = 101
     };
diff --git a/src/client/container.cpp b/src/client/container.cpp
index 4d0e06fd..4c83912e 100644
--- a/src/client/container.cpp
+++ b/src/client/container.cpp
@@ -57,9 +57,22 @@ void Container::onClose()
 
 void Container::onAddItem(const ItemPtr& item, int slot)
 {
-    m_items.push_front(item);
+    slot -= m_firstIndex;
+
+    m_size++;
+    // indicates that there is a new item on next page
+    if(m_hasPages && slot > m_capacity) {
+        callLuaField("onSizeChange", m_size);
+        return;
+    }
+
+    if(slot == 0)
+        m_items.push_front(item);
+    else
+        m_items.push_back(item);
     updateItemsPositions();
 
+    callLuaField("onSizeChange", m_size);
     callLuaField("onAddItem", slot, item);
 }
 
@@ -80,6 +93,7 @@ void Container::onAddItems(const std::vector<ItemPtr>& items)
 
 void Container::onUpdateItem(int slot, const ItemPtr& item)
 {
+    slot -= m_firstIndex;
     if(slot < 0 || slot >= (int)m_items.size()) {
         g_logger.traceError("slot not found");
         return;
@@ -92,8 +106,15 @@ void Container::onUpdateItem(int slot, const ItemPtr& item)
     callLuaField("onUpdateItem", slot, item, oldItem);
 }
 
-void Container::onRemoveItem(int slot)
+void Container::onRemoveItem(int slot, const ItemPtr& lastItem)
 {
+    slot -= m_firstIndex;
+    if(m_hasPages && slot >= (int)m_items.size()) {
+        m_size--;
+        callLuaField("onSizeChange", m_size);
+        return;
+    }
+
     if(slot < 0 || slot >= (int)m_items.size()) {
         g_logger.traceError("slot not found");
         return;
@@ -102,8 +123,16 @@ void Container::onRemoveItem(int slot)
     ItemPtr item = m_items[slot];
     m_items.erase(m_items.begin() + slot);
 
+
+    if(lastItem) {
+        onAddItem(lastItem, m_firstIndex + m_capacity - 1);
+        m_size--;
+    }
+    m_size--;
+
     updateItemsPositions();
 
+    callLuaField("onSizeChange", m_size);
     callLuaField("onRemoveItem", slot, item);
 }
 
diff --git a/src/client/container.h b/src/client/container.h
index f141e605..c87e8bdd 100644
--- a/src/client/container.h
+++ b/src/client/container.h
@@ -57,7 +57,7 @@ protected:
     void onAddItem(const ItemPtr& item, int slot);
     void onAddItems(const std::vector<ItemPtr>& items);
     void onUpdateItem(int slot, const ItemPtr& item);
-    void onRemoveItem(int slot);
+    void onRemoveItem(int slot, const ItemPtr& lastItem);
 
     friend class Game;
 
diff --git a/src/client/game.cpp b/src/client/game.cpp
index d35308e0..71c6d5d6 100644
--- a/src/client/game.cpp
+++ b/src/client/game.cpp
@@ -308,7 +308,9 @@ void Game::processCloseContainer(int containerId)
 {
     ContainerPtr container = getContainer(containerId);
     if(!container) {
-        g_logger.traceError("container not found");
+        /* happens if you close and restart client with container opened
+         * g_logger.traceError("container not found");
+         */
         return;
     }
 
@@ -338,7 +340,7 @@ void Game::processContainerUpdateItem(int containerId, int slot, const ItemPtr&
     container->onUpdateItem(slot, item);
 }
 
-void Game::processContainerRemoveItem(int containerId, int slot)
+void Game::processContainerRemoveItem(int containerId, int slot, const ItemPtr& lastItem)
 {
     ContainerPtr container = getContainer(containerId);
     if(!container) {
@@ -346,7 +348,7 @@ void Game::processContainerRemoveItem(int containerId, int slot)
         return;
     }
 
-    container->onRemoveItem(slot);
+    container->onRemoveItem(slot, lastItem);
 }
 
 void Game::processInventoryChange(int slot, const ItemPtr& item)
@@ -1404,6 +1406,20 @@ void Game::answerModalDialog(int dialog, int button, int choice)
     m_protocolGame->sendAnswerModalDialog(dialog, button, choice);
 }
 
+void Game::browseField(const Position& position)
+{
+    if(!canPerformGameAction())
+        return;
+    m_protocolGame->sendBrowseField(position);
+}
+
+void Game::seekInContainer(int cid, int index)
+{
+    if(!canPerformGameAction())
+        return;
+    m_protocolGame->sendSeekInContainer(cid, index);
+}
+
 void Game::ping()
 {
     if(!m_protocolGame || !m_protocolGame->isConnected())
@@ -1558,6 +1574,10 @@ void Game::setProtocolVersion(int version)
         enableFeature(Otc::GameThingMarks);
     }
 
+    if(version >= 984) {
+        enableFeature(Otc::GameBrowseField);
+    }
+
     if(version >= 1000) {
         enableFeature(Otc::GamePVPMode);
     }
diff --git a/src/client/game.h b/src/client/game.h
index 7fdf582f..4cb35184 100644
--- a/src/client/game.h
+++ b/src/client/game.h
@@ -85,7 +85,7 @@ protected:
     void processCloseContainer(int containerId);
     void processContainerAddItem(int containerId, const ItemPtr& item, int slot);
     void processContainerUpdateItem(int containerId, int slot, const ItemPtr& item);
-    void processContainerRemoveItem(int containerId, int slot);
+    void processContainerRemoveItem(int containerId, int slot, const ItemPtr& lastItem);
 
     // channel related
     void processChannelList(const std::vector<std::tuple<int, std::string> >& channelList);
@@ -258,6 +258,10 @@ public:
     // >= 970 modal dialog
     void answerModalDialog(int dialog, int button, int choice);
 
+    // >= 984 browse field
+    void browseField(const Position& position);
+    void seekInContainer(int cid, int index);
+
     //void reportRuleViolation2();
     void ping();
     void setPingDelay(int delay) { m_pingDelay = delay; }
diff --git a/src/client/luafunctions.cpp b/src/client/luafunctions.cpp
index 012ad72d..ebc29073 100644
--- a/src/client/luafunctions.cpp
+++ b/src/client/luafunctions.cpp
@@ -295,6 +295,8 @@ void Client::registerLuaFunctions()
     g_lua.bindSingletonFunction("g_game", "disableFeature", &Game::disableFeature, &g_game);
     g_lua.bindSingletonFunction("g_game", "isGM", &Game::isGM, &g_game);
     g_lua.bindSingletonFunction("g_game", "answerModalDialog", &Game::answerModalDialog, &g_game);
+    g_lua.bindSingletonFunction("g_game", "browseField", &Game::browseField, &g_game);
+    g_lua.bindSingletonFunction("g_game", "seekInContainer", &Game::seekInContainer, &g_game);
     g_lua.bindSingletonFunction("g_game", "getLastWalkDir", &Game::getLastWalkDir, &g_game);
 
     g_lua.registerSingletonClass("g_shaders");
diff --git a/src/client/protocolcodes.h b/src/client/protocolcodes.h
index 848eabee..14a83a4e 100644
--- a/src/client/protocolcodes.h
+++ b/src/client/protocolcodes.h
@@ -228,6 +228,8 @@ namespace Proto {
         ClientCancelAttackAndFollow         = 190,
         ClientUpdateTile                    = 201,
         ClientRefreshContainer              = 202,
+        ClientBrowseField                   = 203,
+        ClientSeekInContainer               = 204,
         ClientRequestOutfit                 = 210,
         ClientChangeOutfit                  = 211,
         ClientMount                         = 212, // 870
diff --git a/src/client/protocolgame.h b/src/client/protocolgame.h
index f6f4a4df..ccbab188 100644
--- a/src/client/protocolgame.h
+++ b/src/client/protocolgame.h
@@ -111,6 +111,8 @@ public:
     void sendNewNewRuleViolation(int reason, int action, const std::string& characterName, const std::string& comment, const std::string& translation);
     void sendRequestItemInfo(int itemId, int subType, int index);
     void sendAnswerModalDialog(int dialog, int button, int choice);
+    void sendBrowseField(const Position& position);
+    void sendSeekInContainer(int cid, int index);
 
     // otclient only
     void sendChangeMapAwareRange(int xrange, int yrange);
diff --git a/src/client/protocolgameparse.cpp b/src/client/protocolgameparse.cpp
index fd727f19..a4b84014 100644
--- a/src/client/protocolgameparse.cpp
+++ b/src/client/protocolgameparse.cpp
@@ -686,16 +686,17 @@ void ProtocolGame::parseContainerRemoveItem(const InputMessagePtr& msg)
 {
     int containerId = msg->getU8();
     int slot;
+    ItemPtr lastItem;
     if(g_game.getFeature(Otc::GameContainerPagination)) {
         slot = msg->getU16();
 
         int itemId = msg->getU16();
         if(itemId != 0)
-            getItem(msg, itemId);
+            lastItem = getItem(msg, itemId);
     } else {
         slot = msg->getU8();
     }
-    g_game.processContainerRemoveItem(containerId, slot);
+    g_game.processContainerRemoveItem(containerId, slot, lastItem);
 }
 
 void ProtocolGame::parseAddInventoryItem(const InputMessagePtr& msg)
diff --git a/src/client/protocolgamesend.cpp b/src/client/protocolgamesend.cpp
index 502eb820..15487b09 100644
--- a/src/client/protocolgamesend.cpp
+++ b/src/client/protocolgamesend.cpp
@@ -831,6 +831,29 @@ void ProtocolGame::sendAnswerModalDialog(int dialog, int button, int choice)
     send(msg);
 }
 
+void ProtocolGame::sendBrowseField(const Position& position)
+{
+    if(!g_game.getFeature(Otc::GameBrowseField))
+        return;
+
+    OutputMessagePtr msg(new OutputMessage);
+    msg->addU8(Proto::ClientBrowseField);
+    addPosition(msg, position);
+    send(msg);
+}
+
+void ProtocolGame::sendSeekInContainer(int cid, int index)
+{
+    if(!g_game.getFeature(Otc::GameContainerPagination))
+        return;
+
+    OutputMessagePtr msg(new OutputMessage);
+    msg->addU8(Proto::ClientSeekInContainer);
+    msg->addU8(cid);
+    msg->addU16(index);
+    send(msg);
+}
+
 void ProtocolGame::sendChangeMapAwareRange(int xrange, int yrange)
 {
     if(!g_game.getFeature(Otc::GameChangeMapAwareRange))