diff --git a/algo/ca/TrackingChain.cxx b/algo/ca/TrackingChain.cxx
index 1d481261a1af5143deb8128a969175122fcf94eb..d3ee72ab758c4e28ad48eae2805d8cbfdc7054e0 100644
--- a/algo/ca/TrackingChain.cxx
+++ b/algo/ca/TrackingChain.cxx
@@ -40,8 +40,9 @@ using cbm::algo::ca::constants::clrs::GNb;  // grin bald text
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-TrackingChain::TrackingChain(const std::unique_ptr<cbm::algo::qa::Manager>& qaManager, std::string_view name)
+TrackingChain::TrackingChain(ECbmRecoMode recoMode, const std::unique_ptr<cbm::algo::qa::Manager>& qaManager, std::string_view name)
   : fQa(Qa(qaManager, name))
+  , fRecoMode(recoMode)
 {
 }
 
@@ -116,8 +117,13 @@ void TrackingChain::Init()
 
   // ------ Initialize CA framework
   fCaMonitor.Reset();
-  fCaFramework.SetNofThreads(Opts().NumOMPThreads() == std::nullopt ? openmp::GetMaxThreads()
-                                                                    : *(Opts().NumOMPThreads()));
+  if (ECbmRecoMode::Timeslice == fRecoMode) {
+    fCaFramework.SetNofThreads(Opts().NumOMPThreads() == std::nullopt ? openmp::GetMaxThreads()
+                                                                      : *(Opts().NumOMPThreads()));
+  }
+  else {
+    fCaFramework.SetNofThreads(1);
+  }
   fCaFramework.ReceiveParameters(std::move(parameters));
   fCaFramework.Init(ca::TrackingMode::kMcbm);
 
@@ -174,18 +180,26 @@ void TrackingChain::PrepareInput(Input_t recoResults)
   faHitExternalIndices.clear();
   faHitExternalIndices.reserve(nHitsTot);
   if (fbDetUsed[EDetectorID::kSts]) {
+    fCaMonitorData.StartTimer(ca::ETimer::PrepareStsHits);
     ReadHits<EDetectorID::kSts>(recoResults.stsHits);
+    fCaMonitorData.StopTimer(ca::ETimer::PrepareStsHits);
   }
   if (fbDetUsed[EDetectorID::kTrd]) {
+    fCaMonitorData.StartTimer(ca::ETimer::PrepareTrdHits);
     ReadHits<EDetectorID::kTrd>(recoResults.trdHits);
+    fCaMonitorData.StopTimer(ca::ETimer::PrepareTrdHits);
   }
   if (fbDetUsed[EDetectorID::kTof]) {
+    fCaMonitorData.StartTimer(ca::ETimer::PrepareTofHits);
     ReadHits<EDetectorID::kTof>(recoResults.tofHits);
+    fCaMonitorData.StopTimer(ca::ETimer::PrepareTofHits);
   }
   faHitExternalIndices.shrink_to_fit();
   fCaDataManager.SetNhitKeys(fNofHitKeys);
   L_(debug) << "Tracking chain: " << fCaDataManager.GetNofHits() << " hits will be passed to the ca::Framework";
+  fCaMonitorData.StartTimer(ca::ETimer::InputDataTransmission);
   fCaFramework.ReceiveInputData(fCaDataManager.TakeInputData());
+  fCaMonitorData.StopTimer(ca::ETimer::InputDataTransmission);
 }
 
 // ---------------------------------------------------------------------------------------------------------------------
@@ -223,12 +237,13 @@ TrackingChain::Output_t TrackingChain::PrepareOutput()
     trackFirstHit += nHits;
   }
 
-  L_(info) << "TrackingChain: Timeslice contains " << fCaMonitorData.GetCounterValue(ca::ECounter::RecoTrack)
-           << " tracks, with " << fCaMonitorData.GetCounterValue(ca::ECounter::RecoStsHit) << " sts hits, "
-           << fCaMonitorData.GetCounterValue(ca::ECounter::RecoTofHit) << " tof hits, "
-           << fCaMonitorData.GetCounterValue(ca::ECounter::RecoTrdHit) << " trd hits"
-           << "; the FindTracks routine ran " << fCaMonitorData.GetTimer(ca::ETimer::FindTracks).GetTotal() << " s";
-
+  if (ECbmRecoMode::Timeslice == fRecoMode) {
+    L_(info) << "TrackingChain: Timeslice contains " << fCaMonitorData.GetCounterValue(ca::ECounter::RecoTrack)
+             << " tracks, with " << fCaMonitorData.GetCounterValue(ca::ECounter::RecoStsHit) << " sts hits, "
+             << fCaMonitorData.GetCounterValue(ca::ECounter::RecoTofHit) << " tof hits, "
+             << fCaMonitorData.GetCounterValue(ca::ECounter::RecoTrdHit) << " trd hits"
+             << "; the FindTracks routine ran " << fCaMonitorData.GetTimer(ca::ETimer::FindTracks).GetTotal() << " s";
+  }
 
   // QA
   if (fQa.IsActive()) {
@@ -327,6 +342,7 @@ void TrackingChain::ReadHits(PartitionedSpan<const ca::HitTypes_t::at<DetID>> hi
 
       //int iHitExt     = iOffset + iPartHit;
       // ---- Fill ca::Hit
+      fCaMonitorData.StartTimer(ca::ETimer::CaHitCreation);
       ca::Hit caHit;
       if constexpr (IsSts) {
         caHit.SetFrontKey(firstHitKey + hit.fFrontClusterId);
@@ -337,6 +353,15 @@ void TrackingChain::ReadHits(PartitionedSpan<const ca::HitTypes_t::at<DetID>> hi
         caHit.SetFrontKey(firstHitKey + iPartHit);
         caHit.SetBackKey(caHit.FrontKey());
       }
+
+      if constexpr (IsTof) {
+        // Cut the BMon hits (if any)
+        if (hit.Z() < 0.1) {
+          // FIXME: Provide BMon addresses explicitly in all the parameter files
+          continue;
+        }
+      }
+
       caHit.SetX(hit.X());
       caHit.SetY(hit.Y());
       caHit.SetZ(hit.Z());
@@ -366,11 +391,16 @@ void TrackingChain::ReadHits(PartitionedSpan<const ca::HitTypes_t::at<DetID>> hi
       caHit.SetStation(iStActive);
       caHit.SetId(fCaDataManager.GetNofHits());
       if (caHit.Check()) {
-        if ((caHit.T() < lastTime - 1000.) && (dataStream < 100000)) {
-          dataStream++;
+        if (ECbmRecoMode::Timeslice == fRecoMode) {
+          if ((caHit.T() < lastTime - 1000.) && (dataStream < 100000)) {
+            dataStream++;
+          }
+          lastTime = caHit.T();
+          fCaDataManager.PushBackHit(caHit, dataStreamDet | dataStream);
+        }
+        else {
+          fCaDataManager.PushBackHit(caHit);  // A single data stream in event-by-event mode
         }
-        lastTime = caHit.T();
-        fCaDataManager.PushBackHit(caHit, dataStreamDet | dataStream);
         faHitExternalIndices.push_back(std::make_tuple(DetID, iPartition, iPartHit));
         if (fNofHitKeys <= caHit.FrontKey()) {
           fNofHitKeys = caHit.FrontKey() + 1;
@@ -396,6 +426,7 @@ void TrackingChain::ReadHits(PartitionedSpan<const ca::HitTypes_t::at<DetID>> hi
           fCaMonitorData.IncrementCounter(ca::ECounter::UndefinedTofHit);
         }
       }
+      fCaMonitorData.StopTimer(ca::ETimer::CaHitCreation);
       //prevTime = caHit.T();
       // ---- Update number of hit keys
     }  // iPartHit
diff --git a/algo/ca/TrackingChain.h b/algo/ca/TrackingChain.h
index 3f949d3605e87e1f58b5404886a63ffd44c636d1..5d30319fb05404b00584baf1a6be9be787e0518c 100644
--- a/algo/ca/TrackingChain.h
+++ b/algo/ca/TrackingChain.h
@@ -41,9 +41,10 @@ namespace cbm::algo
   class TrackingChain : public SubChain {
    public:
     /// \brief Constructor from parameters
+    /// \param recoMode     Reconstruction mode
     /// \param pManager a QA-manager
     /// \param name A name of the task (histograms directory)
-    TrackingChain(const std::unique_ptr<cbm::algo::qa::Manager>& qaManager = nullptr, std::string_view name = "");
+    TrackingChain(ECbmRecoMode recoMode, const std::unique_ptr<cbm::algo::qa::Manager>& qaManager = nullptr, std::string_view name = "");
 
     /// \struct Input_t
     /// \brief  Input to the TrackingChain
@@ -92,6 +93,7 @@ namespace cbm::algo
     /// \brief  Provides action in the end of the run
     void Finalize();
 
+
    private:
     // *********************
     // **  Utility functions
@@ -132,6 +134,8 @@ namespace cbm::algo
     /// \note  Indexing: [globalHitID], value: (DetID, partitionID, hitID)
     ca::Vector<std::tuple<ca::EDetectorID, uint32_t, uint32_t>> faHitExternalIndices{"faHitExternalIndices"};
 
+    ECbmRecoMode fRecoMode{ECbmRecoMode::Undefined};  ///< Reconstruction mode
+
     static constexpr bool kDEBUG = false;  ///< Debug mode
   };
 
diff --git a/algo/ca/core/data/CaDataManager.cxx b/algo/ca/core/data/CaDataManager.cxx
index 7d237151d6b690ccdaa9cdc4439aba2ee0fb913b..4e74a2524c9aff2641deb285cce8262be38d310f 100644
--- a/algo/ca/core/data/CaDataManager.cxx
+++ b/algo/ca/core/data/CaDataManager.cxx
@@ -17,23 +17,6 @@
 using cbm::algo::ca::DataManager;
 using cbm::algo::ca::InputData;
 
-// ---------------------------------------------------------------------------------------------------------------------
-//
-bool DataManager::SendInputData(InputData& destination)
-{
-  // Set boundary hit indexes
-  InitData();
-
-  // Check data before input
-  if (CheckInputData<constants::control::InputDataQaLevel>()) {
-    destination = std::move(fInputData);
-    assert(this->GetNofHits() == 0);
-    return true;
-  }
-  LOG(error) << "L1: Attempt to set up inconsistent input data";
-  return false;
-}
-
 // ---------------------------------------------------------------------------------------------------------------------
 //
 InputData&& DataManager::TakeInputData()
@@ -93,16 +76,21 @@ void DataManager::InitData()
 {
   // set the end pointers to data streams
   // TODO: SZh 14.08.2023: Move the max allowed number of streams to the constants.h
-  if (fInputData.fvStreamStartIndices.size() > 3000) {
-    LOG(warning) << "ca::DataManager: unexpected order of input data: too many data streams!!! ";
-    fInputData.fvStreamStartIndices.shrink(3000);
-  }
+
   int nStreams = fInputData.fvStreamStartIndices.size();
-  fInputData.fvStreamStopIndices.reset(nStreams);
-  for (int i = 0; i < nStreams - 1; i++) {
-    fInputData.fvStreamStopIndices[i] = fInputData.fvStreamStartIndices[i + 1];
+  if (!nStreams) {  // No data streams provided
+    fInputData.fvStreamStartIndices.push_back(0);
+    fInputData.fvStreamStopIndices.push_back(fInputData.fvHits.size());
   }
-  if (nStreams > 0) {
+  else {
+    if (nStreams > 3000) {
+      LOG(warning) << "ca::DataManager: unexpected order of input data: too many data streams!!! ";
+      fInputData.fvStreamStartIndices.shrink(3000);
+    }
+    fInputData.fvStreamStopIndices.reset(nStreams);
+    for (int i = 0; i < nStreams - 1; i++) {
+      fInputData.fvStreamStopIndices[i] = fInputData.fvStreamStartIndices[i + 1];
+    }
     fInputData.fvStreamStopIndices[nStreams - 1] = fInputData.fvHits.size();
   }
 }
@@ -112,10 +100,12 @@ void DataManager::InitData()
 void DataManager::WriteInputData(const std::string& fileName) const
 {
   // Check current data object for consistency
-  if (!CheckInputData<constants::control::InputDataQaLevel>()) {
-    LOG(error) << "ca::DataManager: input data writer: attempt to write invalid input data object to file \""
-               << fileName << "\"";
-    return;
+  if constexpr (constants::control::InputDataQaLevel > 0) {
+    if (!CheckInputData<constants::control::InputDataQaLevel>()) {
+      LOG(error) << "ca::DataManager: input data writer: attempt to write invalid input data object to file \""
+                 << fileName << "\"";
+      return;
+    }
   }
 
   // Open output binary file
diff --git a/algo/ca/core/data/CaDataManager.h b/algo/ca/core/data/CaDataManager.h
index d210e52b93035516022b1b8411d1a1761b44dc5e..b8dac8630607d978e9152ce3ac392c7f765bf5c1 100644
--- a/algo/ca/core/data/CaDataManager.h
+++ b/algo/ca/core/data/CaDataManager.h
@@ -54,8 +54,9 @@ namespace cbm::algo::ca
     /// \param  nHits  Number of hits to reserve
     void ResetInputData(HitIndex_t nHits = 0) noexcept;
 
-    /// \brief  Pushes back a hit
-    /// \param  hit  An ca::Hit object
+    /// \brief  Pushes back a hit (with a data stream info)
+    /// \param  hit       An ca::Hit object
+    /// \param  streamId  Index of a data stream
     void PushBackHit(const Hit& hit, int64_t streamId)
     {
       if (fInputData.fvStreamStartIndices.size() == 0 || fLastStreamId != streamId) {  // new data stream
@@ -67,14 +68,14 @@ namespace cbm::algo::ca
       fInputData.fvHits.push_back(hit);
     }
 
+    /// \brief  Pushes back a hit
+    /// \param  hit       An ca::Hit object
+    void PushBackHit(const Hit& hit) { fInputData.fvHits.push_back(hit); }
+
     /// \brief  Sets the number of hit keys
     /// \param  nKeys  Number of hit keys
     void SetNhitKeys(int nKeys) { fInputData.fNhitKeys = nKeys; }
 
-    /// \brief Sends (moves) input data to an object (alternative method of data sending)
-    /// \param destination  Destination object of input data
-    bool SendInputData(InputData& destination);
-
     /// \brief Takes (moves) the instance of the input data object
     InputData&& TakeInputData();
 
diff --git a/algo/ca/core/utils/CaTrackingMonitor.h b/algo/ca/core/utils/CaTrackingMonitor.h
index f91de1d75ac356d14bbe01c330800d188b33788e..ffcee0c35371b8b30b40d84b82c347b497c58cd9 100644
--- a/algo/ca/core/utils/CaTrackingMonitor.h
+++ b/algo/ca/core/utils/CaTrackingMonitor.h
@@ -52,6 +52,11 @@ namespace cbm::algo::ca
   {
     TrackingChain,
       PrepareInputData,
+        PrepareStsHits,
+        PrepareTrdHits,
+        PrepareTofHits,
+        InputDataTransmission,
+        CaHitCreation,
       Tracking,
         PrepareTimeslice,
         TrackingThread,
@@ -103,6 +108,11 @@ namespace cbm::algo::ca
 
       SetTimerName(ETimer::TrackingChain, "tracking chain");
       SetTimerName(ETimer::PrepareInputData, "input data preparation");
+      SetTimerName(ETimer::PrepareStsHits, "STS hits preparation");
+      SetTimerName(ETimer::PrepareTrdHits, "TRD hits preparation");
+      SetTimerName(ETimer::PrepareTofHits, "TOF hits preparation");
+      SetTimerName(ETimer::InputDataTransmission, "input data transmission");
+      SetTimerName(ETimer::CaHitCreation, "CA hit creation");
       SetTimerName(ETimer::Tracking, "algorithm execution");
       SetTimerName(ETimer::PrepareTimeslice, "timeslice preparation");
       SetTimerName(ETimer::TrackingThread, "tracking on one thread");
diff --git a/algo/evselector/RecoEventSelectorMonitor.h b/algo/evselector/RecoEventSelectorMonitor.h
new file mode 100644
index 0000000000000000000000000000000000000000..330f7070209a70acf9725d45bd5dff101713cd71
--- /dev/null
+++ b/algo/evselector/RecoEventSelectorMonitor.h
@@ -0,0 +1,75 @@
+/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergei Zharko [committer] */
+
+/// \file   RecoEventSelectorMonitor.h
+/// \date   28.01.2025
+/// \brief  A monitor for reco event selector
+/// \author Sergei Zharko <s.zharko@gsi.de>
+
+#pragma once
+
+#include "CaMonitor.h"
+
+#include <boost/serialization/base_object.hpp>
+
+namespace cbm::algo::evselect
+{
+  /// \enum  ECounter
+  /// \brief Counter keys for the event selector monitor
+  enum class ECounter
+  {
+    EventsTotal,      ///< Total number of events processed
+    EventsNeStsHits,  ///< Events with not enough STS hits
+    EventsNeTofHits,  ///< Events with enough STS hits, but not enough TOF hits
+    EventsNeTracks,   ///< Events with enough hits, but not enough tracks
+    EventsSelected,   ///< Number of selected events
+    END
+  };
+
+  /// \enum  ETimer
+  /// \brief Timer keys for the event selector monitor
+  /* clang-format off */
+  enum class ETimer {
+    EventReconstruction,
+      StsHitFinder,
+      TofHitFinder,
+      TrdHitFinder,
+      TrackFinder,
+    END
+  };
+  /* clang-format on */
+
+  /// \brief Specification of ca::MonitorData for the event selector
+  using MonitorData_t = ca::MonitorData<ECounter, ETimer>;
+
+  /// \class Monitor
+  /// \brief A monitor for the event selector
+  class Monitor : public ca::Monitor<ECounter, ETimer> {
+   public:
+    /// \brief Default constructor
+    Monitor() : ca::Monitor<ECounter, ETimer>("Event-selector Monitor")
+    {
+      SetCounterName(ECounter::EventsTotal, "total events");
+      SetCounterName(ECounter::EventsNeStsHits, "events with not enough STS hits");
+      SetCounterName(ECounter::EventsNeTofHits, "events with enough STS hits, but not enough TOF hits");
+      SetCounterName(ECounter::EventsNeTracks, "events with enough STS and TOF hits, but not enough tracks");
+      SetCounterName(ECounter::EventsSelected, "selected events");
+
+      SetTimerName(ETimer::EventReconstruction, "event reconstruction");
+      SetTimerName(ETimer::StsHitFinder, "hit finding in STS");
+      SetTimerName(ETimer::TofHitFinder, "hit finding in TOF");
+      SetTimerName(ETimer::TrdHitFinder, "hit finding in TRD");
+      SetTimerName(ETimer::TrackFinder, "track finding");
+    }
+
+   private:
+    friend class boost::serialization::access;
+    template<typename Archive>
+    void serialize(Archive& ar, const unsigned int /*version*/)
+    {
+      ar& boost::serialization::base_object<ca::Monitor<ECounter, ETimer>>(*this);
+    }
+  };
+
+}  // namespace cbm::algo::evselect
diff --git a/algo/global/Reco.cxx b/algo/global/Reco.cxx
index a990278ad2cf01f9ab5377f5b4f213a3f97d673b..cfde9b3b479f022e9c08c8a77c36db6e10e10e82 100644
--- a/algo/global/Reco.cxx
+++ b/algo/global/Reco.cxx
@@ -253,16 +253,29 @@ void Reco::Init(const Options& opts)
   // Tracking
   if (Opts().Has(Step::Tracking)) {
     if (fQaManager != nullptr && Opts().Has(QaStep::Tracking)) {
-      fTracking = std::make_unique<TrackingChain>(fQaManager, "CaTimeslice");
+      fTracking = std::make_unique<TrackingChain>(ECbmRecoMode::Timeslice, fQaManager, "CaTimeslice");
     }
     else {
-      fTracking = std::make_unique<TrackingChain>();
+      fTracking = std::make_unique<TrackingChain>(ECbmRecoMode::Timeslice);
     }
     fTracking->RegisterSetup(pTrackingSetup);
     fTracking->SetContext(&fContext);
     fTracking->Init();
   }
 
+  if (fbReconstructDigiEvents) {
+    fEvSelectingMonitor.Reset();
+
+    if (fQaManager != nullptr && Opts().Has(QaStep::Tracking)) {
+      fTracking = std::make_unique<TrackingChain>(ECbmRecoMode::EventByEvent, fQaManager, "CaEvent");
+    }
+    else {
+      fTrackingEvent = std::make_unique<TrackingChain>(ECbmRecoMode::EventByEvent);
+    }
+    fTrackingEvent->RegisterSetup(pTrackingSetup);
+    fTrackingEvent->SetContext(&fContext);
+    fTrackingEvent->Init();
+  
   // Initialize the QA manager
   if (fQaManager != nullptr) {
     fQaManager->Init();
@@ -403,12 +416,15 @@ RecoResults Reco::Run(const fles::Timeslice& ts)
     }
 
     // --- Reconstruct and select digi events
-    if (Opts().ReconstructDigiEvents()) {
+    if (fbReconstructDigiEvents) {
       size_t nDiscardedEvents{0};
+      fEvSelectingMonitor.IncrementCounter(evselect::ECounter::EventsTotal, events.size());
       for (const auto& event : events) {
+        fEvSelectingMonitor.StartTimer(evselect::ETimer::EventReconstruction);
         if (!ReconstructEvent(event)) {
           ++nDiscardedEvents;
         }
+        fEvSelectingMonitor.StopTimer(evselect::ETimer::EventReconstruction);
       }
       L_(info) << "Rate of discarded events " << double(nDiscardedEvents) / events.size();
     }
@@ -461,8 +477,17 @@ void Reco::Finalize()
     fStsHitFinder->Finalize();
   }
   if (fTracking) {
+    L_(info) << "Track finding in a timeslice:";
     fTracking->Finalize();
   }
+  if (fTrackingEvent) {
+    L_(info) << "Track finding in digi events:";
+    fTrackingEvent->Finalize();
+  }
+  if (fbReconstructDigiEvents) {
+    L_(info) << fEvSelectingMonitor.ToString();
+  }
+
 
   if (Opts().Profiling() >= ProfilingSummary) {
     L_(info) << MakeReportSubtimers("Run Summary", fTimesliceTimesAcc) << "\n"
@@ -494,8 +519,11 @@ bool Reco::ReconstructEvent(const DigiEvent& digiEvent)
   RecoResults recoEvent;
   //* STS hit reconstruction
   {
+    fEvSelectingMonitor.StartTimer(evselect::ETimer::StsHitFinder);
     auto stsResults = (*fStsHitFinder)(digiEvent.fSts);
-    if (stsResults.hits.NElements() < 2) {  // TODO: Provide a config for cuts (testing mode for now)
+    fEvSelectingMonitor.StopTimer(evselect::ETimer::StsHitFinder);
+    if (stsResults.hits.NElements() < 4) {  // TODO: Provide a config for cuts (testing mode for now)
+      fEvSelectingMonitor.IncrementCounter(evselect::ECounter::EventsNeStsHits);
       return false;
     }
     recoEvent.stsHits = stsResults.hits;
@@ -503,9 +531,12 @@ bool Reco::ReconstructEvent(const DigiEvent& digiEvent)
 
   //* TOF hit reconstruction
   {
+    fEvSelectingMonitor.StartTimer(evselect::ETimer::TofHitFinder);
     auto [caldigis, calmonitor]          = (*fTofCalibrator)(digiEvent.fTof);
     auto [hits, hitmonitor, digiindices] = (*fTofHitFinder)(caldigis);
-    if (hits.NElements() < 1) {  // TODO: Provide a config for cuts (testing mode for now)
+    fEvSelectingMonitor.StopTimer(evselect::ETimer::TofHitFinder);
+    if (hits.NElements() < 2) {  // TODO: Provide a config for cuts (testing mode for now)
+      fEvSelectingMonitor.IncrementCounter(evselect::ECounter::EventsNeTofHits);
       return false;
     }
     recoEvent.tofHits = std::move(hits);
@@ -514,16 +545,37 @@ bool Reco::ReconstructEvent(const DigiEvent& digiEvent)
   //* TRD hit reconstruction
   {
     // FIXME: additional copy of digis, figure out how to pass 1d + 2d digis at once to hitfinder
+    fEvSelectingMonitor.StartTimer(evselect::ETimer::TrdHitFinder);
     const auto& digis1d = digiEvent.fTrd;
     const auto& digis2d = digiEvent.fTrd2d;
     PODVector<CbmTrdDigi> allDigis{};
     allDigis.reserve(digis1d.size() + digis2d.size());
     std::copy(digis1d.begin(), digis1d.end(), std::back_inserter(allDigis));
     std::copy(digis2d.begin(), digis2d.end(), std::back_inserter(allDigis));
-    auto trdResults   = (*fTrdHitfind)(allDigis);
+    auto trdResults = (*fTrdHitfind)(allDigis);
+    fEvSelectingMonitor.StopTimer(evselect::ETimer::TrdHitFinder);
     recoEvent.trdHits = std::move(std::get<0>(trdResults));
   }
 
+  //* Tracking
+  {
+    fEvSelectingMonitor.StartTimer(evselect::ETimer::TrackFinder);
+    TrackingChain::Input_t input{.stsHits = recoEvent.stsHits,
+                                 .tofHits = recoEvent.tofHits,
+                                 .trdHits = recoEvent.trdHits};
+    TrackingChain::Output_t output = fTrackingEvent->Run(input);
+    recoEvent.tracks               = std::move(output.tracks);
+    recoEvent.trackStsHitIndices   = std::move(output.stsHitIndices);
+    recoEvent.trackTofHitIndices   = std::move(output.tofHitIndices);
+    recoEvent.trackTrdHitIndices   = std::move(output.trdHitIndices);
+    fEvSelectingMonitor.StopTimer(evselect::ETimer::TrackFinder);
+    if (recoEvent.tracks.size() < 2) {  // Reject all events with less then two tracks
+      fEvSelectingMonitor.IncrementCounter(evselect::ECounter::EventsNeTracks);
+      return false;
+    }
+  }
+
+  fEvSelectingMonitor.IncrementCounter(evselect::ECounter::EventsSelected);
   return true;
 }
 
diff --git a/algo/global/Reco.h b/algo/global/Reco.h
index 5a2c62e63a5c0b22bdf2d69175e00b511e4c2243..1ab27d58d38cdfbc3da97d6fbcb3d0b9b74a4021 100644
--- a/algo/global/Reco.h
+++ b/algo/global/Reco.h
@@ -5,6 +5,7 @@
 
 #include "AlgoTraits.h"
 #include "SubChain.h"
+#include "evselector/RecoEventSelectorMonitor.h"
 #include "global/RecoResults.h"
 
 #include <xpu/host.h>
@@ -181,7 +182,11 @@ namespace cbm::algo
     std::unique_ptr<evbuild::EventbuildChain> fEventBuild;
 
     // Tracking
-    std::unique_ptr<TrackingChain> fTracking;
+    std::unique_ptr<TrackingChain> fTracking;       ///< Tracking in timeslice
+    std::unique_ptr<TrackingChain> fTrackingEvent;  ///< Tracking in event
+
+    // Event selection
+    evselect::Monitor fEvSelectingMonitor;  ///< Monitor for event selecting
 
     // QA
     std::unique_ptr<qa::Manager> fQaManager;
diff --git a/algo/global/RecoResults.h b/algo/global/RecoResults.h
index eb64fa2368569a398c21da0137a4678b13e46490..670927953aa74f4a1974e9967288ea19fa9fbcb5 100644
--- a/algo/global/RecoResults.h
+++ b/algo/global/RecoResults.h
@@ -45,5 +45,6 @@ namespace cbm::algo
     ca::Vector<ca::Track> tracks;
     ca::Vector<std::vector<std::pair<uint32_t, uint32_t>>> trackStsHitIndices;
     ca::Vector<std::vector<std::pair<uint32_t, uint32_t>>> trackTofHitIndices;
+    ca::Vector<std::vector<std::pair<uint32_t, uint32_t>>> trackTrdHitIndices;
   };
 }  // namespace cbm::algo