# Closer guides and FAQ

## Closer guide

Welcome to Closer Help docs. This space is created to help you solve any troubling case for you or answer any question you may have while using the app.&#x20;

In case you still need to consult your case with us or prefer human to human conversation, you can contact us via widget on our website\
[closer.app](https://closer.app).\
There is also an email address we dedicated for such cases: <support@closer.app>

Get deeper with getting Closer!

### Onboarding

{% content-ref url="/pages/-Lh\_ehSxxvMyDtKhl6G5" %}
[Configure your widget](/guide/getting-started/configure-your-widget)
{% endcontent-ref %}

{% content-ref url="/pages/-Lh\_e1kRrUhG3RtmpqN-" %}
[Install the widget on your website](/guide/getting-started/install-the-widget-on-your-website)
{% endcontent-ref %}

{% content-ref url="/pages/-Lh\_daWJy1msfpbQFXjS" %}
[Invite your team](/guide/getting-started/invite-your-team)
{% endcontent-ref %}

{% content-ref url="/pages/-Lh\_eS7SW8RidxlUsnqR" %}
[Get the mobile app](/guide/getting-started/get-the-mobile-app)
{% endcontent-ref %}

{% content-ref url="/pages/-MJ76dUNd6DX7mKdxnMY" %}
[Advanced Closer widget integration](/guide/getting-started/advanced-closer-widget-integration)
{% endcontent-ref %}

{% content-ref url="/pages/-Lh\_Yk41DibV9n2FdJON" %}
[Closer guides and FAQ](/)
{% endcontent-ref %}

### How to

{% content-ref url="/pages/-Lh\_a03YqnsfTx-p\_uex" %}
[Schedule online meetings](/guide/getting-deeper/scheduling-online-meetings)
{% endcontent-ref %}

{% content-ref url="/pages/-M71wIAA1ll7xCfFKKZb" %}
[Click to call](/guide/getting-deeper/click-to-call)
{% endcontent-ref %}

{% content-ref url="/pages/-MNY7ddRBFHvjj8oSnV2" %}
[Tagging](/guide/getting-deeper/tagging)
{% endcontent-ref %}

{% content-ref url="/pages/-MNY7\_EFWpo3g13w7fag" %}
[Proactive messages](/guide/getting-deeper/proactive-messages)
{% endcontent-ref %}

{% content-ref url="/pages/-Lh\_aJ7miu2I8Dq7eA0D" %}
[Set up skill-based routing](/guide/getting-deeper/set-up-skill-based-routing)
{% endcontent-ref %}

{% content-ref url="/pages/-Lh\_a40K7E6c1uM\_gNSm" %}
[Manage your team’s workload](/guide/getting-deeper/manage-your-teams-workload)
{% endcontent-ref %}

{% content-ref url="/pages/-Lh\_\_piMIFPh9jskH-po" %}
[Identify leads](/guide/getting-deeper/identify-leads)
{% endcontent-ref %}

{% content-ref url="/pages/-MNYRyVoPRIVieJEpIbL" %}
[Reports](/guide/getting-deeper/reports)
{% endcontent-ref %}

{% content-ref url="/pages/-MNYRq1SVAWeqHcqnlLt" %}
[SLA](/guide/getting-deeper/sla)
{% endcontent-ref %}

{% content-ref url="/pages/-MNY7rLtTTRYocTczHJD" %}
[Customer typing preview](/guide/getting-deeper/customer-typing-preview)
{% endcontent-ref %}

{% content-ref url="/pages/-Lh\_aSEPUAMyzAlJ7sFJ" %}
[Push out data with Webhooks](/guide/getting-deeper/push-out-data-with-webhooks)
{% endcontent-ref %}

### Frequently asked questions

{% content-ref url="/pages/-Lh\_Yk41DibV9n2FdJON" %}
[Closer guides and FAQ](/)
{% endcontent-ref %}

{% content-ref url="/pages/-Lh\_Yk41DibV9n2FdJON" %}
[Closer guides and FAQ](/)
{% endcontent-ref %}


# Back to Closer

Take me back to [Closer homepage](https://closer.app/)


# Onboarding


# Configure your widget

**Closer** allows you to create the perfect experience for your customers and present yourself in a reliable way.

You can set your brand's colour, logo, as well as a welcome message for the widget's header. You can also compose a perfect first message that will be sent to your customers at the very start after they open the widget for the first time.

**Closer** gives you the possibility to decide whether your clients can contact you via call or chat only. &#x20;

Once it's all set, install the widget on your website.


# Install the widget on your website

Instaling the widget on your website is crucial for getting a full **Closer** experience. You might need to ask your developer to do that for you.

Copy and paste the script below into the \<head> of every page, where you want the **Closer** widget to be displayed:

```
<script>
(function(c,l,o,s,e,r){c.closer=c.closer||{q:[]};["init","identify"].forEach(function(m){c.closer[m]=function(){this.q.push({method:m,args:arguments});}});c.closer["scriptUrl"]=s;e=l.createElement(o);e.async=1;e.src=s;r=l.getElementsByTagName(o)[0];r.parentNode.insertBefore(e,r);})(window,document,"script","https://widget.closer.app/widget.js");
</script>
```

After that, you can use the init method to render the widget.\
The orgId parameter is obtained from the [widget configuration](https://closer.app/dashboard/settings/widget-config) page in Closer.

```
closer.init({
  orgId: "00000000-0000-0000-0000-000000000000",
});
```

If your site runs on Wordpress, download our free plugin from <https://wordpress.org/plugins/closer-chat-video-calls-for-sales> and paste the Company ID below in the Closer Settings configuration tab.


# Invite your team

**Closer** is for managing better contacts with your clients. One person can do it, sure, but it doesn't hurt to have some backup. Inviting fellow advisers onboard is as easy as adding their email and pressing the button.

![](/files/-LhkIMcAhhdpsjd8XnSK)

## Manage your team

In time there might be some traction in your team. People come and go, and sometimes they take a break. Handle those cases by easily:

![](/files/-LhkKTpgQn2Hyax0ub81)


# Get the mobile app

At **Closer**, we know how precious your customers are and how valuable time is. Download the mobile app from the top right dropdown menu or from mobile store, to be there whenever your customers need you.

We'll inform you about any new message from your customers by sending you push notifications according to your preferences.

You will also have the possibility to join your meeting and receive audio & video calls from your customers.

(links to [App Store](https://apps.apple.com/us/app/closer-chat-video-for-sales/id1439174103) / [Play Store](https://play.google.com/store/apps/details?id=app.closer.business))

![](/files/-LhkQ9viEZsl9wtZm8BM)

![](/files/-LhkQGkMFa5AYLh4YxT2)

![](/files/-LhkQMR30Ihomg-wO30R)


# Advanced Closer widget integration

The basic method for starting the widget by calling the **closer.init** method with the orgId parameter can be extended with additional attributes:

**apiKey** - enables opening the widget from the client's apiKey, thanks to which we can restore his session. The value is UUID, e.g. "00000000-0000-0000-0000-000000000000"

```javascript
closer.init({
    orgId: "00000000-0000-0000-0000-000000000000",
    apiKey: "00000000-0000-0000-0000-000000000000"
});
```

**initializeBeforeRender (optional)** - **false** by default. Enables running initialization process (that involves backend communication) before rendering the widget. Possible use case: check user session before opening the widget, if auth process fails, init the new session with [forcing new user](/guide/getting-deeper/force-new-user-everytime-in-widget) inside [**onUserAuthorizationFailed()** ](/guide/getting-deeper/user-authorization-callbacks)callback. This should prevent from showing message that the session has expired and make more smooth UX for returning user.

```javascript
closer.init({
    orgId: "00000000-0000-0000-0000-000000000000",
    initializeBeforeRender: true
});
```

**onOpen** - triggers the function given as an attribute every time the widget is opened.

```javascript
closer.init({
    orgId: "00000000-0000-0000-0000-000000000000",
    onOpen: () => { console.log("widget opened") }
});
```

**onClose** - triggers the function given as an attribute each time the widget is closed.

```javascript
closer.init({
    orgId: "00000000-0000-0000-0000-000000000000",
    onClose: () => { console.log("widget closed") }
});
```

**onMessageSent** - triggers the function given as an attribute every time the client sends a message.

```javascript
closer.init({
    orgId: "00000000-0000-0000-0000-000000000000",
    onMessageSent: () => { console.log("client sent message") }
});
```

**onMessageReceived** - triggers the function given as an attribute every time the client receives a message.

```javascript
closer.init({
    orgId: "00000000-0000-0000-0000-000000000000",
    onMessageReceived: () => { console.log("client received message") }
});
```

**getLoginHintToken (optional)** - triggers the function given as an attribute when client authorization with oauth is needed. Function must return `Promise<string>`.

```javascript
closer.init({
    orgId: "00000000-0000-0000-0000-000000000000",
    getLoginHintToken: () => Promise.resolve("myLoginHintToken")
});
```

**onTagsChanged (optional)** - triggers the function given as an attribute every time conversation tags changed. As a parameter function gets `ReadOnlyArray<string>`&#x20;

```javascript
closer.init({
    orgId: "00000000-0000-0000-0000-000000000000",
    onTagsChanged: (tags) => console.log("conversation tags changed to", tags)
});
```

**onLektaContext (context)** - triggers the function given as an attribute every time Lekta Bot sets "onLektaContext" field inside closer context namespace.&#x20;

```javascript
closer.init({
    orgId: "00000000-0000-0000-0000-000000000000",
    onLektaContext: (context) => console.log("got context from Lekta Bot:", context)
});
```

So assuming Lekta context:&#x20;

```
{
	"some_other_stuff": {},
	"closer": {
		"onLektaContext": {
			"relogin": true,
			"arr": [],
			"foo": "bar"
		}
	}
}
```

as a parameter function gets:

```
{
	"relogin": true,
	"arr": [],
	"foo": "bar"
}
```

**onConversationStatusChanged ({status})** - triggered every time the conversation status is changed

```javascript
closer.init({
    orgId: "00000000-0000-0000-0000-000000000000",
    onConversationStatusChanged: ({status}) => console.log(`status: ${status}`)
});
```

`status` can be one of:&#x20;

* `waiting` - when the conversation is waiting to be assigned (usually after transfer). Note: new conversations that are not assigned do **not** emit this event, as in this case `waiting` status is default one and there is no state transition.
* `inProgress` - when the conversation gets assigned
* `solved` - when the conversation gets closed according to [Close conversations](/guide/getting-deeper/manage-your-teams-workload#close-conversations)
* `unsolved`- when the conversation gets closed according to [Close conversations](/guide/getting-deeper/manage-your-teams-workload#close-conversations)

**onMaintenanceModeEnabled (message)** - triggered when maintenance mode enabled and widget chat window visibility changes&#x20;

```javascript
closer.init({
    orgId: "00000000-0000-0000-0000-000000000000",
    onMaintenanceModeEnabled: (message) => console.log(`Maintenance enabled: ${message}`)
});
```

* `message` **-** same message that is presented on widget if current date time falls within the maintenance window.

**enableLog (optional)** -  `boolean`(default: false) Setting it to true will enable gathering frontend logs on the backend side, which is crucial for analysing widget integration issues. In order to effectively organise the debugging process it is highly recommended to contact Closer IT Team by email: <support@closer.app>.

```javascript
closer.init({
    orgId: "00000000-0000-0000-0000-000000000000",
    enableLog: true
});
```

**disableAutoOpen (optional)** -  `boolean`(default: false) Setting it to true will initialise the widget in closed state unconditionally, even if the widget has been previously opened in the current browser context.

```javascript
closer.init({
    orgId: "00000000-0000-0000-0000-000000000000",
    disableAutoOpen: true
});
```

**showButton (optional)** -  `boolean`(default: true) Setting it to false will hide the widget button. If widget was initialized & opened in the browser context, this flag will be overwritten.

```javascript
closer.init({
    orgId: "00000000-0000-0000-0000-000000000000",
    showButton: false
});
```

Use the **closer.deinit** method to log off the client securely. It accepts no arguments. It removes the client's data from the browser and removes the widget from the DOM of **all tabs on the same origin**. After calling this method, we can use closer.init again.

```javascript
closer.deinit();
```


# Zacznij używać Closer

{% content-ref url="/pages/-Mgeumr1bJp6aN07-D3H" %}
[Przewodnik po platformie](/guide/zacznij-uzywac-closer/przewodnik-po-platformie)
{% endcontent-ref %}

{% content-ref url="/pages/-MgjGvMXw6DA7b4QTot\_" %}
[Rozmowy](/guide/zacznij-uzywac-closer/rozmowy)
{% endcontent-ref %}


# Przewodnik po platformie

Przestrzeń platformy **Closer** jest podzielona na kilka sekcji, które są dostępne z nagłówka dashboardu.

![](/files/-Mgf9gY2dpWC0BKi_Kku)

* **Rozmowy** - sekcja zawiera ogólny i szczegółowy podgląd wszystkich rozmów, podstawowe informacje o klientach, akcje i szybki dostęp do kalendarza.&#x20;
* **Spotkania online** - sekcja jest agendą Twoich umówionych spotkań.
* **Sugestie AI** - sekcja, gdzie możesz skonfigurować automatyczne sugerowane odpowiedzi na wiadomości klientów.&#x20;
* **Raporty** -  sekcja służy do przeglądu w czasie rzeczywistym informacji zarówno o działaniach doradców, botów, oraz do informowania o tym co dzieje się w Closerze.
* **Profil i Ustawienia** - w danej sekcji możesz zmieniać swój status dla Rozmówców, stąd masz dostęp do edycji profilu, ustawień firmowych i konfiguracji dostępnych w Closerze funkcji. Dostęp do poszczególnych sekcji zależy od roli i uprawnień użytkownika.

Oprócz wymienionych sekcji w nagłówku są umieszczone:

* **Wyszukiwarka** -  możliwość wyszukania klienta wpisując pierwsze litery jego imienia lub nazwiska.
* **Metryki SLA** - dane sygnalizujące o wydajności doradców. Ustawienia metryk znajdują się
  * Średni czas odpowiedzi na pierwszą wiadomość (min)
  * Ilość klientów czekających w kolejce
  * Ilość otwartych rozmów
* **Pomoc** - link do <https://support.closer.app/>


# Rozmowy

Zakładka Rozmowy jest podzielona na sekcje:

* **Inbox** - tu znajdziesz listę podglądów rozmów zainicjowanych przez Rozmówców wraz z możliwością ich pogrupowania i filtrowania.
* **Okno rozmowy** - w danym oknie jest pokazany przebieg całej rozmowy z poszczególnym Rozmówcą wraz z działaniami, które miały miejsce w jej trakcie i polem do wpisywania wiadomości lub pozostawienia notatki.
* **Dane rozmowy** - w tym miejscu zebrane są wszystkie informacje dotyczące Rozmówcy, z którym prowadzona jest rozmowa: informacje kontaktowe, umówione spotkania, tagi, obserwatorzy, wszystkie pozostawione notatki i przesłane pliki. Z tego miejsca jest możliwość bezpowrotnie usunąć dany kontakt i wszystkie związane z nim dane zgodnie z obowiązującymi przepisami prawa.&#x20;
* **Akcje** - są to gotowe wiadomości, które np. pomogą Ci szybko poprosić klienta o wysłanie danych i usprawnią proces umawiania spotkań.
* **Podgląd kalendarza** - tu się mieści szybki podgląd do Twojego planu dnia.

![](/files/-Mgk-c5CUc6SDFsCZWaG)


# Inbox

Tu znajdziesz listę podglądów rozmów zainicjowanych przez Rozmówców. Dla ułatwienia orientacji rozmowy są podzielone na grupy. Możesz sortować rozmowy używając dostępne filtry.&#x20;

### Grupy&#x20;

Każdą grupę rozmów możesz posortować po dacie: strzałka do góry na ciemnym tle pokazuje filtr w stanie zastosowanym, oznacza to, że Podglądy rozmów na liście zostaną wyświetlone od najnowszej do najstarszej od góry do dołu.

![](/files/-MhE16v-UFZBBgc07aNs)

* **Twoje** - rozmowy przypisane do Ciebie, za których rozwiązanie Ty odpowiadasz.
* **Obserwowane** - rozmowy innych Doradców, które śledzisz.
* **Czeka** - wszystkie rozmowy, które nie zostały wyświetlone, i na które klient nie dostał odpowiedzi.&#x20;
* **W trakcie** - wszystkie rozmowy, które są aktualnie prowadzone przez Ciebie i pozostałe osoby w Twojej firmie.
* **Zamknięte** - wszystkie rozmowy, które zostały zamknięte jako rozwiązane lub nierozwiązane.

### Filtry

Możesz dodatkowo użyć dostępne filtry dla Twoich lub wszystkich rozmów, klikając w przycisk "Więcej filtrów".&#x20;

![](/files/-MhIEeAe54L4Akix2GPn)

**Twoje rozmowy:**

* **Obudzone** - rozmowy przypisane do Ciebie, które były uśpione i obudzone.
* **Nowe** - nowe rozmowy przypisane do Ciebie.

**Wszystkie rozmowy:**

* **Z tagiem** - wszystkie rozmowy z wybranym tagiem w ramach filtrów Twoje, Obserwowane, Czeka, W trakcie, Zamknięte.
* **Z przypisanym doradcą** - wszystkie rozmowy z wybranym doradcą w ramach filtrów Twoje, Obserwowane, Czeka, W trakcie, Zamknięte.
* **Z datą zamknięcia rozmowy** - wszystkie rozmowy zamknięte w wybranym dniu.
* **Uśpione** - wszystkie rozmowy, które zostałe uśpione automatycznie lub ręcznie.


# Zarządzaj doradcami

{% content-ref url="/pages/-Mg5sqBf\_IfvaNfMo-X4" %}
[Zaproś doradców firmy](/guide/managing-advisers/zapros-doradcow-firmy)
{% endcontent-ref %}

{% content-ref url="/pages/-Mg61IYzRPIv6I9h-6Nw" %}
[Ustawienia doradcy](/guide/managing-advisers/ustawienia-doradcy)
{% endcontent-ref %}

{% content-ref url="/pages/-Mg6C3TJvoBqq0AhoW1R" %}
[Grupuj doradców](/guide/managing-advisers/grupuj-doradcow)
{% endcontent-ref %}


# Zaproś doradców firmy

Closer zapewnia większe możliwości kontaktu z klientami. Jedna osoba oczywiście może to zrobić, ale nie zaszkodzi mieć wsparcie. W Closer zapraszanie innych doradców na pokład jest proste, dodaj ich adresy e-mail i zatwierdź jednym przyciskiem.

![](/files/-Mg5vJrYRbuHlfkaWpmX)

![](/files/-Mg5uWcsBfauA0zUSe7k)

### Zarządzaj listą doradców

W każdej chwili możesz wyszukać na liście doradzę wpisując w wyszukiwarce Imię, Nazwisko lub użyć dostępne filtry:

* **Filtr “Doradcy z tagiem"** - wyświetli wszystkich doradców, do których jest przypisany wybrany tag
* **Filtr “Doradcy z grupą tagów”** - wyświetli wszystkich doradców, do których jest przypisana wybrana grupa tagów
* **Filtr “Doradcy z rolą”** - wyświetli wszystkich doradców z wybraną rolą
* **Filtr “Doradcy ze statusem”** - wyświetli wszystkich doradców z wybranym statusem. Dostępni doradcy mają zielony indykator przy nazwisku
* **Filtr “Doradcy usunięci z listy”** - wyświetli wszystkich doradców, którzy zostali usunięci z listy

![](/files/-Mg5zOQzhZHmrqUHIq82)

Możesz usunąć doradcę z listy, klikając w ikonkę “Usuń”. Usunięcie z listy wymaga dodatkowego zatwierdzenia.

Żeby usprawnić pracę, możesz zarządzać listą zaznaczając wszystkich lub kilka doradców na raz i wykonać na zaznaczonych doradcach akcje:

* **Dodaj specjalizację**
* **Usuń specjalizację**
* **Ustaw rolę**
* **Usunięcie doradcy z listy (wraz z dodatkowym potwierdzeniem)**

![](/files/-Mg60PA1UPHEEEY0rkXt)

Po wykonaniu akcji zapisz zmiany.


# Ustawienia doradcy

Wejdź w ustawienia doradcy klikając ikonkę edycji.

![](/files/-Mg63EgY14rjFWpQ0oQE)

### Specjalizacje doradcy

Edytując wybranego z listy doradcę możesz dodać mu specjalizacje w postaci zdefiniowanych tagów i grup tagów. Zgodnie z zasadami działania routingu, zostaną mu przypisane rozmowy, zawierające dane tagi lub kolejki.

![](/files/-Mg67Z5zmq6xIqPuF1by)

### Grupy doradcy

Z poziomu ustawień doradcy możesz sprawdzić do jakich grup doradca należy i wejść w tryb edycji wybranej grupy. Tagi i grupy tagów przypisane do danych grup zostaną automatycznie przypisane do doradcy.

![](/files/-Mg68HelPsbnkkRvlKJ0)

### Rola doradcy

Ustaw rolę doradcy, zawierającą poszczególne uprawniania:

* **Agent** - użytkownik z daną rolą ma uprawnienia do obsługi rozmów z klientem.
* **Admin** - użytkownik z daną rolą ma uprawnienia do obsługi rozmów z klientem, zarządzania doradcami i ustawień wszystkich funkcji dostępnych w platformie.&#x20;

![](/files/-Mg68otbesKiNmHVMl4s)

Po edycji danych zapisz zmiany przyciskiem "Zapisz".


# Grupuj doradców

Grupuj doradców, żeby wygodniej zarządzać firmą. Przypisane do grupy tagi i grupy tagów automatycznie zostana przypisane do doradców, należących do danej grupy. Wpisz nazwę grupy (max. ilość znaków w nazwie grupy 35, zamiast znaku spacji użyj znak “\_”) i dodaj do grupy doradców.

![](/files/-Mg6EGX3cFZyfpzIOsZR)

![](/files/-Mg6EKCTDzjA_YiWYDum)

### Zarządzaj listą grup doradców

Możesz wyszukać na liście grupę wpisując jej nazwę lub użyć dostępne filtry:

* **Filtr “Grupy doradców z tagiem”** - wyświetli wszystkie grupy, zawierające wybrany tag
* **Filtr “Grupy doradców z grupą tagów”** - wyświetli wszystkie grupy, zawierające wybraną grupę tagów
* **Filtr “Grupy doradców z doradcą”** - wyświetli wszystkie grupy, do których jest przypisany wybrany doradca

![](/files/-Mg6GGHV069n4n3Nc905)

Możesz usunąć grupę z listy, kliknij w ikonkę “Usuń”. Usunięcie z listy wymaga dodatkowego zatwierdzenia.

Żeby usprawnić pracę, możesz zarządzać listą zaznaczając wszystkie lub kilka grup na raz i wykonać na zaznaczonych elementach akcje:

* **Dodaj doradcę**
* **Usuń doradcę**
* **Ustaw specjalizację**
* **Usuń specjalizację**
* **Usunięcie grupy doradców z listy (wraz z dodatkowym potwierdzeniem)**

![](/files/-Mg6Jq-TpRw-o45PXfEC)

Aby zedytować nazwę grupy, dodać do grupy doradców lub przypisać specjalizacje, wejdź w ustawienia danej grupy klikając w ikonkę edycji.

![](/files/-Mg6LxkAkmxG6YfeAXO9)


# Skonfiguruj routing

{% content-ref url="/pages/-MgAgWWGT2ZLFc9uzEme" %}
[Wprowadzenie](/guide/routing-configuration/wprowadzenie)
{% endcontent-ref %}

{% content-ref url="/pages/-MgAiYJR7tGs9JCugQOR" %}
[Dodaj tagi](/guide/routing-configuration/dodaj-tagi)
{% endcontent-ref %}

{% content-ref url="/pages/-MgFt4i4exYscLVEX9Ng" %}
[Reguły tagowania](/guide/routing-configuration/reguly-tagowania)
{% endcontent-ref %}

{% content-ref url="/pages/-MgBJFMwHETTYHDyXrdu" %}
[Grupuj tagi](/guide/routing-configuration/grupuj-tagi)
{% endcontent-ref %}

{% content-ref url="/pages/-MgF-q-FK6D2yl9o-Gc6" %}
[Ustawienia grupy tagów](/guide/routing-configuration/ustawienia-grupy-tagow)
{% endcontent-ref %}


# Wprowadzenie

Routing - jest to mechanizm rozdzielania rozmów do doradców. W Closer routing opiera się na tagach - parametrach, określających cechy rozmowy. Tagi służą segmentacji rozmów i właściwemu routingowi rozmów, a także dodatkowym akcjom na widgecie Closera, np. wyświetlaniu proaktywnych wiadomości. Rozmowa może zawierac maksymaknie 64 tagi.

Przypisywanie rozmów odbywa się na podstawie rozdziału rozmów do doradców, którzy posiadają przypisane specjalizacje w postaci tagów i grup tagów, pokrywające się z tagami przypisanymi do danej rozmowy.

Ustawienie ilości slotów dla doradcy na routing automatyczny ustala się z poziomu dashboardu Closera.\ <br>


# Dodaj tagi

W Closer proces tworzenia nowych tagów jest prosty. Stworzony tag nie musi być wykorzstywany w routingu, może służyć wyłącznie do filtrowania.&#x20;

Dodając nowy tag nie stosuj polskich znaków oraz spacji (zamiast spacji zalecamy "\_"). Nazwa może składac się maksymalnie z 35 znaków i jest unikalna.&#x20;

![](/files/-MgB98pfE24a99ErV9Un)

![](/files/-MgB9C21es1kbPFsG01P)

### Parametry tagów

Każdy tag ma poszczególne parametry. Po dodaniu tagu możesz okreslić je zaznaczając lub odznaczając checkboxy:

* **Parametr "Aktywny"** - w stanie zaznaczonym oznacza, że dany tag będzie wykorzystywany w routingu i na widgecie.
* **Parametr "Specjalizacja wymagana" (tag Must)** - w stanie zaznaczonym oznacza, że rozmowa z danym tagiem zostanie przypisana tylko do doradcy, który posiada dany tag jako specjalizację.
* **Parametr "Priorytetowy"** - w stanie zaznaczonym oznacza, że rozmowy z danym tagiem będą przypisywane do doradców przed rozmowami bez aktywacji danego parametru.
* **Parametr "Wyświetlaj w danych rozmowy"** - w stanie zaznaczonym oznacza, że dany tag będzie wyświetlany w danych o rozmowie obok okna dialogowego.

![](/files/-MgBGaTIvd7EyJCdgH6Z)

### Zarządzaj listą tagów

Możesz wyszukać tag na liście wpisując jego nazwę lub użyć dostępne filtry po wymienionych wyżej parametrach:

![](/files/-MgBHAapa2n_GtcORVh8)

Możesz usunąć tag z listy, klikając w ikonkę “Usuń”. Usunięcie z listy wymaga dodatkowego zatwierdzenia.

Żeby usprawnić pracę, możesz zarządzać listą zaznaczając wszystkie lub kilka tagów na raz i wykonać na zaznaczonych tagach akcje:

* **Nadać poszczególne parametry**
* **Usunięcie z listy (wraz z dodatkowym potwierdzeniem)**

![](/files/-MgBHpwN4yYqYU1jypja)

Po wykonaniu akcji zapisz zmiany.


# Reguły tagowania

Reguły tagowania są definiowane z poziomu dashboardu Closera. Tagi moga pochodzić z wielu źródeł:

* Na podstawie **domeny**, na której jest widget Closera, tj. tag ustawiany jest dla wszystkich rozmów, które po stronie klienta zostały zainicjowane na wybranej domenie.
* Na podstawie wyrażenia regularnego od którego **rozpoczyna się adres url**, tj. tag ustawiany jest dla wszystkich rozmów, które po stronie klienta zostały zainicjowane na stronach, których adres url zaczyna się od określonej ścieżki url, np. dla tag ustawiany dla wyrażenia: <https://closer.app/blog/> będzie nadawany dla wszystkich rozmów, które klient inicjuje przez Closera na stronach  <https://closer.app/blog/> ,  <https://closer.app/blog/artykul1>, <https://closer.app/blog/artykul2>, itd
* Na podstawie **adresu url** wybranej strony, gdzie jest inicjowana przez klienta rozmowa przez widget Closera; np. <https://closer.app/pricing/> - tag ustawiany dla rozmów, które po stronie klienta zostały zainicjowane wyłącznie na stronie <https://closer.app/pricing/>&#x20;
* Na podstawie **wartości** [**parametrów utm**](https://pl.wikipedia.org/wiki/Parametry_UTM), np. utm\_source, utm\_medium, utm\_campaign. Aby nadać tag, należy określić parametr utm, oraz jego wartość, np. utm\_source=facebook.
* Na podstawie **buttonu osadzonego na www**, który inicjuje widget Closera. Tj. po kliknięciu w wybrany button na www, który inicjuje widget Closera do danej rozmowy jest nadawany tag określający wszystkie rozmowy uruchamiane danym buttonem. Te tagi określane są z poziomu kodu źródłowego buttonu.
* **Tagi systemowe** dotyczące sesji użytkownika na www:&#x20;

  * **new\_visitor** - gdy użytkownik pierwszy raz odwiedza stronę z widgetem Closera,
  * **returning\_visito**r - gdy użytkownik odwiedza kolejny raz stronę z widgetem Closera,
  * **exit\_intent** - w przypadku kiedy użytkownik chce opuścić stronę www (wyjść poza kartę przeglądarki aby ją zamknąć, albo wpisać nowy adres w pasku przeglądarki).

  Tagi te są “sztywne” co oznacza, że nie możemy ich dowolnie określać.
* Na podstawie wybranych **metadanych dotyczących przeglądarki**, np. język przeglądarki klienta.
* Na podstawie **danych z systemów zintegrowanych z Closerem** **dla rozpoznanych klientów**. Tj. do Closera możemy przekazywać tagi dotyczące rozpoznanego klienta, jeśli istnieje integracja pomiędzy Closerem, a danym systemem, np. dla rozpoznanych klientów dodanie tagu premium jeśli istnieje integracja pomiędzy Closerem, a systemem CRM, w którym oznaczamy wybranych klientów jako klientów premium i przewidziana jest integracja pola dotyczącego oznaczenia klientów premium w CRMie.
* Na podstawie **danych z systemów zintegrowanych z Closerem dla danych dotyczących rozmowy**. Tj. nadawanie rozmowom tagów, jeśli zostały one określone przez zewnętrzne systemy konwersacyjne, tj. boty. Np. bot Max rozpoznaje temat rozmowy i określa to jako tag, który nadawany jest w rozmowie w Closerze.
* **Na potrzeby segmentacji**, tagi niewykorzystywane przy routingu rozmów np. tagi określające nazwę zespołów w firmie.

&#x20;


# Dodaj reguły tagowania

Po dodaniu tagów możesz zdefiniować reguły tagowania w kilka kroków.

![](/files/-MgG58q8YiV_T5PqPMy-)

![](/files/-MgG72mpF3qWfxRfPpLH)

Po utworzeniu nowej reguły tagowania upewnij się, że tagi są aktywne (nazwa taga na zielonym tle) i aktywuj regułę zaznaczając checkbox. Aktywować nieaktywny tag (nazwa taga na szarym tle) możesz w zakładce "Tagi".

![](/files/-MgG7Sag46TdVf0BYLY-)

Możesz usunąć lub zedytować utworzoną regułę, klikając w odpowiednie ikonki i zapisując wprowadzone zmiany.&#x20;

![](/files/-MgG8dULs8p_jiVQlbLU)

### Zarządzaj listą reguł tagowania

Na liście utworzonych reguł możesz wyszukać regułę po tagu, wpisując jego nazwę. Możesz też filtrować listę po wybranej regule lub po aktywnych regułach.&#x20;

![](/files/-MgGCUvtJU_ruVrxkZnU)

Zarządzaj listą reguł tagowania, żeby wykonać akcję na wszystkich lub wybranych pozycjach listy.

![](/files/-MgGDVm7S4Xd9nmYFU4C)

Po wykonanych akcjach zapisz zmiany przyciskiem "Zapisz".


# Grupuj tagi

Grupa tagów - jest to zbiór tagów, konfigurowany z poziomu dashboardu Closera. Możesz stworzyć maksymalnie 128 grup. Dodając nową grupę nie stosuj polskich znaków oraz spacji (zamiast spacji zalecamy "\_"). Nazwa może składac się maksymalnie z 35 znaków i jest unikalna.

* Grupa tagów musi zawierać przynajmniej jeden tag.&#x20;
* Jeden tag może być w wielu grupach.&#x20;
* Nazwa grup tagów ma charakter informacyjny.&#x20;

![](/files/-MgBK3287S4P7JWCbTvR)

![](/files/-MgBK6h7W9s8WrB7OBN4)

Sugerowanie użycie grup tagów to&#x20;

* Wykorzystanie ich do masowej konfiguracji zdolności doradców.&#x20;
* Wykorzystanie ich filtrowaniu raportów.&#x20;
* Wykorzystywanie ich jako “kolejek” znanych z tradycyjnych systemów contact center.

Pojedynczy doradca i grupa doradców mogą posiadać wiele tagów i wiele grup tagów jako specjalizacje.

### Parametry grup tagów

Aktywuj grupę tagów zaznaczając checkbox "Aktywuj". Grupa tagów nie ma parametrów "Wymagana specjalizacja" (Must/Should) ani priorytetu, stosowane one są tylko na tagach.

![](/files/-MgBUdkzXrRuk4mLL2mv)

### Zarządzaj listą grup tagów

Możesz wyszukać grupę na liście wpisując jej nazwę lub użyć dostępne filtry po parametrze lub po tagu dodanym do grupy.

![](/files/-MgBVZf6VzhcFtLhW3Gh)

Możesz usunąć grupę z listy, klikając w ikonkę “Usuń”. Usunięcie z listy wymaga dodatkowego zatwierdzenia.

Zarządzaj listą grup tagów, zaznaczając wszystkie lub kilka pozycji na raz i wykonaj akcje:

* **Aktywuj**
* **Dodaj lub usuń tag do grupy**
* **Ustaw godziny** - ustawiając godziny , okreslasz kiedy dana grupa będzie aktywna i będzie brała udział w routingu.
* **Usunięcie z listy (wraz z dodatkowym potwierdzeniem)**

![](/files/-MgBXHKQ4u_iI1f6LmH5)

Po wykonaniu akcji zapisz zmiany.


# Ustawienia grupy tagów

Wejdź w ustawienia grupy tagów klikając ikonkę edycji.

![](/files/-MgF1yJS39Ac4OsvgyhU)

### Nazwa grupy

W trybie edycji możesz zmienić nazwę grupy tagów. Nie stosuj w nazwie polskich znaków oraz spacji (zamiast spacji zalecamy "\_"). Nazwa może składac się maksymalnie z 35 znaków i jest unikalna.

![](/files/-MgFJ0nag79hUXFrsMFw)

### Tagi grupy

Tu możesz dodać lub usunąć tagi grupy. Upewnij sie, że dodane tagi są aktywne (nazwa taga na zielonym tle). Aktywować nieaktywny tag (nazwa taga na szarym tle) możesz w zakładce "Tagi"

![](/files/-MgFhJvrXXCVOZJD6f0u)

### Ustawienia załączników

Zaznaczając checkbox umożliwiasz klientom wysyłać załączniki w rozmowie z daną grupą tagów.&#x20;

![](/files/-MgFk6LNsR1A6IZtEz0n)

### Godziny aktywacji

Ustaw godziny, w których dana grupa będzie aktywna.&#x20;

![](/files/-MgFkLhuTE-jhkr2yL5P)

Po edycji danych zapisz zmiany przyciskiem "Zapisz".

###


# Getting deeper in dashboard

{% content-ref url="/pages/-MXHE-9vWiMhLO7GV5lJ" %}
[Conversations](/guide/getting-deeper-in-dashboard/conversations)
{% endcontent-ref %}


# Conversations

{% content-ref url="/pages/-MXHFXYSjFrrJZDDujYq" %}
[Inbox](/guide/getting-deeper-in-dashboard/conversations/inbox)
{% endcontent-ref %}

{% content-ref url="/pages/-MXHStmzwTUbqH2bOJdX" %}
[Conversation data](/guide/getting-deeper-in-dashboard/conversations/conversation-data)
{% endcontent-ref %}


# Inbox

Here you will find previews of conversations initiated by the Interlocutors. To facilitate orientation in the conversations, it is possible to sort the conversations.

### Filters

* **Sort by date** - filter applied (up arrow on gray background) - conversations will be displayed from newest to oldest from top to bottom under the filters Yours, Following, Waiting, In progress, Closed. Filter not applied: display order is reversed.
* **Yours** - conversations assigned to you that you are responsible for solving.
* **Followed** - conversations of other Advisors that you follow.
* **Waiting** - all conversations that were not displayed and for which the client did not receive a reply.
* **In progress** - conversations that are currently being conducted by you and others in your company.
* **Closed** - conversations that have been closed.
* **With tag** - all conversations with the selected tag under the filters Yours, Following, Waiting, In progress, Closed.
* **Snoozed** - all conversations with sleep status under the filters Yours, Following, Waiting, In Progress, Closed.

![](/files/-MXI00TE7sdmHaXEZPhU)


# Conversation data

This is where all information about the conversation and the client with whom the conversation is conducted is collected: customer profile, appointments, tags, followers, and notes.

From here, we can close the conversation, irretrievably delete the contact and all related data in accordance with applicable law.

### Customer profile

* **Customer status** - the customer's status depends on whether the client is on the website - not necessarily actively browsing it, it is enough to have an open browser tab where the Closer code is inserted.
* **Contact info** - by clicking on the contact details field, you can edit them. The changes made are updated immediately after clicking the "Save" button.


# Getting deeper in widget

{% content-ref url="/pages/-MXHblUbGQ4li6SPezwq" %}
[Widget guides](/guide/getting-deeper-in-widget/widget-guides)
{% endcontent-ref %}


# Widget guides

### **Chat window**

**The advisor's and bot's messages** with the avatar are displayed on the left side of the window, the time of the message delivery to the client is displayed below the message.&#x20;

**Client messages** are displayed on the right side of the window. Information on whether the message has been sent and read is displayed under the message. The status from "Sent" message to "Read" message in the widget will change when the advisor clicks on a given conversation on the list of conversations in the inbox, thus opening the conversation on the dashboard.


# Notifications

| Treść komunikatu                                                                                      | Warunek wystąpienia komunikatu                                                                                                                                                                                                            |
| ----------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Brak połączenia z serwerem**                                                                        | Brak połączenia z internetem - Widget - Komunikat w belce w górnej części okna rozmowy, pod headerem                                                                                                                                      |
| **Brak połączenia z serwerem**                                                                        | Brak połączenia z internetem - Dashboard - Komunikat w belce na całą szerokość ekranu                                                                                                                                                     |
| **Możesz załączyć 12 plików w wiadomości**                                                            | Załączenie więcej niż 12 plików za jednym razem - Widget - Komunikat w belce w górnej części okna rozmowy, pod headerem                                                                                                                   |
| **Wiadomość nie moze zostać wysłana, bo zawiera niecenzuralne treści**                                | Próba wysłania niecenzuralnych treści, zawartych w słowniku konfigurowalnym z poziomu ustawień administratora - Widget / Dashboard - Komunikat w belce w górnej części okna rozmowy                                                       |
| **Przepraszamy, coś poszło nie tak**                                                                  | Błąd zatwierdzenia formy - Widget - Komunikat w belce w górnej części okna rozmowy, pod headerem                                                                                                                                          |
| **Niepowodzenie wysłania**                                                                            | Błąd przy wysyłaniu wiadomości - Widget / Dashboard - Komunikat w belce w górnej części okna rozmowy                                                                                                                                      |
| **Niektóre załączniki są zbyt duże**                                                                  | Próba załączenia pliku ponad 100 mb - Widget / Dashboard - Komunikat w belce w górnej części okna rozmowy                                                                                                                                 |
| **Wiadomość została ograniczona do 1000 znaków**                                                      | Wysyłanie wiadomości przekraczającej 1000 znaków - Dashboard - Komunikat w belce w górnej części okna rozmowy                                                                                                                             |
| **Nieprawidłowe hasło**                                                                               | Wpisanie nieprawidłowego hasła podczas logowania się - Dashboard - Powiadomienie w tooltopie po najechaniu na ikonkę w inpucie                                                                                                            |
| **Niepoprawny adres e-mail**                                                                          | Wpisanie nieprawidłowego adresu e-mail podczas logowania się - Dashboard - Powiadomienie w tooltopie po najechaniu na ikonkę w inpucie                                                                                                    |
| **To pole jest wymagane**                                                                             | Pola wymagające podania wartości podczas próby zapisania bez żadnej wartości - Dashboard - Ustawienia                                                                                                                                     |
| **Niewłaściwy format daty**                                                                           | Kalendarz - umawianie spotkania, wybór nie istniejącej daty np. 31 lutego                                                                                                                                                                 |
| **Wybierz datę w przyszłości**                                                                        | Kalendarz - umawianie spotkania, wybór daty z przeszłości                                                                                                                                                                                 |
| **Ten termin jest już zajęty**                                                                        | Kalendarz - umawianie spotkania, wybór daty pokrywającej się z innym spotkaniem                                                                                                                                                           |
| **W tym terminie klient umówił spotkanie z innym doradcą**                                            | Kalendarz - umawianie spotkania, wybór daty pokrywającej się ze spotkaniem od innego agenta dla tego samego klienta                                                                                                                       |
| **Musisz podać przynajmniej adres email lub numer telefonu klienta**                                  | Brak niezbędnych danych przy zaplanowaniu spotkania - Dashboard                                                                                                                                                                           |
| **Ups, to zdjęcie jest za duże. Spróbuj przesłać mniejsze**                                           | Próba wczytania pliku ponad 5MB podczas ustawienia zdjęcia profilowego - Dashboard - Ustawienia Profilu                                                                                                                                   |
| **Wpisane hasła nie są jednakowe. Upewnij się, że wpisujesz to samo hasło w obu polach**              | Zmiana hasła - Dashboard                                                                                                                                                                                                                  |
| **Stare hasło nie jest poprawne**                                                                     | Zmiana hasła - Dashboard                                                                                                                                                                                                                  |
| **Wpisany e-mail nie jest poprawny**                                                                  | Dodawanie agenta - Dashboard - Powiadomienie w tooltopie po najechaniu na ikonkę w inpucie                                                                                                                                                |
| **Ten użytkownik został już zaproszony**                                                              | Dodawanie agenta - Dashboard - Powiadomienie w tooltopie po najechaniu na ikonkę w inpucie                                                                                                                                                |
| **Adresy email powtarzają się**                                                                       | Dodawanie agenta - Dashboard - Powiadomienie w tooltopie po najechaniu na ikonkę w inpucie                                                                                                                                                |
| **Nazwa jest wymagana**                                                                               | Dodanie skilla do agenta bez wpisania nazwy taga - Dashboard - Powiadomienie w tooltopie po najechaniu na ikonkę w inpucie                                                                                                                |
| **Specjalizacja o podanej nazwa już istnieje**                                                        | Próba dodania skilla, który jest już dodany na listę - Dashboard - Powiadomienie w tooltopie po najechaniu na ikonkę w inpucie                                                                                                            |
| **To pole nie może zawierać spacji**                                                                  | Pole wpisywania tagu - Dashboard - Ustawienia tagowania                                                                                                                                                                                   |
| **Niepoprawny adres URL**                                                                             | Pole wpisywania adresu url - Dashboard - Ustawienia tagowania                                                                                                                                                                             |
| **Ups, coś poszło nie tak. Spróbuj ponownie**                                                         | Konfiguracja event actions, konfiguracja tagowania, zmiana avatara (przy nieznanym błędzie, na przykład serwer nie działa), zmiana hasła (nie działający serwer, lub zły format requestu), ustawienia metryk sla, sugestie AI - Dashboard |
| <p><strong>Natrafiliśmy na problemy\<br></strong><br><strong>Nasz zespół nad tym pracuje</strong></p> | Ogólny problem z Closer - Dashboard - Cała strona                                                                                                                                                                                         |
| **Masz niezapisane zmiany**                                                                           | Zmiany w ustawieniach nie zostały zapisane przed próbą przejścia na inną stronę - Dashboard                                                                                                                                               |


# How to

{% content-ref url="/pages/-M71wIAA1ll7xCfFKKZb" %}
[Click to call](/guide/getting-deeper/click-to-call)
{% endcontent-ref %}

{% content-ref url="/pages/-Lh\_a03YqnsfTx-p\_uex" %}
[Schedule online meetings](/guide/getting-deeper/scheduling-online-meetings)
{% endcontent-ref %}

{% content-ref url="/pages/-Lh\_\_piMIFPh9jskH-po" %}
[Identify leads](/guide/getting-deeper/identify-leads)
{% endcontent-ref %}

{% content-ref url="/pages/-Lh\_aJ7miu2I8Dq7eA0D" %}
[Set up skill-based routing](/guide/getting-deeper/set-up-skill-based-routing)
{% endcontent-ref %}

{% content-ref url="/pages/-Lh\_a40K7E6c1uM\_gNSm" %}
[Manage your team’s workload](/guide/getting-deeper/manage-your-teams-workload)
{% endcontent-ref %}

{% content-ref url="/pages/-Lh\_aSEPUAMyzAlJ7sFJ" %}
[Push out data with Webhooks](/guide/getting-deeper/push-out-data-with-webhooks)
{% endcontent-ref %}


# Schedule online meetings

**Closer** allows you to create more meaningful relations with your customers by letting your team to talk them, meet face to face, present offers or even co-browse if assistance is needed.

### Set up Company’s working hours

The first step for the best experience in scheduling online meetings in **Closer** is to set up the working hours of your company. Setting working hours influences the ability for your customers to schedule meetings via a bot. It will allow avoiding setting up meetings outside working hours without the adviser’s knowledge.

### Sync your Google Calendar

While scheduling meetings **Closer** can handle double bookings and overlaps with your external Google calendar for you. To do that, add your external Google calendar to **Closer**. It will result in **Closer** treating booked timeslots from Google as a busy and unavailable time.

Surely you can handle it yourself, but once you choose to send a bot for scheduling a meeting to your customer, it’s better to have your busy time slots hidden from the choice. In such moment Google Cal Sync comes in handy.

### Send a scheduling bot to customer

With **Closer**, you can save up some time and unnecessary ping pong of messages while establishing the best time fit for the customer and you to meet. By sending a bot to schedule a meeting, you are making **Closer** handle this process for you.

To your customers **Closer** will only display available time slots to choose from, taking under consideration your working hours, time zone, and events from your synced external calendar.

Once your customer decides on date and time, you will see the confirmation in the chat history and the chosen slot booked in your calendar...

### Set up a meeting with external customer

**Closer** allows you to schedule a meeting with external customers too. By clicking "+" above the **Closer**'s timetable,  you can pick the day and time for the meeting to happen. To be able to finalize this process you will need to provide customer's email or phone number for us to send the invitation link to them. Once done, the chosen slot will be reserved in your **Closer** calendar and **Closer** will send the invitation to the other party via the chosen medium. For future meetings with this customer, you will be able to pick them from the database.


# Click to call

Installing **click to call** feature is quite simple, but you  might need to ask your developer to do that for you.

Find the **closer.init** section on your website. This is the one you have added installing **Closer** widget for the first time. It looks like this (orgId is unique for your company):

```
closer.init({
  orgId: "00000000-0000-0000-0000-000000000000",
});
```

Now add two lines:  "autoClientCalling: true," and "alwaysAutoCall: true,"

After adding it should look like this:

```
closer.init({
  orgId: "00000000-0000-0000-0000-000000000000",
  autoClientCalling: true,
  alwaysAutoCall: true,
});
```

Add those lines to closer.init section on every page, where you want to have instant call button.

Now you can add your personalized button which you can create from your CMS. Just remember to add **onclick="closer.openWidget('autocall')** in the button parameters.&#x20;

Here is an exmaple of how this button could look like:

```
<button onclick="closer.openWidget('autocall')">Open with autocalling</button>
```


# Tagging


# Proactive messages


# Set up skill-based routing

### Add routing tags to customers

We’re giving to your disposal a powerful and flexible system of matching new customers with the appropriate advisers in your team. Just use the tag parameter in the **closer.identify** method to describe which team this customer should be routed to.

```
closer.identify({
  tag: "example",
});
```

Currently, customers can have one tag assigned.

After you’ve added routing tags to your customers based on their context, you should add skills to your team to enable routing.

### Define your team’s skills

Skills are used in conjunction with customer routing tags. When tag is matched with skill, routing is directed to that person(s). Add skills of your team in the [Admin / Assignment rules](https://closer.app/dashboard/settings/assignment-rules) section. Advisers can have multiple skills.

![Skills management](https://storage.googleapis.com/helpdocs-assets/j77potoidz/articles/vc1soyire4/1560434104164/skills-management.png)

### Routing rules

New customers with a tag will be distributed between **available** advisers with the matching skill, until they reach their chat limits. Consecutive customers will be put in the **waiting queue** for that skill. Advisers can pick customers from the waiting queue manually.

Returning customers with unchanged tag will be routed to the assigned adviser (if available) or to the queue for that skill. If there are available advisers with matching skills, the customer will be instantly assigned, as long as chat limits allow for it.

Returning customers with changed tag will be routed as if they were new customers - they will be put in the appropriate queue and routed to the correct team.


# Manage your team’s workload

### Set chat limits

Chat limits are set in the [Admin / Assignment rules](https://closer.app/dashboard/settings/assignment-rules) section. Use them to distribute conversations between your team members and reduce overload.

This variable is global for your whole team.

![Team management - set a chat limit](https://storage.googleapis.com/helpdocs-assets/j77potoidz/articles/c66yvjqds7/1560428890412/chats-number.png)

### Snooze conversations

An adviser can use the snooze function to temporarily increase their chat limit (e.g. when they’re waiting for customer’s reply and would like to take another customer from the waiting queue). Conversation is automatically unsnoozed when customer replies.

### Close conversations

Conversation can be closed with 2 built-in resolution statuses: **Solved** or **Unsolved**. Conversation will be put in the Closed tab, and the **conversation.closed** Webhook will be sent.

When customer replies it will be automatically reopened and assigned either to the last assigned adviser, or put in the waiting queue and automatically distributed.


# Force new user everytime in widget

You can configure widget to always creating new user on init. It's really useful when having oauth configured.

```
closer.init({
  orgId: "00000000-0000-0000-0000-000000000000",
  forceNewUser: true
});
```


# User authorization callbacks

You can provide a function to be called after user succesful user authorization in widget.

```
closer.init({
  orgId: "00000000-0000-0000-0000-000000000000",
  onUserAuthorizationSuccess: (authorizationResult: UserAuthorizationResult) => console.log("USER AUTHORIZED")
});
```

Authorization result object:

```
interface UserAuthorizationResult {
  roomId: string;
  idToken?: string;
}
```

&#x20;If you use OAuth for customers authorization that provides ID Token, it will be available in callback.

```
closer.init({
  orgId: "00000000-0000-0000-0000-000000000000",
  onUserAuthorizationSuccess: (authorizationResult: {idToken?: string}) => console.log(idToken)
});
```

Sometimes your user might not authorize, especially when using OAuth. There is other callback for that situation.

```
closer.init({
  orgId: "00000000-0000-0000-0000-000000000000",
  onUserAuthorizationFailed: () => console.log("User authorization failed")
});
```


# On deinit callback

Closer sdk provides callback on widget deinitialization. Deinitialization might happen when user fails to authorize or when `closer.deinit` was used.

```
closer.init({
  orgId: "00000000-0000-0000-0000-000000000000",
  onDeinit: () => console.log("widget deinitialized")
});
```


# Identify leads

### Set up the contact bot

While you are away, Closer’s bot can help you to gather contact information from the clients who reached out to you. To be able to do that, it needs to be set for the job correctly. In the Profile & Settings>widget configuration, you should add three mandatory fields:

**1. Bot's welcome message**

Customer leaving their contact data may depend on the tone of this message. You can learn more about this subject [here](https://blog.prototypr.io/a-guide-to-developing-bot-personalities-c6eba213d77b)

![Bot's welcome message](/files/-Lh_ae3cnIYoMMrDQ09e)

**2. GDPR agreement**

![Closer GDPR settings](/files/-Lh_aqHk7WxQeKB-qdYw)

**3. Default prefix number**

![Phone default setting for faster entering data](/files/-Lh_b01oOSJXUZgeriKp)

### Identify a customer via our JS SDK

The **apiKey** parameter allows you to identify customers logged in to your website or app, so that their conversation history is stored and synced. To get it, [enter your endpoint’s URL](https://closer.app/dashboard/settings/webhooks) to listen for the **conversation.created** webhook:

![](/files/-Lh_bJ-t4T0ZBQwJeReO)

The data structure being sent contains the **apiKey** parameter. Store it and use it in the **closer.init** method every time the user is logged in with the same credentials.

```
closer.init({
  orgId: "00000000-0000-0000-0000-000000000000",
  apiKey: "00000000-0000-0000-0000-000000000000",
})
```

### Push customer contact data to Closer

Your website or app usually has customer’s contact information at some point. You can use the **closer.identify** method to send this data to Closer. It will be automatically displayed on the dashboard and in the mobile app. You can call this method multiple times, every time some piece of information is added.

```
closer.identify({
  firstName: "Jon",
  lastName: "Snow",
  email: "jon.snow@winterfell.com",
  phone: {
    region: "PL",
    number: "+48123456789",
  },
});
```

To remove data that is no longer valid for the current customer, just use the **closer.identify** with an empty string:

```
closer.identify({
  email: "",
});
```

### Send custom data about the customer

**Closer** also allows you to send custom data in the **key: value** format - you should use the **additionalData** parameter for that purpose. You can use it to send insights that will be visible to your team. You can also define the customer’s language via the **languageLocale** parameter, so that your team know in which language the customer was reading the website.

```
closer.identify({
  languageLocale: "en",
  additionalData: {
    internalId: "value",
    customerGroup: "premium",
  },
});
```

### Use widget in sidebar mode

**Closer** widget can also be displayed in a sidebar instead of floating on top of the page. In order to do that, you need to prepare a container that will hold the widget’s body after opening, and provide this container’s selector via the container parameter of the **closer.init** method.

```
closer.init({
  orgId: "00000000-0000-0000-0000-000000000000",
  container: "#widget-sidebar",
});
```


# Reports


# SLA


# Customer typing preview


# Push out data with Webhooks

You can send information from Closer to your application via Webhooks. If you're new to webhooks, read [this guide](https://requestbin.com/blog/working-with-webhooks/) to learn more.

Rather than requiring you to pull information via our API, webhooks will push information to your endpoint. When one of those events is triggered (for example a new deal is added), Pipedrive will send this notification as an HTTP POST request, with a JSON body, to the endpoint(s) you specify.

To configure endpoint(s) for the webhooks to be sent to, head to the [Admin / Webhooks](https://closer.app/dashboard/settings/webhooks) section.

We support 2 types of events: **conversation.created** and **conversation.closed**.

![](https://storage.googleapis.com/helpdocs-assets/j77potoidz/articles/8ua1vv7dah/1560435509750/webhooks.png)

### Webhook format

**conversation.created** event

```
{
  "customer": {
    "id": "00000000-0000-0000-0000-000000000000",
    "apiKey": "00000000-0000-0000-0000-000000000000",
    "firstName": "Jon",
    "lastName": "Snow",
    "randomName": "Frosty Wolf",
    "backOfficeData": [
      {
        "key": "currentPage",
        "value": "https://yourbusiness.com/"
      },
      {
        "key": "currentPageTitle",
        "value": "Your business"
      },
      {
        "key": "screenSize",
        "value": "1080x1920"
      },
      {
        "key": "browserVersion",
        "value": "67"
      },
      {
        "key": "browserName",
        "value": "Firefox"
      },
      {
        "key": "operatingSystem",
        "value": "Mac OS X 10.14"
      }
    ]
  },
    "email": "jon.snow@winterfell.com",
    "phone": "+48123456789"
  },
  "timestamp": 1560499664789,
  "eventType": "ThreadCreatedEvent"
}

```

**conversation.closed** event

```

{
  "customer": {
    "id": "00000000-0000-0000-0000-000000000000",
    "apiKey": "00000000-0000-0000-0000-000000000000",
    "firstName": "Jon",
    "lastName": "Snow",
    "randomName": "Frosty Wolf",
    "backOfficeData": [
      {
        "key": "currentPage",
        "value": "https://yourbusiness.com/"
      },
      {
        "key": "currentPageTitle",
        "value": "Your business"
      }
    ],
    "email": "jon.snow@winterfell.com",
    "phone": "+48123456789"
  },
  "timestamp": 1560513840901,
  "closedType": "solved",
  "assignee": {
    "id": "00000000-0000-0000-0000-000000000000",
    "firstName": "Bob",
    "lastName": "Holmes",
    "email": "bob.holmes@closer.app"
    "isBot": false
  },
  "messageHistory": [
    {
      "author": {
        "id": "00000000-0000-0000-0000-000000000000",
        "role": "CUSTOMER",
        "email": "jon.snow@winterfell.com",
        "phone": "+48123456789"
      },
      "message": "Hello",
      "timestamp": 1560177613051
    },
    {
      "author": {
        "id": "00000000-0000-0000-0000-000000000000",
        "role": "ADVISER",
        "email": "bob.holmes@closer.app",
        "phone": null
      },
      "message": "Hi!",
      "timestamp": 1560177614270
    },
    {
      "author": {
        "id": "00000000-0000-0000-0000-000000000000",
        "role": "CUSTOMER",
        "email": "jon.snow@winterfell.com",
        "phone": "+48123456789"
      },
      "message": "Nice to meet you",
      "timestamp": 1560177616949
    }
  ],
  "eventType": "ThreadClosedEvent"
}

```


# Routing

## **Tags**

### **Tag definition**

**Tag - parameter defining the feature of a given chat conversation. Tags are used for segmentation of calls and proper call routing, as well as for additional actions on the Closer widget, e.g. displaying proactive messages.**<br>

**Limitations:**

* **Maximum tag length is 35 characters**
* **Maximum number of tags is 256**
* **Tag name has to be unique**
* **Tags names are case insensitive**

### **Tagging system**

**The tagging system is configured at the Closer dashboard level. Tags can come from many sources:**

* **Based on the url of the selected page, where the conversation is initiated by the client via the Closer widget; e.g. <https://closer.app/pricing/> - a tag set for conversations that were initiated on the client's side only on the <https://closer.app/pricing/> website.**
* **Based on the domain on which the Closer widget is located, i.e. the tag is set for all conversations initiated on the client's side on the selected domain.**
* **Based on a regular expression with which the url address begins, i.e. the tag is set for all conversations that on the client side were initiated on pages whose url address begins with a specific url path, e.g. for the tag set for the expression: https: //closer.app/blog/ will be broadcast for all conversations that the client initiates through Closer at <https://closer.app/blog/>, <https://closer.app/blog/artykul1>, https: // closer. app / blog / article2, etc ..**
* **Based on the values of utm parameters, e.g. utm\_source, utm\_medium, utm\_campaign. To assign a tag, you must specify the utm parameter and its value, e.g. utm\_source = facebook.**
* **Based on the button embedded on the www that initiates the Closer widget. Ie after clicking on the selected button on the website, which initiates the Closer widget, a tag is assigned to a given conversation, specifying all conversations launched with a given button. These tags are defined from the button's source code.**
* **System tags for the user's session on the website: new\_visitor - when the user first visits the page with the Closer widget, returning\_visitor - when the user visits the page with the Closer widget again, exit\_intent - when the user wants to leave the website (go beyond the browser tab to close it , or enter a new address in the browser bar). These tags are "rigid" which means we cannot specify them arbitrarily.**
* **Based on selected browser metadata, e.g. the language of the client's browser.**&#x20;
* **Based on data from systems integrated with Closer for recognized customers. Ie we can transfer tags to Closer regarding the identified client, if there is integration between the Closer and the given system, e.g. for recognized clients, adding a premium tag, if there is integration between the Closer and the CRM system, in which we mark selected clients as premium clients and the field integration is provided on marking premium customers in CRM.**
* **Based on data from Closer-integrated systems for call data. Ie tagging conversations if they have been defined by external conversational systems, i.e. bots. For example, the Max bot recognizes the topic of the conversation and defines it as a tag that is assigned in the conversation in Closer.**
* **For segmentation purposes, tags not used in call routing, e.g. tags specifying the name of teams in the company.**

**A conversation can contain up to 64 tags.**<br>

![](https://lh6.googleusercontent.com/yz-lLVaNr4-sVUqKnAXv7bSE9vz276vM2dBWSVr3iLNg_GVXZbGyfdjSSbwxxJJOYYwiTuxjrBOJkA01HY3a4Tx54jIa_28Vw_miS_W-k07OcuCvhvuSR0YPj8kHpGRjeZ3a8Km0)

### **Tag names**

**Naming tags: Polish characters and spaces cannot be used in tag names (we recommend using “\_” instead of spaces). Examples of correctly named tags: home\_page, prepaid, contract\_extension.**

![](https://lh4.googleusercontent.com/LGAqtJO7-JkWA14MhvCuf72aQC2a35qsBIecs16r0igR_J1S_q8zlauD-xK_hsM4PUDPnixNug8s6NGTNhmiMOqYWRdHJ-RZjn9G-WwI8mjOiiAZCQYQxXjhjBb3VWcvdlJxirmP)

### **Tag parameters**

**For each tag we specify the Must / Should parameter and the Priority parameter.**<br>

**Must / Should - a parameter that determines whether the conversation defined by the selected tag is to be routed to advisers with a given tag (must), or whether the given agent does not have to have a given tag in order for the conversation to be assigned to this person (should). Once set, the Must / Should parameter is used for all current and future conversations with the tag, it is possible to change the Must / Should parameter globally for all current and future conversations.**<br>

**Tag priority - the priority of tags affects the order in which conversations are assigned. As part of Closer priority parameter = 0 or 1 - in the case of calls where at least one tag specifying them has a parameter of 1, these calls are assigned first to calls that have only tags with 0 parameters. Once set, the parameter is used for all current and future conversations with a given tag, it is possible to change the given priority globally for all current and future conversations.**<br>

**Active / inactive tag - determining whether a given tag is to be used in routing activities and on the widget.**\ <br>

![](https://lh4.googleusercontent.com/YZg61I0DOpcLG58K75zzfvJEQ4FPQnRYd57YBJv76qbdTtYx_8Nx-EXbcAkoDelkPz-5DB7XgWKtV61vw5MXV0cHSRWJbhSU4AwLLEfef7fWd9PX62oVmm3HvTSULyU2S_ACcGQq)

## **Tag group**

**Tag group - it is a collection of tags, configured from the Closer dashboard. A tag group must contain at least one tag. One tag can be in many groups. The name of the tag groups is for reference only.**&#x20;

**Suggesting the use of tag groups is 1. to use them to massively configure the counselors' abilities. 2. the use of their filtering reports. 3. using them as "queues" known from traditional contact center systems.**

**A single counselor may have multiple tags as abilities, and multiple tag groups as abilities.**

**Naming tag groups: it is recommended not to use Polish characters and spaces in the names of tag groups (we recommend using “\_” instead of spaces). Examples of correctly named groups of tags: sales\_ subscription\_premium, telephony\_clients\_premium. Tag group is just a container for tags, it does not apply any additional logic.**\ <br>

![](https://lh5.googleusercontent.com/maYsS_hAp3mNmpp4__uq0kjd8ihDtAgR6V_IwsdP7zSSy2pillz5GcNp2DFODs6AtI1rJtGIrycXojce9tua20eSfvioZVQclB3nS8zoQULa3zbBBVkAQu148miG9U3tG9e-2xmV)

## **Routing**

**Routing - it is a mechanism for separating calls to advisers. In Closer, routing is based on tags that are assigned to a given chat conversation. One conversation can be defined with up to 64 tags, or it can have no tag at all. Each tag has Must / Should and Priority parameters set in advance.**

**A routing conversation can have any mix of Must and Should tags. Ie One conversation for routing can only be defined by Must tags, only Should tags, no tags, or a combination of Must tags and Should tags.**

**Conversations are assigned based on the distribution of conversations to advisers who have assigned tags that match the tags assigned to a given conversation.**

**Maximum capacity per adviser is 99 conversations.**\ <br>

![](https://lh5.googleusercontent.com/QheH4XsBVIckCmqi94us8_VfxFbOEuK75RK55q0UDzrJAEEfqHzP2FqMvonc6i8E5kHU0jwpDHx41eBAp21jcaI2Y5JZ4wB8NHslmHLYjU9HJ_o_QgXrmmDddB556RNt0Pq0vuNG)

**Routing example:**

**A new conversation with 5 tags to describe it is created: Two of them are Must and three others are Should. In this case, the routing capability in the first step is narrowed down to the group of advisers who have both Must tags. Then the conversation is assigned to the advisor on the basis of:**<br>

1. **If there are advisors available (status available and free chat slots) who have both Must tags and three Should tags as skills, then the conversation is assigned to one of them.**
2. **If none of the available advisers from point 1 there are no slots, the call is routed to those advisors who have both Must tags as skills assigned to the conversation and any two of the three Should tags that are assigned to the conversation.**
3. **If none of the available advisers from point 2 there are no slots, the call is routed to those advisors who have both Must tags as skills assigned to the conversation and any one of the three Should tags that are assigned to the conversatio.**
4. **If none of the available advisers from point 3 there are no free slots, the conversation is routed to those advisers who have both Must tags as skills, which are assigned to the conversation, advisers as skills in this case do not have any skills corresponding to the Should tag, which is assigned to the conversation.**
5. **If there is still no assignment to the advisor, the conversation remains unassigned until one of the advisers from the points above has a slot free or the advisor manually assigns the selected conversation to himself.**

###

### **Diagram: Routing flow.**![https://liveuml.com/view/6045ff9eab19c913d59dcb7a](https://lh4.googleusercontent.com/AgcrIRoOQbvKrB6M3uxgDjuJ1GzTPwZNHrdwSrhn0TyA2qOyxdfGulUu5rkCTra9UtHTFIjY1Kg0KZrpa0IW9KxoE_TFeOBHVUzTje91LqS8ebtrYs6LuatnCheGEumBl7dURUXF)

## **Account manager**

**The use of the Closer tag system allows you to implement the mechanism of a dedicated account manager. To ensure that the client is served by a specific advisor, you should create a dedicated tag for a specific advisor (tag must) and use it to mark calls from selected customers.**<br>

### **Groups of account managers**

**If you want to implement groups of accounts to which specific clients are assigned, it is enough to define the must tag describing the group of accounts, and the should tag pointing to a specific account. Example:**<br>

**Client X is served by the Nowak account managers group and a specific supervisor Adam Nowak. We create two tags GrupaOpiekuniwNowak (must) and AdamNowak (should). After marking the incoming call with these tags, the system will try to adapt to a specific account within the group (Adam Nowak), if Adam is not available, then he will assign the call to any available advisor from GrupaOpiekunowNowak**

**.**<br>

## **Reports**

**Filtering reports: it is possible to filter reports by tags or groups of tags. This allows, first of all, to preview selected statistics at the level of a selected tag group or tag. Examples:**<br>

**Table with the current structure of conversations:**

![](https://lh5.googleusercontent.com/BMinV7KAPS4uiEgQStLmtOw4fI9x_P0Dn_4e0q_mt7vy4qfPzRiO3_BkpK2o0mlD-SWUq7L0rOW6lT7mp5zpNusrSoxvwjSfY4a5yDHHyXIjoPi5zSg18SWKLm23P5I5T8LhCTi1)

**Adviser tag table:**

![](https://lh4.googleusercontent.com/pOE8ggKhBODo5fBXExhZ2qthpaUs6TdSwPc5RVFwVZjIh6g5CsTcdZSmebHzfUMAFk_Tr9oqnBE386D3GiadmAuXclu3iI05On4SiVxcSicsDG_oYS3-Z03mXFDUabBwtsbDEpgF)

**Board with advisers**

![](https://lh5.googleusercontent.com/zbwe79cVqizEXM9G1IIWJICZUKJpandPWbbm2aNjR6sA4s4VSocOy7rwvu7j4_hKOtJqzCf-mjSkhw_TVWGrTtvn9b6oePfiSGwBhMqNeMQx9LKk9gBup5wxxJeN0LS77-llFPXS)

## **Development possibilities (development)**

**Below we present the possibilities of extending the routing in the Closer Platform for more advanced operations.**

### **Numerical prioritization**

**It is possible to extend the determination of the priority of tags from the current one, where we flag a given tag or it has priority over another, to the possibility of specifying a specific number next to the tag (eg from 0 to 100) which would define the priority value in relation to others.**

### **Change of range after time (not assigned calls)**

**It is possible to extend the current scoping for unassigned calls with must tags to a form in which you could define the time after which a given tag would change its scope from must to should. Example:**<br>

1. **We specify that for the pricing tag being must, the range changes after 60 seconds.**
2. **A conversation with the tag pricing (must) falls into the system.**
3. **The conversation is not picked up by any of the advisers for 60 seconds (they are busy or unavailable).**
4. **The pricing tag changes its scope from must to should.**
5. **Re-routing happens with regard to the tag scope change.**

### **Groups of account managers - temporary delegation**

**Changing the scope of the tag from must to should after the X time. In this case, it would allow for greater control of the delegation of the conversation to the group of accounts. Example:**<br>

1. **Client X is served by the Nowak accounts group and a specific supervisor Adam Nowak. We create two tags GrupaOpiekunówNowak (must) and AdamNowak (must). After marking the incoming call with these tags, the system will try to adjust to a specific account within the group (Adam Nowak)**
2. **We determine that for the Adam Nowak tag being must, the range changes to should after 60 seconds.**
3. **Conversation with tags bursts into the system.**
4. **The conversation is not picked up by a specific account for 60 seconds (Adam Nowak is busy or unavailable).**
5. **The AdamNowak tag changes its scope from must to should.**
6. **Re-routing happens with regard to the tag scope change**
7. **The conversation will be assigned to any account from GrupaOpiekunowNowak**

## **FAQ**

**Question: Is it possible to create an empty tag?**

**Answer: It is possible to create a tag, and do not use it in the routing. But, for example still use it for report filtering.**<br>

**Question: Does the MUST/SHOULD rule apply to groups of tags?**

**Answer: MUST/SHOULD rule apply to tags, groups are just containers for tags. Once a MUST/SHOULD rule is applied to a particular tag, the tag will have its rule everywhere in the system.**\ <br>


# Widget OAuth configuration

### Configuration

You can configure oauth authorization for customers on our endpoint: `https://spinner.closer.app/api/oauth-config`. \
All requests needs admin's ApiKey in `X-Api-Key` header.\
To create a config send a `POST` with body:

```
{
  "tokenEndpoint": "http://oauth.com/token",
  "userInfoEndpoint": "http://oauth.com/userinfo",
  "clientId": "clientId",
  "clientSecret": "clientSecret",
  "oauthConfigEnabled": true,
  "allowAnonymousSignUp": true
}
```

You can retrieve config by executing `GET` request. Result should look like this:

```
{
  "tokenEndpoint": "http://oauth.com/token",
  "userInfoEndpoint": "http://oauth.com/userinfo",
  "clientId": "clientId",
  "clientSecret": "**",
  "oauthConfigEnabled": true,
  "allowAnonymousSignUp": true
}
```

To update config you can use `PATCH` request with body:

```
{
  "tokenEndpoint": "http://oauth.com/token",
  "userInfoEndpoint": "http://oauth.com/userinfo",
  "clientId": "clientId",
  "clientSecret": "clientSecret",
  "oauthConfigEnabled": true,
  "allowAnonymousSignUp": true
}
```

All fields are optional. Send only the fields you want to update.

You can also delete your config by simply executing `DELETE` without body.

### /userinfo endpoint

This endpoint should return body:

```
{
  "externalUserId": "external_id_2",
  "userData": {
    "id": "external_id_2",
    "email": "a@example.com",
    "phone": {
      "region": "PL",
      "number": "666777666"
    },
    "firstName": "Tyler",
    "lastName": "Durden",
    "backOfficeData": [
      {
        "key": "office_number",
        "value": "777666777",
        "displayName": "Office number"
      }
    ]
  }
}

```

Required fields:

* <kbd>$.externalUserId</kbd>
* <kbd>$.userData</kbd>
* <kbd>$.userData.id</kbd>
* <kbd>$.userData.backOfficeData</kbd> (can be an empty array)

In <kbd>$.userData.backOfficeData</kbd> you can specify any additional information you want to display for your agents.


# Forms configuration

## Form model

#### Form DTO fields:

* `id` - \[string] uuid of form
* `orgId` - \[string] uuid of organization
* `locale` - \[string] locale which the form was created for
* `availableForAgents` - \[boolean] determines whether agents can access and send the form
* `name` - \[string] name of the form
* `config` - \[object] configuration of the form's inputs (see input types below)
* `expireInterval` - (optional)\[number] - milliseconds after which the form can no longer be submitted
* `sendInterval` - (optional)\[number] - milliseconds after which the form can be sent again
* `blockIfPreviousUnsubmitted` - \[boolean] - determines whether the form can be sent if previous has not been submitted yet
* `routeOnSubmit` - \[boolean] - determines whether submitting the form should result in opening and assignment of the conversation
* `tagGroupIds` - list\[string] - list of tag group's uuids. Form will be available only in rooms with one of the given `tagGroupIds`. Form with empty `tagGroupIds` is available in any room

## Inputs form

{% hint style="info" %}
Use this form to collect information
{% endhint %}

#### Config (inputs) fields:

* `radioButtonsInputs` - array of objects representing radio buttons input
* `multipleButtonsInputs` - array of objects representing multiple buttons input
* `radioListInputs` - array of objects representing radio list input
* `checkboxListInputs` - array of objects representing checkbox list input
* `textInputs` - array of objects representing text input

### **Buttons (multiple choice)**

`multipleButtonsInputs`

![Mulitple buttons input](/files/lHZEfIyRTCUt98nbVDgh)

<details>

<summary>Click here to see the code</summary>

The input above is represented by the following object:

```json
{
    "index": 0,
    "name": "conversation_expectation",
    "displayName": "I expect the conversation to be:",
    "buttons": [
        {
            "value": "quick",
            "displayName": "Quick"
        },
        {
            "value": "nice",
            "displayName": "Nice & kind"
        },
        {
            "value": "helpful",
            "displayName": "Helpful"
        }
    ]
}
```

</details>

### Buttons (single choice)

`radioButtonsInputs`

![Radio buttons input](/files/kysNpRI7YUWtydJEjUA1)

<details>

<summary>Click here to see the code</summary>

The input above is represented by the following object:

```
{
    "index": 1,
    "name": "device_type",
    "displayName": "I have a problem with my:",
    "buttons": [
        {
            "value": "phone",
            "displayName": "Phone"
        },
        {
            "value": "laptop",
            "displayName": "Laptop"
        },
        {
            "value": "elbow",
            "displayName": "Elbow"
        }
    ]
}
```

</details>

### Radio input with list of options (single choice)

`radioListInputs`

![Radio list input](/files/nUXjNEl6fxr50veLvxSO)

<details>

<summary>Click here to see the code</summary>

The input above is represented by the following object:

```
{
    "index": 2,
    "name": "timeline",
    "displayName": "I have been a customer for:",
    "options": [
        {
            "value": "under_six_months",
            "displayName": "<= 6 months"
        },
        {
            "value": "six_months_to_two_years",
            "displayName": "<= 2 years"
        },
        {
            "value": "longer",
            "displayName": "> 2 years"
        }
    ]
}
```

</details>

### Input with list of options (multiple choice)

`checkboxListInputs`

![Checkbox list input](/files/gUicNn7Ghj9cDYwT1duK)

<details>

<summary>Click here to see the code</summary>

The input above is represented by the following object:

```
{
    "index": 3,
    "name": "favorite_colors",
    "displayName": "Colors I like:",
    "options": [
        {
            "value": "white",
            "displayName": "White"
        },
        {
            "value": "black",
            "displayName": "Black"
        },
        {
            "value": "yellow",
            "displayName": "Yellow"
        }
    ]
}
```

</details>

### Text input

`textInputs`

![Text input](/files/HmaEPEoAW2qDekQucBmj)

<details>

<summary>Click here to see the code</summary>

The input above is represented by the following object:

```
{
    "index": 4,
    "name": "language_name",
    "displayName": "The best programming language is:",
    "placeholder": "Type language name here..."
}
```

</details>

### Full example

Inputs order in the form is determined by \`index\` property of representing object

<details>

<summary>Click here to see form with inputs represented above</summary>

```
{
    "id": "0b05797b-a15b-42a5-96ec-XXXXXXXXXXXX",
    "orgId": "95a25389-5b2f-4b43-a311-XXXXXXXXXXXX",
    "locale": "en",
    "config": {
        "radioButtonsInputs": [
            {
                "index": 1,
                "name": "device_type",
                "displayName": "I have a problem with my:",
                "buttons": [
                    {
                        "value": "phone",
                        "displayName": "Phone"
                    },
                    {
                        "value": "laptop",
                        "displayName": "Laptop"
                    },
                    {
                        "value": "elbow",
                        "displayName": "Elbow"
                    }
                ]
            }
        ],
        "multipleButtonsInputs": [
            {
                "index": 0,
                "name": "conversation_expectation",
                "displayName": "I expect the conversation to be:",
                "buttons": [
                    {
                        "value": "quick",
                        "displayName": "Quick"
                    },
                    {
                        "value": "nice",
                        "displayName": "Nice & kind"
                    },
                    {
                        "value": "helpful",
                        "displayName": "Helpful"
                    }
                ]
            }
        ],
        "radioListInputs": [
            {
                "index": 2,
                "name": "timeline",
                "displayName": "I have been a customer for:",
                "options": [
                    {
                        "value": "under_six_months",
                        "displayName": "<= 6 months"
                    },
                    {
                        "value": "six_months_to_two_years",
                        "displayName": "<= 2 years"
                    },
                    {
                        "value": "longer",
                        "displayName": "> 2 years"
                    }
                ]
            }
        ],
        "checkboxListInputs": [
            {
                "index": 3,
                "name": "favorite_colors",
                "displayName": "Colors I like:",
                "options": [
                    {
                        "value": "white",
                        "displayName": "White"
                    },
                    {
                        "value": "black",
                        "displayName": "Black"
                    },
                    {
                        "value": "yellow",
                        "displayName": "Yellow"
                    }
                ]
            }
        ],
        "textInputs": [
            {
                "index": 4,
                "name": "name",
                "displayName": "The best programming language is:",
                "placeholder": "Type language name here..."
            }
        ]
    },
    "availableForAgents": true,
    "name": "Problem questionaire",
    "expireInterval": 60000,
    "sendInterval": 10000,
    "blockIfPreviousUnsubmitted": true,
    "routeOnSubmit": false
}
```

</details>

## Auto assign form

{% hint style="info" %}
Use this form to route clients' conversations based on their choice
{% endhint %}

![Auto assign form](/files/HlNXC6231txECLJXFfQu)

<details>

<summary>Click here to see form configuration</summary>

The form above is represented by the following object:

```
{
    "id": "2909d885-d34c-49b9-8e8e-XXXXXXXXXXXX",
    "orgId": "d90482fe-17bf-48d5-aa75-XXXXXXXXXXXX",
    "locale": "en",
    "config": {
        "type": "auto_assign_form",
        "tagGroups": [
            {
                "tagGroupId": "23b133fa-f2d1-4140-bddc-XXXXXXXXXXXX",
                "displayName": "First tag group"
            },
            {
                "tagGroupId": "c0f47b47-8269-4002-9734-XXXXXXXXXXXX",
                "displayName": "Second tag group"
            },
            {
                "tagGroupId": "c972191f-ddea-40df-bbbe-XXXXXXXXXXXX",
                "displayName": "Third tag group"
            }
        ]
    },
    "availableForAgents": true,
    "name": "assignment_form",
}
```

</details>

## &#x20;Predefined message form

Predefined message is a  form to send simple text without any inputs as a adviser message. Form configuration accepts the only property `` message` ``. Such form could be used to send links and messages with additional conversation data:

* {{roomId}} - conversation room id

![Predefined meesage](/files/uUDdp40NNwPg41cE9255)

<details>

<summary>Click here to see form configuration</summary>

The form above is represented by the following object:

```
{
    "id": "b5cb64ec-9d85-4fe1-8df7-c8a4b8131b2d",
    "orgId": "95a25389-5b2f-4b43-a311-7625f73da813",
    "locale": "pl",
    "config": {
        "type": "predefined_message_form",
        "message": "Simple predefined message with in room id = {{roomId}}"
    },
    "availableForAgents": true,
    "name": "Simple message",
    "routeOnSubmit": false
}
```

</details>

## API

#### Create

**`POST - /api/message-widgets`**

* Creates new form
* Requires apiKey header of an adviser with `settings_action_forms` permission
* Requires body with following fields:
  * required: `locale`, `name`, `availableForAgents`, `config` (described above), `blockIfPreviousUnsubmitted`, `routeOnSubmit`
  * optional: `expireInterval`, `sendInterval`

<details>

<summary>Click here to see an example</summary>

```
Example
curl --location --request POST 'https://spinner.closer.app/api/message-widgets' \
--header 'x-api-key: your-api-key-here' \
--header 'Content-Type: application/json' \
--data-raw '{
    "locale": "en",
    "name": "a_problem_questionaire",
    "availableForAgents": true,
    "config": {
        "textInputs": [
            {
                "index": 0,
                "name": "best_language",
                "displayName": "The best programming language is:",
                "placeholder": "Type language name here..."
            }
        ]
    },
    "blockIfPreviousUnsubmitted": true,
    "routeOnSubmit": true
}'
```

</details>

#### Update

**`PUT - /api/message-widgets/{messageWidgetId}`**

* Updates existing form
* Requires apiKey header of an adviser with `settings_action_forms` permission
* Requires body with the same schema as POST request, but without `locale`

<details>

<summary>Click here to see an example</summary>

```
Example
curl --location --request PUT 'https://spinner.closer.app/api/message-widgets/d7f68940-e47f-4cd3-bc99-79e112749559' \
--header 'x-api-key: your-api-key-here' \
--header 'Content-Type: application/json' \
--data-raw '{
    "name": "a_problem_questionaire",
    "availableForAgents": false,
    "config": {
        "textInputs": [
            {
                "index": 0,
                "name": "best_language",
                "displayName": "The best programming language is:",
                "placeholder": "Type language name here..."
            }
        ]
    },
    "blockIfPreviousUnsubmitted": true,
    "routeOnSubmit": true
}'
```

</details>

#### Read

**`GET - /api/message-widgets?locale={locale}`**

* Gets all created forms' DTOs
* Requires apiKey of organization's adviser

<details>

<summary>Click here to see an example</summary>

```
Example
curl --location --request GET 'https://spinner.stage.closer.app/api/message-widgets?locale=en' \
--header 'x-api-key: your-api-key-here'
```

</details>

**`GET - /api/message-widgets/{messageWidgetId}?orgId={orgId}`**

* Gets single form DTO
* Does not require authentication

<details>

<summary>Click here to see an example</summary>

```
Example
curl --location --request GET 'https://spinner.closer.app/api/message-widgets/0b05797b-a15b-42a5-96ec-fd821456c69e?orgId=95a25389-5b2f-4b43-a311-7625f73da813
```

</details>


# Org configuration API

#### Update

**`POST - /api/orgs/{orgId}/config`**

* Creates new form
* Requires apiKey header of an adviser with `admin` permission
* Requires body with org configuration (example below):

<details>

<summary>Click here to see request example</summary>

```
Example
curl 'https://spinner.stage.closer.app/api/orgs/{orgID}/config' \
  -X 'PUT' \
  -H 'authority: spinner.closer.app' \
  -H 'accept: */*' \
  -H 'accept-language: en-GB,en-US;q=0.9,en;q=0.8' \
  -H 'content-type: application/json' \
  -H 'dnt: 1' \
  -H 'origin: https://closer.app' \
  -H 'sec-ch-ua: "Chromium";v="106", "Google Chrome";v="106", "Not;A=Brand";v="99"' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'sec-ch-ua-platform: "macOS"' \
  -H 'sec-fetch-dest: empty' \
  -H 'sec-fetch-mode: cors' \
  -H 'sec-fetch-site: same-site' \
  -H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36' \
  -H 'x-api-key: bf4dd784-1277-4e32-b60e-a86a82623147' \
  --data-raw $'org configuration object (JSON, see example below)' \
  --compressed
```

</details>

<details>

<summary>Click here to see org configuration example</summary>

<pre class="language-json"><code class="lang-json">{
    "profanitiesCheckingEnabled": true,
    "showAdviserLastNameEnabled": false,
    "cobrowseEnabled": true,
    "forgetMeEnabled": true,
    "continueConversationOnMobileEnabled": true,
    "typingPreviewEnabled": false,
    "callsDisabled": false,
    "defaultAgentAvatarUrl": "https://wheelhouse.stage.closer.app:443/api/resources/files/a6c50667558f457eaead583ccee2671c",
    "color": "#fe7f00",
    "agreement": "aaatreść klauzuli RODO?",
    "name": "Wody Aqua Polska",
    "allowedAttachmentExtensions": [
        ".jpg",
        ".jpeg",
        ".gif",
        ".png",
        ".pdf",
        ".txt",
        ".doc",
        ".docx",
        ".csv",
        ".xls",
        ".xlsx",
        ".ppt",
        ".pptx",
        ".key",
        ".odt",
        ".ods",
        ".odp"
    ],
    "maximumAttachmentSizeBytes": 20000000,
    "messageMaxAllowedCharactersForClient": 1000,
    "phonePrefix": "PL",
    "webSpeechApiEnabled": true,
    "origin": [
        "*"
    ],
    "welcomeMessagePl": "Dzień dobry, witamy w Tutum Insurance!",
    "welcomeMessageEn": "Dzień dobry, witamy w Tutum Insurance!",
    "headerWelcomeMessagePl": "Wody Aqua Polska",
    "headerWelcomeMessageEn": "Wody Aqua Polska",
    "agreementEnabled": false,
    "baseUrl": "https://piotr-dziedziczs-five-star-project.webflow.io/insurance-plans/life-insurance/",
    "autoAssignedLimit": 4,
    "workingHours": [
        {
            "offsetSeconds": -7200,
            "durationSeconds": 900
        },
        {
            "offsetSeconds": 108000,
            "durationSeconds": 8100
        },
        {
            "offsetSeconds": 165600,
            "durationSeconds": 0
        },
        {
            "offsetSeconds": 252000,
            "durationSeconds": 900
        },
        {
            "offsetSeconds": 338400,
            "durationSeconds": 0
        },
        {
            "offsetSeconds": 490500,
            "durationSeconds": 20640
        },
        {
            "offsetSeconds": 511200,
            "durationSeconds": 0
        }
    ],
    "openedConversationsMetricEnabled": false,
    "waitingConversationsMetricEnabled": false,
    "averageResponseTimeMetricEnabled": true,
    "openedConversationsSlaEnabled": true,
    "waitingConversationsSlaEnabled": true,
    "averageResponseTimeSlaEnabled": true,
    "openedConversationsSlaRangeLowerBound": 1,
    "waitingConversationsSlaRangeLowerBound": 10,
    "averageResponseTimeSlaRangeLowerBound": 60000,
    "openedConversationsSlaRangeUpperBound": 3,
    "waitingConversationsSlaRangeUpperBound": 30,
    "averageResponseTimeSlaRangeUpperBound": 300000,
    "autoreassignEnabled": true,
    "reportsEnabled": true,
    "oauthEnabled": false,
    "autoFollowOnUnassign": true,
    "reassignOnLogoutEnabled": true,
    "statusChangeOnCloseEnabled": false,
    "snoozeOnRoomChange": false,
    "autoCloseTimeoutSeconds": 120,
    "autoSnoozeTimeoutSeconds": 120,
    "messageMaxAllowedCharactersForAgent": 1000,
    "contactEnquiryActionEnabled": true,
    "meetingActionEnabled": true,
    "defaultStatusAfterLogin": "unready",
    "autoReassignOnWebsocketUnavailable": true
<strong>}
</strong></code></pre>

</details>

#### Read

**`GET - /api/orgs/{orgId}/config`**

* Gets org config
* Requires apiKey header of an adviser

<details>

<summary>Click here to see request example</summary>

```
Example
curl --location --request GET 'https://spinner.stage.closer.app/api/orgs/{orgId}/config' \
--header 'x-api-key: your-api-key-here'
```

</details>


# Org configuration fields

* `agreement` - service agreement text
* `agreementEnabled` - turn on / off agreement
* `allowedAttachmentExtensions` - an array of allowed attachments extensions for clients and advisers
* `autoAssignedLimit` - maximum amount of conversations handled by one adviser. Can be configured for each advisor separately through the UI. Settings -> Advisers -> {{Adviser}} -> Auto assigned conversations limit
* `autoCloseTimeoutSeconds` - time after no activity in conversation, conversation gets closer (s)
* `autoFollowOnUnassign` - turn on / off change adviser automatically starts follow conversation on reassign
* `autoreassignEnabled` - turn on / off routing for a conversation on manual presence change
* `autoReassignOnWebsocketUnavailable` - ...
* `autoSnoozeTimeoutSeconds` - time after no activity in conversation, conversation gets snoozed (s)
* `averageResponseTimeMetricEnabled` - turn on / off metrics on average response time calculation
* `averageResponseTimeSlaEnabled` - average response time metric SLA
* `averageResponseTimeSlaRangeLowerBound` - lower bound for average response time (ms)
* `averageResponseTimeSlaRangeUpperBound` - upper bound for average response time (ms)
* `baseUrl` - website URL the widget to be displayed on
* ~~`billingPlanStart` - billing start timestamp~~
* `callsEnabled` - turn on / off calls
* `cobrowseEnabled` - turn on / off cobrowse feature
* `color` - primary org color
* `contactEnquiryActionEnabled` - turn on / off ContactEnquiry form
* `continueConversationOnMobileEnabled` - turn on / off "continue on mobile" button on widget
* ~~`country` - country of org company~~
* `coverToken` - token of org logo cover image
* `customerNotify` - turn on / off email notification on chat activity
* `defaultAgentAvatarToken` - token of default adviser avatar
* `externalIntegrationName` - ...
* `fingerprintEnabled` - ...
* `forgetMeEnabled` - turn on / off "forget me button" on widget
* `headerWelcomeMessageEn` - text on widget header for english locale
* `headerWelcomeMessagePl` - text on widget header for polish locale
* `keyboardShortcutsEnabled` - ...
* `languageLocale` - org default locale
* `logoToken` - token of org logo image
* `maintenanceWindows` - ...
* `maximumAttachmentSizeBytes` - maximum attachment size (bytes)
* `meetingActionEnabled` - turn on / off meeting arrangement
* `messageMaxAllowedCharactersForAgent` - maximum symbols in message for adviser
* `messageMaxAllowedCharactersForClient` - maximum symbols in message for client
* `name` - org name
* `oauthEnabled` - turn on / off login with OAuth
* `openedConversationsMetricEnabled` - turn on / off metrics on opened conversation
* `openedConversationsSlaEnabled` - open conversation metric SLA
* `openedConversationsSlaRangeLowerBound` - lower bound for open conversation metric
* `openedConversationsSlaRangeUpperBound` - upper bound for open conversation metric
* `overrideStyles` - ...
* ~~`paidPlanCount` - amount of paid advisers accounts~~
* `phoneRegion` - country code for phone numbers, example: PL
* ~~`planId` - plan\_before\_billing~~
* `profanitiesCheckingEnabled` - turn on / off profanities check for client and adviser
* `recordingEnabled` - ...
* `reportsEnabled` - turn on / off reports
* `resetRoomViewOnClose` - turn on / off room hides on adviser view on conversation close
* `showAdviserLastNameEnabled` - turn on / off adviser's last name in widget
* `showAssignedAgentAvatarEnabled` - ...
* `snoozeOnRoomChange` - ...
* `ttlMs` - ...
* `typingPreviewEnabled` - turn on / off adviser can preview client typed text
* `waitingConversationsMetricEnabled` - turn on / off metrics on waiting conversation
* `waitingConversationsSlaEnabled` - waiting conversation metric SLA
* `waitingConversationsSlaRangeLowerBound` - lower bound for waiting conversation metric
* `waitingConversationsSlaRangeUpperBound` - upper bound for waiting conversation metric
* `webSpeechApiEnabled` - ...
* `welcomeMessageEnabled` - ...
* `welcomeMessageEn` - text is shown on the first widget opening for english locale
* `welcomeMessagePl` - text is shown on the first widget opening for polish locale
* `workingHours` - Setting working hours influences your customers' ability to schedule meetings via bot. It will allow avoiding setting up meetings outside working hours without advisers' knowledge. It is a better way to configure on UI in Settings -> Working hours
* `zoneId` - ...


# Configure OMNI integration

## Setup

To setup OMNI integration two parameters should be added to OrgConfig:

`omniEnabled` - `true` / `false` value to enable / disable OMNI integration

`omniLink` - link to OMNI page. To inject client token to link `token` URL parameter should be used e.g. `www.testlink.test/integration?userToken={{token}}`


# Elasticsearch business logs

For enterprise clients we can provide bussiness logs in elasticsearch. List of available events below.

Agent Login

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
    "message": {
     "event": {
       "agentId": "agentId",
       "orgId": "orgId",
       "firstName": "John",
       "lastName": "Doe",
       "email": "john.doe@example.com",
       "externalId": "some-id"
     },
     "description": {
       "kind": "event",
       "category": [
         "agent"
       ],
       "type": [
         "business_event"
       ],
       "action": "login",
       "outcome": "success"
     },
     "timestamp": 1635418772366
   }
}
```

Agent Logout

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
    "message": {
      "event": {
        "agentId": "agentId",
        "orgId": "orgId",
        "firstName": "Johin",
        "lastName": "Doe",
        "email": "john.doe@example.com",
        "externalId": "some-id"
      },
      "description": {
        "kind": "event",
        "category": [
          "agent"
        ],
        "type": [
          "business_event"
        ],
        "action": "logout",
        "outcome": "success"
      },
      "timestamp": 1635418772366
    }
 }
```

Agent Status Changed

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
    "message": {
      "event": {
        "agentId": "0000-0000...",
        "orgId": "0000-0000...",
        "status": "", // "AWAY", "AVAILABLE" and "UNAVAILABLE"
        "unavailableReason": "" // custom values
      },
      "description": {
        "kind": "event",
        "category": [
          "agent"
        ],
        "type": [
          "business_event"
        ],
        "action": "status_change",
        "outcome": "success"
      },
      "timestamp": 1635418772366
    }
}
```

Conversation created

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
    "message": {
      "event": {
        "roomId": "0000-0000...",
        "orgId": "0000-0000...",
        "guestId": "0000-0000..."
      },
      "description": {
        "kind": "event",
        "category": [
          "conversation"
        ],
        "type": [
          "business_event"
        ],
        "action": "created",
        "outcome": "success"
      },
      "timestamp": 1635418772366
    }
}
```

Conversation backoffice data updated

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
    "message": {
      "event": {
        "roomId": "0000-0000...",
        "orgId": "0000-0000...",
        "guestId": "0000-0000...",
        "backofficeData": [
          {
            "key": "key",
            "value": "value"
          }
        ]
      },
      "description": {
        "kind": "event",
        "category": [
          "conversation"
        ],
        "type": [
          "business_event"
        ],
        "action": "backoffice_data_change",
        "outcome": "success"
      },
      "timestamp": 1635418772366
    }
  }
```

Conversation tag

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
    "message": {
      "event": {
        "roomId": "0000-0000...",
        "orgId": "0000-0000...",
        "tags": [
          "our-tag",
          "my-tag",
          "your-tag"
        ]
      },
      "description": {
        "kind": "event",
        "category": [
          "conversation"
        ],
        "type": [
          "business_event"
        ],
        "action": "tag_change",
        "outcome": "success"
      },
      "timestamp": 1635418772366
    }
}
```

Conversation assigned

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
    "message": {
      "event": {
        "roomId": "0000-0000...",
        "orgId": "0000-0000...",
        "agentId": "",
        "requesterId": "0000-0000..."
      },
      "description": {
        "kind": "event",
        "category": [
          "conversation"
        ],
        "type": [
          "business_event"
        ],
        "action": "assignee_change",
        "outcome": "success"
      },
      "timestamp": 1635418772366
    }
}
```

Conversation status change

```
{
    "@timestamp": "2022-05-02T11:15:44.281+0000",
    "message": {
      "event": {
        "roomId": "0000-0000...",
        "orgId": "0000-0000...",
        "customerId": "0000-0000...",
        "status": "solved" // "unsolved" | "inProgress" | "waiting" ,
        "requesterId": "0000-0000..."
      },
      "description": {
        "kind": "event",
        "category": [
          "conversation"
        ],
        "type": [
          "business_event"
        ],
        "action": "conversation_status_change",
        "outcome": "success"
      },
      "timestamp": 1651490143839
    }
  }
```

Conversation tags change

```
{
    "@timestamp": "2022-05-02T11:35:15.113+0000",
    "message": {
      "event": {
        "roomId": "0000-0000...",
        "orgId": "0000-0000...",
        "customerId": "0000-0000...",
        "tags": [
          "the_tag"
        ],
        "tagGroupId": "0000-0000...",
        "requesterId": "0000-0000..."
      },
      "description": {
        "kind": "event",
        "category": [
          "conversation"
        ],
        "type": [
          "business_event"
        ],
        "action": "tags_change",
        "outcome": "success"
      },
      "timestamp": 1651491314503
    }
  }
```

Thread first assignee message

```
{
    "@timestamp": "2022-04-28T15:09:24.299+0000",
    "message": {
      "event": {
        "roomId": "0000-0000...",
        "orgId": "0000-0000...",
        "threadId": "0000-0000...",
        "agentId": "0000-0000..."
      },
      "description": {
        "kind": "event",
        "category": [
          "conversation"
        ],
        "type": [
          "business_event"
        ],
        "action": "thread_assignee_first_message",
        "outcome": "success"
      },
      "timestamp": 1651158563620
    }
}
```

Lead location change

```
{
    "@timestamp": "2022-04-29T09:53:37.346+0000",
    "message": {
      "event": {
        "roomId": "0000-0000...",
        "orgId": "0000-0000...",
        "customerId": "0000-0000...",
        "ipAddress": "/78.10.119.146",
        "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36",
        "timezone": "Europe/Warsaw",
        "browserLanguage": "en-GB"
      },
      "description": {
        "kind": "event",
        "category": [
          "conversation"
        ],
        "type": [
          "business_event"
        ],
        "action": "lead_location_change",
        "outcome": "success"
      },
      "timestamp": 1651226017173
    }
  }
```

Conversation unassigned

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
    "message": {
      "event": {
        "agentId": "0000-0000...",
        "orgId": "0000-0000...",
        "status": "unavailable",
        "unavailableReason": ""
      },
      "description": {
        "kind": "event",
        "category": [
          "agent"
        ],
        "type": [
          "business_event"
        ],
        "action": "status_change",
        "outcome": "success"
      },
      "timestamp": 1635418772366
    }
}
```

Message sent

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
    "message": {
      "event": {
        "roomId": "0000-0000...",
        "orgId": "0000-0000...",
        "authorId": "0000-0000...",
        "body": "Hey!",
        "messageId": "0000-0000..."
      },
      "description": {
        "kind": "event",
        "category": [
          "conversation"
        ],
        "type": [
          "business_event"
          ],
          "action": "message_sent",
          "outcome": "success"
      },
      "timestamp": 1635418772366
   }
}
```

Custom message sent

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
    "message": {
      "event": {
        "roomId": "0000-0000...",
        "orgId": "0000-0000...",
        "subtag": "LEAD_TAGS_UPDATE", // may be custom (FORM, FORM_SUBMIT)
        "authorId": "0000-0000...",
        "payload": {
          "oldTags": [
            "tag1",
            "tag2"
          ],
          "oldTagGroupId": "0000-0000...",
          "tags": [
            "tag1",
            "tag2"
          ],
          "tagGroupId": "0000-0000..."
        },
        "messageId": "0000-0000..."
      },
      "description": {
        "kind": "event",
        "category": [
          "conversation"
        ],
        "type": [
          "business_event"
        ],
        "action": "custom_message_sent",
        "outcome": "success"
      },
      "timestamp": 1635418772366
    }
}
```

Conversation closed

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
    "message": {
      "event": {
        "roomId": "0000-0000..",
        "orgId": "0000-0000..",
        "status": "true",
        "sub_status": "solved"
      },
      "description": {
        "kind": "event",
        "category": [
          "conversation"
        ],
        "type": [
          "business_event"
        ],
        "action": "closed",
        "outcome": "success"
      },
      "timestamp": 1635418772366
    }
}
```

Conversation reopened

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
    "message": {
      "event": {
        "roomId": "0000-0000...",
        "orgId": "0000-0000...",
        "customerId": "0000-0000..."
      },
      "description": {
        "kind": "event",
        "category": [
          "conversation"
        ],
        "type": [
          "business_event"
        ],
        "action": "reopened"
        "outcome": "success"
      },
      "timestamp": 1635418772366
    }
}
```

Conversation snoozed / unsnoozed

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
    "message": {
      "event": {
        "roomId": "0000-0000...",
        "orgId": "0000-0000...",
        "customerId": "0000-0000...",
        "agentId": "0000-0000..."
      },
      "description": {
        "kind": "event",
        "category": [
          "conversation"
        ],
        "type": [
          "business_event"
        ],
        "action": ""snoozed" // "unsnoozed"
        "outcome": "success"
      },
      "timestamp": 1635418772366
    }
}
```

Conversation thread created

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
    "message": {
      "event": {
        "threadId": "0000-0000...",
        "roomId": "0000-0000...",
        "orgId": "0000-0000..."
      },
      "description": {
        "kind": "event",
        "category": [
          "conversation"
        ],
        "type": [
          "business_event"
        ],
        "action": "thread_created",
        "outcome": "success"
      },
      "timestamp": 1635418772366
    }
}
```

Lead OAuth sign in

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
    "message": {
      "event": {
        "roomId": "0000-0000...",
        "orgId": "0000-0000...",
        "timestamp": 1635418772366,
        "customerId": "0000-0000...",
        "phone": {
          "region": "PL",
          "number": "48123456789"
        },
        "firstName": "John",
        "lastName": "Doe",
        "backofficeData": [
          {
            "key": "key",
            "value": "value"
          }
        ],
        "searchableField": "Johndoe0000-0000..."
      },
      "description": {
        "kind": "event",
        "category": [
          "conversation"
        ],
        "type": [
          "business_event"
        ],
        "action": "lead_sign_in",
        "outcome": "success"
      },
      "timestamp": 1635418772366
    }
}
```


# Elasticsearch security logs

For enterprise clients we can provide our security logs from elasticsearch. Contact us for more details about connecting and pulling logs.

### Logs structure

Our logs monitors all HTTP requests that could change configuration of your organization from users. All logs have `@timestamp` field which provides time when request was executed. Also you can find field `message.source.ip` containing requester ip address. When user is authenticated we include `message.user.id` field which provides user's ID in Closer and `message.user.roles` which describes roles of the user.

We also provide `message.http.request.body` and `message.http.request.method` so you can identify what action user was trying to made. Fields `message.http.response.body` and `message.http.response.status_code` gives you information about result of the action. Full url address at which user was executing request is provided in field `message.url.full`.

For better filtering of logs we provide fields `message.event.category`, `message.event.kind`, `message.event.type`, `message.event.outcome` and `message.event.action`. Those fields are compilant with [ECS event fields](https://www.elastic.co/guide/en/ecs/current/ecs-event.html).\
List of our event actions:

* `org_config_change`- change made to general config of organization
* `free_org_creation`- creation of org with free plan
* `stripe_org_creation`- creation of org with paid plan
* `widget_logo_creation`- creation of new logo on widget header
* `widget_logo_deletion`- deletion of logo on widget header
* `widget_background_creation`- creation of new background image on widget header
* `widget_background_deletion`- deletion of background image on widget header
* `agent_profile_change`- change made to agent profile
* `agent_deactivation`- agent deactivation in organization
* `agent_restore`- agent restore in organization
* `agent_login`- agent login to closer using email and password
* `agent_login_with_magic_link`- agent login using magic link
* `agent_logout`- agent logout from closer
* `agent_password_change`- agent password change from settings
* `agent_password_change_with_token`- agent password change using token
* `agent_password_reset`- agent password reset request
* `agent_skills_change`- change of agent's skills
* `agent_preferences_change`- change of agent preferences about notifications and inbox sorting
* `agent_limit_change`- change of agent assigned conversations limit, currently not used
* `agent_role_change`- change of agent's role, from admin or to admin&#x20;
* `agent_invitation`- invitation to organization for new agent
* `agent_invitation_acceptation`- invitation to organization accepted from new agent
* `agent_avatar_creation`- creation of new agent avatar
* `agent_avatar_deletion`- deletion of agent avatar
* `unavailability_reason_creation`- creation of unavailability reason for agent on unavailable status
* `unavailability_reason_change`- change of unavailability reason for agent on unavailable status
* `unavailability_reason_deletion`- deletion of unavailability reason for agent on unavailable status
* `bot_type_change`- change of bot type in closer
* `lekta_config_creation`- creation of lekta integration config for bot
* `lekta_config_change`- change in lekta integration config for bot
* `event_action_config_creation`- creation of event action config, response that is send by bot on specific event
* `event_action_config_change`- change of event action config
* `event_action_config_deletion`- deletion of event action config
* `ai_suggestions_config_change`- change on ai suggestions config
* `ai_suggestions_intent_creation`- creation of ai suggestions intent
* `ai_suggestions_intent_change`- change of ai suggestions intent
* `ai_suggestions_intent_deletion`- deletion of ai suggestions intent
* `ai_suggestions_dataset_creation`- creation of ai suggestions dataset for nlu
* `ai_suggestions_dataset_change`- change of ai suggestions dataset for nlu
* `ai_suggestions_dataset_deletion`- deletion of ai suggestions dataset for nlu
* `widget_form_config_creation`- creation of widget form config to display for customer on widget
* `widget_form_config_change`- change of widget form config
* `widget_form_config_deletion`- deletion of widget form config
* `oauth_authorization`- authorization of customer using oauth
* `oauth_config_creation`- creation of oauth config for customer authorization
* `oauth_config_change`- change of oauth config
* `oauth_config_deletion`- deletion of oauth config
* `proactive_messages_config_creation`- creation of proactive message config displayed over widget
* `proactive_messages_config_change`- change of proactive message config
* `proactive_messages_config_deletion`- deletion of proactive message config
* `profanities_config_creation`- creation of profanities config that is used to block some words for sending
* `profanities_config_change`- change of profanities config
* `tag_mapping_config_creation`- creation of tag mapping config for tagging customers on specific page
* `tag_mapping_config_change`- change of tag mapping config
* `tag_mapping_config_deletion`- deletion of tag mapping config
* `org_topic_creation`- creation of topic in org
* `org_topic_change`- change of topic in org
* `org_topic_deletion`- deletion of topic in org

### Example event from elasticsearch

```
{
  "_index": "closer",
  "_type": "entry",
  "_id": "s3baO3kBZbVQk2pxTK-w",
  "_version": 1,
  "_score": 0,
  "_source": {
    "@timestamp": "2021-05-05T09:27:12.529+0000",
    "message": {
      "event.kind": [
        "event"
      ],
      "event.category": [
        "configuration"
      ],
      "event.type": [
        "change",
        "user"
      ],
      "event.action": "agent_skills_change",
      "event.outcome": "success",
      "http.request.body.content": "{\"skills\":[\"skill\"]}",
      "http.request.method": "PUT",
      "http.response.status_code": 204,
      "user.id": "00000000-0000-0000-0000-000000000000",
      "user.roles": [
        "ADMIN"
      ],
      "source.ip": "/89.187.249.34",
      "url.full": "http://spinner.stage.closer.app/api/users/agents/00000000-0000-0000-0000-000000000000/skills",
      "ecs.version": "1.9"
    }
  }
}
```


# Manage widget button

**showButton (optional)** -  `boolean`(default: true) Setting it to false will hide the widget button. If widget was initialized & open in the previous browser context, this flag will be overwritten to `true`.

```javascript
closer.init({
    orgId: "00000000-0000-0000-0000-000000000000",
    showButton: false
});
```

**closer.hideButton()** - After widget initialization you can call this to hide the widget button.

**closer.showButton()** - After widget initialization you can call this to show the widget button.

**closer.openWidget()** - After widget initialization you can call this to open the widget, opening the widget will also show the main button.

**Notice** - Every event which opens the widget, will also show the main button.


# Contact us

In case you need to consult your case with us or prefer human to human conversation, you can contact us via widget on our website [closer.app](https://closer.app/). There is also an email address we dedicated for such cases: <support@closer.app>​

Get deeper with getting Closer!

Our address:

Closer sp. z p.o.\
ul. Aleja 3 maja 9 \
30-062 Kraków, \
Poland, \
European Union


# Supported browsers

## **Widget**

### **On desktop**

Widget is fully supported by [**Chrome 64+**](https://www.google.com/chrome/) and [**Firefox 58+**](https://www.mozilla.org/en-US/firefox/) on desktop.

Browsers which either don’t or do not fully support our functionalities like Audio & Video calls, Presentation mode, and Fullscreen mode:

Safari, Edge and Opera. However, you can still chat via them.

### **On mobile**

On mobile widget will fully work on **Safari 11.2+** for iPhone and on **Chrome 70+** for Android.

Safari for iPad, Firefox for iOS, Chrome for iOS, and Samsung Browser for Android will allow you to chat only.

## **Dashboard**

### **On desktop**

Dashboard is fully supported on desktop by [**Chrome 64+**](https://www.google.com/chrome/).

[**Firefox 58+**](https://www.mozilla.org/en-US/firefox/) might face some issues with Audio & Video calls as well as minor issues with emojis and files attachments.

Browsers on which dashboard might not work properly:

Safari, Edge and Opera.

### **On mobile**

We do have [**Android**](https://play.google.com/store/apps/details?id=app.closer.business) and [**iOS**](https://apps.apple.com/us/app/closer-chat-video-for-sales/id1439174103) apps to provide the best possible experience for you. Grab it!

We neither recommend nor support "dashboard on mobile" experience ¯\\\_(ツ)\_/¯


# Upcoming features drafts


# Business events structure (JSON) - Draft

For  clients we provide bussiness events in json webhooks. List of available events below.

Agent Login

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
    "message": {
     "event": {
       "agentId": "agentId",
       "orgId": "orgId",
       "firstName": "John",
       "lastName": "Doe",
       "email": "john.doe@example.com"
     },
     "description": {
       "kind": "event",
       "category": [
         "agent"
       ],
       "type": [
         "business_event"
       ],
       "action": "login",
       "outcome": "success"
     },
     "timestamp": 1635418772366
   }
}
```

Agent Logout

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
    "message": {
      "event": {
        "agentId": "agentId",
        "orgId": "orgId",
        "firstName": "Johin",
        "lastName": "Doe",
        "email": "john.doe@example.com"
      },
      "description": {
        "kind": "event",
        "category": [
          "agent"
        ],
        "type": [
          "business_event"
        ],
        "action": "logout",
        "outcome": "success"
      },
      "timestamp": 1635418772366
    }
 }
```

Agent Status Changed

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
      "message": {
        "event": {
          "agentId": "0000-0000...",
          "orgId": "0000-0000...",
          "status": "", // "AWAY", "AVAILABLE" and "UNAVAILABLE"
          "unavailableReason": "" // custom values
        },
        "description": {
          "kind": "event",
          "category": [
            "agent"
          ],
          "type": [
            "business_event"
          ],
          "action": "status_change",
          "outcome": "success"
        },
        "timestamp": 1635418772366
}
```

Conversation created

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
      "message": {
        "event": {
          "roomId": "0000-0000...",
          "orgId": "0000-0000...",
          "guestId": "0000-0000..."
        },
        "description": {
          "kind": "event",
          "category": [
            "conversation"
          ],
          "type": [
            "business_event"
          ],
          "action": "created",
          "outcome": "success"
        },
        "timestamp": 1635418772366
      }
}
```

Conversation backoffice data updated

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
    "message": {
      "event": {
        "roomId": "0000-0000...",
        "orgId": "0000-0000...",
        "guestId": "0000-0000...",
        "backofficeData": [
          {
            "key": "key",
            "value": "value"
          }
        ]
      },
      "description": {
        "kind": "event",
        "category": [
          "conversation"
        ],
        "type": [
          "business_event"
        ],
        "action": "backoffice_data_change",
        "outcome": "success"
      },
      "timestamp": 1635418772366
    }
  }
```

Conversation tag

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
    "message": {
      "event": {
        "roomId": "0000-0000...",
        "orgId": "0000-0000...",
        "tags": [
          "our-tag",
          "my-tag",
          "your-tag"
        ]
      },
      "description": {
        "kind": "event",
        "category": [
          "conversation"
        ],
        "type": [
          "business_event"
        ],
        "action": "tag_change",
        "outcome": "success"
      },
      "timestamp": 1635418772366
    }
}
```

Conversation assignee change

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
      "message": {
        "event": {
          "roomId": "0000-0000...",
          "orgId": "0000-0000...",
          "agentId": ""
        },
        "description": {
          "kind": "event",
          "category": [
            "conversation"
          ],
          "type": [
            "business_event"
          ],
          "action": "assignee_change",
          "outcome": "success"
        },
        "timestamp": 1635418772366
      }
}
```

Conversation unassigned

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
    "message": {
      "event": {
        "agentId": "0000-0000...",
        "orgId": "0000-0000...",
        "status": "unavailable",
        "unavailableReason": ""
      },
      "description": {
        "kind": "event",
        "category": [
          "agent"
        ],
        "type": [
          "business_event"
        ],
        "action": "status_change",
        "outcome": "success"
      },
      "timestamp": 1635418772366
    }
  }
```

Message sent

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
    "message": {
      "event": {
        "roomId": "0000-0000...",
        "orgId": "0000-0000...",
        "authorId": "0000-0000...",
        "body": "Hey!",
        "messageId": "0000-0000..."
      },
      "description": {
        "kind": "event",
        "category": [
          "conversation"
        ],
        "type": [
          "business_event"
          ],
          "action": "message_sent",
          "outcome": "success"
      },
      "timestamp": 1635418772366
   }
}
```

Custom message sent

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
    "message": {
      "event": {
        "roomId": "0000-0000...",
        "orgId": "0000-0000...",
        "subtag": "LEAD_TAGS_UPDATE", // may be custom (FORM, FORM_SUBMIT)
        "authorId": "0000-0000...",
        "payload": {
          "oldTags": [
            "tag1",
            "tag2"
          ],
          "oldTagGroupId": "0000-0000...",
          "tags": [
            "tag1",
            "tag2"
          ],
          "tagGroupId": "0000-0000..."
        },
        "messageId": "0000-0000..."
      },
      "description": {
        "kind": "event",
        "category": [
          "conversation"
        ],
        "type": [
          "business_event"
        ],
        "action": "custom_message_sent",
        "outcome": "success"
      },
      "timestamp": 1635418772366
    }
}
```

Custom message send (FORM metadata)

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
    "message": {
      "event": {
        "roomId": "0000-0000...",
        "orgId": "0000-0000...",
        "subtag": "MESSAGE_WITH_FORM",
        "authorId": "0000-0000...", // message (form submit) author id
        "payload": {
          "formId": "0000-0000..."
          "inputs": [
				{
					"name": "client-age",
					"value": "33"
				},
				{
					"name": "client-comment",
					"value": "The agent was very helpful!"
				},
				{
					"name": "external-form-id",
					"value": "0000-0000..."
				}
			],

        },
        "messageId": "0000-0000..."
      },
      "description": {
        "kind": "event",
        "category": [
          "conversation"
        ],
        "type": [
          "business_event"
        ],
        "action": "custom_message_sent",
        "outcome": "success"
      },
      "timestamp": 1635418772366
    }
  }
```

Conversation closed

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
    "message": {
      "event": {
        "roomId": "0000-0000..",
        "orgId": "0000-0000..",
        "status": "true",
        "sub_status": "solved"
      },
      "description": {
        "kind": "event",
        "category": [
          "conversation"
        ],
        "type": [
          "business_event"
        ],
        "action": "closed",
        "outcome": "success"
      },
      "timestamp": 1635418772366
    }
}
```

Conversation reopened / snoozed / unsnoozed

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
    "message": {
      "event": {
        "roomId": "0000-0000...",
        "orgId": "0000-0000...",
        "customerId": "0000-0000..."
      },
      "description": {
        "kind": "event",
        "category": [
          "conversation"
        ],
        "type": [
          "business_event"
        ],
        "action": "" // "reopened", "snoozed", "unsnoozed"
        "outcome": "success"
      },
      "timestamp": 1635418772366
    }
}
```

Conversation thread created

```
{
    "@timestamp": "2021-10-28T08:52:59.726+0000",
    "message": {
      "event": {
        "threadId": "0000-0000...",
        "roomId": "0000-0000...",
        "orgId": "0000-0000..."
      },
      "description": {
        "kind": "event",
        "category": [
          "conversation"
        ],
        "type": [
          "business_event"
        ],
        "action": "thread_created",
        "outcome": "success"
      },
      "timestamp": 1635418772366
    }
}
```


# General

## What is the pricing of Closer?

For the current pricing please visit: <https://closer.app/pricing/>

## How to initiate a conversation by sending a link to a new customer?

Currently, you can create outbound invitations by scheduling an online meeting with a new customer. This will result in them receiving an email or SMS (depending on what credentials they had given) with the invitation link in form of a CTA button. We are considering adding a feature to allow to generate the link to a conversation and use it via any way of communication desired.

## Where can I follow roadmap in features?

We’ll be adding roadmap and customer feedback views into the Closer dashboard shortly.

##


# Bots

## Do you offer any sort of automation?

We have mini-bots for lead capture and scheduling calls currently, and for businesses that use Lekta.ai we have an integration with that. We're building more bots and more integrations as well

Mini-bot can currently take your contact data, so that your customers can receive your replies while offline 😀

## Can I customize the mini bots?

Not yet, but we’re planning that. The lead-capture bot will pop up for each new lead that starts a conversation with you. The scheduling bot has to be sent by you to a customer **with some contact data** - either email or phone number (we'll be adding automation to that later).

## How do I create a bot?

We only offer predefined mini-bots (lead-capture and scheduling bots) at this moment. We’ll be adding integrations with leading bot platforms in the future.

## Can I change the first message to other Language?

Not yet. We’ll be adding more translations in the coming months, but currently our capabilities are limited in that matter. Thanks for understanding!


# Calendar

## How does scheduling work?

That's&#x20;

## After scheduling, does the meeting appear in my calendar?

Scheduling can be handled manually or by the scheduling bot (which we recommend).&#x20;

**Bot:**

Before using the bot we encourage you to synchronize your Google calendar, so our bot could schedule a meeting for you without double bookings for you. This meeting will be automatically added to your Closer calendar. You will be able to reschedule or cancel it at any time. We're working on making our Google Cal sync 2-way (currently it's 1-way).<br>

**Manually:**

To schedule a meeting manually you can either drag and drop the “Schedule online meeting” button in your customer’s profile onto the calendar or by going to the “Online meetings” view, pressing the “+” button and choosing the right credentials and time.<br>

#### **On mobile:**&#x20;

You can schedule a meeting directly from the Customer’s profile or from the Calendar tab - rules are the same as on dashboard. You are going to get push notifications about upcoming meetings.

## After scheduling, does the meeting appear in my calendar?

Scheduled meeting will appear in the Closer dashboard and the Closer mobile app. We're working on making our Google Cal sync 2-way (currently it's 1-way).


# Random

## How's it going?

That's a tough question but thankfully, our team is on it. Please bear with us while we're investigating.

![](/files/-LinHRSuZdq9xtkNvbPq)


