diff --git a/docs/development/local-development.md b/docs/development/local-development.md
index 5bdfdef3dcc18f7873bcf42e180b4955fdf4e578..6a20f6988f3e1285b99ac167adcd8416c89d46b4 100644
--- a/docs/development/local-development.md
+++ b/docs/development/local-development.md
@@ -182,6 +182,9 @@ You can run `pnpm build:docs` to generate the docs.
 Then use `pnpm mkdocs serve` to preview the documentation locally.
 The docs will update automatically when you run `pnpm build:docs` again, no need to stop the `pnpm mkdocs serve` command.
 
+Also, make sure to set the `GITHUB_TOKEN` in your environment as we use [gh cli](https://cli.github.com/manual/gh_issue_list) to fetch the issues.
+If you wish to skip fetching the issues, then set `SKIP_GITHUB_ISSUES` to `true` before building the docs.
+
 ## Keeping your Renovate fork up to date
 
 First of all, never commit to the `main` branch of your fork - always use a "feature" branch like `feat/1234-add-yarn-parsing`.
diff --git a/tools/docs/github-query-items.ts b/tools/docs/github-query-items.ts
index 1683158541a861764294dc3097357e34f30a39f5..e98be701b7b50da8d44cf4cfd4864dc8d4e8a0db 100644
--- a/tools/docs/github-query-items.ts
+++ b/tools/docs/github-query-items.ts
@@ -1,31 +1,14 @@
 import { DateTime } from 'luxon';
+import { z } from 'zod';
 import { logger } from '../../lib/logger';
-import * as hostRules from '../../lib/util/host-rules';
-import { GithubHttp } from '../../lib/util/http/github';
-import { getQueryString } from '../../lib/util/url';
-
-const gitHubApiUrl = 'https://api.github.com/search/issues?';
-const githubApi = new GithubHttp();
-
-if (process.env.GITHUB_TOKEN) {
-  logger.info('Using GITHUB_TOKEN from env');
-  hostRules.add({
-    matchHost: 'api.github.com',
-    token: process.env.GITHUB_TOKEN,
-  });
-}
-
-type GithubApiQueryResponse = {
-  total_count: number;
-  incomplete_results: boolean;
-  items: ItemsEntity[];
-};
+import { exec } from '../../lib/util/exec';
 
 export type ItemsEntity = {
-  html_url: string;
+  url: string;
   number: number;
   title: string;
   labels: LabelsEntity[];
+  issueType: 'Bug' | 'Feature';
 };
 
 export type LabelsEntity = {
@@ -46,6 +29,34 @@ export interface Items {
   features: ItemsEntity[];
 }
 
+const GhOutputSchema = z.array(
+  z.object({
+    url: z.string(),
+    title: z.string(),
+    labels: z.array(
+      z.object({
+        name: z.string(),
+      }),
+    ),
+    number: z.number(),
+  }),
+);
+
+async function getIssuesByIssueType(
+  issueType: 'Bug' | 'Feature',
+): Promise<ItemsEntity[]> {
+  const command = `gh issue list --json "title,number,url,labels" --search "type:${issueType}" --limit 1000`;
+  const execRes = await exec(command);
+  const res = GhOutputSchema.safeParse(JSON.parse(execRes.stdout));
+  if (res.error) {
+    throw res.error;
+  }
+
+  return res.data.map((issue) => {
+    return { ...issue, issueType };
+  });
+}
+
 export async function getOpenGitHubItems(): Promise<RenovateOpenItems> {
   const result: RenovateOpenItems = {
     managers: {},
@@ -59,18 +70,21 @@ export async function getOpenGitHubItems(): Promise<RenovateOpenItems> {
     return result;
   }
 
-  const q = `repo:renovatebot/renovate type:issue is:open`;
-  const per_page = 100;
+  if (!process.env.GITHUB_TOKEN) {
+    logger.warn(
+      'No GITHUB_TOKEN found in env, cannot fetch Github issues. Skipping...',
+    );
+    return result;
+  }
+
+  if (process.env.CI) {
+    return result;
+  }
+
   try {
-    const query = getQueryString({ q, per_page });
-    const res = await githubApi.getJsonUnchecked<GithubApiQueryResponse>(
-      gitHubApiUrl + query,
-      {
-        paginationField: 'items',
-        paginate: true,
-      },
+    const rawItems = (await getIssuesByIssueType('Bug')).concat(
+      await getIssuesByIssueType('Feature'),
     );
-    const rawItems = res.body?.items ?? [];
 
     result.managers = extractIssues(rawItems, 'manager:');
     result.platforms = extractIssues(rawItems, 'platform:');
@@ -91,9 +105,8 @@ function extractIssues(items: ItemsEntity[], labelPrefix: string): OpenItems {
   const issuesMap: OpenItems = {};
 
   for (const item of items) {
-    const type = item.labels
-      .find((l) => l.name.startsWith('type:'))
-      ?.name.split(':')[1];
+    const type = item.issueType;
+
     if (!type) {
       continue;
     }
@@ -107,10 +120,10 @@ function extractIssues(items: ItemsEntity[], labelPrefix: string): OpenItems {
       issuesMap[label] = { bugs: [], features: [] };
     }
     switch (type) {
-      case 'bug':
+      case 'Bug':
         issuesMap[label]?.bugs.push(item);
         break;
-      case 'feature':
+      case 'Feature':
         issuesMap[label]?.features.push(item);
         break;
       default:
@@ -127,7 +140,7 @@ function stringifyIssues(items: ItemsEntity[] | undefined): string {
   }
   let list = '';
   for (const item of items) {
-    list += ` - ${item.title} [#${item.number}](${item.html_url})\n`;
+    list += ` - ${item.title} [#${item.number}](${item.url})\n`;
   }
   return list;
 }