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

# Using LaunchDarkly feature flags and Experimentation with Wordpress

export const BlogAuthor = ({date, avatar, alt, name}) => {
  return <div className="-mb-4">
      <p className="m-0 text-base font-semibold">
        <em>Published {date}</em>
      </p>
      <div className="flex items-center -mt-4">
        {avatar && <img src={avatar} alt={alt} className="h-8 w-8 rounded-full m-0" />}
        <p className="ml-[5px] text-lg">{name}</p>
      </div>
    </div>;
};

<View title="Developer" />

<View title="Federal docs" />

<View title="EU docs" />

<BlogAuthor date="May 21, 2026" avatar="/images/authors/glynn-jordan.png" alt="Portrait of Glynn Jordan." name="by Glynn Jordan" />

This tutorial explains how to integrate LaunchDarkly with a self-hosted WordPress site for feature flagging and experimentation. It covers the available SDK approaches, how to handle WordPress-specific constraints like caching, and how to structure your implementation depending on whether your goal is controlled feature rollouts or A/B testing.

WordPress powers a large share of the web, and many organizations use it alongside modern JavaScript front ends and microservice architectures. LaunchDarkly supports this kind of mixed environment through a combination of the PHP server-side SDK and the JavaScript client-side SDK.

<Note>
  **This tutorial applies to self-hosted WordPress sites**

  This tutorial applies to self-hosted WordPress sites on [wordpress.org](https://wordpress.org/). Sites hosted on [wordpress.com](https://wordpress.com/) do not provide PHP execution access and cannot run the LaunchDarkly PHP SDK. For those environments, use the [JavaScript SDK](/docs/sdk/client-side/javascript) with client-side flag evaluation only.
</Note>

## Prerequisites

To complete this tutorial, you should have:

* A self-hosted WordPress installation with PHP 8.1 or higher
* [Composer](https://getcomposer.org/) available in your WordPress environment
* A LaunchDarkly account with at least one project and environment configured
* Access to your WordPress theme files or a custom plugin

## Concepts

Before you read this tutorial, you should understand the following:

* **Feature flags** are the foundation of LaunchDarkly. A feature flag controls whether a code path, UI element, or experience is active for a given user or group of users. Flags can be boolean (on/off) or multivariate (returning strings, numbers, or JSON). Everything in LaunchDarkly, including experiments, is built on top of flags.
* **Experimentation** uses flags to run A/B and multivariate tests. An experiment assigns users to variants through a flag's targeting rules, then measures the effect on defined metrics. Experimentation requires flag evaluation to be consistent per user and per session. The same user must always see the same variant for the duration of the test.
* **Server-side SDKs** evaluate flags on the server before the page is rendered and sent to the browser. This eliminates client-side performance concerns like cold start delays and flicker.
* **Client-side SDKs** evaluate flags in the browser after the page loads. They are simpler to set up but require additional care to avoid flicker in experimentation scenarios.
* **Bootstrapping** is a technique where a server-side SDK pre-evaluates all flags for a given user and injects the results into the HTML response. The client-side SDK then initializes instantly using those values, with no additional network request.
* **Contexts** are the objects LaunchDarkly uses to evaluate flags and record experiment data. A context has a `kind` (usually `user`) and a `key` that uniquely identifies the entity being evaluated.

## Choose your approach

There are two main approaches to integrating LaunchDarkly with WordPress. Your choice depends on your WordPress setup and requirements.

<table>
  <thead>
    <tr>
      <th />

      <th>PHP SDK (server-side)</th>
      <th>JS SDK only (client-side)</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>Requires</td>
      <td>PHP access, Composer</td>
      <td>Script tag in {'<head>'}</td>
    </tr>

    <tr>
      <td>Flicker risk</td>
      <td>None</td>
      <td>Yes, without mitigation</td>
    </tr>

    <tr>
      <td>Cold start delay</td>
      <td>None</td>
      <td>\~100–200ms on first load</td>
    </tr>

    <tr>
      <td>Works with full-page caching</td>
      <td>With hybrid pattern (see below)</td>
      <td>Yes</td>
    </tr>

    <tr>
      <td>Best for</td>
      <td>Performance-sensitive pages, SEO-critical pages</td>
      <td>Simple setups, WordPress.com</td>
    </tr>
  </tbody>
</table>

Most production experimentation use cases on self-hosted WordPress will benefit from the PHP SDK approach. The sections below cover both approaches.

## Option 1: PHP SDK with bootstrapping (recommended)

This approach evaluates flags server-side in PHP and injects the results into the page before it reaches the browser. The JavaScript SDK initializes instantly from those pre-evaluated values.

### Step 1: Install the PHP SDK

From your WordPress root or theme directory, install the SDK using Composer:

<CodeGroup>
  ```shell title="Install the SDK" lines wrap theme={null}
  composer require launchdarkly/server-sdk
  ```
</CodeGroup>

Then include the autoloader in your theme's `functions.php`:

<CodeGroup>
  ```php title="Autoloader" lines wrap theme={null}
  require_once __DIR__ . '/vendor/autoload.php';
  ```
</CodeGroup>

The LaunchDarkly PHP SDK version 6.x requires PHP 8.1 or higher. Starting with version 6.6, it also requires the `apcu` PHP extension to be installed and enabled.

### Step 2: Evaluate flags in PHP and inject bootstrap data

Add the following to your theme's `functions.php`. This function evaluates all client-side flags for the current user and outputs them as an inline script that the JavaScript SDK can read on initialization.

<CodeGroup>
  ```php title="Evaluation function" expandable lines wrap theme={null}
  use LaunchDarkly\LDClient;
  use LaunchDarkly\LDContext;

  function ld_get_visitor_id() {
      if ( ! isset( $_COOKIE['ld_visitor_id'] ) ) {
          $visitor_id = bin2hex( random_bytes( 16 ) );
          setcookie( 'ld_visitor_id', $visitor_id, [
              'expires'  => time() + YEAR_IN_SECONDS,
              'path'     => '/',
              'secure'   => is_ssl(),
              'httponly' => false, // JS SDK needs to read this
              'samesite' => 'Lax',
          ] );
          $_COOKIE['ld_visitor_id'] = $visitor_id; // available to other code on this request
      }
      return sanitize_text_field( $_COOKIE['ld_visitor_id'] );
  }

  function ld_get_bootstrap_data( $visitor_id ) {
      $context_key = is_user_logged_in() ? (string) get_current_user_id() : $visitor_id;

      $context = LDContext::builder( $context_key )
          ->set( 'loggedIn', is_user_logged_in() )
          ->build();

      // Initialize the PHP SDK
      // For high-traffic sites, configure the PHP SDK to use the Relay Proxy instead
      $client = new LDClient( 'YOUR_SDK_KEY' );

      // allFlagsState() returns data in the exact format the JS SDK expects for bootstrap
      return $client->allFlagsState( $context, [ 'clientSideOnly' => true ] );
  }

  function ld_inject_bootstrap_script() {
      $visitor_id  = ld_get_visitor_id();
      $flag_state  = ld_get_bootstrap_data( $visitor_id );
      echo '<script>'
          . 'var ldVisitorId = ' . wp_json_encode( $visitor_id ) . ';'
          . 'var ldBootstrap = ' . wp_json_encode( $flag_state ) . ';'
          . '</script>';
  }
  add_action( 'wp_head', 'ld_inject_bootstrap_script', 1 );
  ```
</CodeGroup>

<Note>
  **PHP performance**

  By default, the PHP SDK caches flag data in memory per process. This is appropriate for low-to-medium traffic environments. For higher-traffic sites, you can configure the SDK's HTTP cache to use Memcached or Redis using the `cache` option, or use the [Relay Proxy](/docs/sdk/relay-proxy) in daemon mode which is LaunchDarkly's recommended approach for high-throughput PHP environments.
</Note>

### Step 3: Initialize the JavaScript SDK with bootstrap data

In your theme or page template, initialize the JavaScript SDK using the injected bootstrap values. The SDK will be immediately ready with no network fetch required.

Register the SDK script alongside your other theme assets. We recommend self-hosting the SDK file rather than loading it from a third-party CDN like unpkg or jsDelivr, which we do not support for production use. To learn more, read the [JavaScript SDK reference](/docs/sdk/client-side/javascript).

<CodeGroup>
  ```php title="Register the SDK in functions.php" lines wrap theme={null}
  function ld_enqueue_js_sdk() {
      wp_enqueue_script(
          'launchdarkly-js-client-sdk',
          get_template_directory_uri() . '/js/launchdarkly-js-client-sdk.min.js',
          [],
          'EXAMPLE-VERSION', // pin to an exact SDK version
          false // load in the <head>
      );
  }
  add_action( 'wp_enqueue_scripts', 'ld_enqueue_js_sdk' );
  ```

  ```html title="Initialize in your template" lines wrap theme={null}
  <script>
    const context = {
      kind: 'user',
      key: ldVisitorId // injected by PHP, guaranteed to match bootstrap
    };

    const ldClient = LDClient.initialize('YOUR_CLIENT_SIDE_ID', context, {
      bootstrap: ldBootstrap // injected by PHP above
    });

    // Flags are available immediately — no need to wait for 'ready'
    const flagValue = ldClient.variation('your-flag-key', 'control');
  </script>
  ```
</CodeGroup>

## Handling caching

Full-page caching (WP Rocket, W3 Total Cache, Nginx FastCGI, Cloudflare, and similar caching layers) stores a rendered HTML snapshot and serves it to all subsequent visitors. This means PHP does not re-execute per user, and the same evaluated flag values are served to everyone.

This is not a LaunchDarkly-specific limitation. It affects any server-side A/B testing tool running on a cached WordPress page.

There are two approaches to resolve this.

### Approach A: Hybrid cookie pattern (recommended)

This pattern keeps full-page caching enabled for the majority of traffic while ensuring each user receives a correctly bucketed, consistent variant.

How it works:

1. New visitors (with no variant cookie) bypass the cache and hit PHP, which evaluates the flag and sets a per-user cookie
2. The caching layer is configured to serve cached pages only when the variant cookie is present
3. On subsequent visits, the cached page loads and the JavaScript SDK reads the variant from the cookie with no PHP execution, no network call, no flicker

If you're using PHP, evaluate once and set a cookie:

<CodeGroup>
  ```php title="Evaluate and set a cookie" expandable lines wrap theme={null}
  use LaunchDarkly\LDClient;
  use LaunchDarkly\LDContext;

  function ld_set_variant_cookie() {
      $flag_key    = 'your-experiment-flag';
      $cookie_name = 'ld_variant_' . $flag_key;

      // If the user already has a variant assignment, do nothing
      if ( isset( $_COOKIE[ $cookie_name ] ) ) {
          return;
      }

      $visitor_id  = ld_get_visitor_id(); // shared helper from Step 2
      $context_key = is_user_logged_in() ? (string) get_current_user_id() : $visitor_id;
      $context     = LDContext::builder( $context_key )->build();
      $client      = new LDClient( 'YOUR_SDK_KEY' );
      $variant     = $client->variation( $flag_key, $context, 'control' );

      // Write the variant to a cookie readable by the JS SDK on cached loads
      setcookie( $cookie_name, $variant, [
          'expires'  => time() + ( 30 * DAY_IN_SECONDS ),
          'path'     => '/',
          'domain'   => '.yourdomain.com', // replace with your domain
          'secure'   => is_ssl(),
          'httponly' => false, // JS SDK needs to read this
          'samesite' => 'Lax',
      ] );
  }
  add_action( 'template_redirect', 'ld_set_variant_cookie' );
  ```
</CodeGroup>

Set the variant cookie expiration to match or exceed your typical experiment duration. If a returning visitor's variant cookie has expired, they'll be re-bucketed on their next visit, which can cause variant jumping in long-running experiments.

If you're using JavaScript, read the variant on cached page loads:

<CodeGroup>
  ```js title="Read the variant" lines wrap theme={null}
  function getCookieValue(name) {
    const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
    return match ? match[2] : null;
  }

  const context = {
    kind: 'user',
    key: getCookieValue('ld_visitor_id')
  };

  const variant = getCookieValue('ld_variant_your-experiment-flag') ?? 'control';

  const ldClient = LDClient.initialize('YOUR_CLIENT_SIDE_ID', context, {
    bootstrap: { 'your-experiment-flag': variant }
  });
  ```
</CodeGroup>

<Info>
  **Exposure events in the cookie pattern**

  The PHP `variation()` call that sets the cookie records the experiment exposure server-side, so subsequent cached page loads do not need to fire another exposure event from JavaScript. Use the bootstrapped variant to gate your UI, and use `ldClient.track()` to record conversion events on the same context key. Avoid passing the full `allFlagsState()` payload through the cookie, since that bootstrap form is intended to be regenerated per-request by the server and grows with your client-side flag count. To learn more, read [Bootstrapping](/docs/sdk/features/bootstrapping).
</Info>

#### Cache bypass configuration

Configure your caching layer to bypass cache when the variant cookie is absent, for example, new visitors who need a fresh PHP evaluation:

<table>
  <thead>
    <tr>
      <th>Caching layer</th>
      <th>Configuration</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>WP Rocket</td>
      <td>Settings → Advanced Rules → Never Cache Cookies → add <code>ld\_visitor\_id</code></td>
    </tr>

    <tr>
      <td>W3 Total Cache</td>
      <td>Page Cache → Rejected Cookies → add <code>ld\_visitor\_id</code></td>
    </tr>

    <tr>
      <td>Nginx FastCGI</td>

      <td>
        <code>
          {'set $skip_cache 1; if ($http_cookie ~* "ld_variant_") { set $skip_cache 0; }'}
        </code>
      </td>
    </tr>

    <tr>
      <td>Cloudflare</td>

      <td>
        Cache Rules: bypass cache for requests that have <strong>no</strong> <code>ld\_variant\_\*</code> cookie so PHP can assign a variant. Exact configuration depends on your Cloudflare plan. On Pro and above, use Cache Rules with an expression such as{' '}
        <code>not http.cookie contains "ld\_variant\_"</code> and a <strong>Bypass cache</strong> action. On Free, you may need to use a Worker or Page Rules to achieve the same effect.
      </td>
    </tr>
  </tbody>
</table>

### Approach B: Exclude experiment pages from caching

It is also possible to disable caching entirely on pages where an experiment is running. This is the simplest configuration change but means those pages lose the performance benefit of full-page caching.

We generally do not recommend this approach for SEO-critical or high-traffic landing pages where cache performance is a requirement. It may be appropriate for lower-traffic pages where cache performance is less important.

## Option 2: JavaScript SDK only (client-side)

If you are unable to modify PHP or are running on a platform where PHP execution is restricted, you can use the JavaScript SDK alone.

Self-host the SDK file alongside your other JavaScript resources and load it from your theme's `<head>` using `wp_enqueue_script()`.

<CodeGroup>
  ```html title="Add the JavaScript SDK" expandable lines wrap theme={null}
  <!-- Load the self-hosted SDK file via wp_enqueue_script() in functions.php -->
  <script>
    let visitorId = localStorage.getItem('ld_visitor_id');
    if (!visitorId) {
      visitorId = crypto.randomUUID();
      localStorage.setItem('ld_visitor_id', visitorId);
    }

    const ldClient = LDClient.initialize('YOUR_CLIENT_SIDE_ID', {
      kind: 'user',
      key: visitorId,
      anonymous: true
    }, {
      bootstrap: 'localStorage'
    });

    ldClient.on('ready', () => {
      const variant = ldClient.variation('your-flag-key', 'control');
      // apply variant
    });
  </script>
  ```
</CodeGroup>

### Mitigating flicker in client-side mode

When the SDK loads asynchronously, the page renders before flag values are available. Users may briefly see the control variant before the treatment is applied. This is called "flicker."

To prevent flicker, hide the element under test until the SDK is ready, then reveal it:

<CodeGroup>
  ```js title="CSS and JavaScript" lines wrap theme={null}
  // CSS
  .ld-pending {
    visibility: hidden;
  }
  // JavaScript
  ldClient.on('ready', () => {
    const variant = ldClient.variation('your-flag-key', 'control');
    // apply variant logic
    document.querySelectorAll('.ld-pending').forEach(el => {
      el.style.visibility = 'visible';
    });
  });
  ```
</CodeGroup>

Loading the SDK with `async` or `defer` improves page load metrics but makes flicker worse, because the page renders before the script executes. If you use `async`/`defer`, the CSS hide pattern above becomes essential. The PHP bootstrap approach in Option 1 eliminates this tradeoff entirely.

By default, the JavaScript SDK fetches flags from LaunchDarkly on every page load, so the \~100–200ms cold start applies to every initialization. To cache flag values across visits, pass `bootstrap: 'localStorage'` to `LDClient.initialize()`. With this enabled, after the first visit the SDK reads cached values from `localStorage` and emits the `ready` event immediately, while still fetching the latest values in the background. Note that this can introduce stale-value flicker if flags change between visits, and that first-time visitors still see the full cold start. The PHP bootstrap approach in Option 1 avoids both tradeoffs.

## Feature flags in WordPress

Feature flags let you control which users see which experiences without code deployments. Common use cases in WordPress include:

* **Gradual rollouts**: Roll out a new page template, content block, or UI component to a percentage of visitors before releasing to everyone
* **Targeted experiences**: Serve specific content to users based on attributes like country, logged-in status, or subscription tier
* **Kill switches**: Instantly disable a feature if problems arise, without a deployment
* **Beta access**: Expose new features only to specific users or groups

### Example: show a new hero section to 20% of visitors

In your WordPress template, add the following:

<CodeGroup>
  ```php title="WordPress template" lines wrap theme={null}
  $visitor_id = ld_get_visitor_id();
  $context = LDContext::builder( $visitor_id )->build();
  $client  = new LDClient( 'YOUR_SDK_KEY' );

  if ( $client->variation( 'new-hero-section', $context, false ) ) {
      get_template_part( 'template-parts/hero', 'new' );
  } else {
      get_template_part( 'template-parts/hero', 'default' );
  }
  ```
</CodeGroup>

In the LaunchDarkly UI, set the flag to a 20% percentage rollout to gradually expose the new hero to traffic. Increase the percentage as confidence grows, or roll back instantly by turning the flag off.

## Experimentation in WordPress

Experimentation builds on feature flags to run controlled A/B tests and measure the effect of changes on defined metrics. The typical WordPress experimentation flow involves the landing page (WordPress), downstream conversion pages (often React or other front-end apps), and a metric like signup or purchase completion.

### Setting up a simple experiment

To set up an experiment:

1. Create a multivariate flag: In the LaunchDarkly UI, create a string flag with two variations, for example, `control` and `treatment`. Enable client-side SDK access on the flag.
2. Create a metric: Create a custom event metric in LaunchDarkly. For example, a metric named "signup-completed" tied to an event key of `signup-completed`. Set the metric definition to **Occurrence (Percent)** (did this event happen for this user at all?).
3. Create the experiment: Create an experiment, attach the flag, select the metric, and configure the traffic allocation. Set the targeting rule to evaluate the flag for all users or a specific segment, then start the experiment.
4. Evaluate the flag on the WordPress landing page (LP):

<CodeGroup>
  ```php title="Evaluation" lines wrap theme={null}
  $variant = $client->variation( 'lp-hero-experiment', $context, 'control' );

  if ( $variant === 'treatment' ) {
      // render treatment version
  } else {
      // render control version
  }
  ```
</CodeGroup>

5. Track the conversion event from your downstream app: When the user completes the goal action (for example, signup), fire a `track()` call from wherever that event occurs, whether that's the WordPress page itself or a downstream React application:

<CodeGroup>
  ```js title="Track call" lines wrap theme={null}
  ldClient.track('signup-completed');
  ```
</CodeGroup>

LaunchDarkly connects the `track()` event to the experiment exposure using the same context key. As long as the same `userId` or `visitorId` is used consistently across your WordPress LP and downstream apps, attribution will be correct.

### Passing variant decisions to downstream apps

If your WordPress LP is the entry point but conversion happens in a React app on the same domain, you can persist the variant assignment in a cookie and read it in the downstream app without re-initializing LaunchDarkly:

<CodeGroup>
  ```php title="PHP" lines wrap theme={null}
  // In WordPress PHP — write the variant to a cross-subdomain cookie
  setcookie( 'lp_variant', $variant, time() + ( 24 * 60 * 60 ), '/', '.yourdomain.com' );
  ```

  ```js title="JavaScript" lines wrap theme={null}
  // In your React app — read the variant without any LaunchDarkly initialization
  const variant = document.cookie.match(/lp_variant=([^;]+)/)?.[1] ?? 'control';
  ```
</CodeGroup>

This approach requires the WordPress LP and the React app to share the same root domain. If they are on separate domains, initialize the LaunchDarkly SDK in each app using the same context key instead.

### Anonymous visitor to authenticated user

When a user arrives anonymously and later signs up or logs in, you can link their pre-login experiment exposure to their authenticated identity using a multi-context identify call. This ensures experiment attribution is preserved across the anonymous and authenticated states.

At the moment of login or signup:

<CodeGroup>
  ```js title="Identify" lines wrap theme={null}
  ldClient.identify({
    kind: 'multi',
    user: {
      key: authenticatedUserId, // your system's user ID
      loggedIn: true
    },
    visitor: {
      key: visitorId, // the anonymous ID used before login
      anonymous: true // see note below
    }
  });
  ```
</CodeGroup>

<Note>
  **Anonymous vs tracked visitor contexts**

  Marking the `visitor` sub-context as `anonymous: true` is recommended for most A/B testing scenarios because it reduces your monthly active user (MAU) consumption and excludes pre-login traffic from the contexts list. If you instead want to individually target specific anonymous visitors, audit which variations each visitor saw, or preserve pre-login attributes as a durable record on the contexts list, omit `anonymous: true` so the visitor is tracked. To learn more, read [Anonymous contexts](/docs/home/flags/anonymous-contexts).

  Note also that `visitor` is a custom context kind defined by your application. If you use this kind, use the same kind name consistently across your application and in any experiment's randomization unit configuration. To learn more, read [Contexts](/docs/home/flags/contexts).
</Note>

## Using the Relay Proxy in daemon mode

For WordPress sites with significant traffic, configure the PHP SDK to use the [LaunchDarkly Relay Proxy](/docs/sdk/relay-proxy) in daemon mode. The Relay Proxy maintains a persistent connection to LaunchDarkly and stores flag data in Redis or DynamoDB. This means:

* The PHP SDK reads flag values from a local store on every request, with no outbound HTTP call to LaunchDarkly
* Flag updates are received by the Relay Proxy and propagated to the store in real time
* Your WordPress server is isolated from any LaunchDarkly availability events

<CodeGroup>
  ```php title="Relay Proxy in daemon mode (Redis)" lines wrap theme={null}
  // Daemon mode: SDK reads flag data directly from a persistent store
  // that the Relay Proxy keeps up to date. No per-request HTTP call to LaunchDarkly.

  use LaunchDarkly\Integrations\Redis;

  $client = new LaunchDarkly\LDClient( 'YOUR_SDK_KEY', [
      'feature_requester' => Redis::featureRequester( [
          'redis_host' => 'localhost',
          'redis_port' => 6379,
      ] ),
  ] );
  ```
</CodeGroup>

This requires the [`launchdarkly/server-sdk-redis-predis`](https://packagist.org/packages/launchdarkly/server-sdk-redis-predis) (or [`launchdarkly/server-sdk-redis-phpredis`](https://packagist.org/packages/launchdarkly/server-sdk-redis-phpredis)) Composer package, and the Relay Proxy must be configured to write to the same Redis instance. To learn more, read [Using daemon mode](/docs/sdk/features/relay-proxy-configuration/daemon-mode) and [Storing data](/docs/sdk/features/storing-data).

To learn more, read [The Relay Proxy](/docs/sdk/relay-proxy).

## Conclusion

In this tutorial, you learned how to:

* Install and configure the LaunchDarkly PHP SDK in a self-hosted WordPress environment
* Bootstrap the JavaScript SDK with server-evaluated flag values to eliminate cold start delays and flicker
* Handle full-page caching using a hybrid cookie pattern that preserves cache performance
* Use feature flags for controlled rollouts and targeted content in WordPress templates
* Set up A/B experiments across a WordPress LP and downstream React applications
* Link anonymous visitor identities to authenticated user identities using multi-context

For more information, read:

* [PHP SDK reference](/docs/sdk/server-side/php)
* [JavaScript SDK reference](/docs/sdk/client-side/javascript)
* [Bootstrapping](/docs/sdk/features/bootstrapping)
* [Experimentation](/docs/home/experimentation)
* [Contexts](/docs/home/flags/contexts)
* [Relay Proxy](/docs/sdk/relay-proxy)
