---
title: "Link errors to commits with Suspect Commits | Grafana Cloud documentation"
description: "Link frontend errors to the Git commit most likely responsible using Suspect Commits, by injecting the build's commit hash with the Faro bundler plugins, the Faro CLI, or directly in the Faro Web SDK."
---

> For a curated documentation index, see [llms.txt](/llms.txt). For the complete documentation index, see [llms-full.txt](/llms-full.txt).

# 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](/docs/grafana-cloud/monitor-applications/frontend-observability/configure/sourcemap-uploads/bundlers/), 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](/docs/grafana-cloud/monitor-applications/frontend-observability/configure/sourcemap-uploads/bundlers/) 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 ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```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 ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```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 ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```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 ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```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](https://github.com/grafana/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 ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```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 ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```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 ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```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 ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```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 ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```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](#explicit-override) section to set `gitHash` explicitly.
