Skip to content

Conversation

@BYK
Copy link
Member

@BYK BYK commented Nov 13, 2025

Implements full Spotlight spec with support for multiple framework-specific
environment variable prefixes. Adds defensive environment variable access
for both process.env and import.meta.env to support various bundlers.

Supported environment variables (in priority order):

  • PUBLIC_SENTRY_SPOTLIGHT (SvelteKit, Astro, Qwik)
  • NEXT_PUBLIC_SENTRY_SPOTLIGHT (Next.js)
  • VITE_SENTRY_SPOTLIGHT (Vite)
  • NUXT_PUBLIC_SENTRY_SPOTLIGHT (Nuxt)
  • REACT_APP_SENTRY_SPOTLIGHT (Create React App)
  • VUE_APP_SENTRY_SPOTLIGHT (Vue CLI)
  • GATSBY_SENTRY_SPOTLIGHT (Gatsby)
  • SENTRY_SPOTLIGHT (base/official)

SENTRY_SPOTLIGHT is last as in environments like Docker Compose, we actually make the front-end env variable different than the base SENTRY_SPOTLIGHT one -- the backends need to reach docker.host.internal whereas front-ends always need localhost as we assume the browser runs on the same host with Spotlight.

Refactors envToBool utility from node-core to core package for shared usage.
Adds resolveSpotlightOptions utility to ensure consistent precedence rules
across Browser and Node SDKs.

Includes comprehensive test coverage for all new utilities and integration
tests for environment variable precedence behavior.

Closes #18404

@github-actions
Copy link
Contributor

github-actions bot commented Nov 13, 2025

size-limit report 📦

Path Size % Change Change
@sentry/browser 24.81 kB - -
@sentry/browser - with treeshaking flags 23.3 kB - -
@sentry/browser (incl. Tracing) 41.55 kB - -
@sentry/browser (incl. Tracing, Profiling) 46.14 kB - -
@sentry/browser (incl. Tracing, Replay) 79.97 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 69.7 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 84.64 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 96.89 kB - -
@sentry/browser (incl. Feedback) 41.52 kB - -
@sentry/browser (incl. sendFeedback) 29.49 kB - -
@sentry/browser (incl. FeedbackAsync) 34.48 kB - -
@sentry/react 26.52 kB - -
@sentry/react (incl. Tracing) 43.75 kB - -
@sentry/vue 29.27 kB - -
@sentry/vue (incl. Tracing) 43.36 kB - -
@sentry/svelte 24.82 kB - -
CDN Bundle 27.3 kB +0.25% +66 B 🔺
CDN Bundle (incl. Tracing) 42.3 kB +0.17% +70 B 🔺
CDN Bundle (incl. Tracing, Replay) 78.83 kB +0.1% +75 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) 84.27 kB +0.08% +61 B 🔺
CDN Bundle - uncompressed 80.18 kB +0.17% +136 B 🔺
CDN Bundle (incl. Tracing) - uncompressed 125.53 kB +0.11% +136 B 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed 241.56 kB +0.06% +136 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 254.32 kB +0.06% +136 B 🔺
@sentry/nextjs (client) 46.79 kB +1.79% +820 B 🔺
@sentry/sveltekit (client) 41.92 kB - -
@sentry/node-core 51.52 kB +0.05% +21 B 🔺
@sentry/node 159.84 kB +0.01% +14 B 🔺
@sentry/node - without tracing 92.92 kB +0.01% +8 B 🔺
@sentry/aws-serverless 108.46 kB +0.03% +27 B 🔺

View base workflow run

@github-actions
Copy link
Contributor

github-actions bot commented Nov 13, 2025

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

Scenario Requests/s % of Baseline Prev. Requests/s Change %
GET Baseline 8,889 - 8,630 +3%
GET With Sentry 1,732 19% 1,759 -2%
GET With Sentry (error only) 5,981 67% 6,085 -2%
POST Baseline 1,171 - 1,193 -2%
POST With Sentry 590 50% 595 -1%
POST With Sentry (error only) 1,043 89% 1,067 -2%
MYSQL Baseline 3,315 - 3,241 +2%
MYSQL With Sentry 455 14% 490 -7%
MYSQL With Sentry (error only) 2,701 81% 2,642 +2%

View base workflow run

…ration

- Add support for multiple framework/bundler-specific environment variables with proper precedence
  - SENTRY_SPOTLIGHT (highest priority - base name, supported natively by many bundlers)
  - PUBLIC_SENTRY_SPOTLIGHT (SvelteKit, Astro, Qwik)
  - NEXT_PUBLIC_SENTRY_SPOTLIGHT (Next.js)
  - VITE_SENTRY_SPOTLIGHT (Vite)
  - NUXT_PUBLIC_SENTRY_SPOTLIGHT (Nuxt.js)
  - REACT_APP_SENTRY_SPOTLIGHT (Create React App)
  - VUE_APP_SENTRY_SPOTLIGHT (Vue CLI)
  - GATSBY_SENTRY_SPOTLIGHT (Gatsby)
- Add defensive environment variable access via process.env (transformed by all major bundlers)
- Move envToBool utility from node-core to core for shared usage
- Add resolveSpotlightOptions utility for consistent precedence rules
- Update node-core and aws-serverless to use shared utilities
- Add comprehensive tests for all new utilities and SDK integration

Note: import.meta.env is intentionally not checked because bundlers only replace static
references (e.g., import.meta.env.VITE_VAR) at build time, not dynamic access. All major
bundlers transform process.env references, making it the universal solution.
@BYK BYK force-pushed the feat/spotlight-environment-variable-support branch from 92ffd33 to 6cb5513 Compare November 13, 2025 22:51
@BYK BYK force-pushed the feat/spotlight-environment-variable-support branch from 4f6dcd0 to fda3d61 Compare November 14, 2025 11:31
@BYK BYK marked this pull request as ready for review November 14, 2025 11:32
@BYK BYK requested review from Lms24, andreiborza and timfish November 14, 2025 11:32
Before submitting a pull request, please take a look at our

[Contributing](https://github.com/getsentry/sentry-javascript/blob/master/CONTRIBUTING.md)
guidelines and verify:

- [x] If you've added code that should be tested, please add tests.
- [x] Ensure your code lints and the test suite passes (`yarn lint`) &
(`yarn test`).

Fixes a test failure where `getSpotlightConfig` was returning empty or
whitespace-only strings for `SENTRY_SPOTLIGHT` environment variables,
instead of `undefined`. This change explicitly filters out such values,
aligning the function's behavior with test expectations and preventing
invalid Spotlight configurations.

---
<a
href="https://cursor.com/background-agent?bcId=bc-88bd0365-3796-47b2-bb84-29c93d0430e8"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/open-in-cursor-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/open-in-cursor-light.svg"><img alt="Open in
Cursor"
src="https://cursor.com/open-in-cursor.svg"></picture></a>&nbsp;<a
href="https://cursor.com/agents?id=bc-88bd0365-3796-47b2-bb84-29c93d0430e8"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/open-in-web-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/open-in-web-light.svg"><img alt="Open in Web"
src="https://cursor.com/open-in-web.svg"></picture></a>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
@BYK BYK requested a review from a team as a code owner November 14, 2025 16:59
Copy link
Member

@Lms24 Lms24 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First pass review. I still want to figure out why size bot reports a slight increase for the CDN bundles.

Comment on lines 3 to 9
* Checks process.env which is transformed by most bundlers (Webpack, Vite, Rollup, Rspack, Parcel, etc.)
* at build time.
*
* Note: We don't check import.meta.env because:
* 1. Bundlers only replace static references like `import.meta.env.VITE_VAR`, not dynamic access
* 2. Dynamic access causes syntax errors in unsupported environments
* 3. Most bundlers transform process.env references anyway
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m: My impression while doing some research for #18050 (comment) was what very few bundlers inject process.env into browser bundles. For example, this code will not work in Angular.
Vite instructs checking on import.meta.env, so not sure if it double-writes to process.env (my gut feeling is no).

Did you test this in the respective frameworks? Maybe I'm also misinformed and this works just fine 😅 Ideally we can add an e2e test for at least NextJS and some Vite-based framework app to be sure.

Comment on lines 62 to 64

// No Spotlight configuration found in environment
return undefined;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: neat size trick: You can let the function return void and simply omit the return undefined here. Saves a couple of bytes and JS returns undefined anyway. 😅 (but feel free to ignore since this is shaken out for prod builds anyway)

Before submitting a pull request, please take a look at our

[Contributing](https://github.com/getsentry/sentry-javascript/blob/master/CONTRIBUTING.md)
guidelines and verify:

- [x] If you've added code that should be tested, please add tests.
- [x] Ensure your code lints and the test suite passes (`yarn lint`) &
(`yarn test`).

---

This PR addresses critical feedback regarding environment variable
detection, particularly for Vite-based frameworks.

**Key Changes:**

* **`packages/browser/src/utils/env.ts`**: The `getEnvValue` function
now checks both `process.env` (for Webpack, Next.js, CRA) and
`import.meta.env` (for Vite, Astro, SvelteKit). This ensures that
environment variables (like those for Spotlight) are correctly detected
across a wider range of bundlers and frameworks, fixing a significant
compatibility issue.
* **`packages/browser/test/utils/env.test.ts`**: Updated unit tests to
focus on `process.env` scenarios. Added a note explaining that
`import.meta.env` cannot be unit tested due to its read-only,
compile-time nature and is covered by e2e tests.
* **`packages/browser/src/utils/spotlightConfig.ts`**: Added a comment
to clarify the explicit `return undefined` for readability, noting its
optimization in production builds.

---
<a
href="https://cursor.com/background-agent?bcId=bc-d6001dc9-59fc-42eb-8354-a573e3ae71a9"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/open-in-cursor-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/open-in-cursor-light.svg"><img alt="Open in
Cursor"
src="https://cursor.com/open-in-cursor.svg"></picture></a>&nbsp;<a
href="https://cursor.com/agents?id=bc-d6001dc9-59fc-42eb-8354-a573e3ae71a9"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/open-in-web-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/open-in-web-light.svg"><img alt="Open in Web"
src="https://cursor.com/open-in-web.svg"></picture></a>

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Copy link
Collaborator

@timfish timfish left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good but needs some e2e tests of some kind otherwise we could inadvertently break this in the future.

It should be quite easy to test Vite by adding some additional tests to dev-packages/bundler-tests with the specific variables set and then check they make it into the bundle.

Then as @Lms24 says, a Nextjs test would probably be a good idea too!

@BYK BYK requested a review from a team as a code owner November 20, 2025 14:08
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Breaking change: `envToBool` export removed from `@sentry/node-core` (Bugbot Rules)

The envToBool function was previously exported from @sentry/node-core but has been removed in this change (now exported from @sentry/core instead). This is a breaking change for any external consumers who were importing envToBool directly from @sentry/node-core. The function is still available from @sentry/core, but existing code using import { envToBool } from '@sentry/node-core' will break. Flagging this per the review rules about "Removal of publicly exported functions, classes, or types."

packages/node-core/src/index.ts#L44-L45

export { ensureIsWrapped } from './utils/ensureIsWrapped';
export { createMissingInstrumentationContext } from './utils/createMissingInstrumentationContext';

Fix in Cursor Fix in Web


Comment on lines 149 to 159
const spotlightEnvValue = process.env.NEXT_PUBLIC_SENTRY_SPOTLIGHT;
if (spotlightEnvValue !== undefined && options.spotlight === undefined) {
const boolValue = envToBool(spotlightEnvValue, { strict: true });
const spotlightConfig = boolValue !== null ? boolValue : spotlightEnvValue;
const spotlightValue = resolveSpotlightOptions(undefined, spotlightConfig);

if (spotlightValue) {
const spotlightArgs = typeof spotlightValue === 'string' ? { sidecarUrl: spotlightValue } : undefined;
customDefaultIntegrations.push(spotlightBrowserIntegration(spotlightArgs));
}
}

This comment was marked as outdated.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Module field removed from browser package.json

The "module" field was removed from packages/browser/package.json. This field was previously set to "build/npm/esm/prod/index.js" and is used by older bundlers (e.g., Webpack 4, older Rollup versions) that don't support the "exports" field for ESM module resolution. Without it, these bundlers will fall back to the "main" field (CJS), potentially causing issues in ESM-expecting environments. This change appears unrelated to the PR's goal of adding Spotlight environment variable support and may be accidental.

packages/browser/package.json#L14-L16

],
"main": "build/npm/cjs/prod/index.js",
"types": "build/npm/types/index.d.ts",

Fix in Cursor Fix in Web


Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Removed `module` field breaks older bundler compatibility

The module field ("module": "build/npm/esm/prod/index.js") was removed from @sentry/browser's package.json. While modern bundlers support the exports field, older bundlers (like Webpack 4 and older Rollup versions) rely on the module field to resolve ES module entry points. This is inconsistent with other SDK packages (@sentry/core, @sentry/react, @sentry/vue) which still have this field, and could cause older bundlers to incorrectly use the CJS build instead of ESM.

packages/browser/package.json#L14-L16

],
"main": "build/npm/cjs/prod/index.js",
"types": "build/npm/types/index.d.ts",

Fix in Cursor Fix in Web


Comment on lines +373 to 383
// Applying turbopack config when webpack is used is safe (webpack ignores it).
if (isTurbopack || isTurbopackSupported) {
turboPackConfig = constructTurbopackConfig({
userNextConfig: incomingUserNextConfigObject,
userSentryOptions,
routeManifest,
nextJsVersion,
spotlightConfig,
});
}

This comment was marked as outdated.

Comment on lines +174 to 184
if (spotlightValue) {
const spotlightArgs = typeof spotlightValue === 'string' ? { sidecarUrl: spotlightValue } : undefined;
customDefaultIntegrations.push(spotlightBrowserIntegration(spotlightArgs));
// eslint-disable-next-line no-console
console.log('[Sentry Next.js DEBUG] Spotlight integration ADDED');
}
}

return customDefaultIntegrations;
}

This comment was marked as outdated.

optionsSpotlight: options.spotlight,
GLOBAL_OBJ_keys: Object.keys(GLOBAL_OBJ),
};
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Debug data exposed on globalThis in production builds

Debug information is being exposed on globalThis._sentrySpotlightDebug in the getDefaultIntegrations function. This object contains internal debugging data like processEnvSpotlight, GLOBAL_OBJ_keys, and other internal values that leak implementation details. This code is not wrapped in development-only markers and will be included in production bundles, potentially exposing internal state to end users.

Fix in Cursor Fix in Web

"preview": "vite preview --port 3030",
"test": "playwright test",
"test:build": "pnpm install && pnpm build",
"test:build": "pnpm install",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: E2E test skips production build by removing pnpm build

The test:build script was changed from pnpm install && pnpm build to just pnpm install, and the playwright config now uses pnpm dev instead of pnpm preview. This means tests no longer run against the production build, potentially masking production-specific bugs like the new ESM/CJS stripping behavior. The tests removed debug_meta assertions which are only generated in production builds.

Additional Locations (1)

Fix in Cursor Fix in Web

expect(errorEvent.exception?.values?.[0]?.value).toBe('Uncaught Error: Uncaught error in worker');
expect(errorEvent.exception?.values?.[0]?.stacktrace?.frames).toHaveLength(1);
expect(errorEvent.exception?.values?.[0]?.stacktrace?.frames?.[0]?.filename).toMatch(/worker-.+\.js$/);
expect(errorEvent.exception?.values?.[0]?.stacktrace?.frames?.[0]?.filename).toMatch(WORKER_FILENAME_PATTERN);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Test no longer verifies debug IDs despite test name

The test is named "captures an error with debug ids and pageload trace context" but the debug_meta assertion that verified debug IDs has been removed. The test name claims to verify debug ID functionality, but now only checks trace context. Debug IDs could break without the test failing. This represents a test coverage regression where the actual test behavior no longer matches its documented purpose.

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(browser): Add environment variable support for Spotlight configuration

4 participants