You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/guides/engineering/nextjs-setup.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -42,7 +42,7 @@ offlineInit({
42
42
43
43
This function is synchronous and ready to handle assignments after it returns.
44
44
45
-
Additional details are available in the [offline initialization documentation](/sdks/client-sdks/javascript#off-line-initialization) for the client SDK.
45
+
Additional details are available in the [offline initialization documentation](/sdks/client-sdks/javascript#offline-initialization) for the client SDK.
Copy file name to clipboardExpand all lines: docs/sdks/architecture/overview.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,7 +2,7 @@
2
2
sidebar_position: 2
3
3
---
4
4
5
-
# Architecture overview
5
+
# Overview
6
6
7
7
Eppo's SDK is designed to be lightweight and work alongside your existing stack. By using a "dumb server, smart client" architecture, the SDK can be thought of as a simple JSON delivery service. On initialization, the SDK will make a request to our CDN (built on [Fastly](https://www.fastly.com/)) to get a JSON containing active flags and targeting logic. Server-side SDKs will poll the CDN at a regular cadence to keep this config up to date.
Copy file name to clipboardExpand all lines: docs/sdks/client-sdks/ios.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -40,7 +40,7 @@ let assignment = try eppoClient.getStringAssignment(
40
40
);
41
41
```
42
42
43
-
During initialization, the SDK sends an API request to Eppo to retrieve the most recent experiment configurations: variation values, traffic allocation, etc. The SDK stores these configurations in memory, meaning assignments are effectively instant (accordingly, assignment is a synchronous operation). For more information, see the [architecture overview](/sdks/architecture) page.
43
+
During initialization, the SDK sends an API request to Eppo to retrieve the most recent experiment configurations: variation values, traffic allocation, etc. The SDK stores these configurations in memory, meaning assignments are effectively instant (accordingly, assignment is a synchronous operation). For more information, see the [architecture overview](/sdks/architecture/overview) page.
44
44
45
45
Eppo's SDK also supports providing the configuration directly at initialization. For more information, see the [initialization modes](#initialization-modes) section below.
During initialization, the SDK sends an API request to Eppo to retrieve the most recent experiment configurations (variation values, traffic allocation, etc.). The SDK stores these configurations in memory so that assignments are effectively instant. For more information, see the [architecture overview](/sdks/architecture) page.
82
+
During initialization, the SDK sends an API request to Eppo to retrieve the most recent experiment configurations (variation values, traffic allocation, etc.). The SDK stores these configurations in memory so that assignments are effectively instant. For more information, see the [architecture overview](/sdks/architecture/overview) page.
83
83
84
84
You can customize initialization and polling preferences by passing in additional [initialization options](#initialization-options).
After initialization, the SDK begins polling Eppo’s API at regular intervals to retrieve the most recent experiment configurations (variation values, traffic allocation, etc.). You can customize initialization and polling preferences by passing in additional [initialization options](#initialization-options).
64
64
65
-
The SDK stores these configurations in memory so that assignments thereafter are effectively instant. For more information, see the [architecture overview](/sdks/architecture) page.
65
+
The SDK stores these configurations in memory so that assignments thereafter are effectively instant. For more information, see the [architecture overview](/sdks/architecture/overview) page.
Eppo's SDKs all follow a similar architecture and interface. Whether you are using Eppo for feature gates, progressive rollouts, or randomized experiments, you can determine what variant a specific subject (e.g., user) should see with a call like this:
8
+
Eppo's SDKs are built for simplicity, speed, and reliability, and support everything from simple kill switches to cutting-edge experimentation methods. Developers only need to learn one simple, consistent API for all feature flagging and experiments use cases, abstracting away the complexity of the underlying allocation logic.
9
9
10
+
This page provides an introduction to Eppo's SDKs: the basics of keeping configurations in sync for users around the world, how the flag-assignment model supports a wide variety of use cases through simple concepts, and the design principles that help the SDK fit naturally into your tech stack and development workflows.
11
+
12
+
The examples on this page will all be in JavaScript, but Eppo supports a variety of languages and frameworks. You can find the complete list of SDKs on the [client SDK](/sdks/client-sdks) and [server SDK](/sdks/server-sdks) pages.
13
+
14
+
## Initialize once, assign anywhere
15
+
16
+
Eppo follows a "initialize once, evaluate anywhere" approach. On app start, initialize the SDK with a call like this:
17
+
18
+
```javascript
19
+
import { init } from"@eppo/js-client-sdk";
20
+
21
+
awaitinit({apiKey:"<SDK_KEY>"});
22
+
```
23
+
24
+
You can then evaluate flags anywhere in your app with the `get<Type>Assignment` method:
10
25
11
26
```javascript
27
+
import*asEppoSdkfrom"@eppo/js-client-sdk";
28
+
12
29
consteppoClient=EppoSdk.getInstance();
30
+
13
31
constvariation=eppoClient.getStringAssignment(
14
-
"<FLAG-KEY>",
15
-
"<SUBJECT-KEY>",
16
-
<SUBJECT-ATTRIBUTES>,
17
-
"<DEFAULT-VALUE>",
32
+
'show-new-feature', // flag key
33
+
user.id, // subject key
34
+
{}, // optional subject attributes for targeting
35
+
'control'// default value
18
36
);
19
37
```
20
38
21
-
Here,`FLAG-KEY` is a unique identifier for the feature of interest (e.g., `new_user_onboarding`). `SUBJECT-KEY` is a unique identifier for the unit on which you are assigning (e.g., `user_id`). `SUBJECT-ATTRIBUTES` provides subject-level properties for targeting (can be an empty object if none are needed). `DEFAULT-VALUE` is the value that will be returned if no allocation matches the subject, if the flag is not enabled, or if the SDK was not able to retrieve the flag configuration.
39
+
:::note
40
+
The examples on this page will focus on user-randomized experiments. Eppo's SDK can however be used to randomize on any unit (cookie, company ID, etc.). For these scenarios, simply pass in an appropriate identifier as the subject key and replace the word "user" with your unit of randomization.
41
+
:::
42
+
43
+
### Local evaluation
44
+
45
+
On initialization, SDK configurations are pulled from Eppo's CDN (hosted on Fastly). The CDN is globally distributed and for most regions returns the configuration within 20 ms. From there, flags are evaluated locally. That is, there are no additional network calls required to determine a user's variant. Accordingly, evaluation of a specific flag is incredibly fast (typically under 1 ms).
46
+
47
+
Targeting attributes are passed in as part of the `get<Type>Assignment` call, meaning that changes in eligibility based on user behavior are reflected immediately. Imagine a use case where you only want to target users once they perform a specific action. Server-side evaluation would require you to do a network call to understand new targeting eligibility each time the user context changes. By doing all evaluations locally, you can get very expressive with realtime targeting, all without any performance degradation.
48
+
49
+
For client SDKs, this [configuration is obfuscated](/sdks/sdk-features/obfuscation/) to ensure that end users cannot reverse engineer what flags are active, or what targeting logic is in place.
50
+
51
+
52
+
### Configurable polling
53
+
54
+
To keep targeting logic up to date, most of Eppo's SDKs provide automatic polling out of the box. Once the SDK is initialized, a background process runs to periodically check for new updates for the configuration file. This process is highly configurable, allowing you to set polling cadence, request timeouts, and much more.
55
+
56
+
### Offline initialization
57
+
58
+
Some teams prefer to manage the configuration file themselves as opposed to requesting it from Eppo's CDN on initialization. This is supported through [**offline mode**](/sdks/architecture/deployment-modes/#local-flag-evaluation-using-configurations-from-internal-server). Most server-side SDKs have the option to export configurations as JSON. You can then pass that JSON to your client-side applications via an internal endpoint as part of routine app start up. The client-side SDK can be initialized from this JSON directly, without any additional network calls to Eppo.
59
+
60
+
61
+
## Built for advanced allocation
62
+
63
+
Each flag in Eppo has a set of associated **assignments** specifying who should see what. These come in two flavors: feature gates (for a single variant) or experiments (for randomizing across multiple variants). These assignments are evaluated in a waterfall fashion allowing for complex rollouts while still providing an intuitive UI to understand who will see what:
64
+
65
+

66
+
67
+
In this example, when you evaluate the `add-profile-picture-nudge` flag, the SDK will first check if it's an internal user (based on the specified `user_id`). If so, it will return true, specifying to render the new feature. Otherwise, it will check the next condition: whether `has_profile_pic` is false. If so, it will randomly return either treatment or variant. This will continue for the rest of the waterfall and if no targeting conditions are met, it will return whatever is specified as the default value.
68
+
69
+
### Cascading hash-based randomization
70
+
71
+
Subsequent calls to the `get<Type>Assignment` method method will always return the same variant for a subject, as long as they are still in the same target audience. This is done using a set of cascading hash-based randomization functions to implement sampling, randomization, and any active holdouts or mutual exclusivity.
72
+
73
+
When you call `get<Type>Assignment`, the SDK will evaluate assignments in order until one is met, apply the cascading hashing described above, and deterministically return the correct variant. All of the underlying allocation logic is abstracted away from the engineer implementing the experiment.
74
+
75
+
### High quality data capture
76
+
77
+
Experimentation programs depend on high quality analytic data to track experiment assignments. Eppo's interface reinforces best practices: tracking *why* a user saw a variant (was it an override or a true randomized assignment?), identifying when a user moves from one target audience to another, and attributing experiment assignments to the precise moment a user was exposed to a new variant.
78
+
79
+
When you use Eppo's SDKs, you'll pass in a logging callback function at initialization:
80
+
81
+
```javascript
82
+
import { init } from"@eppo/js-client-sdk";
83
+
84
+
awaitinit({
85
+
apiKey:"<SDK_KEY>",
86
+
assignmentLogger,
87
+
});
88
+
```
89
+
90
+
This `assignmentLogger` function takes a single input: an Eppo-maintained `assignment` analytic event. This function is invoked each time the `get<Type>Assignment` method is called, meaning that once the SDK is installed in your application, engineers need to think about assignment logging. The `assignment`[analytic event](/sdks/event-logging/) contains all of the fields needed for Eppo's analytic engine, including targeting details and holdout group evaluations.
91
+
92
+
## Ergonomic API
93
+
94
+
Eppo's interface is designed to be intuitive and consistent. Whether you are using Eppo for a kill switch, targeted rollout, A/B/n experiment, dynamic configuration, mutual exclusive layer, or even a global holdout, your call to Eppo remains the same:
95
+
96
+
```javascript
97
+
get<Type>Assignment: (
98
+
flagKey: string,
99
+
subjectKey: string,
100
+
subjectAttributes: Record<string, any>,
101
+
defaultValue:<Type>,
102
+
) =><Type>
103
+
```
104
+
105
+
Note that flags in Eppo all have an associated type, specified upon creation in the UI. Each of these types has a corresponding function to evaluate. To read more, see our page on [flag types](/sdks/sdk-features/flag-types).
106
+
107
+
## Flags for all of your environments
108
+
109
+
Modern software teams need to manage flags across both environments (local, staging, production, etc.) and across surface areas (mobile apps, web clients, servers, etc.).
110
+
111
+
Eppo allows you to easily manage flags across both of these dimensions. Unlimited environments can be created in the UI to match your development process. You can then, for instance, turn a flag on for all traffic in your local or staging environments without impacting production.
112
+
113
+
You can also manage what instances of the SDK should have which flags. For example, you may want to load a different set of flags for your mobile applications than you do for your backend server, or even match flags to specific app versions. This helps manage the SDK configuration file size as your number of flags increases over time.
114
+
115
+
116
+
## Navigating the docs
117
+
118
+
We hope that you are excited to explore how Eppo can fit into your work stream and tech stack. To start integrating Eppo, check out our getting started guides on [creating your first flag](/feature-flag-quickstart/) and [running your first experiment](/experiment-allocation-quickstart/).
119
+
120
+
The read more about our specific SDKs, check out the SDK-specific docs below:
121
+
122
+
### Client SDKs
123
+
124
+
-[JavaScript](client-sdks/javascript)
125
+
-[React Native](client-sdks/react-native)
126
+
-[Android](client-sdks/android)
127
+
-[iOS](client-sdks/ios)
128
+
129
+
130
+
### Server SDKs
131
+
132
+
-[Node](server-sdks/node)
133
+
-[Java](server-sdks/java)
134
+
-[Python](server-sdks/python)
135
+
-[Go](server-sdks/go)
136
+
-[Rust](server-sdks/rust)
137
+
-[Ruby](server-sdks/ruby)
138
+
-[.NET](server-sdks/dotnet)
139
+
-[PHP](server-sdks/php)
140
+
141
+
### Hybrid implementations
22
142
23
-
For experimentation use cases, Eppo uses a deterministic hashing function to ensure that the same variant is returned for a given `SUBJECT-KEY`. This guarantee also holds across different SDKs. That is, experiment assignments from a server SDK will be consistent with experiment assignments from a client SDK for the same `SUBJECT-KEY`.
143
+
If you'd like to explore managing the Eppo configuration file yourself, or other advanced deployment options, check out our [deployment modes page](/sdks/architecture/deployment-modes). If you are using Next JS, see our [Next JS setup guide](/guides/engineering/nextjs-setup).
24
144
25
-
Before using the Eppo SDK, you'll need to [generate an SDK key](/sdks/sdk-keys) and [create a logging callback function](/sdks/event-logging).
145
+
## Getting help
26
146
27
-
You can read more about our specific SDKs here:
28
-
1.[Client SDKs](/sdks/client-sdks)
29
-
2.[Server SDKs](/sdks/server-sdks)
147
+
At Eppo we strive to keep our documentation thorough, up to date, and intuitive. If you find any gaps or sections that could be more clear, don't hesitate to file an issue on our public documentation [Github repository](https://github.com/Eppo-exp/eppo-docs/).
Copy file name to clipboardExpand all lines: docs/sdks/sdk-features/bandits.md
+2-1Lines changed: 2 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -89,7 +89,8 @@ Therefore, the logger should write to a table with the following columns (they c
89
89
| action_numeric_attributes (JSON) | Metadata about numeric attributes of the assigned action; Mapping of attribute names to their values | {"discount": 0.2} |
90
90
| action_categorical_attributes (JSON) | Metadata about non-numeric attributes of the assigned action; Mapping of attribute names to their values | {"promoTextColor": "white"} |
91
91
92
-
:::info Assignment attributes must be single-level. Eppo's bandits do not support multiple levels of JSON attributes.
92
+
:::note
93
+
Assignment attributes must be single-level. Eppo's bandits do not support multiple levels of JSON attributes.
93
94
:::
94
95
95
96
We also recommend storing additional information that is provided to the bandit logger that is not directly used for training the bandit, but is useful for transparency and debugging:
Copy file name to clipboardExpand all lines: docs/sdks/server-sdks/dotnet.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -27,7 +27,7 @@ var eppoClientConfig = new EppoClientConfig(apiToken, new AssignmentLogger());
27
27
vareppoClient=EppoClient.Init(eppoClientConfig);
28
28
```
29
29
30
-
After initialization, the SDK begins polling Eppo's API at regular intervals to retrieve the most recent experiment configurations such as variation values and traffic allocation. The SDK stores these configurations in memory so that assignments thereafter are effectively instant. For more information, see the [architecture overview](/sdks/architecture) page.
30
+
After initialization, the SDK begins polling Eppo's API at regular intervals to retrieve the most recent experiment configurations such as variation values and traffic allocation. The SDK stores these configurations in memory so that assignments thereafter are effectively instant. For more information, see the [architecture overview](/sdks/architecture/overview) page.
31
31
32
32
If you are using the SDK for experiment assignments, make sure to pass in an assignment logging callback (see [section](#define-an-assignment-logger-experiment-assignment-only) below).
0 commit comments