diff --git a/docs/usage/self-hosted-configuration.md b/docs/usage/self-hosted-configuration.md
index 4757232ff2ca150b9f4af9323b4546260dd2a9e3..a4dc8516a9888ba6ac1889dce98ff9c2e266f799 100644
--- a/docs/usage/self-hosted-configuration.md
+++ b/docs/usage/self-hosted-configuration.md
@@ -130,6 +130,14 @@ If using negations, all repositories except those who match the regex are added
 Some platforms allow you to add tags, or topics, to repositories and retrieve repository lists by specifying those
 topics. Set this variable to a list of strings, all of which will be topics for the autodiscovered repositories.
 
+For example:
+
+```json
+{
+  "autodiscoverTopics": ["managed-by-renovate"]
+}
+```
+
 ## baseDir
 
 By default Renovate uses a temporary directory like `/tmp/renovate` to store its data.
diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts
index e2500a1c1189f97f4c3cbc8ffa88ba37dfed35d7..9a14ef74fc528265f7bad4f9a64981f8b970d9f2 100644
--- a/lib/config/options/index.ts
+++ b/lib/config/options/index.ts
@@ -800,13 +800,13 @@ const options: RenovateOptions[] = [
   },
   {
     name: 'autodiscoverTopics',
-    description: '',
+    description: 'Filter the list of autodiscovered repositories by topics.',
     stage: 'global',
     type: 'array',
     subType: 'string',
     default: null,
     globalOnly: true,
-    supportedPlatforms: ['gitlab'],
+    supportedPlatforms: ['github', 'gitlab'],
   },
   {
     name: 'prCommitsPerRunLimit',
diff --git a/lib/modules/platform/github/index.spec.ts b/lib/modules/platform/github/index.spec.ts
index 109c177e7acdb78acbe3dcece97a2094f12e8e6e..23ce1e3f27c9d7df9c642db9ea29e5a95216a56f 100644
--- a/lib/modules/platform/github/index.spec.ts
+++ b/lib/modules/platform/github/index.spec.ts
@@ -192,6 +192,33 @@ describe('modules/platform/github/index', () => {
       expect(repos).toMatchSnapshot();
     });
 
+    it('should filters repositories by topics', async () => {
+      httpMock
+        .scope(githubApiHost)
+        .get('/user/repos?per_page=100')
+        .reply(200, [
+          {
+            full_name: 'a/b',
+            archived: false,
+            topics: [],
+          },
+          {
+            full_name: 'c/d',
+            archived: false,
+            topics: ['managed-by-renovate'],
+          },
+          {
+            full_name: 'e/f',
+            archived: true,
+            topics: ['managed-by-renovate'],
+          },
+          null,
+        ]);
+
+      const repos = await github.getRepos({ topics: ['managed-by-renovate'] });
+      expect(repos).toEqual(['c/d']);
+    });
+
     it('should return an array of repos when using Github App endpoint', async () => {
       //Use Github App token
       await github.initPlatform({
diff --git a/lib/modules/platform/github/index.ts b/lib/modules/platform/github/index.ts
index 84795983f8c030d04e91e4f6e641d3a317b86e3a..d0b85a6fc5b7073028c16ebd791d4f494fa0ba36 100644
--- a/lib/modules/platform/github/index.ts
+++ b/lib/modules/platform/github/index.ts
@@ -42,6 +42,7 @@ import { fromBase64, looseEquals } from '../../../util/string';
 import { ensureTrailingSlash } from '../../../util/url';
 import type {
   AggregatedVulnerabilities,
+  AutodiscoverConfig,
   BranchStatusConfig,
   CreatePRConfig,
   EnsureCommentConfig,
@@ -187,9 +188,7 @@ export async function initPlatform({
   return platformResult;
 }
 
-// Get all repositories that the user has access to
-export async function getRepos(): Promise<string[]> {
-  logger.debug('Autodiscovering GitHub repositories');
+async function fetchRepositories(): Promise<GhRestRepo[]> {
   try {
     if (platformConfig.isGHApp) {
       const res = await githubApi.getJson<{
@@ -198,19 +197,13 @@ export async function getRepos(): Promise<string[]> {
         paginationField: 'repositories',
         paginate: 'all',
       });
-      return res.body.repositories
-        .filter(is.nonEmptyObject)
-        .filter((repo) => !repo.archived)
-        .map((repo) => repo.full_name);
+      return res.body.repositories;
     } else {
       const res = await githubApi.getJson<GhRestRepo[]>(
         `user/repos?per_page=100`,
         { paginate: 'all' }
       );
-      return res.body
-        .filter(is.nonEmptyObject)
-        .filter((repo) => !repo.archived)
-        .map((repo) => repo.full_name);
+      return res.body;
     }
   } catch (err) /* istanbul ignore next */ {
     logger.error({ err }, `GitHub getRepos error`);
@@ -218,6 +211,22 @@ export async function getRepos(): Promise<string[]> {
   }
 }
 
+// Get all repositories that the user has access to
+export async function getRepos(config?: AutodiscoverConfig): Promise<string[]> {
+  logger.debug('Autodiscovering GitHub repositories');
+  return (await fetchRepositories())
+    .filter(is.nonEmptyObject)
+    .filter((repo) => !repo.archived)
+    .filter((repo) => {
+      if (config?.topics) {
+        const autodiscoverTopics = config.topics;
+        return repo.topics.some((topic) => autodiscoverTopics.includes(topic));
+      }
+      return true;
+    })
+    .map((repo) => repo.full_name);
+}
+
 async function getBranchProtection(
   branchName: string
 ): Promise<BranchProtection> {
diff --git a/lib/modules/platform/github/types.ts b/lib/modules/platform/github/types.ts
index e285ea5a23b036d879c8399cf4a377486338484d..b8baebf8fa3a317991ecf611e020f588efbbe295 100644
--- a/lib/modules/platform/github/types.ts
+++ b/lib/modules/platform/github/types.ts
@@ -27,6 +27,7 @@ export interface GhRestRepo {
     login: string;
   };
   archived: boolean;
+  topics: string[];
 }
 
 export interface GhRestPr {