Custom Instrumentation

On this page you will learn how to manually propagate trace information into and out of your Unity application.

To set it up you have to make sure your game extracts incoming headers and to set those headers again when making an outgoing request.

Unity supports two approaches for making HTTP requests out of the box:

  • HttpClient: Use .NET's HttpClient with SentryHttpMessageHandler for automatic trace propagation. This is the simplest approach and works on all platforms except WebGL. It supports modern async/await patterns.
  • UnityWebRequest (Required for WebGL): Use Unity's UnityWebRequest, as HttpClient is not supported in WebGL due to browser security restrictions. This approach also works well if you prefer Unity's coroutine-based patterns or need consistent behavior across all platforms.

Incoming tracing information has to be extracted and stored in memory for later use. Sentry provides the ContinueTrace() function to help you with this. Tracing information can come from incoming headers, for example, by another Sentry SDK used in your backend service.

If you're using .NET's HttpClient, you can extract trace headers from the response:

Copied
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using UnityEngine;

public class TraceReceiver : MonoBehaviour
{
    private static readonly HttpClient httpClient = new HttpClient();

    async Task MakeRequest()
    {
        try
        {
            var response = await httpClient.GetAsync("https://example.com/api/data");

            if (response.IsSuccessStatusCode)
            {
                // Extract Sentry trace headers from the response
                var sentryTraceHeader = string.Empty;
                var sentryBaggageHeader = string.Empty;

                if (response.Headers.TryGetValues("sentry-trace", out var traceValues))
                {
                    sentryTraceHeader = traceValues.FirstOrDefault() ?? string.Empty;
                }

                if (response.Headers.TryGetValues("baggage", out var baggageValues))
                {
                    sentryBaggageHeader = baggageValues.FirstOrDefault() ?? string.Empty;
                }

                // Continue the trace from the backend service
                var transactionContext = SentrySdk.ContinueTrace(sentryTraceHeader, sentryBaggageHeader);
                var transaction = SentrySdk.StartTransaction(transactionContext);

                // Process your data here...
                var content = await response.Content.ReadAsStringAsync();

                transaction.Finish();
            }
        }
        catch (HttpRequestException e)
        {
            Debug.LogError($"Request failed: {e.Message}");
        }
    }
}

For WebGL builds or if you prefer Unity's coroutine-based approach, use UnityWebRequest:

Copied
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

public class TraceReceiver : MonoBehaviour
{
    IEnumerator MakeRequest()
    {
        using var www = UnityWebRequest.Get("https://example.com/api/data");
        yield return www.SendWebRequest();

        if (www.result == UnityWebRequest.Result.Success)
        {
            // Extract headers from the incoming response
            var responseHeaders = www.GetResponseHeaders();
            if (responseHeaders != null)
            {
                var sentryTraceHeader = string.Empty;
                var sentryBaggageHeader = string.Empty;

                if (responseHeaders.TryGetValue("sentry-trace", out var traceHeader))
                {
                    sentryTraceHeader = traceHeader;
                }

                if (responseHeaders.TryGetValue("baggage", out var baggageHeader))
                {
                    sentryBaggageHeader = baggageHeader;
                }

                // Continue the trace from the backend service
                var transactionContext = SentrySdk.ContinueTrace(sentryTraceHeader, sentryBaggageHeader);
                var transaction = SentrySdk.StartTransaction(transactionContext);

                // Process your data here...

                transaction.Finish();
            }
        }
    }
}

If you pass these headers to Sentry's ContinueTrace() function it will store them in memory for later use.

For distributed tracing to work, the two headers sentry-trace and baggage, must now also be added to outgoing requests.

The easiest way to propagate traces is to use .NET's HttpClient with SentryHttpMessageHandler. This automatically adds tracing headers to all outgoing requests:

Copied
using System.Net.Http;
using System.Threading.Tasks;
using Sentry.Http;
using UnityEngine;

public class TraceSender : MonoBehaviour
{
    private static readonly HttpClient httpClient = new HttpClient(new SentryHttpMessageHandler());

    async Task SendRequest()
    {
        try
        {
            var response = await httpClient.PostAsync(
                "https://example.com/api/action",
                new StringContent("{}", System.Text.Encoding.UTF8, "application/json"));

            if (response.IsSuccessStatusCode)
            {
                Debug.Log("Request sent with automatic trace headers");
            }
        }
        catch (HttpRequestException e)
        {
            Debug.LogError($"Request failed: {e.Message}");
        }
    }
}

Note that SentryHttpMessageHandler automatically adds the sentry-trace and baggage headers, so you don't need to do anything manually.

For WebGL builds or if you prefer Unity's coroutine-based approach, you can manually add trace headers using Unity's UnityWebRequest:

Copied
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

public class TraceSender : MonoBehaviour
{
    IEnumerator SendRequest()
    {
        var jsonData = "{}";
        using var www = UnityWebRequest.Post("https://example.com/api/action", jsonData, "application/json");

        // Add Sentry trace headers to propagate the trace
        var traceHeader = SentrySdk.GetTraceHeader();
        if (traceHeader != null)
        {
            www.SetRequestHeader("sentry-trace", traceHeader.ToString());
        }

        var baggageHeader = SentrySdk.GetBaggage();
        if (baggageHeader != null)
        {
            www.SetRequestHeader("baggage", baggageHeader.ToString());
        }

        yield return www.SendWebRequest();

        if (www.result == UnityWebRequest.Result.Success)
        {
            Debug.Log("Request sent with trace headers");
        }
    }
}

This way, tracing information is propagated to the project receiving the message. If this project uses the Sentry .NET SDK, it will extract and save the tracing information for later use.

The two services are now connected with your custom distributed tracing implementation.

If you make outgoing requests from your project to other services, check if the headers sentry-trace and baggage are present in the request. If so, distributed tracing is working.

Was this helpful?
Help improve this content
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").