--- title: Spotlight sidebar_order: 5 --- [Sentry Spotlight](https://spotlightjs.com/) is a local development tool that provides real-time observability for errors, traces, logs, and performance data during development. SDKs should implement support for Spotlight to unlock the power of Sentry for local development. ## Configuration Options SDKs should support Spotlight configuration through one of two approaches: ### Single Attribute Approach (Recommended) This approach MUST be used if the SDK language allows for a single configuration attribute to have 2 different types (`boolean` and `string`). The SDK accepts a single `spotlight` configuration attribute that can be: - `false` or `undefined`/`null`: Spotlight is disabled - `true`: Spotlight is enabled using the default URL (`http://localhost:8969/stream`) - `string`: Spotlight is enabled using the provided URL **Example:** ```python # Disabled spotlight: False # Enabled with default URL spotlight: True # Enabled with custom URL spotlight: "http://localhost:3000/stream" ``` ### Two-Attribute Approach (Alternative) The SDK accepts two separate configuration attributes: - `spotlight: Optional[boolean]`: Enable or disable Spotlight - `spotlightUrl: Optional[string]`: Specify the Spotlight backend URL **Important:** If `spotlightUrl` is set to any truthy string value, it implies `spotlight: true` unless `spotlight` is explicitly set to `false`. **Example:** ```python # Disabled spotlight: False # Enabled with default URL spotlight: True # Enabled with custom URL (spotlightUrl implies spotlight: true) spotlightUrl: "http://localhost:3000/stream" # Explicitly disabled even with spotlightUrl set spotlight: False spotlightUrl: "http://localhost:3000/stream" # Ignored ``` ## Environment Variable Handling SDKs must support the `SENTRY_SPOTLIGHT` environment variable. The value should be parsed according to the following rules: ### Truthy Values The following values should be treated as `spotlight: true` (enabling Spotlight with the default URL): - `"true"` - `"t"` - `"y"` - `"yes"` - `"on"` - `"1"` ### Falsy Values The following values should be treated as `spotlight: false` (disabling Spotlight): - `"false"` - `"f"` - `"n"` - `"no"` - `"off"` - `"0"` ### URL String Values Any other string value should be treated as a Spotlight backend URL, enabling Spotlight with that URL. **Example parsing logic (Python reference):** ```python def parse_spotlight_env(env_value): if not env_value: return None env_value_lower = env_value.lower().strip() # Truthy values if env_value_lower in ("true", "t", "y", "yes", "on", "1"): return True # Falsy values if env_value_lower in ("false", "f", "n", "no", "off", "0"): return False # Any other value is treated as a URL return env_value ``` ## Precedence Rules The interaction between configuration options and environment variables follows these precedence rules: 1. **Config option takes precedence over env var**, except: - If `spotlight: true` (boolean, no URL specified) AND `SENTRY_SPOTLIGHT` is set to a URL string → use the env var URL - This allows developers to enable Spotlight via config but override the URL via environment variable 2. **If `spotlight` is set to a string URL** → it overrides the env var completely 3. **If using two-attribute approach:** - If `spotlightUrl` config and env var are both set → prefer config value (`spotlightUrl`) - If `spotlight: false` is explicitly set → ignore `spotlightUrl` value and the env var 4. **If `spotlight: false` explicitly set** → ignore env var and any URL configuration **Precedence Examples:** ```python # Example 1: Config boolean true + env var URL → use env var URL # Config: spotlight: True # Env: SENTRY_SPOTLIGHT=http://custom:3000/stream # Result: Enabled with http://custom:3000/stream # Example 2: Config URL string → always use config URL # Config: spotlight: "http://config:3000/stream" # Env: SENTRY_SPOTLIGHT=http://env:3000/stream # Result: Enabled with http://config:3000/stream # Example 3: Config false → disable regardless of env var # Config: spotlight: False # Env: SENTRY_SPOTLIGHT=http://localhost:8969/stream # Result: Disabled # Example 4: Two-attribute approach with spotlightUrl # Config: spotlightUrl: "http://config:3000/stream" # Env: SENTRY_SPOTLIGHT=http://env:3000/stream # Result: Enabled with http://config:3000/stream (config takes precedence) ``` ## Data Collection Behavior When Spotlight is enabled, SDKs must implement the following data collection behavior: ### Envelope Transmission - Send a copy of **every envelope** to the Spotlight server - This includes errors, transactions, sessions, profiles, replays, and all other envelope types - The Spotlight server HTTP semantics are the same as the Sentry server HTTP semantics (e.g. use POST to send envelopes) ### Sampling - Enable **100% sample rate** for the Spotlight pipeline - This should **not affect** the upstream Sentry sample rates - The ideal implementation uses a **separate pipeline** that ignores sampling settings - Fallback: If separate pipeline is not feasible, enable sampling manually if no DSN is configured in development mode ### PII Data Collection - Enable **all PII data collection** for Spotlight (equivalent to `sendDefaultPii: true`) - This should **not affect** upstream Sentry PII settings - Spotlight is intended for local development, so full data visibility is expected ### Profiling and Logs - Enable profiling data transmission to Spotlight - Enable log data transmission to Spotlight - These should be sent regardless of upstream Sentry configuration ### Pipeline Architecture **Ideal Implementation:** ```python # Separate pipeline that bypasses sampling def send_to_spotlight(envelope): # Clone envelope to avoid affecting upstream spotlight_envelope = clone_envelope(envelope) # Override sampling - ensure 100% sample rate spotlight_envelope.sample_rate = 1.0 # Enable all PII spotlight_envelope.send_default_pii = True # Send to Spotlight server spotlight_transport.send(spotlight_envelope) ``` **Fallback Implementation:** If separate pipeline is not feasible: ```python # Enable sampling if no DSN in development if not dsn and is_development_mode(): sample_rate = 1.0 send_default_pii = True ``` ## Default Values ### Default Spotlight URL The default Spotlight backend URL is: ``` http://localhost:8969/stream ``` This URL should be used when: - `spotlight: true` is set (boolean, no URL specified) - `SENTRY_SPOTLIGHT` is set to a truthy value (not a URL string) ### Default Behavior - Spotlight is **disabled by default** - SDKs should only enable Spotlight when explicitly configured or when the environment variable is set ## Error Handling SDKs must handle Spotlight server connectivity issues gracefully: ### Unreachable Server - If the Spotlight server is unreachable, SDKs should: - Log an error message (ideally once, not per-envelope) - Implement exponential backoff retry logic - Continue normal Sentry operation without interruption ### Retry Logic **Recommended retry strategy:** ```python import time import logging logger = logging.getLogger(__name__) class SpotlightTransport: def __init__(self, url): self.url = url self.retry_delay = 1.0 # Start with 1 second self.max_retry_delay = 60.0 # Max 60 seconds self.error_logged = False def send(self, envelope): try: # Attempt to send self._send_envelope(envelope) # Reset retry delay on success self.retry_delay = 1.0 self.error_logged = False except ConnectionError as e: # Exponential backoff if not self.error_logged: logger.error(f"Spotlight server unreachable at {self.url}: {e}") self.error_logged = True # Wait before retry time.sleep(self.retry_delay) self.retry_delay = min(self.retry_delay * 2, self.max_retry_delay) # Retry once, then give up for this envelope try: self._send_envelope(envelope) self.retry_delay = 1.0 except ConnectionError: # Silently drop envelope after retry pass ``` ### Logging - Log errors at the appropriate level (typically `ERROR` or `WARNING`) - Avoid logging errors for every failed envelope to prevent log spam - Consider logging once per connection failure, then periodically if failures persist ### Non-Blocking Behavior - Spotlight transmission must **never block** normal Sentry operation - If Spotlight is unavailable, the SDK should continue sending data to Sentry normally - Spotlight failures should not affect event capture, transaction recording, or any other SDK functionality ## Implementation Examples ### Python SDK Reference The Python SDK implementation serves as a reference. Key implementation details: - Single attribute approach: `spotlight: Optional[Union[str, bool]]` - Environment variable: `SENTRY_SPOTLIGHT` - Default URL: `http://localhost:8969/stream` - Separate transport pipeline for Spotlight **Configuration Example:** ```python import sentry_sdk sentry_sdk.init( dsn="https://...@sentry.io/...", spotlight=True, # Enable with default URL # or spotlight="http://localhost:3000/stream", # Custom URL ) ``` ### JavaScript/TypeScript SDK Pattern ```typescript interface SpotlightOptions { spotlight?: boolean | string; } function init(options: SpotlightOptions) { const spotlightEnabled = resolveSpotlightConfig(options); if (spotlightEnabled) { const spotlightUrl = typeof spotlightEnabled === 'string' ? spotlightEnabled : 'http://localhost:8969/stream'; setupSpotlightTransport(spotlightUrl); } } function resolveSpotlightConfig(options: SpotlightOptions): boolean | string | null { // Config takes precedence if (options.spotlight === false) { return null; } if (options.spotlight === true) { // Check env var for URL override const envValue = process.env.SENTRY_SPOTLIGHT; if (envValue && !isTruthyFalsy(envValue)) { return envValue; // Use env var URL } return true; // Use default URL } if (typeof options.spotlight === 'string') { return options.spotlight; // Config URL takes precedence } // Check env var const envValue = process.env.SENTRY_SPOTLIGHT; if (envValue) { return parseSpotlightEnv(envValue); } return null; } ``` ### Java SDK Pattern ```java public class SpotlightConfig { private Boolean enabled; private String url; public static SpotlightConfig fromOptions(Options options, String envVar) { SpotlightConfig config = new SpotlightConfig(); // Config takes precedence if (options.getSpotlight() != null) { if (options.getSpotlight() instanceof Boolean) { config.enabled = (Boolean) options.getSpotlight(); if (config.enabled && envVar != null && !isTruthyFalsy(envVar)) { config.url = envVar; // Env var URL override } } else if (options.getSpotlight() instanceof String) { config.enabled = true; config.url = (String) options.getSpotlight(); } } else if (envVar != null) { Object parsed = parseSpotlightEnv(envVar); if (parsed instanceof Boolean) { config.enabled = (Boolean) parsed; } else if (parsed instanceof String) { config.enabled = true; config.url = (String) parsed; } } if (config.enabled == null || !config.enabled) { return null; // Spotlight disabled } config.url = config.url != null ? config.url : "http://localhost:8969/stream"; return config; } } ``` ## References - [Sentry Spotlight Documentation](https://spotlightjs.com/) - [Sentry Spotlight GitHub Repository](https://github.com/getsentry/spotlight) - [Python SDK Implementation Reference](https://github.com/getsentry/sentry-python/blob/master/sentry_sdk/utils.py)