diff --git a/apps/scpickfilter/descriptions/scpickfilter.xml b/apps/scpickfilter/descriptions/scpickfilter.xml
index 19fdd62cc28d54ea90a689b74abbf74bbbb0c875..cfa2782c03e35bf80ca3c67fb9daaf1e8711996a 100644
--- a/apps/scpickfilter/descriptions/scpickfilter.xml
+++ b/apps/scpickfilter/descriptions/scpickfilter.xml
@@ -19,6 +19,12 @@
           groupingInterval to declare an active shot
         </description>
       </parameter>
+      <parameter name="mustInclude" type="string">
+        <description>
+          Empty or a station ("net.sta.loc") that must be present in a pick group
+          to consider a valid active shot
+        </description>
+      </parameter>
       <parameter name="droppingPeriod" type="double" unit="sec">
         <description>
           For how long to drop picks after an active shot
diff --git a/apps/scpickfilter/main.cpp b/apps/scpickfilter/main.cpp
index 3de2158d0b862aa0b0b0bf167cbf986fab4bbcda..5649e64f038f5cb2c0f8a8b48a1ebe3e6b50c649 100644
--- a/apps/scpickfilter/main.cpp
+++ b/apps/scpickfilter/main.cpp
@@ -236,6 +236,7 @@ private:
   Core::TimeSpan _groupingInterval;
   Core::TimeSpan _droppingPeriod;
   unsigned _minNumPicks;
+  std::string _mustInclude;
   std::string _epFile;
   PickBuffer _buf;
   struct {
@@ -275,6 +276,10 @@ protected:
     _groupingInterval = configGetDouble("groupingInterval");
     _minNumPicks = configGetInt("minNumPicks");
     _droppingPeriod = configGetDouble("droppingPeriod");
+    try {
+      _mustInclude = configGetString("mustInclude");
+    } catch (...) {
+    }
 
     if (!_epFile.empty())
       setMessagingEnabled(false);
@@ -344,8 +349,11 @@ protected:
       std::sort(objs.begin(), objs.end());
 
       auto acceptedCb = [&ep](PickPtr pick) { ep->add(pick.get()); };
-      auto droppedCb =
-          [this](const deque<PickPtr> &picks) { /* nothing to do */ };
+      auto droppedCb = [this](const deque<PickPtr> &picks) {
+        SEISCOMP_INFO("Dropped %zu picks: %s ~ %s", picks.size(),
+                      picks.front()->time().value().iso().c_str(),
+                      picks.back()->time().value().iso().c_str());
+      };
 
       SEISCOMP_INFO("Processing picks");
 
@@ -355,17 +363,16 @@ protected:
         _counter.newPicks++;
         processPicks(acceptedCb, droppedCb);
       }
-      while (_buf.size() >  0) {
+      while (_buf.size() > 0) {
         Core::msleep(100);
         processPicks(acceptedCb, droppedCb);
       }
 
       SEISCOMP_INFO("Processed picks %lu", _counter.newPicks);
       SEISCOMP_INFO("Accepted picks %lu", _counter.acceptedPicks);
-      SEISCOMP_INFO(
-          "Dropped picks %lu (group picks %lu dropping period picks %lu)",
-          (_counter.droppedGroupPicks + _counter.droppedPeriodPicks),
-          _counter.droppedGroupPicks, _counter.droppedPeriodPicks);
+      SEISCOMP_INFO("Dropped picks %lu (group picks %lu after group picks %lu)",
+                    (_counter.droppedGroupPicks + _counter.droppedPeriodPicks),
+                    _counter.droppedGroupPicks, _counter.droppedPeriodPicks);
       SEISCOMP_INFO("Dropped pick groups %lu", _counter.droppedGroups);
       if (_buf.size() != 0) {
         SEISCOMP_WARNING("Unprocessed picks (%lu)", _buf.size());
@@ -483,15 +490,41 @@ private:
           oldestPick->time().value() + _groupingInterval;
       deque<PickPtr> group = _buf.getExpiredPicks(notAfter);
 
-      if (group.size() >= _minNumPicks - 1) { // group detected
+      bool groupDetected = false;
+
+      if (group.size() >= _minNumPicks - 1) { // possble group detected
+
+        if (_mustInclude.empty()) { // no net.sta.loc configured
+          groupDetected = true;
+        } else { // check if _mustInclude net.sta.loc is present
+          string wfid = oldestPick->waveformID().networkCode() + "." +
+                        oldestPick->waveformID().stationCode() + "." +
+                        oldestPick->waveformID().locationCode();
+          if (wfid == _mustInclude) {
+            groupDetected = true;
+          } else {
+            for (PickPtr pick : group) {
+              wfid = pick->waveformID().networkCode() + "." +
+                     pick->waveformID().stationCode() + "." +
+                     pick->waveformID().locationCode();
+              if (wfid == _mustInclude) {
+                groupDetected = true;
+                break;
+              }
+            }
+          }
+        }
+      }
+
+      if (groupDetected) { // group detected
         // drop picks
         for (PickPtr pick : group) {
           if (!_buf.removePick(pick.get())) {
             throw Core::GeneralException("Internal logic error");
           }
         }
-        group.push_front(oldestPick);
-        droppedCb(group);
+        group.push_front(oldestPick); // it was handled by popExpiredPick
+
         _counter.droppedGroupPicks += group.size();
         _counter.droppedGroups++;
 
@@ -507,10 +540,10 @@ private:
           if (!_buf.removePick(oldestPick.get())) {
             throw Core::GeneralException("Internal logic error");
           }
-          droppedCb({oldestPick});
+          group.push_back(oldestPick);
           _counter.droppedPeriodPicks++;
         }
-
+        droppedCb(group);
       } else {
         // accept the oldest pick
         acceptedCb(oldestPick);