---
title: Instrumenting Azure API Management
description: Datadog, the leading service for cloud-scale monitoring.
breadcrumbs: >-
  Docs > APM > Application Instrumentation > Tracing a Proxy > Instrumenting
  Azure API Management
---

# Instrumenting Azure API Management

Datadog APM can create **inferred spans** for requests that pass through Azure API Management to your backend services. The spans enable end-to-end traces, service maps, and sampling based on the API Management gateway.

Inferred spans for Azure API Management are supported for **.NET**, **JavaScript** (Node.js), and **Python** only. Other runtimes (for example Go, Java, or PHP) do not emit Azure API Management inferred spans, even if they support inferred spans for other gateways.

## Prerequisites{% #prerequisites %}

- `DD_TRACE_INFERRED_PROXY_SERVICES_ENABLED=true` is set in your application settings.
- Your backend uses a **supported runtime**, **minimum tracer version**, and **web framework** from the table below.

### Supported runtimes and web frameworks{% #supported-runtimes-and-web-frameworks %}

| Runtime | Datadog Tracer    | Minimum tracer version | Frameworks                                                                                                                             |
| ------- | ----------------- | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| Node.js | `dd-trace-js`     | v5.87.0+               | express, fastify, hapi, koa, microgateway-core, next, paperplane, restify, router, apollo                                              |
| Python  | `dd-trace-py`     | v4.6.0+                | aiohttp, asgi, bottle, cherrypy, django, djangorestframework, falcon, fastapi, flask, molten, pyramid, sanic, starlette, tornado, wsgi |
| .NET    | `dd-trace-dotnet` | v3.39.0+               | ASP.NET, ASP.NET Core                                                                                                                  |

## Setup{% #setup %}

To create inferred spans, Azure API Management must pass the following headers to your backend services:

| Header                       | Value                                                               |
| ---------------------------- | ------------------------------------------------------------------- |
| `x-dd-proxy`                 | `azure-apim`                                                        |
| `x-dd-proxy-request-time-ms` | Request timestamp in Unix milliseconds                              |
| `x-dd-proxy-httpmethod`      | HTTP method (for example, from `context.Operation.Method`)          |
| `x-dd-proxy-path`            | URL template (for example, from `context.Operation.UrlTemplate`)    |
| `x-dd-proxy-region`          | Deployment region (for example, from `context.Deployment.Region`)   |
| `x-dd-proxy-domain-name`     | Request host (for example, from `context.Request.OriginalUrl.Host`) |

### Inbound policy{% #inbound-policy %}

Add the following policy to the **inbound** section of your API in Azure API Management so these headers are set on requests to your backend:

```xml
<set-header name="x-dd-proxy" exists-action="override">
    <value>azure-apim</value>
</set-header>
<set-header name="x-dd-proxy-request-time-ms" exists-action="override">
    <value>@(new DateTimeOffset(context.Timestamp).ToUnixTimeMilliseconds().ToString())</value>
</set-header>
<set-header name="x-dd-proxy-httpmethod" exists-action="override">
    <value>@(context.Operation.Method)</value>
</set-header>
<set-header name="x-dd-proxy-path" exists-action="override">
    <value>@(context.Operation.UrlTemplate)</value>
</set-header>
<set-header name="x-dd-proxy-region" exists-action="override">
    <value>@(context.Deployment.Region)</value>
</set-header>
<set-header name="x-dd-proxy-domain-name" exists-action="override">
    <value>@(context.Request.OriginalUrl.Host)</value>
</set-header>
```

You can add this policy at the API level in the Azure portal under **API Management** > your API > **Design** → **Inbound processing** → **Code view** (see [Set or edit Azure API Management policies](https://learn.microsoft.com/en-us/azure/api-management/set-edit-policies)), using the Azure API Management REST API, or policies in your API definition.

## Update sampling rules{% #update-sampling-rules %}

Head-based sampling still applies when using Azure API Management tracing. Because the inferred span becomes the new trace root, update your rules so the service value matches the API Management service name shown in Datadog.

For example, if the original sampling rule is:

```shell
DD_TRACE_SAMPLING_RULES='[{"service":"my-backend","sample_rate":0.5}]'
```

Update the rule so the `service` value matches your API Management API name as it appears in Datadog, or remove the `service` key to apply the rule to all root spans:

```shell
DD_TRACE_SAMPLING_RULES='[{"service":"my-azure-apim-api","sample_rate":0.5}]'
```

Or apply to all root spans:

```shell
DD_TRACE_SAMPLING_RULES='[{"sample_rate":0.5}]'
```

## Further Reading{% #further-reading %}

- [Azure integrations](https://docs.datadoghq.com/integrations/guide/azure-integrations.md)
- [Ignoring Unwanted Resources in APM](https://docs.datadoghq.com/tracing/guide/ignoring_apm_resources.md)
- [Trace Context Propagation](https://docs.datadoghq.com/tracing/trace_collection/trace_context_propagation.md)
