Skip to main content
The Sentry Ember SDK is an Ember addon that wraps @sentry/browser with Ember-specific functionality including automatic error capture and performance instrumentation.

Installation

Install as an Ember addon:
ember install @sentry/ember

Basic Setup

Initialize Sentry in your app.js before the application initializes:
// app/app.js
import Application from '@ember/application';
import Resolver from 'ember-resolver';
import loadInitializers from 'ember-load-initializers';
import config from './config/environment';
import * as Sentry from '@sentry/ember';

Sentry.init({
  dsn: 'YOUR_DSN_HERE',
  
  // Performance Monitoring
  tracesSampleRate: 1.0,
  
  // Set tracesSampleRate to 1.0 to capture 100%
  // of transactions for performance monitoring.
  // We recommend adjusting this value in production
});

export default class App extends Application {
  modulePrefix = config.modulePrefix;
  podModulePrefix = config.podModulePrefix;
  Resolver = Resolver;
}

loadInitializers(App, config.modulePrefix);

Configuration

Environment Configuration

Configure Ember-specific options in config/environment.js:
// config/environment.js
module.exports = function (environment) {
  let ENV = {
    // ... other config
    
    '@sentry/ember': {
      // Disable automatic performance instrumentation
      disablePerformance: false,
      
      // All runloop queue durations will be added as spans
      minimumRunloopQueueDuration: 5, // ms, default: 5
      
      // Disable automatic component instrumentation
      disableInstrumentComponents: false,
      
      // All component render durations will be added as spans
      minimumComponentRenderDuration: 2, // ms, default: 2
      
      // Enable component definition tracking
      enableComponentDefinition: false,
    },
  };
  
  return ENV;
};

Performance Monitoring

Route Instrumentation

Instrument routes to track lifecycle hooks:
// app/routes/dashboard.js
import Route from '@ember/routing/route';
import { instrumentRoutePerformance } from '@sentry/ember';

class DashboardRoute extends Route {
  async beforeModel(transition) {
    // This will be tracked
    await this.checkPermissions();
  }
  
  async model(params) {
    // This will be tracked
    return await this.store.query('dashboard', params);
  }
  
  async afterModel(model, transition) {
    // This will be tracked
    await this.loadRelatedData(model);
  }
  
  setupController(controller, model) {
    // This will be tracked
    super.setupController(controller, model);
    controller.set('extraData', this.computeExtraData(model));
  }
}

// Wrap the route to enable instrumentation
export default instrumentRoutePerformance(DashboardRoute);
This tracks:
  • beforeModel hook duration
  • model hook duration
  • afterModel hook duration
  • setupController hook duration

Runloop Queue Instrumentation

The SDK automatically instruments Ember’s runloop queues:
// config/environment.js
ENV['@sentry/ember'] = {
  // Set minimum duration threshold (ms)
  minimumRunloopQueueDuration: 0, // Track all queue durations
};
Tracked queues:
  • sync - Synchronization queue
  • actions - Action queue
  • routerTransitions - Router transition queue
  • render - Render queue
  • afterRender - After render queue
  • destroy - Destroy queue

Component Instrumentation

Non-Glimmer components are automatically tracked:
// app/components/user-profile.js
import Component from '@ember/component';

export default Component.extend({
  // Component initialization is automatically tracked
  init() {
    this._super(...arguments);
    // Your code
  },
  
  // didInsertElement to didRender is tracked
  didInsertElement() {
    this._super(...arguments);
    // Your code
  },
});
Configuration:
// config/environment.js
ENV['@sentry/ember'] = {
  // Disable component tracking
  disableInstrumentComponents: false,
  
  // Set minimum render duration threshold (ms)
  minimumComponentRenderDuration: 0, // Track all components
};

Glimmer Component Tracking

For Glimmer components, enable component definition tracking:
// config/environment.js
ENV['@sentry/ember'] = {
  // Show component definitions in traces
  enableComponentDefinition: true,
};

Error Handling

Automatic Error Capture

Errors are automatically captured:
// app/routes/posts.js
import Route from '@ember/routing/route';

export default class PostsRoute extends Route {
  model() {
    // This error will be automatically captured
    throw new Error('Failed to load posts');
  }
}

Manual Error Capture

import Component from '@glimmer/component';
import { action } from '@ember/object';
import * as Sentry from '@sentry/ember';

export default class FormComponent extends Component {
  @action
  async handleSubmit() {
    try {
      await this.saveData();
    } catch (error) {
      Sentry.captureException(error, {
        tags: {
          component: 'FormComponent',
          action: 'submit',
        },
      });
    }
  }
}

Context & User Information

Setting User Context

// app/services/session.js
import Service from '@ember/service';
import * as Sentry from '@sentry/ember';

export default class SessionService extends Service {
  async login(credentials) {
    const user = await this.authenticate(credentials);
    
    // Set user context
    Sentry.setUser({
      id: user.id,
      email: user.email,
      username: user.username,
    });
    
    return user;
  }
  
  logout() {
    Sentry.setUser(null);
  }
}

Adding Context

import Route from '@ember/routing/route';
import * as Sentry from '@sentry/ember';

export default class ApplicationRoute extends Route {
  beforeModel() {
    // Set global context
    Sentry.setContext('app', {
      version: config.APP.version,
      environment: config.environment,
    });
    
    // Add tags
    Sentry.setTag('locale', this.intl.locale);
  }
}
import Component from '@glimmer/component';
import { action } from '@ember/object';
import * as Sentry from '@sentry/ember';

export default class NavigationComponent extends Component {
  @action
  navigate(route) {
    Sentry.addBreadcrumb({
      category: 'navigation',
      message: `User navigated to ${route}`,
      level: 'info',
    });
    
    this.router.transitionTo(route);
  }
}

Advanced Configuration

// config/environment.js
ENV['@sentry/ember'] = {
  // Disable all automatic performance instrumentation
  disablePerformance: true,
};

Custom Performance Tracking

import Component from '@glimmer/component';
import { action } from '@ember/object';
import * as Sentry from '@sentry/ember';

export default class DataTableComponent extends Component {
  @action
  async loadData() {
    await Sentry.startSpan(
      {
        name: 'DataTable.loadData',
        op: 'ui.ember.component.load',
      },
      async () => {
        const data = await fetch('/api/table-data');
        this.data = await data.json();
      },
    );
  }
}

Session Replay

// app/app.js
import * as Sentry from '@sentry/ember';

Sentry.init({
  dsn: 'YOUR_DSN_HERE',
  
  integrations: [
    Sentry.replayIntegration({
      maskAllText: true,
      blockAllMedia: true,
    }),
  ],
  
  tracesSampleRate: 1.0,
  replaysSessionSampleRate: 0.1,
  replaysOnErrorSampleRate: 1.0,
});

Testing

When testing your Ember app with Sentry:
// tests/test-helper.js
import Application from '../app';
import config from '../config/environment';
import { setApplication } from '@ember/test-helpers';
import { start } from 'ember-qunit';
import * as Sentry from '@sentry/ember';

// Initialize Sentry for tests (with disabled transport)
Sentry.init({
  dsn: 'https://[email protected]/12345',
  beforeSend: () => null, // Don't send events in tests
});

setApplication(Application.create(config.APP));

start();

Supported Versions

  • Ember.js: v4.0 or above
  • Node.js: v14.18 or above

Best Practices

Route Instrumentation

Wrap routes with instrumentRoutePerformance to track lifecycle hooks.

Threshold Tuning

Adjust duration thresholds to focus on performance bottlenecks.

Component Tracking

Enable component definition tracking for Glimmer components.

Context

Set user and app context in your ApplicationRoute.

Configuration Reference

// config/environment.js
ENV['@sentry/ember'] = {
  // Performance Settings
  disablePerformance: false,
  minimumRunloopQueueDuration: 5, // ms
  
  // Component Settings
  disableInstrumentComponents: false,
  minimumComponentRenderDuration: 2, // ms
  enableComponentDefinition: false,
};
In app.js:
Sentry.init({
  dsn: 'YOUR_DSN_HERE',
  
  // Standard Sentry options
  environment: 'production',
  release: '[email protected]',
  tracesSampleRate: 0.2,
  
  // Browser SDK options
  integrations: [
    Sentry.browserTracingIntegration(),
    Sentry.replayIntegration(),
  ],
  
  replaysSessionSampleRate: 0.1,
  replaysOnErrorSampleRate: 1.0,
});

Next Steps

Source Maps

Upload source maps for production builds

Performance

Deep dive into performance monitoring

Session Replay

Set up session replay

Ember Guides

Ember.js official documentation

Build docs developers (and LLMs) love