> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hopx.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Monitoring

> Real-time monitoring and streaming metrics via Server-Sent Events (SSE) in HopX sandboxes. Stream sandbox events, monitor system metrics in real-time, track resource usage, and receive live updates via SSE. Perfect for dashboards, alerting, and real-time monitoring. Includes Python and JavaScript SDK examples and SSE endpoints.

Stream real-time metrics from your sandbox using Server-Sent Events (SSE). This provides continuous monitoring of agent performance metrics without polling.

## Overview

SSE monitoring is ideal for:

* Real-time dashboards and visualizations
* Continuous agent performance monitoring
* Alerting on threshold breaches
* Long-term performance tracking

<Note>
  SSE monitoring is available through the Control Plane API endpoint `/v1/sandboxes/:id/metrics/stream`. This streams metrics from the VM agent to your application.
</Note>

## Basic Streaming

Connect to the metrics stream and receive real-time updates:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    import requests
    from hopx_ai import Sandbox

    sandbox = Sandbox.create(template="code-interpreter")
    info = sandbox.get_info()

    # Get API key and base URL
    api_key = sandbox._api_key  # Access internal API key
    base_url = "https://api.hopx.dev"

    # Stream metrics via SSE
    headers = {
        "Authorization": f"Bearer {api_key}",
        "Accept": "text/event-stream"
    }

    stream_url = f"{base_url}/v1/sandboxes/{sandbox.sandbox_id}/metrics/stream"

    with requests.get(stream_url, headers=headers, stream=True) as response:
        for line in response.iter_lines():
            if line and line.startswith(b"data: "):
                import json
                data = json.loads(line[6:])  # Skip "data: " prefix
                print(f"Uptime: {data.get('uptime_seconds', 0)}s")
                print(f"Total Executions: {data.get('total_executions', 0)}")
                print(f"Active Executions: {data.get('active_executions', 0)}")
                print(f"Error Count: {data.get('error_count', 0)}")

    sandbox.kill()
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    import { Sandbox } from '@hopx-ai/sdk';
    import EventSource from 'eventsource';

    const sandbox = await Sandbox.create({
      template: 'code-interpreter'
    });

    const info = await sandbox.getInfo();

    // Get API key and base URL
    const apiKey = sandbox.apiKey;  // Access API key
    const baseUrl = 'https://api.hopx.dev';

    // Stream metrics via SSE
    const streamUrl = `${baseUrl}/v1/sandboxes/${sandbox.sandboxId}/metrics/stream?token=${apiKey}`;

    const eventSource = new EventSource(streamUrl);

    eventSource.onmessage = (event) => {
      const data = JSON.parse(event.data);
      console.log(`Uptime: ${data.uptime_seconds || 0}s`);
      console.log(`Total Executions: ${data.total_executions || 0}`);
      console.log(`Active Executions: ${data.active_executions || 0}`);
      console.log(`Error Count: ${data.error_count || 0}`);
    };

    eventSource.onerror = (error) => {
      console.error('SSE error:', error);
      eventSource.close();
    };

    // Close after 30 seconds
    setTimeout(() => {
      eventSource.close();
      sandbox.kill();
    }, 30000);
    ```
  </Tab>
</Tabs>

## Processing Stream Events

Handle different event types from the SSE stream:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    import requests
    import json
    from hopx_ai import Sandbox

    sandbox = Sandbox.create(template="code-interpreter")
    info = sandbox.get_info()

    api_key = sandbox._api_key
    base_url = "https://api.hopx.dev"

    headers = {
        "Authorization": f"Bearer {api_key}",
        "Accept": "text/event-stream"
    }

    stream_url = f"{base_url}/v1/sandboxes/{sandbox.sandbox_id}/metrics/stream"

    with requests.get(stream_url, headers=headers, stream=True) as response:
        for line in response.iter_lines():
            if not line:
                continue
            
            line_str = line.decode('utf-8')
            
            # Handle different SSE event types
            if line_str.startswith("event: "):
                event_type = line_str[7:]
                print(f"Event type: {event_type}")
            
            elif line_str.startswith("data: "):
                data = json.loads(line_str[6:])
                
                # Process metrics data
                print(f"Metrics - Uptime: {data.get('uptime_seconds', 0)}s")
                print(f"  Total Executions: {data.get('total_executions', 0)}")
                print(f"  Active Executions: {data.get('active_executions', 0)}")
                print(f"  Error Count: {data.get('error_count', 0)}")
            
            elif line_str.startswith("id: "):
                event_id = line_str[4:]
                # Use event ID for reconnection logic if needed

    sandbox.kill()
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    import { Sandbox } from '@hopx-ai/sdk';
    import EventSource from 'eventsource';

    const sandbox = await Sandbox.create({
      template: 'code-interpreter'
    });

    const info = await sandbox.getInfo();
    const apiKey = sandbox.apiKey;
    const baseUrl = 'https://api.hopx.dev';

    const streamUrl = `${baseUrl}/v1/sandboxes/${sandbox.sandboxId}/metrics/stream?token=${apiKey}`;

    const eventSource = new EventSource(streamUrl);

    // Handle different event types
    eventSource.addEventListener('message', (event) => {
      const data = JSON.parse(event.data);
      
      console.log(`Metrics - Uptime: ${data.uptime_seconds || 0}s`);
      console.log(`  Total Executions: ${data.total_executions || 0}`);
      console.log(`  Active Executions: ${data.active_executions || 0}`);
      console.log(`  Error Count: ${data.error_count || 0}`);
    });

    eventSource.addEventListener('error', (event) => {
      console.error('SSE error:', event);
      eventSource.close();
    });

    // Close after 30 seconds
    setTimeout(() => {
      eventSource.close();
      sandbox.kill();
    }, 30000);
    ```
  </Tab>
</Tabs>

## Building a Metrics Dashboard

Create a simple dashboard that displays real-time metrics:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    import requests
    import json
    import time
    from datetime import datetime
    from hopx_ai import Sandbox

    sandbox = Sandbox.create(template="code-interpreter")

    api_key = sandbox._api_key
    base_url = "https://api.hopx.dev"

    headers = {
        "Authorization": f"Bearer {api_key}",
        "Accept": "text/event-stream"
    }

    stream_url = f"{base_url}/v1/sandboxes/{sandbox.sandbox_id}/metrics/stream"

    print("=== Real-Time Metrics Dashboard ===")
    print("Press Ctrl+C to stop\n")

    try:
        with requests.get(stream_url, headers=headers, stream=True) as response:
            for line in response.iter_lines():
                if line and line.startswith(b"data: "):
                    data = json.loads(line[6:])
                    
                    timestamp = datetime.now().strftime("%H:%M:%S")
                    uptime = data.get('uptime_seconds', 0)
                    total_exec = data.get('total_executions', 0)
                    active_exec = data.get('active_executions', 0)
                    errors = data.get('error_count', 0)
                    
                    # Simple text-based dashboard
                    print(f"[{timestamp}] Uptime: {uptime:6d}s | Executions: {total_exec:4d} | Active: {active_exec:2d} | Errors: {errors:3d}")
                    
                    time.sleep(0.1)  # Throttle output

    except KeyboardInterrupt:
        print("\nStopping monitoring...")

    finally:
        sandbox.kill()
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    import { Sandbox } from '@hopx-ai/sdk';
    import EventSource from 'eventsource';

    const sandbox = await Sandbox.create({
      template: 'code-interpreter'
    });

    const apiKey = sandbox.apiKey;
    const baseUrl = 'https://api.hopx.dev';

    const streamUrl = `${baseUrl}/v1/sandboxes/${sandbox.sandboxId}/metrics/stream?token=${apiKey}`;

    console.log('=== Real-Time Metrics Dashboard ===');
    console.log('Press Ctrl+C to stop\n');

    const eventSource = new EventSource(streamUrl);

    eventSource.addEventListener('message', (event) => {
      const data = JSON.parse(event.data);
      
      const timestamp = new Date().toLocaleTimeString();
      const uptime = data.uptime_seconds || 0;
      const totalExec = data.total_executions || 0;
      const activeExec = data.active_executions || 0;
      const errors = data.error_count || 0;
      
      // Simple text-based dashboard
      console.log(`[${timestamp}] Uptime: ${uptime.toString().padStart(6)}s | Executions: ${totalExec.toString().padStart(4)} | Active: ${activeExec.toString().padStart(2)} | Errors: ${errors.toString().padStart(3)}`);
    });

    eventSource.addEventListener('error', (error) => {
      console.error('Stream error:', error);
      eventSource.close();
      sandbox.kill();
    });

    // Handle graceful shutdown
    process.on('SIGINT', () => {
      console.log('\nStopping monitoring...');
      eventSource.close();
      sandbox.kill();
      process.exit(0);
    });
    ```
  </Tab>
</Tabs>

## Alerting on Thresholds

Set up alerts when metrics exceed thresholds:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    import requests
    import json
    from hopx_ai import Sandbox

    sandbox = Sandbox.create(template="code-interpreter")

    api_key = sandbox._api_key
    base_url = "https://api.hopx.dev"

    headers = {
        "Authorization": f"Bearer {api_key}",
        "Accept": "text/event-stream"
    }

    stream_url = f"{base_url}/v1/sandboxes/{sandbox.sandbox_id}/metrics/stream"

    # Thresholds
    ERROR_COUNT_THRESHOLD = 10
    ACTIVE_EXECUTIONS_THRESHOLD = 5

    print("Monitoring for threshold breaches...")

    with requests.get(stream_url, headers=headers, stream=True) as response:
        for line in response.iter_lines():
            if line and line.startswith(b"data: "):
                data = json.loads(line[6:])
                
                error_count = data.get('error_count', 0)
                active_executions = data.get('active_executions', 0)
                
                # Check thresholds
                if error_count > ERROR_COUNT_THRESHOLD:
                    print(f"⚠️  ALERT: Error count {error_count} exceeds threshold {ERROR_COUNT_THRESHOLD}")
                
                if active_executions > ACTIVE_EXECUTIONS_THRESHOLD:
                    print(f"⚠️  ALERT: Active executions {active_executions} exceeds threshold {ACTIVE_EXECUTIONS_THRESHOLD}")

    sandbox.kill()
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    import { Sandbox } from '@hopx-ai/sdk';
    import EventSource from 'eventsource';

    const sandbox = await Sandbox.create({
      template: 'code-interpreter'
    });

    const apiKey = sandbox.apiKey;
    const baseUrl = 'https://api.hopx.dev';

    const streamUrl = `${baseUrl}/v1/sandboxes/${sandbox.sandboxId}/metrics/stream?token=${apiKey}`;

    // Thresholds
    const ERROR_COUNT_THRESHOLD = 10;
    const ACTIVE_EXECUTIONS_THRESHOLD = 5;

    console.log('Monitoring for threshold breaches...');

    const eventSource = new EventSource(streamUrl);

    eventSource.addEventListener('message', (event) => {
      const data = JSON.parse(event.data);
      
      const errorCount = data.error_count || 0;
      const activeExecutions = data.active_executions || 0;
      
      // Check thresholds
      if (errorCount > ERROR_COUNT_THRESHOLD) {
        console.log(`⚠️  ALERT: Error count ${errorCount} exceeds threshold ${ERROR_COUNT_THRESHOLD}`);
      }
      
      if (activeExecutions > ACTIVE_EXECUTIONS_THRESHOLD) {
        console.log(`⚠️  ALERT: Active executions ${activeExecutions} exceeds threshold ${ACTIVE_EXECUTIONS_THRESHOLD}`);
      }
    });

    eventSource.addEventListener('error', (error) => {
      console.error('Stream error:', error);
      eventSource.close();
      sandbox.kill();
    });
    ```
  </Tab>
</Tabs>

## Best Practices

<Tip>
  **Use SSE for real-time monitoring** when you need continuous updates. For one-time snapshots, use `get_metrics_snapshot()` instead.
</Tip>

<Tip>
  **Handle reconnection logic** in production applications. SSE connections can drop, and you should reconnect automatically.
</Tip>

<Warning>
  **SSE streams consume resources**. Close connections when no longer needed to free up server resources.
</Warning>

<Tip>
  **Throttle processing** if you're receiving metrics faster than you can process them. The stream sends updates frequently.
</Tip>

## API Reference

### Control Plane API

* **GET** `/v1/sandboxes/:id/metrics/stream` - Stream metrics via SSE
  * **Headers**: `Authorization: Bearer {token}`, `Accept: text/event-stream`
  * **Response**: Server-Sent Events stream with JSON metrics data

### SSE Event Format

```
event: message
data: {"system": {"cpu": {"usage_percent": 25.5}, ...}}

id: 12345
```

## Related

* [System Metrics](/core-concepts/observability/metrics) - Get snapshot metrics
* [Process Monitoring](/core-concepts/observability/processes) - Monitor processes
* **API**: [GET /v1/sandboxes/:id/metrics/stream](/api/control-plane/stream-metrics) - Control Plane API endpoint

## Next Steps

* Learn about [System Metrics](/core-concepts/observability/metrics) for snapshot metrics

* Explore [Process Monitoring](/core-concepts/observability/processes) to monitor processes

* Review [Code Execution](/core-concepts/code-execution/synchronous) to generate metrics

* [Metrics](/core-concepts/observability/metrics) - Get metrics snapshots

* [Processes](/core-concepts/observability/processes) - Monitor processes

* **[CLI Reference](/cli/introduction)** - Use HopX from the command line
