# Custom instrumentation

Copy as Markdown[Open in ChatGPT](https://chatgpt.com/?q=Read%20https%3A%2F%2Fcoralogix.com%2Fdocs%2Fuser-guides%2Frum%2Fsdk-installation%2Fjavascript%2Fbrowser-sdk%2Ffeatures%2Fcustom-instrumentation.md%20and%20help%20me%20with%20my%20question%20about%20this%20Coralogix%20documentation%20page.)[Open in Claude](https://claude.ai/new?q=Read%20https%3A%2F%2Fcoralogix.com%2Fdocs%2Fuser-guides%2Frum%2Fsdk-installation%2Fjavascript%2Fbrowser-sdk%2Ffeatures%2Fcustom-instrumentation.md%20and%20help%20me%20with%20my%20question%20about%20this%20Coralogix%20documentation%20page.)

### Custom Measurement[​](#custom-measurement "Direct link to Custom Measurement")

Custom measurement allows you to send numeric data to Coralogix for precise monitoring and analysis.

```
CoralogixRum.sendCustomMeasurement('my-page-load', 1000);
```

### Add Timing[​](#add-timing "Direct link to Add Timing")

Add timing is a simple API to add extra performance timing to your RUM data.<br />The timing relates to the time between the page load and the moment the timing is added.<br />For example, you can add a timing for the first click event.

```
window.addEventListener('click', function handler() {

  window.removeEventListener('click', handler);



  CoralogixRum.addTiming('first-click');

});
```

OR

You can provide your own timing.

```
window.addEventListener('click', function handler() {

  window.removeEventListener('click', handler);



  CoralogixRum.addTiming('first-click', 1000);

});
```

### Custom Time Measurement[​](#custom-time-measurement "Direct link to Custom Time Measurement")

Custom time measurement allows you to track the time between two points by starting a timer with `startTimeMeasure` and stopping it with `endTimeMeasure`, using a unique name to identify each measurement. Labels can be added at the start for additional context.

```
CoralogixRum.startTimeMeasure('login', {

  paymentMethod: 'visa',

  userTheme: 'dark',

});
```

```
CoralogixRum.endTimeMeasure('login');
```

A few behaviours worth knowing:

* Starting a key while a measurement for it is still in progress does nothing, and neither does a blank key: `startTimeMeasure` returns and the running timer is left alone.
* `endTimeMeasure` takes only the key, so there is no way to pass labels at the end. The object handed to `startTimeMeasure` is held by reference, and at the end it is merged over the SDK's global labels as they stand then - so a later `CoralogixRum.setLabels()` does affect the result.
* Ending a measurement releases its key, so the same key can be measured again afterwards.
* Open measurements are dropped the next time you start or end one while the session is idle. The check runs on those calls rather than on a timer, and activity clears the idle flag, so a measurement spanning a short idle gap may still report.

### Microfrontend support[​](#microfrontend-support "Direct link to Microfrontend support")

This feature allows you to track multiple applications on the same page.<br />**Only errors with stacktrace are supported.**

#### Pre Requisites[​](#pre-requisites "Direct link to Pre Requisites")

To support microfrontend, you need to install one of these plugins: [webpack](https://www.npmjs.com/package/@coralogix/webpack-plugin), [esbuild](https://www.npmjs.com/package/@coralogix/esbuild-plugin), [vite](https://www.npmjs.com/package/@coralogix/vite-plugin) and include them in your build process.

When an error occurs, the SDK will find the correlated microfrontend and will add a label with the microfrontend app/version to the error event.

```
CoralogixRum.init({

  // ...

  supportMfe: true,

});
```

### Custom Spans[​](#custom-spans "Direct link to Custom Spans")

Create your own custom spans to track specific operations in your application.<br />Each span will share the same trace ID, which will allow you to create flows in your application and see them in the [Tracing view](https://coralogix.com/docs/user-guides/data_exploration/spans/explore-spans.md).<br />Labels can be added during span creation for additional context.

```
const customTracer = CoralogixRum.getCustomTracer();

const globalSpan = customTracer.startGlobalSpan('global-span', { page: 'posts' });



// Easily create custom spans for specific operations in your application.

globalSpan.startCustomSpan('submit-button', { action: 'click' }).endSpan();



// You can also use the with context method to modeling a specific flow in your application.

globalSpan.withContext(async () => {

  globalSpan.startCustomSpan('get-data-btn', { action: 'click' }).endSpan();

  const res = await fetch('my-api-endpoint');

  globalSpan.startCustomSpan('click-on-first-row', { action: 'click' }).endSpan();



  // ... your code

});



// note: End the global span only after the operation is complete.

globalSpan.endSpan();
```

#### Ignored Instruments[​](#ignored-instruments "Direct link to Ignored Instruments")

After creating a global span, some of the instrumented events (network, errors, interactions) will automatically share the same trace ID, unless specifically ignored.

```
const customTracer = CoralogixRum.getCustomTracer({

  ignoredInstruments: [CoralogixEventType.NETWORK_REQUEST, CoralogixEventType.ERROR, CoralogixEventType.USER_INTERACTION],

});



// ... your code
```

#### When getCustomTracer returns nothing[​](#when-getcustomtracer-returns-nothing "Direct link to When getCustomTracer returns nothing")

`getCustomTracer` returns `undefined` rather than throwing, so a missing prerequisite shows up as a `TypeError` on the next line instead. It returns nothing when:

* the SDK has not been initialized yet
* `traceParentInHeader` is not enabled - custom spans need it, and only a debug-level message says so
* a custom tracer already exists, which logs `Custom tracer already exists`

`startGlobalSpan` behaves the same way: with a global span already open it warns `Global span already exists` and returns `undefined`, rather than replacing it.

A few more things worth knowing:

* Every span must be ended explicitly. `endSpan` ends the span and releases it, so a new global span can be started afterwards.
* Labels are applied to the span they are passed with. A child span created by `startCustomSpan` does not inherit the global span's labels.
* Open global spans are ended for you when the session resets, which happens after an hour of session time or 15 minutes of inactivity.

### Traces Exporter[​](#traces-exporter "Direct link to Traces Exporter")

The `tracesExporter` callback gives you full control over how collected trace events are handled.<br />It receives a `TraceExporterData` object containing all trace data that the SDK has collected.

Setting it redirects your traces rather than copying them. The span data is removed from what the SDK sends to Coralogix and delivered to your callback instead, so Coralogix stops receiving traces until you forward them yourself from inside the callback.

This happens per batch, and only for batches that carry OpenTelemetry span data. When one does, the strip applies to every log in it, not only to custom spans: views, errors and network events still reach Coralogix as RUM events, but without their `instrumentation_data`, the field holding request and response span detail. A batch with no span data at all is sent unchanged and your callback is not called for it.

Treat the payload as a subset rather than a mirror. A span missing its trace id, span id, name or timestamps is dropped from the conversion, as is one whose timestamps fall outside the accepted window - more than an hour ahead or a day behind. Those spans can still reach Coralogix inside the RUM payload without a matching entry in what your callback receives, so `resource_spans` can be shorter than you expect, or empty.

Warning

The callback runs inline on the path that sends the RUM payload, and it is not wrapped. An exception escaping your callback also stops that batch reaching Coralogix, so keep your own work inside a `try`/`catch`.

```
CoralogixRum.init({

  tracesExporter: (data: TraceExporterData) => {

    fetch('https://api.mycompany.com/rum-traces', {

      method: 'POST',

      headers: {

        'Content-Type': 'application/json',

      },

      body: JSON.stringify(data),

    });

  },

});
```

### OpenTelemetry Batch Configuration[​](#opentelemetry-batch-configuration "Direct link to OpenTelemetry Batch Configuration")

The SDK batches logs and traces through an OpenTelemetry `BatchSpanProcessor` before sending them to Coralogix. Use `otelConfig` to tune that batching — for example, to flush less frequently and reduce the number of network requests your app makes.

All fields are optional. Omitting `otelConfig` keeps the SDK defaults, and any out-of-range value is clamped to the documented bounds.

```
CoralogixRum.init({

  // ...

  otelConfig: {

    maxExportBatchSize: 50, // Max spans per export; reaching it triggers an early flush. Defaults to 50, min 1, max 256

    scheduledDelayMillis: 2000, // Delay in ms between two consecutive exports. Defaults to 2000(2s), min 2000(2s), max 30000(30s)

    maxQueueSize: 2048, // Max buffered spans before new spans are dropped. Defaults to 2048, min 512, max 4096

  },

});
```

### Soft Navigations — Experimental[​](#soft-navigations--experimental "Direct link to Soft Navigations — Experimental")

Soft navigations are navigations that do not trigger a full page reload, such as SPA navigations. Defaults to false. With this option enabled, the SDK will track soft navigations and Partial Web vitals metrics such as (TTFB, FCP, LCP, CLS, INP).

\*\****&#x20;This feature requires enabling the feature flag(#enable-experimental-web-platform-features) in the browser.&#x20;***\*\*

```
CoralogixRum.init({

  // ...

  trackSoftNavigations: false,

});
```

### Memory Usage - Experimental[​](#memory-usage---experimental "Direct link to Memory Usage - Experimental")

Memory usage is a feature that allows you to track the memory usage of your application. It uses the [measureUserAgentSpecificMemory](https://developer.mozilla.org/en-US/docs/Web/API/Performance/measureUserAgentSpecificMemory) API.<br />The SDK will collect memory usage data every interval and send it to Coralogix.<br />To enable the feature, your website needs to be in a [secure context](https://developer.mozilla.org/en-US/docs/Web/API/Performance/measureUserAgentSpecificMemory#security_requirements).

```
CoralogixRum.init({

  // ...

  memoryUsageConfig: {

    enabled: true,

    interval: 300_000, // Defaults to 5 minutes

  },

});
```

You can also manually trigger memory usage data collection.

```
CoralogixRum.measureUserAgentSpecificMemory();
```
