> For the complete documentation index, see [llms.txt](https://developer.harness.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.harness.io/feature-management-experimentation/new-to-fme/get-started/install-the-sdk.md).

# Install the FME SDK

Our SDKs are designed to live at the application layer of your application and provide a secure and out-of-the-box method for controlling your experiments and feature flags.

Each SDK has two main functions:

* [Serve as a decision engine for your application](#decision-engine)
* [Automatically capture what variants of your features your customers are served](#capturing-what-your-customer-was-served)

### Harness FME SDKs <a href="#harness-fme-sdks" id="harness-fme-sdks"></a>

Split SDKs are for specific languages or use cases. To choose the best SDK for your scenario, see the respective SDK documentation.

#### Client-side SDKs

<table data-view="cards"><thead><tr><th align="center"></th><th align="center"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td align="center"><img src="/files/oWRKBcvYbKBZJMMRBmwI" alt="" data-size="original"></td><td align="center"><strong>Android SDK</strong></td><td><a href="/pages/8AF59NZ2aqPq17XR8ugB">/pages/8AF59NZ2aqPq17XR8ugB</a></td></tr><tr><td align="center"><img src="/files/soPWT6wbCTl0b9bEFgDV" alt="" data-size="original"></td><td align="center"><strong>Angular Utilities</strong></td><td><a href="/pages/LJUbiHqsA3WW7eSs02EX">/pages/LJUbiHqsA3WW7eSs02EX</a></td></tr><tr><td align="center"><img src="/files/CqaWt0Uy93H5vJ0nFmtJ" alt="" data-size="original"></td><td align="center"><strong>Browser SDK</strong></td><td></td></tr><tr><td align="center"><img src="/files/D01mpEtmTHjfjToJj0KA" alt="" data-size="original"></td><td align="center"><strong>Flutter Plugin</strong></td><td><a href="/pages/snGwWXajHlfJW7GDuFNF">/pages/snGwWXajHlfJW7GDuFNF</a></td></tr><tr><td align="center"><img src="/files/pL4DiVOsgdh4w7jQ2Txe" alt="" data-size="original"></td><td align="center"><strong>iOS SDK</strong></td><td><a href="/pages/7GUS0j7lBbffwUUTAgvq">/pages/7GUS0j7lBbffwUUTAgvq</a></td></tr><tr><td align="center"><img src="/files/pQNKS701qi00prXBdB5T" alt="" data-size="original"></td><td align="center"><strong>JavaScript SDK</strong></td><td><a href="/pages/2W8f1cXqxHpZb3xLL5je">/pages/2W8f1cXqxHpZb3xLL5je</a></td></tr><tr><td align="center"><img src="/files/PliXZnKOzH0SvzaaLkPP" alt="" data-size="original"></td><td align="center"><strong>React SDK</strong></td><td><a href="/pages/avzO8zntoEWOK5ZVqkA3">/pages/avzO8zntoEWOK5ZVqkA3</a></td></tr><tr><td align="center"><img src="/files/PliXZnKOzH0SvzaaLkPP" alt="" data-size="original"></td><td align="center"><strong>React Native SDK</strong></td><td><a href="/pages/foy1cK0LEZ2lp8QguIuf">/pages/foy1cK0LEZ2lp8QguIuf</a></td></tr><tr><td align="center"><img src="/files/AhgbPtOGsnmICleCirfp" alt="" data-size="original"></td><td align="center"><strong>Redux SDK</strong></td><td><a href="/pages/zbpMQAvyCnZBKNbFmCc3">/pages/zbpMQAvyCnZBKNbFmCc3</a></td></tr></tbody></table>

#### Client-side SDK Suites

<table data-view="cards"><thead><tr><th align="center"></th><th align="center"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td align="center"><img src="/files/oWRKBcvYbKBZJMMRBmwI" alt="" data-size="original"></td><td align="center"><strong>Android Suite</strong></td><td><a href="/pages/3ks69wKAhG4XvmVbZ6Xj">/pages/3ks69wKAhG4XvmVbZ6Xj</a></td></tr><tr><td align="center"><img src="/files/CqaWt0Uy93H5vJ0nFmtJ" alt="" data-size="original"></td><td align="center"><strong>Browser Suite</strong></td><td><a href="/pages/DcRGs2KekvF0tPE9vuNf">/pages/DcRGs2KekvF0tPE9vuNf</a></td></tr><tr><td align="center"><img src="/files/pL4DiVOsgdh4w7jQ2Txe" alt="" data-size="original"></td><td align="center"><strong>iOS Suite</strong></td><td><a href="/pages/gmtzCtH7qKd30fjMDfMg">/pages/gmtzCtH7qKd30fjMDfMg</a></td></tr></tbody></table>

#### Client-side RUM Agents

<table data-view="cards"><thead><tr><th align="center"></th><th align="center"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td align="center"><img src="/files/oWRKBcvYbKBZJMMRBmwI" alt="" data-size="original"></td><td align="center"><strong>Android Agents</strong></td><td><a href="/pages/0H5kmb6WM71VzZ9yyTm0">/pages/0H5kmb6WM71VzZ9yyTm0</a></td></tr><tr><td align="center"><img src="/files/CqaWt0Uy93H5vJ0nFmtJ" alt="" data-size="original"></td><td align="center"><strong>Browser Agents</strong></td><td><a href="/pages/K1e9ai9ihe27QesIrvhC">/pages/K1e9ai9ihe27QesIrvhC</a></td></tr><tr><td align="center"><img src="/files/pL4DiVOsgdh4w7jQ2Txe" alt="" data-size="original"></td><td align="center"><strong>iOS Agents</strong></td><td><a href="/pages/1tDiwj1CsAH84dpM6m1T">/pages/1tDiwj1CsAH84dpM6m1T</a></td></tr></tbody></table>

#### Server-side SDKs

<table data-view="cards"><thead><tr><th align="center"></th><th align="center"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td align="center"><img src="/files/WzGzu4Nf8SoNby9GUWhA" alt="" data-size="original"></td><td align="center"><strong>Elixir Thin Client SDK</strong></td><td><a href="/pages/aCR1qteofOk23blhGAC4">/pages/aCR1qteofOk23blhGAC4</a></td></tr><tr><td align="center"><img src="/files/iV8qoC0fhM7nzwYPv0W2" alt="" data-size="original"></td><td align="center"><strong>Go SDK</strong></td><td><a href="/pages/9S5EdLJQSGskpM0SkLxH">/pages/9S5EdLJQSGskpM0SkLxH</a></td></tr><tr><td align="center"><img src="/files/enkqAOrD5JqaMZnSLNTI" alt="" data-size="original"></td><td align="center"><strong>Java SDK</strong></td><td><a href="/pages/uwrbv211wAgmTIdyenQD">/pages/uwrbv211wAgmTIdyenQD</a></td></tr><tr><td align="center"><img src="/files/pSnfLIeCWIbUqYGIboFk" alt="" data-size="original"></td><td align="center"><strong>.NET SDK</strong></td><td><a href="/pages/AogFQGSeilYEy4E1M6nj">/pages/AogFQGSeilYEy4E1M6nj</a></td></tr><tr><td align="center"><img src="/files/yXQAFoZTuiGLRY8rscAS" alt="" data-size="original"></td><td align="center"><strong>NodeJS SDK</strong></td><td><a href="/pages/Ffpw4KXywnonGdBt79yQ">/pages/Ffpw4KXywnonGdBt79yQ</a></td></tr><tr><td align="center"><img src="/files/7KrpBwtIDV2gmi0Hl9QX" alt="" data-size="original"></td><td align="center"><strong>PHP SDK</strong></td><td><a href="/pages/VECjaZVbNH17j4LpfoZZ">/pages/VECjaZVbNH17j4LpfoZZ</a></td></tr><tr><td align="center"><img src="/files/7KrpBwtIDV2gmi0Hl9QX" alt="" data-size="original"></td><td align="center"><strong>PHP Thin Client SDK</strong></td><td><a href="/pages/Iv28tuwRX9swh3cpgarB">/pages/Iv28tuwRX9swh3cpgarB</a></td></tr><tr><td align="center"><img src="https://developer.harness.io/provider-logos/python-logo.svg" alt="Python SDK"></td><td align="center"><strong>Python SDK</strong></td><td><a href="/pages/sLjI7D2F7J7Fvg1ZKE9g">/pages/sLjI7D2F7J7Fvg1ZKE9g</a></td></tr><tr><td align="center"><img src="https://developer.harness.io/provider-logos/ruby-logo.svg" alt="Ruby SDK"></td><td align="center"><strong>Ruby SDK</strong></td><td><a href="/pages/ZRyRRi2ra4rGRlie7iRQ">/pages/ZRyRRi2ra4rGRlie7iRQ</a></td></tr></tbody></table>

#### Optional Infrastructure

<table data-view="cards"><thead><tr><th align="center"></th><th align="center"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td align="center"><img src="/files/2MGj9EG8USVRxyzF99M0" alt="" data-size="original"></td><td align="center"><strong>Split Daemon (splitd)</strong></td><td><a href="/pages/KN0KengJjX4SrBWxHj1F">/pages/KN0KengJjX4SrBWxHj1F</a></td></tr><tr><td align="center"><img src="/files/2MGj9EG8USVRxyzF99M0" alt="" data-size="original"></td><td align="center"><strong>Split Evaluator</strong></td><td><a href="/pages/1MrRpfxzlUFAYdKytfbE">/pages/1MrRpfxzlUFAYdKytfbE</a></td></tr><tr><td align="center"><img src="/files/2MGj9EG8USVRxyzF99M0" alt="" data-size="original"></td><td align="center"><strong>Split Proxy</strong></td><td><a href="/pages/EZJVipUInU5cBablPXFa">/pages/EZJVipUInU5cBablPXFa</a></td></tr><tr><td align="center"><img src="/files/2MGj9EG8USVRxyzF99M0" alt="" data-size="original"></td><td align="center"><strong>Split Synchronizer</strong></td><td><a href="/pages/OkOmXqVarqMVzjp9Mc2K">/pages/OkOmXqVarqMVzjp9Mc2K</a></td></tr><tr><td align="center"><img src="/files/pQNKS701qi00prXBdB5T" alt="" data-size="original"></td><td align="center"><strong>Split JavaScript Synchronizer Tools</strong></td><td><a href="/pages/tzgtoFntiMLb2i0YXoa4">/pages/tzgtoFntiMLb2i0YXoa4</a></td></tr><tr><td align="center"><img src="/files/fyqx3OhtVlKcs6kapWSE" alt="" data-size="original"></td><td align="center"><strong>Harness Proxy</strong></td><td><a href="/pages/h2pZlZukvBQ5yFZCItjJ">/pages/h2pZlZukvBQ5yFZCItjJ</a></td></tr></tbody></table>

#### OpenFeature Providers

<table data-view="cards"><thead><tr><th align="center"></th><th align="center"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td align="center"><img src="/files/oWRKBcvYbKBZJMMRBmwI" alt="" data-size="original"></td><td align="center"><strong>Android SDK</strong></td><td><a href="/pages/L21NxV2qsSkETdB3b2fH">/pages/L21NxV2qsSkETdB3b2fH</a></td></tr><tr><td align="center"><img src="/files/pL4DiVOsgdh4w7jQ2Txe" alt="" data-size="original"></td><td align="center"><strong>iOS SDK</strong></td><td><a href="/pages/wKCMCSy0eAvjEQvvJe8S">/pages/wKCMCSy0eAvjEQvvJe8S</a></td></tr><tr><td align="center"><img src="/files/CqaWt0Uy93H5vJ0nFmtJ" alt="" data-size="original"></td><td align="center"><strong>Web SDK</strong></td><td><a href="/pages/GtRMAnJJOu6nLmargGJk">/pages/GtRMAnJJOu6nLmargGJk</a></td></tr><tr><td align="center"><img src="/files/soPWT6wbCTl0b9bEFgDV" alt="" data-size="original"></td><td align="center"><strong>Angular</strong></td><td><a href="/pages/lPP4BZLYhof32eH7UV70">/pages/lPP4BZLYhof32eH7UV70</a></td></tr><tr><td align="center"><img src="/files/PliXZnKOzH0SvzaaLkPP" alt="" data-size="original"></td><td align="center"><strong>React</strong></td><td><a href="/pages/dwzC7qGMzj8DZoYmEdi5">/pages/dwzC7qGMzj8DZoYmEdi5</a></td></tr><tr><td align="center"><img src="/files/enkqAOrD5JqaMZnSLNTI" alt="" data-size="original"></td><td align="center"><strong>Java SDK</strong></td><td><a href="/pages/M49Dup7gNFA7GgWO7TU2">/pages/M49Dup7gNFA7GgWO7TU2</a></td></tr><tr><td align="center"><img src="/files/yXQAFoZTuiGLRY8rscAS" alt="" data-size="original"></td><td align="center"><strong>Node.js</strong></td><td><a href="/pages/wUGhgu41rrhmshqWOgDU">/pages/wUGhgu41rrhmshqWOgDU</a></td></tr><tr><td align="center"><img src="https://developer.harness.io/provider-logos/python-logo.svg" alt="Python SDK"></td><td align="center"><strong>Python SDK</strong></td><td><a href="/pages/0HBp8Zx2WSsj2tud8GDt">/pages/0HBp8Zx2WSsj2tud8GDt</a></td></tr><tr><td align="center"><img src="/files/pSnfLIeCWIbUqYGIboFk" alt="" data-size="original"></td><td align="center"><strong>.NET SDK</strong></td><td><a href="/pages/GX3SPITzEp8F3Gz1C6Yu">/pages/GX3SPITzEp8F3Gz1C6Yu</a></td></tr><tr><td align="center"><img src="/files/iV8qoC0fhM7nzwYPv0W2" alt="" data-size="original"></td><td align="center"><strong>Go SDK</strong></td><td><a href="/pages/F8pnEyyfCWslBkS6oUlU">/pages/F8pnEyyfCWslBkS6oUlU</a></td></tr></tbody></table>

### Decision engine <a href="#decision-engine" id="decision-engine"></a>

When you set up rules for your feature flags and experiments to be targeted to subsets of your customer base in Split (e.g., run a 50/50 test of a new home page on customers in New York), our SDKs automatically download down these rules and maintain a local copy of them on your machines. From there, our SDKs then take care of keeping themselves up to date by periodically checking for any changes to the rules that are made in the Split user interface.

When your application then loads for your customers, you can simply ask the SDK via a method called `getTreatment` to decide what variant of a feature the customer should see.

Since the SDK is maintaining a local copy of the rules that govern your features and experiments, it can simply reference that copy of your rules and make the decision to serve "on" or "off" to your customer without having to make a single remote call. From there, you can take the decision returned by our SDK and use that information to serve up the proper experience to your customer.

The `getTreatment` function requires a customer ID, which is usually a hash representation of the current session's customer. The SDK uses the customer ID when the feature flag includes percentage-based targeting rules (for example: 50% `"On"` and 50% `"Off"`). In this case, this is not relevant since we are assigning 100% of a single treatment. However, the SDK still requires the customer ID to calculate the treatment.

If the implementation will not use percentage-based treatments, then apply a dummy customer ID with any string value.

In this manner, our SDK is able to abstract out any need to hardcode this type of decision making in your application.

### Capturing what your customer was served <a href="#capturing-what-your-customer-was-served" id="capturing-what-your-customer-was-served"></a>

Each time our SDK makes a decision of what your customer should be served, it automatically takes that information and queues it up on your machines. The SDK then takes care of all the work in passing this information up to Split in the background without ever slowing down your application.

By capturing this information, you can easily understand what customers are being served and set the basis for being able to properly measure your experiments.

### Handling impressions and events load <a href="#handling-impressions-and-events-load" id="handling-impressions-and-events-load"></a>

{% hint style="danger" %}
**WHAT HAPPENS IF THE SDK CANNOT KEEP UP WITH THE INCOMING IMPRESSIONS AND EVENTS LOAD?**

The SDK will post the queue content when it becomes full. However, if the load consistently exceeds capacity, the queue will repeatedly fill and be posted, clearing it. Meanwhile, new impressions or events generated during this period are not stored because the queue is full, resulting in data loss.

Harness recommends verifying these SDK configuration parameters against your production generation rates for impressions and events, ensuring the SDK is properly configured to handle the load.
{% endhint %}

By default, all FME SDKs have configuration parameters that allow them to process a heavy load of generated Impressions and Events. These default parameter values are documented in the respective SDK documentation.

In the [Java SDK](/feature-management-experimentation/new-to-fme/sdks-and-customer-deployed-components/server-side-sdks/java-sdk.md#configuration), for example, the Configuration section includes parameters and default values for posting impressions:

* `impressionsRefreshRate = 60` (seconds)
* `impressionsQueueSize = 30k`

These settings mean the SDK can handle up to 30,000 impressions (each generated by a single `getTreatment` call) every 60 seconds.

If your application generates more than 30,000 impressions per minute, you will need to adjust these parameters. For instance, generating 60,000 impressions per minute could be handled by setting:

* `impressionsRefreshRate = 20` or `impressionsQueueSize = 70k`

Harness recommends providing some buffer so the SDK can handle the actual load. If the queue size is reached, the SDK will attempt to post its contents regardless of the impression post thread’s scheduled run time.

The same concept applies to events created using the SDK’s `track()` method.

The relevant Java SDK parameters for posting events are:

* `eventFlushIntervalInMillis = 30000` (30 seconds)
* `eventsQueueSize = 500`

These values allow the Java SDK to handle up to 1,000 events per minute.
