How Sentry is Integrated for Error Tracking in Ghost: Backend and Frontend Implementation
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 for the backend and 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 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/versionpackage - Environment: Derived from
PRO_ENVor the standardenvsetting - DSN: Pulled from
config.get('sentry').dsn
// 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:
- The standard HTTP integration for request tracing
- A custom
SentryKnexTracingIntegration(defined inghost/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:
// 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 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.
// 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:
Debugintegration activates in development environments for verbose loggingReplayintegration 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_userto 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. 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) and frontend (ghost/admin/app/utils/sentry.js) concerns for comprehensive error tracking. - The backend implementation uses
beforeSendhooks to normalize MySQL errors, enrich Ghost-specific error contexts, and filter out non-500 status codes. - Transaction whitelisting via
beforeSendTransactionensures only relevant API and frontend route performance data is captured, eliminating noise from internal endpoints. - The frontend factory function
getSentryConfigprovides environment-aware configurations including session replay and debug integrations. - Optional Knex query tracing via
SentryKnexTracingIntegrationenables database performance monitoring whensentry.tracing.enabledis 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. 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 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 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →