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
yarn --cwd packages/app add @backstage-community/plugin-copilot
Add the Copilot page route
Edit packages/app/src/App.tsx
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
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
yarn --cwd packages/backend add @backstage-community/plugin-copilot-backend
New backend system
Edit packages/backend/src/index.ts
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
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
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
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
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
Set up Backstage in minutes with Roadie
Focus on using Backstage, rather than building and maintaining it.