diff --git a/CHANGELOG b/CHANGELOG
index 049d162bd1ab3ca3b77c77121752cc62199dd57e..ae083be77ffe70acee36cb395a646d119e72b115 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -8,6 +8,7 @@ BornAgain-1.18.99, ongoing development
     * Removed some interference functions constructors
     * Remove old R&T computations from API (now in Code/Legacy and Tests)
     * Python plot API entirely keyword based
+    * Add support for Q-Offset in QSpecScan
   > Fixes of unreported bugs:
     * Several GUI bugs that caused crashes
     * For alpha_i=0, set scattered intensity to 0
diff --git a/Core/Scan/QSpecScan.cpp b/Core/Scan/QSpecScan.cpp
index ffb4c3487c77aa8924f27dd072ed37bcfe37ede2..305700f79dab26ec79e4b5dad4e52cb6be39eed9 100644
--- a/Core/Scan/QSpecScan.cpp
+++ b/Core/Scan/QSpecScan.cpp
@@ -41,6 +41,7 @@ QSpecScan::~QSpecScan() = default;
 QSpecScan* QSpecScan::clone() const {
     auto* result = new QSpecScan(*m_qs);
     result->setQResolution(*m_resolution);
+    result->setOffset(m_offset);
     return result;
 }
 
@@ -52,7 +53,9 @@ QSpecScan::generateSimulationElements(const Instrument& instrument) const {
     std::vector<SpecularSimulationElement> result;
     result.reserve(qz.size());
     for (size_t i = 0, size = qz.size(); i < size; ++i)
-        result.emplace_back(SpecularSimulationElement(-qz[i] / 2.0, instrument, qz[i] >= 0));
+        result.emplace_back(
+            SpecularSimulationElement(-(qz[i] + m_offset) / 2.0, instrument, qz[i] >= 0));
+
     return result;
 }
 
diff --git a/Core/Scan/QSpecScan.h b/Core/Scan/QSpecScan.h
index 89bf72cfe5d5e744577b0df861cecf54758446c7..7838a73bcc9cc2f130a0f8011d0fe10632884cd3 100644
--- a/Core/Scan/QSpecScan.h
+++ b/Core/Scan/QSpecScan.h
@@ -83,6 +83,9 @@ public:
     void setAbsoluteQResolution(const IRangedDistribution& distr,
                                 const std::vector<double>& std_dev);
 
+    void setOffset(double offset) { m_offset = offset; }
+    double offset() const { return m_offset; }
+
 private:
     void checkInitialization();
     std::vector<double> generateQzVector() const;
@@ -91,6 +94,8 @@ private:
     const std::unique_ptr<IAxis> m_qs;
     std::unique_ptr<ScanResolution> m_resolution;
     mutable std::vector<std::vector<ParameterSample>> m_q_res_cache;
+
+    double m_offset = 0.;
 };
 
 #endif // BORNAGAIN_CORE_SCAN_QSPECSCAN_H
diff --git a/Examples/fit56_SpecularAdvanced/Pt_layer_fit.py b/Examples/fit56_SpecularAdvanced/Pt_layer_fit.py
index 95ea478c3acba5e0b77e12ff4353923debbdce26..8438bd423b902b908401408829acb265c62c8883 100644
--- a/Examples/fit56_SpecularAdvanced/Pt_layer_fit.py
+++ b/Examples/fit56_SpecularAdvanced/Pt_layer_fit.py
@@ -57,9 +57,9 @@ def get_sample(params):
 
 def get_simulation(q_axis, parameters):
 
-    q_axis = q_axis + parameters["q_offset"]
     scan = ba.QSpecScan(q_axis)
-
+    scan.setOffset( parameters["q_offset"] )
+    
     n_sig = 4.0
     n_samples = 25
 
@@ -84,12 +84,12 @@ def run_simulation(q_axis, fitParams):
     return simulation  #.result()
 
 
-def qr(result, q_offset=0):
+def qr(result):
     """
     helper function to return the q axis and 
     reflectivity from simulation result
     """
-    q = numpy.array(result.result().axis(ba.Axes.QSPACE)) - q_offset
+    q = numpy.array(result.result().axis(ba.Axes.QSPACE))
     r = numpy.array(result.result().array(ba.Axes.QSPACE))
 
     return q, r
@@ -232,8 +232,7 @@ if __name__ == '__main__':
     paramsInitial = {d: v[0] for d, v in startParams.items()}
 
     qzs = numpy.linspace(qmin, qmax, scan_size)
-    q, r = qr(run_simulation(qzs, paramsInitial),
-              dict(paramsInitial, **fixedParams)["q_offset"])
+    q, r = qr(run_simulation(qzs, paramsInitial))
     data = get_Experimental_data(qmin, qmax)
 
     plot(q, r, data, f'PtLayerFit_initial.pdf',
@@ -246,6 +245,5 @@ if __name__ == '__main__':
         print("Fit Result:")
         print(fitResult)
 
-        q, r = qr(run_simulation(qzs, fitParams=fitResult),
-                  fitResult["q_offset"])
+        q, r = qr(run_simulation(qzs, fitParams=fitResult))
         plot(q, r, data, f'PtLayerFit_fit.pdf', dict(fitResult, **fixedParams))
diff --git a/Tests/UnitTests/Core/Fresnel/SpecularScanTest.cpp b/Tests/UnitTests/Core/Fresnel/SpecularScanTest.cpp
index 4c35f9afbfea82b8cf6405e07a43eef74aa9f5e9..3df1c01142d516e9ef1f7443883e9a3163549c71 100644
--- a/Tests/UnitTests/Core/Fresnel/SpecularScanTest.cpp
+++ b/Tests/UnitTests/Core/Fresnel/SpecularScanTest.cpp
@@ -7,6 +7,8 @@
 #include "Device/Instrument/Instrument.h"
 #include "Device/Resolution/ScanResolution.h"
 #include "Param/Distrib/RangedDistributions.h"
+#include "Sample/Material/MaterialFactoryFuncs.h"
+#include "Sample/Slice/Slice.h"
 #include "Tests/GTestWrapper/google_test.h"
 
 class SpecularScanTest : public ::testing::Test {};
@@ -123,6 +125,7 @@ TEST_F(SpecularScanTest, QScanInit) {
         EXPECT_EQ(scan.numberOfSimulationElements(), axis.size());
         EXPECT_EQ(scan.footprintFactor(), nullptr);
         EXPECT_EQ(scan.footprint(0, 1), std::vector<double>{1.0});
+        EXPECT_EQ(scan.offset(), 0.);
         EXPECT_THROW(scan.footprint(1, axis.size()), std::runtime_error);
         EXPECT_NO_THROW(scan.footprint(0, axis.size()));
     };
@@ -166,11 +169,13 @@ TEST_F(SpecularScanTest, AngularScanClone) {
 
 TEST_F(SpecularScanTest, QScanClone) {
     QSpecScan scan(std::vector<double>{0.1, 0.2, 0.3});
+    scan.setOffset(2.22);
 
     std::unique_ptr<QSpecScan> scan_clone(scan.clone());
     EXPECT_EQ(*scan_clone->coordinateAxis(), *scan.coordinateAxis());
     EXPECT_NE(scan_clone->coordinateAxis(), scan.coordinateAxis());
     EXPECT_EQ(scan_clone->footprintFactor(), nullptr);
+    EXPECT_EQ(scan_clone->offset(), scan.offset());
 }
 
 TEST_F(SpecularScanTest, GenerateSimElements) {
@@ -183,13 +188,26 @@ TEST_F(SpecularScanTest, GenerateSimElements) {
     for (size_t i = 0; i < sim_elements.size(); ++i)
         EXPECT_TRUE(sim_elements[i].isCalculated());
 
-    QSpecScan scan2(std::vector<double>{0.0, 0.2, 0.3});
+    const auto scan2_qvector = std::vector<double>{0.0, 0.2, 0.3};
+    QSpecScan scan2(scan2_qvector);
     std::vector<SpecularSimulationElement> sim_elements2 =
-        scan.generateSimulationElements(instrument);
+        scan2.generateSimulationElements(instrument);
     EXPECT_EQ(sim_elements2.size(), scan2.numberOfSimulationElements());
     EXPECT_EQ(scan2.numberOfSimulationElements(), 3u);
     for (size_t i = 0; i < sim_elements2.size(); ++i)
         EXPECT_TRUE(sim_elements2[i].isCalculated());
+    
+    const double offset = 1.;
+    scan2.setOffset(offset);
+    std::vector<SpecularSimulationElement> sim_elements3 =
+        scan2.generateSimulationElements(instrument);
+    std::vector<Slice> slices;
+    slices.emplace_back(0., MaterialBySLD());
+    for (size_t i = 0; i < sim_elements3.size(); ++i){
+        const auto generatedKzs = sim_elements3[i].produceKz(slices);
+        EXPECT_EQ(generatedKzs[0].imag(), 0.);
+        EXPECT_EQ(2. * generatedKzs[0].real(), scan2_qvector[i] + offset);
+    }
 }
 
 TEST_F(SpecularScanTest, ErrorInput) {
diff --git a/auto/Wrap/libBornAgainCore.py b/auto/Wrap/libBornAgainCore.py
index cfecc37f6fe9182d06665a9092b1b78d89369dfe..41bfd1defca874425258fe94dfcce45a500d4b56 100644
--- a/auto/Wrap/libBornAgainCore.py
+++ b/auto/Wrap/libBornAgainCore.py
@@ -3448,6 +3448,14 @@ class QSpecScan(object):
         """
         return _libBornAgainCore.QSpecScan_setAbsoluteQResolution(self, *args)
 
+    def setOffset(self, offset):
+        r"""setOffset(QSpecScan self, double offset)"""
+        return _libBornAgainCore.QSpecScan_setOffset(self, offset)
+
+    def offset(self):
+        r"""offset(QSpecScan self) -> double"""
+        return _libBornAgainCore.QSpecScan_offset(self)
+
 # Register QSpecScan in _libBornAgainCore:
 _libBornAgainCore.QSpecScan_swigregister(QSpecScan)
 
diff --git a/auto/Wrap/libBornAgainCore_wrap.cpp b/auto/Wrap/libBornAgainCore_wrap.cpp
index 7adfb9bbec23ffddc375fbf1566027c00dbffcab..4c09c1ce5fe7f533e6ac4df0be6e3201fd6b31c6 100644
--- a/auto/Wrap/libBornAgainCore_wrap.cpp
+++ b/auto/Wrap/libBornAgainCore_wrap.cpp
@@ -38690,6 +38690,58 @@ fail:
 }
 
 
+SWIGINTERN PyObject *_wrap_QSpecScan_setOffset(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  QSpecScan *arg1 = (QSpecScan *) 0 ;
+  double arg2 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  double val2 ;
+  int ecode2 = 0 ;
+  PyObject *swig_obj[2] ;
+  
+  if (!SWIG_Python_UnpackTuple(args, "QSpecScan_setOffset", 2, 2, swig_obj)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_QSpecScan, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "QSpecScan_setOffset" "', argument " "1"" of type '" "QSpecScan *""'"); 
+  }
+  arg1 = reinterpret_cast< QSpecScan * >(argp1);
+  ecode2 = SWIG_AsVal_double(swig_obj[1], &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "QSpecScan_setOffset" "', argument " "2"" of type '" "double""'");
+  } 
+  arg2 = static_cast< double >(val2);
+  (arg1)->setOffset(arg2);
+  resultobj = SWIG_Py_Void();
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_QSpecScan_offset(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  QSpecScan *arg1 = (QSpecScan *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject *swig_obj[1] ;
+  double result;
+  
+  if (!args) SWIG_fail;
+  swig_obj[0] = args;
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_QSpecScan, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "QSpecScan_offset" "', argument " "1"" of type '" "QSpecScan const *""'"); 
+  }
+  arg1 = reinterpret_cast< QSpecScan * >(argp1);
+  result = (double)((QSpecScan const *)arg1)->offset();
+  resultobj = SWIG_From_double(static_cast< double >(result));
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
 SWIGINTERN PyObject *QSpecScan_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *obj;
   if (!SWIG_Python_UnpackTuple(args, "swigregister", 1, 1, &obj)) return NULL;
@@ -44550,6 +44602,8 @@ static PyMethodDef SwigMethods[] = {
 		"Sets qz resolution values via IRangedDistribution and values of standard deviations.  std_dev can be either single-valued or a numpy array. In the latter case the length of the array should coinside with the length of the qz-axis. \n"
 		"\n"
 		""},
+	 { "QSpecScan_setOffset", _wrap_QSpecScan_setOffset, METH_VARARGS, "QSpecScan_setOffset(QSpecScan self, double offset)"},
+	 { "QSpecScan_offset", _wrap_QSpecScan_offset, METH_O, "QSpecScan_offset(QSpecScan self) -> double"},
 	 { "QSpecScan_swigregister", QSpecScan_swigregister, METH_O, NULL},
 	 { "QSpecScan_swiginit", QSpecScan_swiginit, METH_VARARGS, NULL},
 	 { "delete_ISimulation", _wrap_delete_ISimulation, METH_O, "\n"