diff --git oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentDiscoveryLiteService.java oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentDiscoveryLiteService.java
index 3d7e0f9..1c14c02 100644
--- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentDiscoveryLiteService.java
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentDiscoveryLiteService.java
@@ -662,7 +662,7 @@ public class DocumentDiscoveryLiteService implements ClusterStateChangeListener,
         // Now from the above it also results that this only wakes up the
         // backgroundWorker if we have any pending 'backlogy instances'
         // otherwise this is a no-op
-        if (info == null) {
+        if (CommitInfo.isExternal(info)) {
             // then ignore this as this is likely an external change
             // note: it could be a compacted change, in which case we should
             // probably still process it - but we have a 5sec fallback
diff --git oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/secondary/SecondaryStoreObserver.java oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/secondary/SecondaryStoreObserver.java
index ea21882..8545980 100644
--- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/secondary/SecondaryStoreObserver.java
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/secondary/SecondaryStoreObserver.java
@@ -43,6 +43,8 @@ import org.apache.jackrabbit.oak.stats.TimerStats;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.apache.jackrabbit.oak.spi.commit.CommitInfo.isExternal;
+
 public class SecondaryStoreObserver implements Observer {
     private final Logger log = LoggerFactory.getLogger(getClass());
     private final NodeStore nodeStore;
@@ -93,7 +95,7 @@ public class SecondaryStoreObserver implements Observer {
             NodeState updatedSecondaryRoot = nodeStore.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
             secondaryObserver.contentChanged(DelegatingDocumentNodeState.wrap(updatedSecondaryRoot, differ));
 
-            TimerStats timer = info == null ? external : local;
+            TimerStats timer = isExternal(info) ? external : local;
             timer.update(w.elapsed(TimeUnit.NANOSECONDS), TimeUnit.NANOSECONDS);
 
             if (!firstEventProcessed){
diff --git oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/filter/FilterBuilder.java oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/filter/FilterBuilder.java
index 9b983b2..378b571 100644
--- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/filter/FilterBuilder.java
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/filter/FilterBuilder.java
@@ -425,7 +425,7 @@ public final class FilterBuilder {
             }
 
             private boolean isExternal(CommitInfo info) {
-                return info == null;
+                return CommitInfo.isExternal(info);
             }
             
             @Override
diff --git oak-core/src/main/java/org/apache/jackrabbit/oak/spi/commit/BackgroundObserver.java oak-core/src/main/java/org/apache/jackrabbit/oak/spi/commit/BackgroundObserver.java
index 6c456ce..e1174be 100644
--- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/commit/BackgroundObserver.java
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/commit/BackgroundObserver.java
@@ -24,6 +24,7 @@ import static com.google.common.base.Preconditions.checkState;
 import static com.google.common.collect.Iterables.filter;
 import static com.google.common.collect.Iterables.size;
 import static com.google.common.collect.Queues.newArrayBlockingQueue;
+import static org.apache.jackrabbit.oak.spi.commit.CommitInfo.isExternal;
 
 import java.io.Closeable;
 import java.lang.Thread.UncaughtExceptionHandler;
@@ -246,7 +247,7 @@ public class BackgroundObserver implements Observer, Closeable {
                 return size(filter(queue, new Predicate<ContentChange>() {
                     @Override
                     public boolean apply(ContentChange input) {
-                        return input.info != null;
+                        return !isExternal(input.info);
                     }
                 }));
             }
@@ -256,7 +257,7 @@ public class BackgroundObserver implements Observer, Closeable {
                 return size(filter(queue, new Predicate<ContentChange>() {
                     @Override
                     public boolean apply(ContentChange input) {
-                        return input.info == null;
+                        return isExternal(input.info);
                     }
                 }));
             }
@@ -273,7 +274,7 @@ public class BackgroundObserver implements Observer, Closeable {
         checkState(!stopped);
         checkNotNull(root);
 
-        if (alwaysCollapseExternalEvents && info == null && last != null && last.info == null) {
+        if (alwaysCollapseExternalEvents && isExternal(info) && last != null && isExternal(last.info)) {
             // This is an external change. If the previous change was
             // also external, we can drop it from the queue (since external
             // changes in any case can cover multiple commits) to help
diff --git oak-core/src/main/java/org/apache/jackrabbit/oak/spi/commit/CommitInfo.java oak-core/src/main/java/org/apache/jackrabbit/oak/spi/commit/CommitInfo.java
index 640a8f3..c4b0a51 100644
--- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/commit/CommitInfo.java
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/commit/CommitInfo.java
@@ -53,6 +53,8 @@ public final class CommitInfo {
 
     private final Map<String, Object> info;
 
+    private final boolean external;
+
     /**
      * Creates a commit info for the given session and user.
      *
@@ -72,9 +74,32 @@ public final class CommitInfo {
      * @param info info map
      */
     public CommitInfo(@Nonnull String sessionId, @Nullable String userId, Map<String, Object> info) {
+        this(sessionId, userId, info, false);
+    }
+
+    /**
+     * Creates a commit info for the given session and user and info map.
+     *  @param sessionId session identifier
+     * @param userId The user id.
+     * @param info info map
+     * @param external indicates if the commit info is from external change
+     */
+    public CommitInfo(@Nonnull String sessionId, @Nullable String userId, Map<String, Object> info, boolean external) {
         this.sessionId = checkNotNull(sessionId);
         this.userId = (userId == null) ? OAK_UNKNOWN : userId;
         this.info = checkNotNull(info);
+        this.external = external;
+    }
+
+    /**
+     * A ContentChange is considered external if the CommitInfo associated with it
+     * is null or has external flag set
+     *
+     * @param info commit info to check
+     * @return true if the given commit info is external
+     */
+    public static boolean isExternal(CommitInfo info) {
+        return info == null || info.isExternal();
     }
 
     /**
@@ -101,6 +126,18 @@ public final class CommitInfo {
     }
 
     /**
+     * Return a flag indicating whether this is commit info is
+     * for an external change
+     *
+     * @return true if commit info is for an external change
+     */
+    public boolean isExternal() {
+        return external;
+    }
+
+    /**
+
+    /**
      * Returns the base path of this commit. All changes within this commit
      * are expected to be located within the returned path. By default this
      * is the root path, but a particular commit can declare a more specific
@@ -135,6 +172,7 @@ public final class CommitInfo {
             return sessionId.equals(that.sessionId)
                     && userId.equals(that.userId)
                     && this.date == that.date
+                    && this.external == that.external
                     && info.equals(that.info);
         } else {
             return false;
@@ -143,7 +181,7 @@ public final class CommitInfo {
 
     @Override
     public int hashCode() {
-        return Objects.hashCode(sessionId, userId, date, info);
+        return Objects.hashCode(sessionId, userId, date, info, external);
     }
 
     @Override
@@ -151,6 +189,7 @@ public final class CommitInfo {
         return toStringHelper(this).omitNullValues()
                 .add("sessionId", sessionId)
                 .add("userId", userId)
+                .add("external", external)
                 .add("date", date)
                 .add("info", info)
                 .toString();
diff --git oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventFactory.java oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventFactory.java
index eba2108..833784d 100644
--- oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventFactory.java
+++ oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventFactory.java
@@ -64,7 +64,7 @@ public class EventFactory {
 
     EventFactory(NamePathMapper mapper, CommitInfo commitInfo) {
         this.mapper = mapper;
-        if (commitInfo != null) {
+        if (!CommitInfo.isExternal(commitInfo)) {
             this.userID = commitInfo.getUserId();
             Object userData = commitInfo.getInfo().get(USER_DATA);
             this.userData = userData instanceof String ? (String) userData : null;
diff --git oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/hybrid/LocalIndexObserver.java oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/hybrid/LocalIndexObserver.java
index e5ccf0f..e8eb138 100644
--- oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/hybrid/LocalIndexObserver.java
+++ oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/hybrid/LocalIndexObserver.java
@@ -41,7 +41,7 @@ public class LocalIndexObserver implements Observer{
     @Override
     public void contentChanged(@Nonnull NodeState root, @Nullable CommitInfo info) {
         //TODO [hybrid] Do external diff?
-        if (info == null){
+        if (CommitInfo.isExternal(info)){
            return;
         }
 
