diff --git a/app/assets/javascripts/lib/utils/url_utility.js b/app/assets/javascripts/lib/utils/url_utility.js
index 1bc81d2e4a4e320074cd0ed1e49ed7d64794262c..09c4261b3187d25d5486220db2a7035844749b7f 100644
--- a/app/assets/javascripts/lib/utils/url_utility.js
+++ b/app/assets/javascripts/lib/utils/url_utility.js
@@ -66,6 +66,13 @@
         return results;
       })()).join('&');
     };
+    w.gl.utils.removeParams = (params) => {
+      const url = new URL(window.location.href);
+      params.forEach((param) => {
+        url.search = w.gl.utils.removeParamQueryString(url.search, param);
+      });
+      return url.href;
+    };
     w.gl.utils.getLocationHash = function(url) {
       var hashIndex;
       if (typeof url === 'undefined') {
diff --git a/app/assets/javascripts/pager.js b/app/assets/javascripts/pager.js
index e35cf6d295e37c4a22f4464cf8927b35dcb507fb..5f6bc902cf856acef181ae80165ba91789368c09 100644
--- a/app/assets/javascripts/pager.js
+++ b/app/assets/javascripts/pager.js
@@ -1,11 +1,15 @@
+require('~/lib/utils/common_utils');
+require('~/lib/utils/url_utility');
+
 (() => {
   const ENDLESS_SCROLL_BOTTOM_PX = 400;
   const ENDLESS_SCROLL_FIRE_DELAY_MS = 1000;
 
   const Pager = {
     init(limit = 0, preload = false, disable = false, callback = $.noop) {
+      this.url = $('.content_list').data('href') || gl.utils.removeParams(['limit', 'offset']);
       this.limit = limit;
-      this.offset = this.limit;
+      this.offset = parseInt(gl.utils.getParameterByName('offset'), 10) || this.limit;
       this.disable = disable;
       this.callback = callback;
       this.loading = $('.loading').first();
@@ -20,7 +24,7 @@
       this.loading.show();
       $.ajax({
         type: 'GET',
-        url: $('.content_list').data('href') || window.location.href,
+        url: this.url,
         data: `limit=${this.limit}&offset=${this.offset}`,
         dataType: 'json',
         error: () => this.loading.hide(),
diff --git a/changelogs/unreleased/28030-infinite-offset.yml b/changelogs/unreleased/28030-infinite-offset.yml
new file mode 100644
index 0000000000000000000000000000000000000000..6f4082d7684f305ab08a3db1acedbae9a4bb620f
--- /dev/null
+++ b/changelogs/unreleased/28030-infinite-offset.yml
@@ -0,0 +1,4 @@
+---
+title: allow offset query parameter for infinite list pages
+merge_request:
+author:
diff --git a/spec/javascripts/pager_spec.js b/spec/javascripts/pager_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..d966226909bc9ba1100b9bf8339adc28d24d684f
--- /dev/null
+++ b/spec/javascripts/pager_spec.js
@@ -0,0 +1,90 @@
+/* global fixture */
+
+require('~/pager');
+
+describe('pager', () => {
+  const Pager = window.Pager;
+
+  it('is defined on window', () => {
+    expect(window.Pager).toBeDefined();
+  });
+
+  describe('init', () => {
+    const originalHref = window.location.href;
+
+    beforeEach(() => {
+      setFixtures('<div class="content_list"></div><div class="loading"></div>');
+      spyOn($, 'ajax');
+    });
+
+    afterEach(() => {
+      window.history.replaceState({}, null, originalHref);
+    });
+
+    it('should use data-href attribute from list element', () => {
+      const href = `${gl.TEST_HOST}/some_list.json`;
+      setFixtures(`<div class="content_list" data-href="${href}"></div>`);
+      Pager.init();
+      expect(Pager.url).toBe(href);
+    });
+
+    it('should use current url if data-href attribute not provided', () => {
+      const href = `${gl.TEST_HOST}/some_list`;
+      spyOn(gl.utils, 'removeParams').and.returnValue(href);
+      Pager.init();
+      expect(Pager.url).toBe(href);
+    });
+
+    it('should get initial offset from query parameter', () => {
+      window.history.replaceState({}, null, '?offset=100');
+      Pager.init();
+      expect(Pager.offset).toBe(100);
+    });
+
+    it('keeps extra query parameters from url', () => {
+      window.history.replaceState({}, null, '?filter=test&offset=100');
+      const href = `${gl.TEST_HOST}/some_list?filter=test`;
+      spyOn(gl.utils, 'removeParams').and.returnValue(href);
+      Pager.init();
+      expect(gl.utils.removeParams).toHaveBeenCalledWith(['limit', 'offset']);
+      expect(Pager.url).toEqual(href);
+    });
+  });
+
+  describe('getOld', () => {
+    beforeEach(() => {
+      setFixtures('<div class="content_list" data-href="/some_list"></div><div class="loading"></div>');
+      Pager.init();
+    });
+
+    it('shows loader while loading next page', () => {
+      spyOn(Pager.loading, 'show');
+      Pager.getOld();
+      expect(Pager.loading.show).toHaveBeenCalled();
+    });
+
+    it('hides loader on success', () => {
+      spyOn($, 'ajax').and.callFake(options => options.success({}));
+      spyOn(Pager.loading, 'hide');
+      Pager.getOld();
+      expect(Pager.loading.hide).toHaveBeenCalled();
+    });
+
+    it('hides loader on error', () => {
+      spyOn($, 'ajax').and.callFake(options => options.error());
+      spyOn(Pager.loading, 'hide');
+      Pager.getOld();
+      expect(Pager.loading.hide).toHaveBeenCalled();
+    });
+
+    it('sends request to url with offset and limit params', () => {
+      spyOn($, 'ajax');
+      Pager.offset = 100;
+      Pager.limit = 20;
+      Pager.getOld();
+      const [{ data, url }] = $.ajax.calls.argsFor(0);
+      expect(data).toBe('limit=20&offset=100');
+      expect(url).toBe('/some_list');
+    });
+  });
+});