---
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)
