GitHub Copilot Adoption Metrics logo

Backstage GitHub Copilot Adoption Metrics Plugin

Created by ESW

GitHub Copilot Adoption Metrics helps you see how your org uses Copilot. It pulls metrics and seat billing data from GitHub to show adoption, engagement, and license use. The Backstage plugin brings this view into your portal so you do not need another dashboard.

You can explore data at enterprise or organization scope. Pick a team and compare it with the whole org. GitHub only returns team metrics when a team has at least five active users in a day. The plugin shows trends over a time range with simple charts. You see totals like assigned seats, seats never used, and seats inactive in the last 7 14 or 28 days. You also see averages for the period such as active users, engaged users, IDE completion users, IDE chat users, GitHub chat users, and GitHub pull request users. Averages exclude weekends to reduce noise. The plugin does not store personal details.

Use it to track rollouts, spot unused seats, and target enablement. Share clear numbers with leaders. Plan renewals based on real usage. See which teams lean on completions or chat. Find teams that need help. If you run Backstage for a self hosted portal, this plugin gives your developers and platform team a shared view of Copilot impact inside the tools they already use.

Installation Instructions

These instructions apply to self-hosted Backstage only.

Install the frontend package

Run this from the Backstage root

Copy
yarn --cwd packages/app add @backstage-community/plugin-copilot

Add the Copilot page route

Edit packages/app/src/App.tsx

Copy
import React from 'react';
import { Route } from 'react-router';
import { FlatRoutes } from '@backstage/core-app-api';
import { CopilotIndexPage } from '@backstage-community/plugin-copilot';

export const AppRoutes = () => (
  <FlatRoutes>
    <Route path="/copilot" element={<CopilotIndexPage />} />
  </FlatRoutes>
);

If your App.tsx composes routes in a different place, add the same route in that component

Add the Copilot item to the sidebar

Edit packages/app/src/components/Root/Root.tsx

Copy
import React, { PropsWithChildren } from 'react';
import { SidebarPage, Sidebar, SidebarGroup, SidebarScrollWrapper } from '@backstage/core-components';
import MenuIcon from '@material-ui/icons/Menu';
import { CopilotSidebar } from '@backstage-community/plugin-copilot';

export const Root = ({ children }: PropsWithChildren<{}>) => (
  <SidebarPage>
    <Sidebar>
      <SidebarGroup label="Menu" icon={<MenuIcon />}>
        <SidebarScrollWrapper>
          <CopilotSidebar />
        </SidebarScrollWrapper>
      </SidebarGroup>
    </Sidebar>
    {children}
  </SidebarPage>
);

This renders a Copilot entry in the sidebar that links to the page at path /copilot

Install the backend package

Run this from the Backstage root

Copy
yarn --cwd packages/backend add @backstage-community/plugin-copilot-backend

New backend system

Edit packages/backend/src/index.ts

Copy
import { createBackend } from '@backstage/backend-defaults';
import { loggerToWinstonLogger } from '@backstage/backend-common';
import { copilotPlugin } from '@backstage-community/plugin-copilot-backend';

const backend = createBackend();

// add your other features before or after
backend.add(copilotPlugin());

backend.start().catch(err => {
  const logger = loggerToWinstonLogger(console);
  logger.error(err);
  process.exit(1);
});

The Copilot backend will mount under the service root for the backend The default path is /api/copilot

Legacy backend system

Create a router module for the plugin

Create packages/backend/src/plugins/copilot.ts

Copy
import { Router } from 'express';
import { PluginEnvironment } from '../types';
import { createRouter } from '@backstage-community/plugin-copilot-backend';

export default async function createPlugin(
  env: PluginEnvironment,
): Promise<Router> {
  return await createRouter({
    logger: env.logger,
    config: env.config,
    discovery: env.discovery,
    tokenManager: env.tokenManager,
    httpAuth: env.httpAuth,
  });
}

Register the plugin router

Edit packages/backend/src/index.ts

Copy
import { createServiceBuilder } from '@backstage/backend-common';
import { notFoundHandler, errorHandler } from '@backstage/backend-common';
import express from 'express';
import cors from 'cors';
import { DatabaseManager, getRootLogger, HostDiscovery, UrlReaders, SingleHostDiscovery } from '@backstage/backend-common';
import { ConfigReader } from '@backstage/config';
import createCopilot from './plugins/copilot';

async function main() {
  const logger = getRootLogger();
  const config = new ConfigReader({});
  const discovery = SingleHostDiscovery.fromConfig(config);
  const tokenManager = { getToken: async () => ({ token: '' }) } as any;

  const app = express();
  app.use(cors());
  app.use(express.json());

  const env = {
    logger,
    config,
    reader: UrlReaders.default({
      logger,
      config,
    }),
    discovery,
    database: await DatabaseManager.fromConfig(config).forPlugin('app'),
    cache: undefined as any,
    tokenManager,
    httpAuth: { credentials: async () => undefined } as any,
    permissions: undefined as any,
    scheduler: undefined as any,
  };

  app.use('/api/copilot', await createCopilot(env));

  app.use(notFoundHandler());
  app.use(errorHandler());

  const service = createServiceBuilder(module)
    .setPort(7007)
    .addRouter('', app);

  await service.start();
}

main().catch(err => {
  getRootLogger().error(err);
  process.exit(1);
});

If your backend uses the typical PluginEnvironment factory pattern, wire the router in the same way you wire other plugin routers Mount it at /api/copilot

Configure GitHub access

Add a GitHub integration entry Use a token that can read Copilot metrics for your org or enterprise

Edit app-config.yaml

Copy
integrations:
  github:
    - host: github.com
      token: ${GITHUB_TOKEN}
# for GitHub Enterprise Server
#  github:
#    - host: ghe.example.com
#      apiBaseUrl: https://ghe.example.com/api/v3
#      token: ${GHE_TOKEN}

Set the env vars in your backend process

Copy
export GITHUB_TOKEN=your_token_here
# or for GHES
# export GHE_TOKEN=your_token_here

No frontend config is needed for the backend URL The plugin uses a relative path to the backend /api/copilot

Where everything shows up

  • The Copilot page is served at path /copilot
  • The sidebar shows Copilot in the Menu group
  • The backend serves under /api/copilot for both systems

Changelog

This changelog is produced from commits made to the GitHub Copilot Adoption Metrics plugin since a year ago, and based on the code located here. It may not contain information about all commits. Releases and version bumps are intentionally omitted. This changelog is generated by AI.

Breaking changes

None

Features

  • Add support for private tokens for the plugin #1928 10 months ago
  • Enable GitHub App auth for the Copilot backend. You can mix auth types #2585 8 months ago
  • Support organization and team metrics views. Let users pick a team and compare to overall data #1261 10 months ago
  • Move the Copilot UI to the new Backstage frontend system #4632 2 months ago
  • Allow a relative URL for the Copilot page. For example /stats/copilot #3462 6 months ago
  • Switch the backend to the GitHub metrics API. Keep the current UI working by converting data on the server #2989 6 months ago

Performance

  • Improve metrics ingestion by skipping teams with fewer than five members. Query seats once per organization #4784 27 days ago

Bug fixes

  • Remove extra semi colon in Route usage. Prevent a stray text node in the new frontend #5010 27 days ago
  • Ensure errors show up clearly in logs #4756 2 months ago
  • Fetch enterprise seats in the enterprise task. Do not fetch organization seats there #3550 5 months ago
  • Use the correct timezone when checking the latest data point #3533 6 months ago
  • Handle missing editors in metrics safely #3228 6 months ago
  • Compute acceptance rate using suggestion count and acceptance count. This matches the expected metric #2170 8 months ago

Documentation

  • Fix the scheduler config example key #4645 2 months ago
  • Clarify install steps for frontend and backend #2467 8 months ago
  • Remove Portuguese text from the README #2489 8 months ago
  • Update README links to the community plugins repository #3931 5 months ago

Dependencies

  • Update octokit rest to 20.1.2 #3537 3 months ago

Maintenance

  • Bump Backstage to 1.38.1 and apply the new jsx transform #3674 5 months ago
  • Remove uses of at backstage backend tasks #2359 8 months ago
  • Remove unused at backstage backend common dependency #1826 10 months ago
  • Cut knip false positives with a workspace config #3018 6 months ago

Set up Backstage in minutes with Roadie