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

# Export to Surface Area

> Configure where spans go over OTLP, how they are batched, and how to flush them reliably.

Spans leave your process over OTLP (the OpenTelemetry Protocol) and land in your Surface Area project. This page covers where they go, how the SDK batches them, and how to avoid losing them on exit.

## Where spans go

`tracing.init()` configures an OTLP/HTTP exporter pointed at Surface Area. The exporter authenticates with HTTP Basic auth built from your public and secret keys, so the same three variables that connect the SDK also authorize the export.

| Variable | Purpose |
| - | - |
| `GATEWAY_HOST` | Surface Area server URL, for example `https://withgateway.ai` |
| `GATEWAY_PUBLIC_KEY` | Project public key (`pk-lf-...`) |
| `GATEWAY_SECRET_KEY` | Project secret key (`sk-lf-...`) |
| `GATEWAY_OTLP_ENDPOINT` | Optional full OTLP endpoint URL, overriding the derived one |

When `GATEWAY_OTLP_ENDPOINT` is not set, the endpoint is derived from the host by appending `/api/public/otel/v1/traces`. A host of `https://withgateway.ai` exports to `https://withgateway.ai/api/public/otel/v1/traces`.

<Info>
  All three of `GATEWAY_HOST`, `GATEWAY_PUBLIC_KEY`, and `GATEWAY_SECRET_KEY` must be present for the exporter to configure. If any is missing, `init()` logs that no exporter was configured and spans are not persisted. Run with `debug="INFO"` to see the export status.
</Info>

## Override the endpoint

Point at a different ingestion URL with the `gateway_endpoint` parameter (or `GATEWAY_OTLP_ENDPOINT`). The override replaces the derived path entirely.

```python theme={null}
import os
import gatewaysdk.tracing as tracing

tracing.init(
    gateway_host=os.environ["GATEWAY_HOST"],
    gateway_public_key=os.environ["GATEWAY_PUBLIC_KEY"],
    gateway_secret_key=os.environ["GATEWAY_SECRET_KEY"],
    gateway_endpoint="https://ingest.internal.example.com/api/public/otel/v1/traces",
)
```

## Spans are batched in the background

The exporter buffers spans and sends them in batches, so individual spans do not each make a network call. Tune the batching at init when the defaults do not fit your workload.

| Parameter | Default | Effect |
| - | - | - |
| `batch_queue_size` | `2048` | Max spans buffered in memory. Increase for bulk imports |
| `batch_flush_interval` | `5000` (ms) | How often the buffer flushes. Decrease for lower-latency export |
| `batch_max_export_size` | `512` | Max spans per export call |

```python theme={null}
import gatewaysdk.tracing as tracing

# A high-throughput batch job: bigger buffer, larger export batches.
tracing.init(
    service_name="bulk-import",
    batch_queue_size=16384,
    batch_max_export_size=2048,
)
```

<Info>
  Buffered spans reach the dashboard within the flush interval, or immediately after a `flush()` or `shutdown()` call.
</Info>

## Flush before exit

Call `tracing.shutdown()` before the process exits so the buffer drains. Register it with `atexit`:

```python theme={null}
import atexit
import gatewaysdk.tracing as tracing

tracing.init()
atexit.register(tracing.shutdown)
```

Call `tracing.flush()` to drain the buffer at a checkpoint without ending the tracing session. It returns `True` when the flush completes and `False` if it times out.

```python theme={null}
import gatewaysdk.tracing as tracing

for batch in batches:
    process(batch)
    tracing.flush()  # Make sure each batch's spans are exported
```

<Info>
  A short-lived script that exits without `shutdown()` can drop its last spans, because they are still buffered when the process ends. Always flush or shut down before exit.
</Info>

## Send custom exporters alongside Surface Area

Pass your own OpenTelemetry `SpanExporter` instances to `init(exporters=[...])` to send spans to another backend. Custom exporters replace the auto-configured Surface Area exporter, so include a Surface Area exporter explicitly when you still want spans in Surface Area.

```python theme={null}
import gatewaysdk.tracing as tracing

# Gateway reads credentials from the environment when called with no args.
gateway = tracing.gateway_exporter()

tracing.init(exporters=[gateway, my_other_exporter])
```

## Where to go next

* [Instrument an agent](./setup): produce the spans that get exported.
* [Auto-instrumentation](./auto-instrumentation): the library calls Surface Area exports for you.
* [Metadata & identity](./metadata): the attributes that ride along on every exported span.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.