Grafana Cloud

Link errors to commits with Suspect Commits

The Suspect Commits feature in Frontend Observability surfaces the Git commit most likely responsible for an error on the error summary page, so you can jump from a stack trace to a candidate fix without leaving Grafana. Enabling commit hash injection adds a directly recorded signal: when an error first appears, the SDK reports the build’s SHA, and Suspect Commits pins that commit at the top of the candidate list.

To enable this, inject the current commit hash into your built JavaScript at build time. The Faro Web SDK reads it and includes it as meta.app.gitHash on every telemetry payload. You can inject the hash with the Faro bundler plugins, the Faro CLI, or directly in the Faro Web SDK configuration.

Note

The Faro Web SDK transmits the injected commit hash to Grafana Cloud as part of Faro telemetry and stores it with the error’s first-seen record. If you operate in a regulated industry or your repository is proprietary, review your organization’s data-handling policies before enabling this feature.

Minimum versions:

  • @grafana/faro-web-sdk (and @grafana/faro-react): 2.7.0
  • Bundler plugins: @grafana/faro-webpack-plugin 0.12.0, @grafana/faro-rollup-plugin 0.11.0, @grafana/faro-esbuild-plugin 0.6.0, @grafana/faro-metro-plugin 0.2.0
  • CLI (for post-build injection): @grafana/faro-cli 0.10.0

Inject the commit hash with the bundler plugins

If you use the Faro bundler plugins to upload source maps, the same plugins can inject the commit hash. The plugin resolves the hash in this priority order:

  1. Explicit gitHash value passed to the plugin
  2. Auto-detected via git rev-parse HEAD at build time

If neither resolves, the plugin emits [Faro] Git hash could not be resolved to the build log and no hash is injected. The build still succeeds.

Auto-detection via git rev-parse HEAD

When gitHash is not specified, the plugin runs git rev-parse HEAD during the build. This works for most local development environments and CI setups where the .git directory is present in the build context:

JavaScript
new FaroSourceMapUploaderPlugin({
  appName: '$your-app-name',
  endpoint: '$your-faro-sourcemap-api-url',
  // ...other required options
  // gitHash auto-detected from git rev-parse HEAD
});

Warning

Multi-stage Docker builds commonly exclude .git via .dockerignore, which causes auto-detection to silently fail. The build succeeds but no hash is injected. Either keep .git in the build context or set gitHash explicitly (see below).

Explicit override

Set gitHash explicitly when auto-detection won’t pick the right SHA:

  • Multi-stage Docker builds, or any build context without access to .git
  • GitHub Actions pull_request events, where git rev-parse HEAD and process.env.GITHUB_SHA both resolve to a synthetic merge commit that doesn’t exist on any branch. To point at the PR head, pass ${{ github.event.pull_request.head.sha }} through as an env var.
  • Any environment where the desired SHA differs from the local checkout
JavaScript
new FaroSourceMapUploaderPlugin({
  appName: '$your-app-name',
  endpoint: '$your-faro-sourcemap-api-url',
  // ...other required options
  gitHash: process.env.FARO_GIT_HASH,
});

On GitHub Actions, expose the PR head SHA to the build step.

Use pull_request.head.sha so the injected SHA points at the PR head, not the synthetic merge commit GitHub creates for pull_request events:

YAML
- name: build
  env:
    FARO_GIT_HASH: ${{ github.event.pull_request.head.sha || github.sha }}
  run: yarn build

Post-build injection via the Faro CLI

If you can’t run the bundler plugin at build time (for example, you ship pre-built artifacts produced elsewhere), the @grafana/faro-cli package exposes an inject-git-hash command that mirrors inject-bundle-id and patches the hash into existing JavaScript artifacts after the fact:

Bash
npx @grafana/faro-cli inject-git-hash \
  --app-name '$your-app-name' \
  --git-hash $(git rev-parse HEAD) \
  --files 'dist/**/*.js'

Refer to the faro-JavaScript-bundler-plugins repository for the full CLI reference.

Set gitHash directly in the Faro Web SDK configuration

If you don’t use the Faro bundler plugins, you can set app.gitHash directly when initializing the Faro Web SDK. Because browsers have no process.env, the commit SHA must be embedded into the bundle at build time:

1. Make the SHA available to the build:

For local builds:

Bash
export GIT_HASH=$(git rev-parse HEAD)

For CI environments, use the appropriate environment variable:

  • GitHub Actions: export GIT_HASH=$GITHUB_SHA
  • Jenkins: export GIT_HASH=$GIT_COMMIT
  • GitLab CI: export GIT_HASH=$CI_COMMIT_SHA

2. Configure your bundler to inline it.

For Create React App and Next.js, no extra config is needed. They automatically inline prefixed env vars. Set REACT_APP_GIT_HASH (CRA) or NEXT_PUBLIC_GIT_HASH (Next.js) instead of GIT_HASH in step 1, and reference it directly as process.env.REACT_APP_GIT_HASH / process.env.NEXT_PUBLIC_GIT_HASH.

For Vite, no extra configuration is needed. Vite embeds import.meta.env.VITE_*. Set VITE_GIT_HASH in step 1 and reference it as import.meta.env.VITE_GIT_HASH.

For Webpack, use DefinePlugin:

JavaScript
// webpack.config.js
const webpack = require('webpack');

module.exports = {
  // ...
  plugins: [
    new webpack.DefinePlugin({
      'process.env.GIT_HASH': JSON.stringify(process.env.GIT_HASH),
    }),
  ],
};

For Rollup, use @rollup/plugin-replace:

JavaScript
// rollup.config.js
import replace from '@rollup/plugin-replace';

export default {
  // ...
  plugins: [
    replace({
      preventAssignment: true,
      'process.env.GIT_HASH': JSON.stringify(process.env.GIT_HASH),
    }),
  ],
};

For esbuild, use the define option:

JavaScript
// build.js
import * as esbuild from 'esbuild';

await esbuild.build({
  // ...
  define: {
    'process.env.GIT_HASH': JSON.stringify(process.env.GIT_HASH),
  },
});

3. Reference it in your Faro initialization:

JavaScript
import { initializeFaro } from '@grafana/faro-web-sdk';

initializeFaro({
  url: '$your-faro-collector-url',
  app: {
    name: '$your-app-name',
    version: '1.0.0',
    gitHash: process.env.GIT_HASH, // or import.meta.env.VITE_GIT_HASH for Vite
  },
  // ...other config
});

Only the meta.app.gitHash check below applies when using this approach. The bundler plugins set window.__faroGitHash_<app-name> only.

Verify the commit hash is captured

After a successful build, you can confirm the hash flows end-to-end:

  • Build log: Grep for [Faro] Git hash could not be resolved. If the plugin couldn’t determine a SHA, this string appears in the build output. Its absence means the plugin resolved a hash successfully.
  • Bundle: Open DevTools console on a page using the bundle and run window.__faroGitHash_<your-app-name>. Expect a 40-character SHA. (Bundler plugin path only.)
  • Telemetry: In the browser Network tab, inspect a Faro /collect request. meta.app.gitHash should be set on the payload.

If the hash is missing, the most common cause is a build context without .git (multi-stage Docker, .dockerignore excluding .git). Refer to the Explicit override section to set gitHash explicitly.