# How to Programmatically Destroy a Web‑Tracing Instance: Complete Cleanup Guide

> Learn how to programmatically destroy a Web Tracing instance. This guide shows you how to clean up timers, listeners, WebSocket connections, and flush telemetry.

- Repository: [m-cheng-web/web-tracing](https://github.com/m-cheng-web/web-tracing)
- Tags: how-to-guide
- Published: 2026-03-06

---

**Call the `destroy()` method on your `WebTracing` instance to clear timers, remove event listeners, close WebSocket connections, and flush pending telemetry.**

When working with the `m-cheng-web/web-tracing` library, properly terminating your tracing session is critical to prevent memory leaks and ensure all telemetry data reaches your backend. The library maintains active timers, DOM event listeners, and persistent network connections that continue running until explicitly stopped. Understanding how to programmatically destroy a web-tracing instance ensures your application can cleanly shut down tracing during SPA navigation, user logout, or test teardown without leaving orphaned resources.

## Why You Must Explicitly Destroy Web‑Tracing Instances

The **Web‑Tracing** library creates a singleton-style object that registers listeners, starts a background sampler, and opens a WebSocket (or HTTP) connection to the tracing backend. Without proper cleanup:

- Interval timers and `requestAnimationFrame` callbacks continue firing indefinitely
- Event listeners attached via `window.addEventListener` and `document.addEventListener` accumulate
- Open WebSocket or EventSource connections remain active, consuming network resources
- Internal buffers retain references, preventing garbage collection

Calling `destroy()` is the only officially supported method to release these resources and allow the JavaScript engine to reclaim memory.

## How the `destroy()` Method Works Internally

In [`src/web-tracing.ts`](https://github.com/m-cheng-web/web-tracing/blob/main/src/web-tracing.ts), the `destroy()` method implements a systematic teardown sequence. The implementation ensures that every component registered during initialization is properly reversed.

### Stopping the Background Sampler

The tracing instance starts a sampling loop via `this._sampler.start()` during construction. During destruction, `destroy()` calls `this._sampler.stop()` (implemented in [`src/sampler.ts`](https://github.com/m-cheng-web/web-tracing/blob/main/src/sampler.ts)) to cancel the interval or `requestAnimationFrame` loop immediately.

### Removing Registered Event Listeners

The instance maintains an internal registry `this._registeredListeners` containing all DOM events subscribed during initialization. The `destroy()` method iterates this collection and invokes `removeEventListener` for each entry, ensuring no tracing-related handlers remain attached to `window` or `document`.

### Closing Network Connections

If the instance established a WebSocket connection (`this._socket`), the method executes `socket.close()` to terminate the transport gracefully. This step also closes any active EventSource or fetch-based long-polling connections opened for trace submission.

### Flushing Pending Telemetry

Before clearing state, `destroy()` executes `await this._flushPending()` to transmit any buffered spans to the configured endpoint. This asynchronous flush ensures no trace data is lost during shutdown, returning a Promise that resolves once the network operation completes.

## Code Examples for Destroying Web‑Tracing

### Class-Based Instance

When instantiating `WebTracing` directly, store the reference and await the cleanup:

```typescript
import { WebTracing } from "web-tracing";

const tracing = new WebTracing({
  endpoint: "https://tracing.example.com/collect",
  sampleRate: 0.5,
});

tracing.startSpan("page-load");

// Later, when tracing is no longer needed:
await tracing.destroy();

```

After `destroy()` resolves, the `tracing` variable holds no active timers, listeners, or connections.

### Default Singleton

If using the default exported singleton from [`src/index.ts`](https://github.com/m-cheng-web/web-tracing/blob/main/src/index.ts), invoke destroy directly on the imported object:

```typescript
import tracing from "web-tracing";

// Application logic here...

await tracing.destroy();

```

## Key Source Files in web-tracing

Understanding the source structure helps debug cleanup issues:

- **[`src/web-tracing.ts`](https://github.com/m-cheng-web/web-tracing/blob/main/src/web-tracing.ts)** – Core `WebTracing` class containing the constructor, `start`, `destroy`, and internal helper methods such as `_flushPending()`
- **[`src/sampler.ts`](https://github.com/m-cheng-web/web-tracing/blob/main/src/sampler.ts)** – Implements `Sampler.start()` and `Sampler.stop()` methods that control the background collection loop
- **[`src/index.ts`](https://github.com/m-cheng-web/web-tracing/blob/main/src/index.ts)** – Public entry point exporting both the class and default singleton instance

These files collectively define the lifecycle management that makes programmatic destruction possible.

## Summary

- The **WebTracing** class exposes a `destroy()` method that performs complete cleanup of the tracing instance
- **Timers and samplers** are stopped via `this._sampler.stop()` to prevent further execution
- **Event listeners** are removed by iterating `this._registeredListeners` and calling `removeEventListener`
- **Network connections** are closed through `socket.close()` and similar transport-specific methods
- **Pending data** is flushed asynchronously via `_flushPending()` before returning
- After destruction, the instance can be garbage collected and the library safely reinitialized

## Frequently Asked Questions

### What happens if I don't call destroy() on my WebTracing instance?

If you fail to call `destroy()`, the instance continues running background timers, maintaining DOM event listeners, and keeping WebSocket connections open. This leads to memory leaks in single-page applications and can cause duplicate data submission if you attempt to create a new instance without cleaning up the old one.

### Can I restart tracing after calling destroy()?

Yes, but you must create a fresh instance. Once `destroy()` completes, the original instance becomes inert and cannot be restarted. Instantiate `new WebTracing(config)` again to begin collecting traces, which is particularly useful in test suites or when switching between user contexts.

### Is the destroy() method synchronous or asynchronous?

The `destroy()` method is **asynchronous** and returns a `Promise`. It awaits the completion of `this._flushPending()` to ensure all buffered telemetry reaches the backend before resolving. Always use `await tracing.destroy()` or handle the returned Promise to guarantee cleanup completes before proceeding.

### Does destroy() remove all trace data stored locally?

The `destroy()` method flushes pending spans to the server but does not explicitly wipe historical data from browser storage mechanisms like `localStorage` or `IndexedDB` if the library uses them. It primarily concerns runtime resources—timers, listeners, and connections—rather than persistent storage cleanup.