diff --git a/static/app/components/onboarding/gettingStartedDoc/layout.tsx b/static/app/components/onboarding/gettingStartedDoc/layout.tsx
index d140b2a9c6958..892f5d8efc868 100644
--- a/static/app/components/onboarding/gettingStartedDoc/layout.tsx
+++ b/static/app/components/onboarding/gettingStartedDoc/layout.tsx
@@ -31,7 +31,7 @@ export type LayoutProps = {
nextSteps?: NextStep[];
};
-export function Layout({steps, nextSteps, newOrg}: LayoutProps) {
+export function Layout({steps, nextSteps = [], newOrg}: LayoutProps) {
const organization = useOrganization();
const {isSelfHosted} = useLegacyStore(ConfigStore);
@@ -53,7 +53,7 @@ export function Layout({steps, nextSteps, newOrg}: LayoutProps) {
))}
- {nextSteps && (
+ {nextSteps.length > 0 && (
{t('Next Steps')}
diff --git a/static/app/components/onboarding/gettingStartedDoc/sdkDocumentation.tsx b/static/app/components/onboarding/gettingStartedDoc/sdkDocumentation.tsx
index 05e4edd4c54e3..ed2befbddeba3 100644
--- a/static/app/components/onboarding/gettingStartedDoc/sdkDocumentation.tsx
+++ b/static/app/components/onboarding/gettingStartedDoc/sdkDocumentation.tsx
@@ -12,6 +12,7 @@ export const migratedDocs = [
'javascript-angular',
'javascript-vue',
'javascript-gatsby',
+ 'javascript-ember',
];
type SdkDocumentationProps = {
diff --git a/static/app/gettingStartedDocs/javascript/ember.spec.tsx b/static/app/gettingStartedDocs/javascript/ember.spec.tsx
new file mode 100644
index 0000000000000..bed7a8feb86f9
--- /dev/null
+++ b/static/app/gettingStartedDocs/javascript/ember.spec.tsx
@@ -0,0 +1,44 @@
+import {render, screen} from 'sentry-test/reactTestingLibrary';
+
+import {StepTitle} from 'sentry/components/onboarding/gettingStartedDoc/step';
+import {ProductSolution} from 'sentry/components/onboarding/productSelection';
+
+import GettingStartedWithEmber, {nextSteps, steps} from './ember';
+
+describe('GettingStartedWithEmber', function () {
+ it('all products are selected', function () {
+ const {container} = render(
+
+ );
+
+ // Steps
+ for (const step of steps()) {
+ expect(
+ screen.getByRole('heading', {name: StepTitle[step.type]})
+ ).toBeInTheDocument();
+ }
+
+ // Next Steps
+ const filteredNextStepsLinks = nextSteps.filter(
+ nextStep =>
+ ![
+ ProductSolution.PERFORMANCE_MONITORING,
+ ProductSolution.SESSION_REPLAY,
+ ].includes(nextStep.id as ProductSolution)
+ );
+
+ for (const filteredNextStepsLink of filteredNextStepsLinks) {
+ expect(
+ screen.getByRole('link', {name: filteredNextStepsLink.name})
+ ).toBeInTheDocument();
+ }
+
+ expect(container).toSnapshot();
+ });
+});
diff --git a/static/app/gettingStartedDocs/javascript/ember.tsx b/static/app/gettingStartedDocs/javascript/ember.tsx
new file mode 100644
index 0000000000000..4daf854ebda31
--- /dev/null
+++ b/static/app/gettingStartedDocs/javascript/ember.tsx
@@ -0,0 +1,163 @@
+import {Layout, LayoutProps} from 'sentry/components/onboarding/gettingStartedDoc/layout';
+import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
+import {getUploadSourceMapsStep} from 'sentry/components/onboarding/gettingStartedDoc/utils';
+import {ProductSolution} from 'sentry/components/onboarding/productSelection';
+import {t, tct} from 'sentry/locale';
+
+// Configuration Start
+const replayIntegration = `
+new Sentry.Replay(),
+`;
+
+const replayOtherConfig = `
+// Session Replay
+replaysSessionSampleRate: 0.1, // This sets the sample rate at 10%. You may want to change it to 100% while in development and then sample at a lower rate in production.
+replaysOnErrorSampleRate: 1.0, // If you're not already sampling the entire session, change the sample rate to 100% when sampling sessions where errors occur.
+`;
+
+const performanceOtherConfig = `
+// Performance Monitoring
+tracesSampleRate: 1.0, // Capture 100% of the transactions, reduce in production!
+`;
+
+export const steps = ({
+ sentryInitContent,
+}: {
+ sentryInitContent?: string;
+} = {}): LayoutProps['steps'] => [
+ {
+ language: 'bash',
+ type: StepType.INSTALL,
+
+ description: t(
+ 'Sentry captures data by using an SDK within your application’s runtime.'
+ ),
+ configurations: [
+ {
+ code: `
+ # Using ember-cli
+ ember install @sentry/ember
+ `,
+ },
+ ],
+ },
+ {
+ language: 'javascript',
+ type: StepType.CONFIGURE,
+ description: tct(
+ 'You should [code:init] the Sentry SDK as soon as possible during your application load up in [code:app.js], before initializing Ember:',
+ {
+ code:
,
+ }
+ ),
+ configurations: [
+ {
+ code: `
+ 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({
+ ${sentryInitContent}
+ });
+
+ export default class App extends Application {
+ modulePrefix = config.modulePrefix;
+ podModulePrefix = config.podModulePrefix;
+ Resolver = Resolver;
+ }
+ `,
+ },
+ ],
+ },
+ getUploadSourceMapsStep(
+ 'https://docs.sentry.io/platforms/javascript/guides/ember/sourcemaps/'
+ ),
+ {
+ language: 'javascript',
+ type: StepType.VERIFY,
+ description: t(
+ "This snippet contains an intentional error and can be used as a test to make sure that everything's working as expected."
+ ),
+ configurations: [
+ {
+ code: `myUndefinedFunction();`,
+ },
+ ],
+ },
+];
+
+export const nextSteps = [
+ {
+ id: 'performance-monitoring',
+ name: t('Performance Monitoring'),
+ description: t(
+ 'Track down transactions to connect the dots between 10-second page loads and poor-performing API calls or slow database queries.'
+ ),
+ link: 'https://docs.sentry.io/platforms/javascript/guides/ember/performance/',
+ },
+ {
+ id: 'session-replay',
+ name: t('Session Replay'),
+ description: t(
+ 'Get to the root cause of an error or latency issue faster by seeing all the technical details related to that issue in one visual replay on your web application.'
+ ),
+ link: 'https://docs.sentry.io/platforms/javascript/guides/ember/session-replay/',
+ },
+];
+// Configuration End
+
+type Props = {
+ activeProductSelection: ProductSolution[];
+ dsn: string;
+ newOrg?: boolean;
+};
+
+export default function GettingStartedWithEmber({
+ dsn,
+ newOrg,
+ activeProductSelection,
+}: Props) {
+ const integrations: string[] = [];
+ const otherConfigs: string[] = [];
+
+ let nextStepDocs = [...nextSteps];
+
+ if (activeProductSelection.includes(ProductSolution.PERFORMANCE_MONITORING)) {
+ otherConfigs.push(performanceOtherConfig.trim());
+ nextStepDocs = nextStepDocs.filter(
+ step => step.id !== ProductSolution.PERFORMANCE_MONITORING
+ );
+ }
+
+ if (activeProductSelection.includes(ProductSolution.SESSION_REPLAY)) {
+ integrations.push(replayIntegration.trim());
+ otherConfigs.push(replayOtherConfig.trim());
+ nextStepDocs = nextStepDocs.filter(
+ step => step.id !== ProductSolution.SESSION_REPLAY
+ );
+ }
+
+ let sentryInitContent: string[] = [`dsn: "${dsn}",`];
+
+ if (integrations.length > 0) {
+ sentryInitContent = sentryInitContent.concat('integrations: [', integrations, '],');
+ }
+
+ if (otherConfigs.length > 0) {
+ sentryInitContent = sentryInitContent.concat(otherConfigs);
+ }
+
+ return (
+
+ );
+}