# Go v2.1.X

### Introduction

#### SDK overview

Welcome to the Flagship Go SDK documentation!

The following documentation will help you get Flagship running in your Go environment (server-side) with preconfigured methods to implement the Decision API & Bucketing.

Feel free to [contact us](mailto:product.feedback@abtasty.com?subject=Flagship%20Developer%20Documentation) if you have any questions regarding this documentation.

#### SDK features

That SDK version helps you :

* Set a [visitor ID](https://docs.abtasty.com/server-side/glossary#visitor-id)
* Update [user context](https://docs.abtasty.com/server-side/glossary#user-context)
* Assign campaigns via the [Decision API](https://docs.abtasty.com/server-side/decision-api) or the [Bucketing](https://docs.abtasty.com/server-side/concepts/bucketing)
* Get modifications
* Activate campaigns
* Send hits to our [Universal Collect](https://docs.abtasty.com/server-side/concepts/universal-collect-1)

#### Prerequisites

* This SDK requires **Go 1.12** version or later to work
* Your server/device must have an access to the internet.

#### Good to know

* Github repository: <https://github.com/flagship-io/flagship-go-sdk>
* Open source demo app: <https://github.com/flagship-io/flagship-go-sdk/tree/master/examples/ecommerce>

### Getting Started

#### Installation

Follow these steps to install the Go SDK

**Install from github**

To install from github, just run a `go get` to add the SDK to your GOPATH

`go get github.com/abtasty/flagship-go-sdk/v2`

**Install from source**

To install from github, just run a `go get` to add the SDK to your GOPATH,\
and run a `go install` to add the library to your installed dependencies.

`go get github.com/abtasty/flagship-go-sdk/v2`

`cd $GOPATH/src/github.com/abtasty/flagship-go-sdk`

`go install`

**Install using go.mod**

Add the Flaship SDK dependency to your go.mod file and

```go
module mymodule

go 1.12

require (
	github.com/abtasty/flagship-go-sdk/v2 v2.0.2
)
```

If you are already using go.mod in your application you can run the following:

`go mod edit -require github.com/abtasty/flagship-go-sdk/v2@v2.0.2`

#### Initialization

**Environment ID**

You can find your environment id in the parameters\integration section of your Flagship account. (Check [Getting Started](https://github.com/flagship-io/Gitbook/blob/main/docs/getting-started/README.md))

```go
// Using the Decision API (default)
fsClient, err := flagship.Start(environmentID, apiKey)

// Using the Bucketing mode
fsClient, err := flagship.Start(environmentID, apiKey, client.WithBucketing())
```

To initialize and start the library, just call the *Start* function of the *flagship* package,\
using the bucketing function builder if you want to use the bucketing mode

The start function return a Flagship client instance for your environment.

| Parameter      | Type               | Description                                  |
| -------------- | ------------------ | -------------------------------------------- |
| envId          | string             | Environment id provided by Flagship.         |
| apiKey         | string             | Api authentication key provided by Flagship. |
| optionBuilders | Variadic functions | Option builder functions.                    |

{% hint style="info" %}
📘 You can find your `apiKey` and your `environmentId` on your Flagship account, in Parameters > Environment & Security. [**Find this ID**](https://docs.abtasty.com/server-side/readme)
{% endhint %}

#### Decision Mode

**`DECISION_API`Mode**

When the SDK is running in `DECISION_API` mode, the campaign assignments and targeting validation take place server-side.\
In this mode, each call to the `SynchronizeModifications` method to refresh the modifications will create an HTTP request.

**`BUCKETING`Mode**

When the SDK is running in `BUCKETING` mode, the SDK downloads all the campaigns configurations at once in a single bucketing file so that variation assignment can be computed client-side by the SDK.\
This bucketing file is stored in cache and will only be downloaded again when campaign configurations are modified in the Flagship interface.\
It is possible to configure the interval of polling refresh with the PollingInterval configuration builder.

#### Options

**`func decision.WithDecisionAPI(...apiOptionBuilder): Builder`**

Start Flagship SDK in `DECISION API` mode (which is the default).\
`apiOptionBuilders` functions allows you to customize the API engine.

| Parameter         | Type               | Description                       |
| ----------------- | ------------------ | --------------------------------- |
| apiOptionBuilders | Variadic functions | option builder for the Bucketing. |

**`func decisionapi.Timeout((timeout time.Duration)`**

API Option builder that sets the Decision API URL for the `DECISION API` mode.\
Useful to prevent the Decision API calls from having performance impacts on your app.\
If the Decision API call throws a timeout, then default modification values will be returned when calling `GetModifications`.

| Parameter | Type          | Description                   |
| --------- | ------------- | ----------------------------- |
| timeout   | time.Duration | The Decision API call timeout |

**`func WithBucketing(...bucketingOptionBuilder)`**

Start Flagship SDK in `BUCKETING` mode (client-side) instead of `DECISION API` mode.\
`bucketingOptionBuilder` functions allows you to customize the bucketing engine.

| Parameter               | Type               | Description                       |
| ----------------------- | ------------------ | --------------------------------- |
| bucketingOptionBuilders | Variadic functions | option builder for the Bucketing. |

**`func PollingInterval(interval time.Duration)`**

Set the polling interval for the bucketing engine (set by default to 60 seconds).

| Parameter | Type          | Description                             |
| --------- | ------------- | --------------------------------------- |
| interval  | time.Duration | The polling interval for the bucketing. |

#### Create a visitor

The SDK provides a method create a new visitor with an ID and a context.

The context is a property dataset which defines the current user of your app. This dataset is sent and used by the Flagship decision API as targeting for campaign allocation. For example, you could pass a VIP status in the context and then the decision API would enable or disable a specific feature flag.

{% hint style="info" %}
📘 Visitor context values are used to match a visitor to the targeting of a campaign
{% endhint %}

{% hint style="info" %}
📘

Visitor context values type must be:

* string
* Number (int or float64)
* bool
  {% endhint %}

```go
// Create visitor context
context := map[string]interface{}{
  "isVip": true,
  "age": 30,
  "name": "visitor",
}
// Create a visitor
fsVisitor, err := fsClient.NewVisitor("visitor_id", context)
```

The NewVisitor function takes the following parameters:

| Parameter      | Type                    | Description                                                                                             |
| -------------- | ----------------------- | ------------------------------------------------------------------------------------------------------- |
| VisitorID      | string                  | The ID of the visitor (must be unique for a visitor)                                                    |
| Context        | map\[string]interface{} | The context of the visitor. It should match those defined in your campaigns to target your users on it. |
| visitorOptions | Variadic functions      | Option builder functions.                                                                               |

**Visitor Options**

**`func decision.WithAuthenticated(isAuthenticated bool)`**

Specify if the visitor starts as authenticated or anonymous, if you plan on using the [Experience Continuity](https://docs.abtasty.com/server-side/concepts/experience-continuity)

| Parameter       | Type | Description                                         |
| --------------- | ---- | --------------------------------------------------- |
| isAuthenticated | bool | Should the visitor ID be authenticated or anonymous |

## Updating the visitor Context

The visitor context can be updated in case some context linked to your visitor has changed.\
The SDK provides 2 methods to change the visitor context:

* Either change a single key of the context
* Or replace the whole context with a new one

```go
// Update a single key
fsVisitor.UpdateContextKey("vipUser", true)
fsVisitor.UpdateContextLey("age", 30)

// Update the whole context
newContext := map[string]interface{}{
  "isVip": true,
  "age": 30,
  "name": "visitor",
}
fsVisitor.UpdateContext(newContext)
```

### UpdateContextKey(key string, value interface{})

This functions update the visitor context value matching the given key.\
A new context value associated with this key will be created if there is no previous matching value.

| Parameter | Type        | Description                               |
| --------- | ----------- | ----------------------------------------- |
| key       | string      | key to associate with the following value |
| value     | interface{} | new context value                         |

### UpdateContext(newContext map\[string]interface{})

| Parameter  | Type                    | Description                               |
| ---------- | ----------------------- | ----------------------------------------- |
| newContext | map\[string]interface{} | key to associate with the following value |

{% hint style="info" %}
📘 Visitor context values type must be:

* string
* Number (int or float64)
* bool
  {% endhint %}

## Campaign synchronization

### Synchronizing campaigns

Synchronizing campaign modifications allows you to automatically call the Flagship decision API (or bucketing file), which makes the allocation according to user context and gets all their modifications.

All the applicable modifications are stored in the SDK and are updated synchronously when `SynchronizeModifications()` is called.

This function has no parameters

```go
fsVisitor.SynchronizeModifications()
```

{% hint style="warning" %}
🚧 SynchronizeModifications must be called before trying to get a modification value
{% endhint %}

### Getting modifications

Once the campaign has been **allocated** and **synchronized** all the modifications are stored in the SDK. Then, you can retrieve them with the following functions:

```go
discountName, err := fsVisitor.GetModificationstring("discountName", "Black Friday", true);

// If there is not error (and if there is, your value will still be set to defaut), you can use your modification value in your business logic
discountValue := getDiscountFromDB(discountName)
```

* Get Modification for Number value:\
  \
  \&#xNAN;**`func (v *FlagshipVisitor) GetModificationNumber(key string, defaultValue float64, activate bool) (castVal float64, err error)`**
* Get Modification for String value:\
  \
  \&#xNAN;**`func (v *FlagshipVisitor) GetModificationString(key string, defaultValue string, activate bool) (castVal string, err error)`**
* Get Modification for Boolean value:\
  \
  \&#xNAN;**`func (v *FlagshipVisitor) GetModificationBool(key string, defaultValue bool, activate bool) (castVal bool, err error)`**
* Get Modification for Object value:\
  \
  \&#xNAN;**`func (v *FlagshipVisitor) GetModificationBool(key string, defaultValue map[string]interface{}, activate bool) (castVal map[string]interface{}, err error)`**
* Get Modification for Array value:\
  \
  \&#xNAN;**`func (v *FlagshipVisitor) GetModificationBool(key string, defaultValue []interface{}, activate bool) (castVal []interface{}, err error)`**

| Parameter    | Type                                                           | Required | Description                                                                                                                                                                                                                  |
| ------------ | -------------------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| key          | string                                                         | Yes      | key associated to the modification.                                                                                                                                                                                          |
| defaultValue | string, bool, float64, map\[string]interface{}, \[]interface{} | Yes      | default value returned when the key **doesn't match any modification value**.                                                                                                                                                |
| activate     | bool                                                           | No       | **false by default** Set this parameter to **true** to automatically report on our server that the current visitor has seen this modification. If false, call the [activateModification()](#activating-modifications) later. |

### Getting campaign information

You may need to send campaign IDs to a third-party for reporting and/or analytics purposes. It is now possible to retrieve **campaign IDs** for a specific modification key.

```go
infos, err := fsVisitor.GetModificationInfo("visitor_id")
```

**`func (v *Visitor) GetModificationInfo(key string) (modifInfo *ModificationInfo, err error)`**

| Parameter | Type | Description                           |
| --------- | ---- | ------------------------------------- |
| key       | str  | Key associated with the modification. |

It returns a struct containing `CampaignId`, `VariationGroupID`, `VariationID`, `Value` (modification key value), or `nil` if the modification is not found (i.e. user does not belong to the campaign).

#### Activating modifications

Once a modification has been printed on the screen for a user, you must send an activation event to tell Flagship that the user has seen this specific variation.

```go
// Activate the modification automatically when retrieving it
color, err := Flagship.GetModificationString("discountName", "Black Friday", true)

// ---OR---

// Activate the modification later on manually
err := Flagship.ActivateModification("discountName")
```

**`func (v *FlagshipVisitor) ActivateModification(key string)`**

| Parameter | Type   | Description                           |
| --------- | ------ | ------------------------------------- |
| key       | String | key which identifies the modification |

## Experience Continuity

Dealing with anonymous and logged-in users, experience continuity allows you to maintain consistency between sessions and devices.

{% hint style="warning" %}
🚧 Make sure that the experience continuity option is enabled on the flagship platform before using those methods.
{% endhint %}

### Authenticate

**`func authenticate(newID string, newContext map[string]interface{}, sync bool)`**

| Parameter  | Type                    | Description                                                                                                                                                       |
| ---------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| newID      | string                  | new ID of the new authenticated visitor.                                                                                                                          |
| newContext | map\[string]interface{} | (optional) Replace the current visitor context. Passing nil wont replace context and will insure consistency with the previous visitor context.                   |
| sync       | bool                    | if true, the SDK will automatically update the campaigns modifications. You also have the possibility to update it manually by calling synchronizeModifications() |

### Unauthenticate

**`func unauthenticate(newContext map[string]interface{}, sync bool)`**

| Parameter  | Type                    | Description                                                                                                                                                       |
| ---------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| newContext | map\[string]interface{} | (optional) Replace the current visitor context. Passing nil wont replace context and will insure consistency with the previous visitor context.                   |
| sync       | bool                    | if true, the SDK will automatically update the campaigns modifications. You also have the possibility to update it manually by calling synchronizeModifications() |

### Example code

```go
// Your visitor logs in
user := getUser(session)

// Update the new context with your user data
newContext := map[string]interface{}{
  "session_id": session.ID,
  "age": user.Age,
  "name": user.Name,
}

// Updates the Flagship visitor ID, the new context and resynchronize campaigns
err := fsVisitor.Authenticate("logged_in_id", newContext, true)

// Get the new modification value when retrieving it
discountName, err := Flagship.GetModificationString("discountName", "Black Friday", true)

// Use your modification inside your code
price := getPrice(discountName)

// ...
// Then later on, when your visitor logs out, you can unauthenticate the visitor
// and clear the context
newContext = map[string]interface{}{
  "session_id": "sessionID",
}
err := fsVisitor.Unauthenticate(newContext, true)
```

## Hit Tracking

This section helps send tracking and learn how to build hits in order to aprove campaign goals.

The different types of Hits are:

* [Page](#page)
* [Screen](#screen)
* [Transaction](#transaction)
* [Item](#item)
* [Event](#event)

**They must all be built and sent with the following function:**

**`func (v *FlagshipVisitor) SendHit(hit model.HitInterface) (err error)`**

### Common parameters

These parameters can be sent with any type of hit.

\\

| Parameter               | Type   | Description                            |
| ----------------------- | ------ | -------------------------------------- |
| UserIP                  | String | **optional** User IP                   |
| ScreenResolution        | String | **optional** Screen Resolution.        |
| UserLanguage            | String | **optional** User Language             |
| CurrentSessionTimeStamp | Int64  | **optional** Current Session Timestamp |
| SessionNumber           | Int    | **optional** Session Number            |

### Hit types

#### Page

```go
fsVisitor.SendHit(&model.PageHit{
  DocumentLocation: "http://localhost:8080",
})
```

This hit should be sent each time a visitor arrives on a new interface.

| Hit parameter    | Type   | Required | Description                          |
| ---------------- | ------ | -------- | ------------------------------------ |
| DocumentLocation | String | Yes      | URL of the page, must be a valid URL |

#### Screen

```go
fsVisitor.SendHit(&model.ScreenHit{
  DocumentLocation: "My page name",
})
```

This hit should be sent each time a visitor arrives on a new interface.

| Hit parameter    | Type   | Required | Description      |
| ---------------- | ------ | -------- | ---------------- |
| DocumentLocation | String | Yes      | Name of the page |

#### Transaction

This hit should be sent when a user complete a Transaction.

```go
fsVisitor.SendHit(&model.TransactionHit{
  TransactionID: "YOUR_TRANSACTION_ID",
  Affiliation: "GOAL_NAME", // The goal name set in Flagship campaign
  Revenue: 100,
  Shipping: 10,
  Tax: 5,
  Currency: "EUR",
  CouponCode: "discount",
  PaymentMethod: "Card",
  ShippingMethod: "postal",
  ItemCount: 2,
})
```

| Hit Parameter  | Type    | Required | Description                                                                                                      |
| -------------- | ------- | -------- | ---------------------------------------------------------------------------------------------------------------- |
| TransactionId  | String  | Yes      | Transaction unique identifier.                                                                                   |
| Affiliation    | String  | Yes      | Transaction name. Name of the goal in the reporting.                                                             |
| Revenue        | Float64 | No       | Total revenue associated with the transaction. This value should include any shipping or tax costs.              |
| Shipping       | Float64 | No       | Specifies the total shipping cost of the transaction.                                                            |
| ShippingMethod | String  | No       | Specifies the shipping method of the transaction.                                                                |
| Tax            | Float64 | No       | Specifies the total taxes of the transaction.                                                                    |
| Currency       | String  | No       | Specifies the currency used for all transaction currency values. Value should be a valid ISO 4217 currency code. |
| PaymentMethod  | String  | No       | Specifies the payment method for the transaction.                                                                |
| ItemCount      | Int     | No       | Specifies the number of items for the transaction.                                                               |
| CouponCode     | String  | No       | Specifies the coupon code used by the customer for the transaction.                                              |

#### Item

```go
fsVisitor.SendHit(&model.ItemHit{
  TransactionID: "YOUR_TRANSACTION_ID", // Must be the same as for the Transaction Hit
  Name: "t-shirt",
  Category: "Clothes",
  Code: "SN123456",
  Quantity: 5,
  Price: 25.4,
})
```

This hit is linked to a transaction. It must be send after the corresponding transaction.

**`class Item(transactionId: String, productName: String) : HitBuilder<Item>()`**

| Hit Parameter | Type    | Required | Description                     |
| ------------- | ------- | -------- | ------------------------------- |
| TransactionId | String  | Yes      | Transaction unique identifier.  |
| Name          | String  | Yes      | Product name.                   |
| Price         | Float64 | No       | Specifies the item price.       |
| Code          | String  | Yes      | Specifies the item code or SKU. |
| Category      | String  | No       | Specifies the item category.    |
| Quantity      | Int     | No       | Specifies the item quantity     |

{% hint style="danger" %}
❗️ The `Item` hit isn't available yet in the Flagship reporting view.
{% endhint %}

#### Event

```go
fsVisitor.SendHit(&model.EventHit{
  Action: "GOAL_NAME", // The event goal name set in the Flagship campaign
  Category: "Action Tracking",
  Label: "Event label",
  Value: 5,
})
```

This hit can be anything you want: for example a click or a newsletter subscription.

| Hit Parameter | Type   | Required | Description                                                     |
| ------------- | ------ | -------- | --------------------------------------------------------------- |
| Category      | String | Yes      | category of the event ("Action Tracking" or "User Engagement"). |
| Action        | String | Yes      | the event action.                                               |
| Label         | String | No       | label of the event.                                             |
| Value         | Number | No       | Specifies a value for this event. must be non-negative.         |

## Appendix

### Implementation sample

```go
// Start SDK
fsClient, _ := flagship.Start(ENVIRONMENT_ID, API_KEY)
// if err != nil

// Create a visitor
fsVisitor, _ := fsClient.NewVisitor("visitor_123", nil)
// if err != nil

// Update context to target visitors & synchronize
_ = fsVisitor.UpdateContext(map[string]interface{}{
	"vip": true,
})
// if err != nil
fsVisitor.SynchronizeModifications()

featureTitle, _ := fsVisitor.GetModificationString("feature_title", "default_title", false)
_ = fsVisitor.ActivateModification("feature_title")

fmt.Println("featureTitle", featureTitle)

// Send hit
fsVisitor.SendHit(&model.EventHit{
	Action: "feature_click",
})
```

### API reference

<https://godoc.org/github.com/abtasty/flagship-go-sdk>
