Analytics Module Generic HTTP lets you send Backstage analytics events to any HTTP endpoint you control. It plugs into the built in Backstage Analytics API and forwards captured events with simple POST requests. You can point it at a Knative sink or a custom service in your stack. This gives you tracking without tying your data to a single vendor. It is a light way to understand how people use your portal while keeping the pipeline in your hands.
The module follows Backstage event shapes such as action, subject, attributes, and context. It can enrich events with team and owner details from the catalog to make rollups easier. You choose how events leave the browser. Stream them right away for near real time dashboards or batch them on a timer to reduce traffic. Secure delivery with basic auth or bearer tokens. Turn on debug logs when you need to verify what is sent.
Common use cases are straightforward. Ship usage to your analytics lake or warehouse. Post to an internal event bus or webhook gateway. Feed a Knative based pipeline for custom processing. Prototype measurement for new plugins before you commit to a commercial tool. The goal is simple control over what you track and where it goes.
Installation Instructions
These instructions apply to self-hosted Backstage only.
Install the package
- From your Backstage root
yarn add --cwd packages/app @pfeifferj/backstage-plugin-analytics-generic
Register the API in your app
- Open packages/app/src/apis.ts
- Add the imports and the API factory
// packages/app/src/apis.ts
import {
AnyApiFactory,
createApiFactory,
discoveryApiRef,
analyticsApiRef,
configApiRef,
errorApiRef,
identityApiRef,
} from '@backstage/core-plugin-api';
import { catalogApiRef } from '@backstage/plugin-catalog-react';
import { GenericAnalyticsAPI } from '@pfeifferj/backstage-plugin-analytics-generic';
export const apis: AnyApiFactory[] = [
// keep your other factories here
createApiFactory({
api: analyticsApiRef,
deps: {
configApi: configApiRef,
errorApi: errorApiRef,
identityApi: identityApiRef,
catalogApi: catalogApiRef,
},
factory: ({ configApi, errorApi, identityApi, catalogApi }) =>
GenericAnalyticsAPI.fromConfig(
configApi,
errorApi,
identityApi,
catalogApi,
),
}),
];Configure your app config
- Open app-config.yaml
- Add the analytics config
- Set your host and optional settings
app:
analytics:
generic:
host: ${ANALYTICS_GENERIC_HOST}
interval: ${ANALYTICS_GENERIC_INTERVAL}
basicAuthToken: ${ANALYTICS_GENERIC_BASIC_AUTH}
bearerAuthToken: ${ANALYTICS_GENERIC_BEARER_TOKEN}
debug: true
includeTeamMetadata: true
backend:
cors:
Access-Control-Allow-Origin: '*'Notes
- interval is minutes to ship logs
- set interval to 0 for instant streaming
- basicAuthToken is base64 username password
- bearerAuthToken is a JWT or OAuth bearer token
- if both auth values are set then basic auth is used
Add a small visible test in the UI
This makes it clear that events are being emitted from the browser.
- Create a small component that sends an event when you click a button
// packages/app/src/components/AnalyticsDemo/AnalyticsDemo.tsx
import React from 'react';
import { useAnalytics } from '@backstage/core-plugin-api';
import { Content, Page, Header, Button } from '@backstage/core-components';
export const AnalyticsDemo = () => {
const analytics = useAnalytics();
const sendEvent = () => {
analytics.captureEvent({
context: 'app',
action: 'click',
subject: 'generic analytics demo button',
attributes: { source: 'analytics-demo' },
});
};
return (
<Page themeId="home">
<Header title="Analytics Demo" />
<Content>
<Button variant="contained" color="primary" onClick={sendEvent}>
Send analytics event
</Button>
</Content>
</Page>
);
};- Add a route so you can render it
// packages/app/src/App.tsx
import React from 'react';
import { FlatRoutes, Route } from '@backstage/core-app-api';
import { AppRouter } from '@backstage/core-app-api';
import { AnalyticsDemo } from './components/AnalyticsDemo/AnalyticsDemo';
// keep your other imports
export const App = () => (
<AppRouter>
<FlatRoutes>
{/* keep your existing routes */}
<Route path="/analytics-demo" element={<AnalyticsDemo />} />
</FlatRoutes>
</AppRouter>
);Open the new route in your browser and click the button. The module will publish the event to your configured endpoint.
Backend setup
This module does not add a backend plugin. No backend package install is needed. Keep your backend as is.
Old backend system
Add the cors entry shown earlier in app-config.yaml if your endpoint needs it.
backend:
cors:
Access-Control-Allow-Origin: '*'New backend system
Add the same cors entry in app-config.yaml if your endpoint needs it.
backend:
cors:
Access-Control-Allow-Origin: '*'RHDH dynamic plugin optional
If you run Red Hat Developer Hub you can deploy the dynamic package. Add this to your values file or dynamic plugin config.
global:
dynamic:
plugins:
- package: '@pfeifferj/backstage-plugin-analytics-generic-dynamic@latest'
disabled: false
pluginConfig:
app:
analytics:
generic:
host: ${ANALYTICS_GENERIC_HOST}
interval: ${ANALYTICS_GENERIC_INTERVAL}
basicAuthToken: ${ANALYTICS_GENERIC_BASIC_AUTH}
bearerAuthToken: ${ANALYTICS_GENERIC_BEARER_TOKEN}
debug: true
includeTeamMetadata: trueTips
- identity is optional but helps add user context to events
includeTeamMetadatauses the catalog API to enrich events with team info- use either basic auth or bearer token based on your endpoint setup
Set up Backstage in minutes with Roadie
Focus on using Backstage, rather than building and maintaining it.
