Spotlight
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
Sentry Spotlight 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.
SDKs MUST support Spotlight configuration through one of two approaches:
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 MUST accept a single spotlight configuration attribute that can be:
falseorundefined/null: Spotlight is disabledtrue: Spotlight is enabled using the default URL (http://localhost:8969/stream)string: Spotlight is enabled using the provided URL
Example:
# Disabled
spotlight: False
# Enabled with default URL
spotlight: True
# Enabled with custom URL
spotlight: "http://localhost:3000/stream"
The SDK MUST accept two separate configuration attributes:
spotlight: Optional[boolean]: Enable or disable SpotlightspotlightUrl: Optional[string]: Specify the Spotlight backend URL
Important: If spotlightUrl is set to any truthy string value, it MUST imply spotlight: true unless spotlight is explicitly set to false.
Example:
# 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
SDKs MUST support the SENTRY_SPOTLIGHT environment variable. This is to enable spotlight run to be used as a development server, which is the preferred way to run Spotlight. In this mode Spotlight runs your development command for you, with a fresh, unique Spotlight server running on a random port. To enable Spotlight on the target application, it sets the SENTRY_SPOTLIGHT environment variable to the URL of the Spotlight server. It also does some accommodations based on the target application, such as altering the host value for Docker Compose while keeping the front-end ones the same. It will also support emulator-based development environments and will set the host value accordingly in the near future.
The value MUST be parsed according to the following rules:
The following values MUST be treated as spotlight: true (enabling Spotlight with the default URL):
"true""t""y""yes""on""1"
The following values MUST be treated as spotlight: false (disabling Spotlight):
"false""f""n""no""off""0"
Any other string value MUST be treated as a Spotlight backend URL, enabling Spotlight with that URL.
Example parsing logic (Python reference):
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
The interaction between configuration options and environment variables MUST follow these precedence rules:
Config option MUST take precedence over env var, except:
- If
spotlight: true(boolean, no URL specified) ANDSENTRY_SPOTLIGHTis set to a URL string → MUST use the env var URL This allows developers to enable Spotlight via config but override the URL via environment variable
- If
If
spotlightis set to a string URL → it MUST override the env var completely When this happens, the SDK MUST print a warning to the console indicating that the config URL is taking precedence over the env varIf using two-attribute approach:
- If
spotlightUrlconfig and env var are both set → MUST use config value (spotlightUrl) - If
spotlight: falseis explicitly set → MUST ignorespotlightUrlvalue, the env var, and any URL configuration - In either case the SDK MUST print a warning to the console explaining the reason for deactivation of Spotlight or that the env variable exists but not being used due to hard-coded configuration.
- If
Precedence Examples:
# 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)
When Spotlight is enabled, SDKs MUST implement the following data collection behavior:
General Requirements:
- SDKs SHOULD use a separate pipeline for Spotlight that does not affect upstream Sentry behavior
- All Spotlight-specific settings (sample rates, PII collection, etc.) MUST NOT affect upstream Sentry configuration
- Fallback: If a separate pipeline is not feasible, SDKs SHOULD enable Spotlight-specific settings manually if no DSN is configured in development mode
- MUST 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)
- MUST enable 100% sample rate for all telemetry types for the Spotlight pipeline
- MUST enable all PII data collection for Spotlight (equivalent to
sendDefaultPii: true) - Spotlight is intended for local development, so full data visibility is expected
- To achieve this, the RECOMMENDED approach is to collect all PII data and then scrub it locally before sending it to Sentry while keeping it for Spotlight.
- MUST enable profiling to Spotlight
- MUST enable log collection to Spotlight
Ideal Implementation:
# 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:
# Enable sampling if no DSN in development
if not dsn and is_development_mode():
sample_rate = 1.0
send_default_pii = True
The default Spotlight backend URL is:
http://localhost:8969/stream
This URL MUST be used when:
spotlight: trueis set (boolean, no URL specified) andSENTRY_SPOTLIGHTis not setSENTRY_SPOTLIGHTis set to a truthy value (not a URL string) andspotlightconfig is not set
- Spotlight MUST be disabled by default and MUST only be enabled when explicitly configured or when the environment variable is set.
SDKs MUST handle Spotlight server connectivity issues gracefully:
- If the Spotlight server is unreachable, SDKs:
- MUST log an error message at least once
- MUST NOT log an error message for every failed envelope
- SHOULD implement exponential backoff retry logic
- MUST continue normal Sentry operation without interruption
RECOMMENDED retry strategy:
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
- SHOULD log errors at the appropriate level (typically
ERRORorWARNING) - MUST avoid logging errors for every failed envelope to prevent log spam
- MAY consider logging once per connection failure, then periodically if failures persist
- Spotlight transmission MUST never block normal Sentry operation
- If Spotlight is unavailable, the SDK MUST continue sending data to Sentry normally
- Spotlight failures MUST NOT affect event capture, transaction recording, or any other SDK functionality
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:
import sentry_sdk
sentry_sdk.init(
dsn="https://...@sentry.io/...",
spotlight=True, # Enable with default URL
# or
spotlight="http://localhost:3000/stream", # Custom URL
)
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;
}
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;
}
}
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").