# How Sentry is Integrated for Error Tracking in Ghost: Backend and Frontend Implementation

> Discover how Ghost integrates Sentry for comprehensive error tracking. Explore backend Node.js and frontend Ember implementation, noise filtering, and context enrichment.

- Repository: [Ghost/Ghost](https://github.com/TryGhost/Ghost)
- Tags: internals
- Published: 2026-05-18

---

**Ghost implements Sentry error tracking across both its Node.js backend and Ember-based admin frontend using a dual-layer architecture that filters noise, enriches events with Ghost-specific context, and optionally traces database queries.**

The TryGhost/Ghost repository employs a sophisticated, full-stack approach to error monitoring that captures server crashes, client-side UI failures, and performance bottlenecks. By splitting the integration between [`ghost/core/core/shared/sentry.js`](https://github.com/TryGhost/Ghost/blob/main/ghost/core/core/shared/sentry.js) for the backend and [`ghost/admin/app/utils/sentry.js`](https://github.com/TryGhost/Ghost/blob/main/ghost/admin/app/utils/sentry.js) for the frontend, Ghost ensures comprehensive visibility while maintaining strict control over data quality and relevance.

## Backend Sentry Integration Architecture

The backend implementation resides in [`ghost/core/core/shared/sentry.js`](https://github.com/TryGhost/Ghost/blob/main/ghost/core/core/shared/sentry.js) and serves as the central hub for server-side error capture and performance monitoring.

### Initialization and Configuration

Sentry initializes only when a valid `sentry` configuration block exists in Ghost's config and is not explicitly disabled. The module sets critical metadata to ensure errors are properly categorized:

- **Release**: Formatted as `ghost@<full-version>` using the `@tryghost/version` package
- **Environment**: Derived from `PRO_ENV` or the standard `env` setting
- **DSN**: Pulled from `config.get('sentry').dsn`

```javascript
// Configuration structure in ghost/core/core/shared/sentry.js
const sentryConfig = {
    dsn: config.get('sentry').dsn,
    release: `ghost@${version}`,
    environment: config.get('proEnv') || config.get('env'),
    // Additional hooks and integrations below
};

```

### Error Enrichment with beforeSend

The **`beforeSend`** hook in the backend implementation performs intelligent error enrichment and filtering. When Ghost-specific errors from the `@tryghost/errors` library are detected, the hook extracts custom fields—including `type`, `code`, `id`, and `status_code`—and maps them to Sentry tags for improved searchability.

For database failures, the hook normalizes MySQL errors by adding a dedicated `mysql` context containing the raw `errno`, SQL statement, and other diagnostic information. Critically, the implementation filters out non-500 status codes, ensuring only serious server failures are transmitted to Sentry and reducing alert fatigue from client-caused errors.

### Transaction Filtering and Performance Monitoring

Ghost implements a **`beforeSendTransaction`** hook that aggressively whitelists HTTP transactions to prevent noisy performance data. Only requests belonging to specific routes—Ghost's public API, members API, or frontend routes—are retained. This selective approach ensures performance monitoring focuses on user-facing functionality rather than internal health checks or administrative endpoints.

When `sentry.tracing.enabled` is set to true, Ghost activates two additional components:
1. The standard HTTP integration for request tracing
2. A custom `SentryKnexTracingIntegration` (defined in [`ghost/core/core/shared/sentry-knex-tracing-integration.js`](https://github.com/TryGhost/Ghost/blob/main/ghost/core/core/shared/sentry-knex-tracing-integration.js)) that captures database query spans

### Express Middleware Implementation

The Sentry module exports three critical Express middleware functions and utility methods that integrate seamlessly into Ghost's server stack:

```javascript
// Example: Implementing Sentry middleware in the Express stack
const {
    requestHandler, 
    errorHandler, 
    tracingHandler, 
    initQueryTracing
} = require('./shared/sentry');

// Start a Sentry transaction per request
app.use(requestHandler());

// Optional: Enable database query tracing
app.use(tracingHandler());

// Route handlers would go here...

// Capture and send errors to Sentry
app.use(errorHandler());

// Initialize Knex query tracing if configured
initQueryTracing(knexInstance);

```

## Frontend Sentry Integration in the Ghost Admin

The client-side implementation in [`ghost/admin/app/utils/sentry.js`](https://github.com/TryGhost/Ghost/blob/main/ghost/admin/app/utils/sentry.js) handles error tracking for Ghost's Ember-based administrative interface.

### Client-Side Configuration Factory

The frontend exposes a **`getSentryConfig`** factory function that returns a configuration object tailored for the Ember-compatible Sentry SDK (`@sentry/ember`). This factory accepts the DSN, environment, application version, and an optional custom transport for testing environments.

```javascript
// Example: Initializing Sentry in the admin app (admin/app.js)
import * as Sentry from '@sentry/ember';
import {getSentryConfig} from './utils/sentry';

const sentryConfig = getSentryConfig(
    process.env.SENTRY_DSN,
    process.env.NODE_ENV,
    APP_VERSION,
    null // optional custom transport for tests
);

Sentry.init(sentryConfig);

```

### Environment-Aware Integrations

The configuration dynamically loads environment-specific integrations:
- **`Debug`** integration activates in development environments for verbose logging
- **`Replay`** integration enables session replay capabilities in non-testing environments
- **Custom ignore patterns** filter known harmless browser errors that would otherwise clutter reports

### Error Sanitization and Filtering

The frontend **`beforeSend`** hook performs several sanitization steps to ensure high signal-to-noise ratios:
- Strips "handled" UI errors marked with `shown_to_user` to focus on uncaught exceptions
- Filters out requests matching `FILTERED_URL_REGEX` (specifically Ghost's analytics endpoint)
- Normalizes model-id strings (e.g., `<(post|page):...>`) to improve error grouping in Sentry's UI
- Enhances AJAX error reports with the original server-side payload, including error type, context, and message

## Database Query Tracing with Knex

For deployments requiring deep performance insights, Ghost includes a custom tracing integration in [`ghost/core/core/shared/sentry-knex-tracing-integration.js`](https://github.com/TryGhost/Ghost/blob/main/ghost/core/core/shared/sentry-knex-tracing-integration.js). When enabled via the tracing configuration, this integration wraps Knex queries to create detailed spans showing database execution times and query patterns. This allows developers to identify N+1 queries or slow database operations directly within Sentry's performance monitoring dashboard.

## Summary

- Ghost employs a **dual-layer Sentry integration** splitting backend ([`ghost/core/core/shared/sentry.js`](https://github.com/TryGhost/Ghost/blob/main/ghost/core/core/shared/sentry.js)) and frontend ([`ghost/admin/app/utils/sentry.js`](https://github.com/TryGhost/Ghost/blob/main/ghost/admin/app/utils/sentry.js)) concerns for comprehensive error tracking.
- The backend implementation uses **`beforeSend`** hooks to normalize MySQL errors, enrich Ghost-specific error contexts, and filter out non-500 status codes.
- **Transaction whitelisting** via `beforeSendTransaction` ensures only relevant API and frontend route performance data is captured, eliminating noise from internal endpoints.
- The frontend factory function **`getSentryConfig`** provides environment-aware configurations including session replay and debug integrations.
- Optional **Knex query tracing** via `SentryKnexTracingIntegration` enables database performance monitoring when `sentry.tracing.enabled` is true.

## Frequently Asked Questions

### How do I enable Sentry error tracking in Ghost?

Enable Sentry by adding a `sentry` configuration block to your Ghost configuration file with a valid DSN. Set `sentry.dsn` to your project’s DSN, and optionally enable performance tracing by setting `sentry.tracing.enabled` to `true`. The backend initializes automatically when the configuration is present and not disabled, while the frontend picks up the DSN from environment variables during the admin build process.

### What types of errors does Ghost filter out from Sentry reports?

The backend explicitly filters out errors with non-500 HTTP status codes, ensuring only server-side failures are reported while ignoring client errors like 404s or 400s. The frontend filters handled UI errors marked as `shown_to_user` and requests to Ghost’s internal analytics endpoint. Both implementations use `beforeSend` hooks to drop events matching specific ignore patterns, ensuring reports contain only actionable exceptions.

### How does Ghost handle database query tracing with Sentry?

When tracing is enabled in the configuration, Ghost loads a custom `SentryKnexTracingIntegration` from [`ghost/core/core/shared/sentry-knex-tracing-integration.js`](https://github.com/TryGhost/Ghost/blob/main/ghost/core/core/shared/sentry-knex-tracing-integration.js). This integration wraps the Knex query builder to create spans for each database operation, allowing Sentry to display query execution times and identify performance bottlenecks. Developers must call `initQueryTracing(knexInstance)` after initializing the database connection to activate this feature.

### What is the difference between the backend and frontend Sentry implementations in Ghost?

The backend implementation in [`ghost/core/core/shared/sentry.js`](https://github.com/TryGhost/Ghost/blob/main/ghost/core/core/shared/sentry.js) uses the Node.js Sentry SDK and provides Express middleware for request handling, while normalizing server errors and MySQL failures. The frontend implementation in [`ghost/admin/app/utils/sentry.js`](https://github.com/TryGhost/Ghost/blob/main/ghost/admin/app/utils/sentry.js) uses the Ember-specific Sentry SDK and focuses on sanitizing browser errors, normalizing model identifiers, and integrating session replay capabilities. The backend handles transaction filtering for API routes, whereas the frontend manages environment-specific integrations like Debug and Replay.