# Getting Started

Welcome to the Lucky Orange developer documentation.

{% hint style="info" %}
New to Lucky Orange? This documentation covers how to implement Lucky Orange from a technical point-of-view. If you'd like to learn more about the features offered by Lucky Orange, take a look at our [Help Center](https://help-preview.luckyorange.com).
{% endhint %}

## Choose your environment

{% content-ref url="/pages/-MWBAjrefRQ36-Nh9KiH" %}
[Browser](/libraries/browser)
{% endcontent-ref %}

{% content-ref url="/pages/-MWBAw6Y6Oho3Ow5a-d8" %}
[Node.js](/libraries/node)
{% endcontent-ref %}

## Looking for Lucky Orange Classic?

The developer documentation found here is for the new Lucky Orange. The developer API has been completely overhauled to be more consistent, powerful, and easier to use. If you are using Lucky Orange Classic, please see the [existing help documentation](https://help.luckyorange.com/).

Even though the API has completely changed, in order to help with the transition, the new browser library offers various backwards compatible functionality. Use the link below to learn more about how to migrate.

{% content-ref url="/pages/-MWPH2MK6JmJ3AOF2pYi" %}
[Moving From Classic](/moving-from-classic)
{% endcontent-ref %}


# Moving From Classic

If you are using the classic version of Lucky Orange and want to move to the latest version, use this guide to see what you need to change to make the migration as smooth as possible.

## Testing the latest version

The latest version of browser library can be used alongside the classic version. Both versions will track independently so you can test the new version without worrying about causing any issues for your existing sites.

If you are running both versions of the browser library at the same time, their `LO` API methods will be merged together on a single object. For example, you will have access to both `LO.get_recording_id()` and `LO.sessions.getSessionId()`.

## Backwards Compatibility

If you are already using the existing on page `LO` API, certain functionality will continue to work seamlessly with the latest version.

### Tracking behavior tags as events

If you are using the existing [Javascript Behavior Tagging API](https://help.luckyorange.com/article/126-tagging-with-javascript), those tags will automatically be tracked as events using the new version.

### Using custom data to identify visitor profiles

If you are using the existing [Custom Data API](https://help.luckyorange.com/article/41-passing-in-custom-user-data) to add data to recordings, that custom data will now automatically be used to identify the active visitor profile.


# Browser

Use the browser library to take advantage of features such as Session Recordings, Live Chat, Announcements and Surveys.

## Installation

Lucky Orange can currently be used in a browser environment through the use of an HTML snippet, but with an `npm` package coming soon.

#### HTML Snippet

You can place the following snippet wherever you'd like, but we generally recommend placing in before the closing `</head>` tag in your document. The snippet will append a new `<script>` tag to the document that will load with the `async` attribute in order to prevent blocking the rest of the page from being evaluated while the script is being loaded.

You will need to replace `YOUR-SITE-ID` with the unique ID of the site you wish to connect to.

```markup
<script async defer src="https://tools.luckyorange.com/core/lo.js?site-id=YOUR-SITE-ID"></script>
```

#### NPM Package

Coming soon.

## Usage

Out of the box, Lucky Orange will automatically be set up for all features available in the app itself. Sessions and visitor profiles will be created for any new visitors to your website. All features can be controlled from the app without having to make changes to the code implementation.

That being said, a robust developer API exists on the page to support more advanced use cases.&#x20;

After you have installed Lucky Orange, you will now have access to the `LO` object. If you installed using the HTML snippet, `LO` will exist on the top level `window` in the page once the script has loaded.

### Ensure Lucky Orange is ready

Before you can use the `LO` object, you need to make sure it has loaded. You can use the `ready` callback to trigger any code that relies on `LO` existing. You will also need to make sure that you `await` the module on `LO` that you are trying to use.

```javascript
window.LOQ = window.LOQ || []
window.LOQ.push(['ready', async LO => {
    // Track an event
    await LO.$internal.ready('events')
    LO.events.track('My Event')
    
    // Or, identify a visitor
    await LO.$internal.ready('visitor')
    LO.visitor.identify({ email: 'test@example.com' })
}])
```

If you are using GTM to place the code you will need use ES5 syntax instead of the ES6 syntax above.&#x20;

```javascript
window.LOQ = window.LOQ || []
window.LOQ.push(['ready', function (LO) {
    // Track an event
    LO.$internal.ready('events').then(function() {
        LO.events.track('My Event')
    })

    // Or, identify a visitor
    LO.$internal.ready('visitor').then(function() {
        LO.visitor.identify({ email: 'test@example.com' })
    })
}])
```

{% hint style="danger" %}
If you do not use the `ready` callback or `$internal.ready()` functions, you are likely to see errors such as "LO is not defined" or "Cannot read property of undefined."
{% endhint %}

### Link your users to visitor profiles in Lucky Orange

For each new visitor to your website, a visitor profile is created within Lucky Orange. By default, session information such as browser, device, and geolocation data will be associated with the profile and an anonymous name will be given (Ex. Blue Apple). To better align these anonymous profiles with your own user information, use the `identify()` API. You can pass in a custom user ID and any arbitrary profile data. This data can then be used as filters throughout the app.

Certain keywords are already associated with each Lucky Orange visitor profile by default. These include name, email, and phone and can optionally be included in the meta object. Passing in any of these will update the corresponding field in the visitor profile. Including the name will update the visitor row in the visitors table to help better identify the visitor. The name passed in must be a string, as seen below.&#x20;

```javascript
LO.visitor.identify('test-user-123', { email: 'test@example.com', name: 'Test Name' })
```

### Track events

Out of the box, Lucky Orange will automatically track various behaviors throughout a visitor's session. Viewing surveys, clicking buttons, etc. are just a few examples of these behaviors. To track specific business metrics, you can use the `track()` API. Events tracked using this API are automatically associated to the active visitor's profile, can be used as Announcement triggers, and act as filters throughout the app.

Events require a name and, optionally, can take in any arbitrary metadata that can help give context to an event.

```javascript
LO.events.track('Account Created', { acceptedTerms: true })
```

### Debugging

If you feel like the browser library is behaving in a way that you do not expect, you can turn on debug logging by setting a `debug` key in `localStorage`.

```javascript
window.localStorage.setItem('debug', '*')
```

Setting this will begin logging `[LO]` prefixed messages to your browser's console. There can potentially be a lot of information, but it will give you a clear picture into what Lucky Orange is currently doing.


# Chat

Lucky Orange provides a robust messenger tool that handles displaying surveys, announcements, chat invites, and the ability to interact with your support team.

## Trigger Chat Programmatically&#x20;

By default, chat is only opened when a visitor clicks on the chat launcher displayed on your site. If you would like a button or another element on your site to control the chat state, you can take advantage of the messenger API.&#x20;

Utilizing the `LO.messenger` API, you can control the state by calling `open()` or `close()` .

```javascript
function openChat () {
    LO.messenger.open()
}

function closeChat () {
    LO.messenger.close()
}
```

{% hint style="warning" %}
The `LO.messenger` API is only available once chat has been set up for your site.
{% endhint %}

The chat launcher can also be completely hidden, should you desire to control the chat state exclusively through an element on your site. You can find this and other chat launcher settings in the Lucky Orange app under the **Chat Settings** tab, located within your site's **Settings** section.&#x20;


# Content Security Policy

A common layer of security used by many websites is a [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP). These policies help prevent unauthorized access to website visitor data, and can help mitigate certain types of website attacks. If your website employs the use of a CSP, it will be important to whitelist the Lucky Orange tracking script in order for features like recordings, chat, and the heatmap tool to function properly.

## Necessary policy additions

<table data-header-hidden><thead><tr><th width="140.76953125">Directive</th><th width="520.7578125">Value</th></tr></thead><tbody><tr><td>Directive</td><td>Value</td></tr><tr><td><strong>connect-src</strong></td><td><p>https://*.luckyorange.com</p><p>https://pubsub.googleapis.com</p><p>wss://*.visitors.live</p></td></tr><tr><td><strong>script-src</strong></td><td>https://tools.luckyorange.com<br>https://storage.googleapis.com/lucky-orange-public/heatmap2/*</td></tr><tr><td><strong>worker-src</strong></td><td>blob:</td></tr></tbody></table>

{% hint style="info" %}
**Note:** The `blob:` directive is used to improve the performance of our code by performing certain actions within a web worker. The `googleapis.com` directive is used as fallback in the rare event our own data ingestion pipeline is unavailable.
{% endhint %}

{% hint style="info" %}
Note: The `https://storage.googleapis.com/lucky-orange-public/heatmap2/*` directive is used by our heatmap tool. You do not need to add this if you do not plan to use our heatmap tool.&#x20;
{% endhint %}

{% hint style="warning" %}
**Note:** For most sites, the additions in the table above will be enough. However, if you notice live chat, surveys, or announcements that are not being triggered and you aren't able to see live visitors, you may need to add the below additional value to the **connect-src** directive. You can check for errors in the console of the tracked site or reach out to Lucky Orange support if you are unsure.

`wss://realtime.luckyorange.com/mqtt`
{% endhint %}


# Cookies & Storage

This page contains a list of all cookies and other storage technologies that might be used by the browser library.

## Why Cookies?

Whether it is privacy regulation or third-party cookie blocking by browser vendors, cookies have a lot of baggage associated with them. Lucky Orange only uses cookies in situations where it is helpful to store information across subdomains within a single website. For example, it is helpful to identify a single visitor across app.example.com and [www.example.com](http://www.example.com). **Lucky Orange never uses third-party cookies**.

### Cookie disclosure

| Name            | Purpose                                                                                                                             | Expiration |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ---------: |
| lo-domain-check | Created temporarily to determine the top-level domain for the website and then immediately deleted.                                 |  Instantly |
| lo-opt-out      | Indicates that the visitor has opted out of tracking and will prevent the browser library from running.                             |    2 Years |
| lo-uid          | Identifies the visitor using a unique ID. Related sessions, events, and conversations are linked to a single visitor using this ID. |    2 Years |
| lo-visits       | Keeps a count of the number of unique sessions for a visitor. This is represented as the "Visit #" in the app.                      |    2 Years |

{% hint style="info" %}
All cookies are **secure**, have **samesite set to strict**, and have an **explicitly set domain.**
{% endhint %}

## Local Storage

All other data is stored within the browser's local storage. To keep things clean, instead of creating many top level keys, there are three keys that contain well structured objects that explain exactly what Lucky Orange is storing:

* `lo-session`
* `lo-messenger` (Only used when taking advantage of Announcements, Chat, or Surveys)
* `lo-visitor`


# Privacy Tools

Lucky Orange takes privacy and privacy regulation very seriously. The browser library provides powerful tools to make compliance with privacy regulation simple and easy to implement.

## Require consent

By default, Lucky Orange creates a visitor profile and session immediately after it has been loaded. If your website requires opting-in to tracking features, or you'd rather just control the session lifecycle yourself, you can take advantage of the consent API.

Part of the `LO.privacy` API, you can control consent by calling `setConsentStatus()` whenever your visitor has provided consent. If the status is set to `true` and was previously `false`, a new session recording will automatically begin.

```javascript
function onOptIn () {
    LO.privacy.setConsentStatus(true)
}
```

You can check if consent is current given using the following method:

```javascript
LO.privacy.getConsentStatus()
```

Finally, you'll need to toggle "Require Consent" in your site's [privacy settings](https://app.luckyorange.com/settings/app/privacy):

![](/files/-MlC19sNldGXQxhf7hwo)

## Hide sensitive content

The following content is always prevented from being sent as part of a session recording:

* Credit card numbers
* Social security numbers
* Keystrokes (`input` and `textarea`)

Any additional content can be hidden through the use of special CSS classes. Placing one of these classes on an element will scramble any text and blank out any images within that element.

* `lo-sensitive`
* `losensitive`

You can also mark specific elements as not sensitive. **This, however, will not override the above list of content that is always prevented.**

* `lo-not-sensitive`
* `lonotsensitive`

{% hint style="info" %}
Using the above classes will affect all nested children of the given element unless a child includes a class that negates the inherited class. Ex `lo-not-sensitive` within `lo-sensitive`.
{% endhint %}

## Opt-out of tracking

You can programmatically opt a visitor out of tracking with the following method on the privacy API.

```javascript
LO.privacy.optOut()
```

The above will set a first-party cookie in the visitor's browser that will prevent them from being tracked again unless they clear their cookies. This will only affect your website, the visitor will continue to be tracked on other websites that use Lucky Orange.

### Global opt out (Do Not Track)

Lucky Orange honors the browser "Do Not Track" setting in browsers that offer it. Visitors with this setting enabled will never be tracked by Lucky Orange.

## Allow visitors to control their data

In order to be transparent as possible as to what data Lucky Orange has collected for a specific visitor, a self-serve data management tool is available. This tool makes it very easy for visitors to see what data has been collected during their visits, allows deletion of that data, and explains how to opt out of tracking completely across all websites using Lucky Orange.

![](/files/-Mj4woL4P4IWOfwRyh_2)

Using this tool requires passing a visitor's unique ID as a URL parameter:

```
https://privacy.luckyorange.com/visitor/{VISITOR-ID}
```

The on-page privacy API provides a convenient method to generate the necessary link:

```javascript
LO.privacy.getInfoLink()
```

For example, you could tie a button press to open a link to the privacy page:

{% tabs %}
{% tab title="Vanilla JS" %}

```markup
<button id="privacy-button">Manage my data</button>

<script>
    document
        .querySelector('#privacy-button')
        .addEventListener('click', () => {
            window.open(LO.privacy.getInfoLink())
        })
</script>
```

{% endtab %}

{% tab title="Vue" %}

```markup
<template>
    <a :href="getLink()" target="_blank">Manage my data</a>
</template>

<script>
export default {
    methods: {
        getLink () {
            return LO.privacy.getInfoLink()
        }
    }
}
</script>
```

{% endtab %}
{% endtabs %}


# Node.js

Use the server library to track events and users as they perform events from your backend systems and APIs.

## Installation

Add the official Lucky Orange package to your project via NPM:

```bash
$ npm i @luckyorange/server
```

## Usage

After installation, the first step to using Lucky Orange is initializing it with your unique site ID.

```javascript
const LuckyOrange = require('@luckyorange/server')
const luckyorange = new LuckyOrange({ siteId: 'YOUR-SITE-ID' })
```

### Track events

The `track()` method accepts three arguments. The first is the name of the event you wish to track. The second is any arbitrary metadata that you want to associate with the event. Finally, you can send a context object. This allows the event to be associated with a particular user that you have identified or a session created by the Lucky Orange browser library.

```javascript
luckyorange.events.track(
  'Account Created', 
  { acceptedTerms: true }, 
  { userId: 'test-user-123' }
)
```

### Identify users

In order to connect user accounts and their properties in your system with visitor profiles in Lucky Orange, use `identify()`. You must provide a unique ID that will then become an alias for a visitor created internally by Lucky Orange. If you also use `identify()` in the browser tracking code, the same user's behavior will be combined into one profile.

```javascript
luckyorange.visitors.identify('test-user-123', { email: 'test@example.com' })
```


