diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build
index 4d2a09bd7041..80c425e13ccd 100644
--- a/include/libcamera/internal/meson.build
+++ b/include/libcamera/internal/meson.build
@@ -40,6 +40,7 @@ libcamera_internal_headers = files([
     'process.h',
     'pub_key.h',
     'request.h',
+    'sequence_sync_helper.h',
     'shared_mem_object.h',
     'source_paths.h',
     'sysfs.h',
diff --git a/include/libcamera/internal/sequence_sync_helper.h b/include/libcamera/internal/sequence_sync_helper.h
new file mode 100644
index 000000000000..407c6383dca6
--- /dev/null
+++ b/include/libcamera/internal/sequence_sync_helper.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2025, Ideas on Board
+ *
+ * Sequence sync helper
+ */
+
+#pragma once
+
+#include <queue>
+
+#include <libcamera/base/log.h>
+
+namespace libcamera {
+
+LOG_DECLARE_CATEGORY(SequenceSyncHelper)
+
+class SequenceSyncHelper
+{
+public:
+	int gotFrame(size_t expectedSequence, size_t actualSequence)
+	{
+		ASSERT(!corrections_.empty());
+		int diff = actualSequence - expectedSequence;
+		int corr = corrections_.front();
+		corrections_.pop();
+		expectedOffset_ -= corr;
+		int necessaryCorrection = diff - expectedOffset_;
+		correctionToApply_ += necessaryCorrection;
+
+		LOG(SequenceSyncHelper, Debug) << "Sync frame "
+					       << "expected: " << expectedSequence
+					       << " actual: " << actualSequence
+					       << " correction: " << corr
+					       << " expectedOffset: " << expectedOffset_
+					       << " correctionToApply " << correctionToApply_;
+
+		expectedOffset_ += necessaryCorrection;
+		return necessaryCorrection;
+	}
+
+	void cancelFrame()
+	{
+		int corr = corrections_.front();
+		corrections_.pop();
+		expectedOffset_ -= corr;
+	}
+
+	/* Value to be added to the source sequence */
+	int correction()
+	{
+		return correctionToApply_;
+	}
+
+	void pushCorrection(int correction)
+	{
+		corrections_.push(correction);
+		correctionToApply_ -= correction;
+		LOG(SequenceSyncHelper, Debug)
+			<< "Push correction " << correction
+			<< " correctionToApply " << correctionToApply_;
+	}
+
+	void reset()
+	{
+		corrections_ = {};
+		correctionToApply_ = 0;
+		expectedOffset_ = 0;
+	}
+
+	std::queue<int> corrections_;
+	int correctionToApply_ = 0;
+	int expectedOffset_ = 0;
+};
+
+} /* namespace libcamera */
diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
index d15943586300..8b82555a5e81 100644
--- a/src/libcamera/meson.build
+++ b/src/libcamera/meson.build
@@ -49,6 +49,7 @@ libcamera_internal_sources = files([
     'pipeline_handler.cpp',
     'process.cpp',
     'pub_key.cpp',
+    'sequence_sync_helper.cpp',
     'shared_mem_object.cpp',
     'source_paths.cpp',
     'sysfs.cpp',
diff --git a/src/libcamera/sequence_sync_helper.cpp b/src/libcamera/sequence_sync_helper.cpp
new file mode 100644
index 000000000000..7f0b9c9111a7
--- /dev/null
+++ b/src/libcamera/sequence_sync_helper.cpp
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2026, Ideas on Board.
+ *
+ * Helper to easily record debug metadata inside libcamera.
+ */
+
+#include "libcamera/internal/sequence_sync_helper.h"
+
+#include <libcamera/base/log.h>
+
+namespace libcamera {
+
+LOG_DEFINE_CATEGORY(SequenceSyncHelper)
+
+/**
+ * \file debug_controls.h
+ * \brief Helper to synchronize buffer sequences
+ */
+
+} /* namespace libcamera */
