# JavaScript API

Once the HelpHero script loads it makes a global object `HelpHero` object available to your web page. This allows your to interact with HelpHero from your own scripts, meaning you can start & stop tours, listen to events and more. The following methods are available on the global `HelpHero` object.

## `HelpHero.identify(userId, [properties])`

Identify the current user with a userId (string or number) and an optional set of user properties (object).

```js
HelpHero.identify("<USER_ID>", {
  name: "<NAME>",
  role: "<USER_ROLE>"
});
```

:::note
<details>
<summary>Avoiding fallback to anonymous</summary>

If the userId supplied is invalid such as an empty string, null or undefined, the API will fallback to using HelpHero.anonymous(). If you wish to avoid this behavior please perform a null check before passing the userId to HelpHero.identify

```js
if (userId != null && !/^s*$/.test(userId)) {
  HelpHero.identify(userId);
}
```

</details>

<details>
<summary>Avoiding overlap across environments</summary>

If userId is an integer value (e.g. 146) and you have installed HelpHero on different environments like live.example.com and staging.example.com etc. Then there is the possibility that the IDs will overlap between environments. To avoid this we recommend appending the hostname

```js
HelpHero.identify(location.hostname + userId);
```

</details>
:::

## `HelpHero.anonymous()`

Generates a unique user id which will be persisted in the user’s browser until the browser cache is cleared.

## `HelpHero.update(properties)`

Calling the update method with an object of user properties will update those fields on the current user and then check if any tours should be auto started based on the new properties.

```js
HelpHero.update({
  hasPlan: true
});
```

Or pass function to update based on current properties

```js
HelpHero.update(function(currentProperties) {
  return {
    hasPlan: !currentProperties.hasPlan
  };
});
```

## `HelpHero.startTour(tourId, [options])`

Starts tour with the specified tour id. The tour will only start if the user is on an URL that matches the starting URL match specified in the tour. [How do you find your **tourId**?](/docs/starting-tours/#find-tour-id)

Start tour even if user has already seen tour:

```js
HelpHero.startTour("<TOUR_ID>")
```

Options you can pass to override the default behavior of `startTour`

<details>
<summary>skipIfAlreadySeen: boolean</summary>

Start tour only if user has **NOT** already seen tour:

```js
HelpHero.startTour("<TOUR_ID>", { skipIfAlreadySeen: true })
```

</details>

<details>
<summary>redirectIfNeeded: boolean</summary>

By default the tour will not start if the current page does not match the starting URL match of the tour. Perform a redirect before starting the tour:

```js
HelpHero.startTour("<TOUR_ID>", { redirectIfNeeded: true })
```

</details>

<details>
<summary>stepId: string</summary>

By default the tour will start from the first step. If you wish to start the tour at a later step you can pass a step ID.

```js
HelpHero.startTour("<TOUR_ID>", { stepId: "<STEP_ID>" })
```

</details>

## `HelpHero.advanceTour([options])`

The current active tour is moved forward one step. Is ignored when current step is a highlight which requires the user to click within highlighted area.

```js
HelpHero.advanceTour()
```

Options you can pass to override the default behavior of `advanceTour`

<details>
<summary>stepId: string | number</summary>

By default the tour will proceed to the very next step. You can pass a step ID if you wish to move the tour forwards or backwards to a specific step.

```js
HelpHero.advanceTour({ stepId: "<STEP_ID>" })
```

Alternatively you can pass a number to move the tour a relative number of steps from the current step. For example to move the tour back 2 steps:

```js
HelpHero.advanceTour({ stepId: -2 })
```

</details>

## `HelpHero.cancelTour()`

The current active tour is immediately cancelled.

## `HelpHero.startChecklist(checklistId)`

Starts checklist with the specified checklist id. The checklist will only start if:

- The user is on an URL that matches the starting URL match specified in the checklist.
- All conditions specified for showing the checklist are satisfied.
- At least one of the checklist items is eligible to be displayed.

## `HelpHero.openChecklist()`

Opens the checklist if there is one available for the current page.

## `HelpHero.closeChecklist()`

Closes the checklist if there is one available for the current page.

## `HelpHero.setOptions(options)`

Allows you to set HelpHero options by passing an object which can contain any of the following:

<details>
<summary>show: boolean</summary>

Toggle the display of all HelpHero content such as tours, hotspots and checklists on or off. Default value is true.

```js
HelpHero.setOptions({ show: false })
```

</details>

<details>
<summary>showBeacon: boolean</summary>

Control whether HelpHero checklist beacon should be visible. Will override the [default visibility.](/docs/checklists/#hide-beacon)

```js
HelpHero.setOptions({ showBeacon: false })
```

</details>

<details>
<summary>navigate: (url: string) => void</summary>

Control how HelpHero handles navigation between pages in your application. If not set defaults to using location.assign.

```js
function handleNavigate(url) {
  // use history or your frameworks router to change location
  // if using history please ensure your app responds to history changes
  try {
    history.pushState({}, '', url);
  } catch (err) {
    location.assign(url);
  }
}
HelpHero.setOptions({ navigate: handleNavigate });
```

</details>

## `HelpHero.reset()`

Calling reset stops all HelpHero content such as tours, hotspots and checklists from being displayed until either `HelpHero.identify` or `HelpHero.anonymous` is called again.

:::note
<details>
<summary>Transitioning between anonymous and identified?</summary>

By default HelpHero transfers any info such as the records of what tours, hotspots and checklists the user has seen or completed when a user is transitioned from anonymous to identified and vice versa. If you would like to avoid this behavior you can call `HelpHero.reset` before calling either `HelpHero.anonymous` or `HelpHero.identify`.

</details>
:::

## `HelpHero.on([eventName], listenerFn, [context])`

Register a listener function that will be invoked when tour events occur.

- **tour_started**
A tour has been started either automatically, from a checklist or via the API.
- **tour_completed**
A tour has been completed from start to finish.
- **tour_advanced**
A tour has been advanced to the next step either by the user, by a funnel step or via the API.
- **tour_backtracked**
A tour has backtracked to a previous step either by the user or a funnel step.
- **tour_cancelled**
A tour has been cancelled either by the user or via the API.
- **tour_interrupted**
A tour was interrupted due to user navigating away from the page or because the appropriate element to highlight was not found within the timeout specified.
- **tour_dismissed**
A tour has been dismissed by the user clicking on a special [dismiss button](/docs/steps/additional-buttons/#dismiss-button).
- **checklist_item_completed**
An item in a checklist has been completed.
- **checklist_completed**
All the items in a checklist have been completed.
- **hotspot_visited**
Hotspot popup was opened by the user.
- **hotspot_dismissed**
A hotspot has been dismissed by the user clicking on a special [dismiss button](/docs/steps/additional-buttons/#dismiss-button).

Registering a listener for a specific event:

```js
HelpHero.on("tour_started", function(event, info) {
  console.log(event, info);  
})
```

Registering a listener for all events:

```js
HelpHero.on(function(event, info) {
  console.log(event, info);  
})
```

:::note
The listener receives the following arguments for tour events:

<details>
<summary>1) event: Event</summary>

```ts
type EventKind =
  | "tour_started"
  | "tour_completed"
  | "tour_advanced"
  | "tour_backtracked"
  | "tour_cancelled"
  | "tour_interrupted";

type Event = {
  kind: EventKind;
  tourId: string;
  stepId: string;
};
```

</details>

<details>
<summary>2) info: Info</summary>

```ts
type Step = {
  id: string;
  name: string;
};

type Tour = {
  id: string;
  name: string;
};

type Info = {
  tour: Tour;
  step: Step;
};
```

</details>
:::

:::note
The listener receives the following arguments for checklist events:

<details>
<summary>1) event: Event</summary>

```ts
type EventKind =
  | "checklist_item_completed"
  | "checklist_completed";

type Event = {
  kind: EventKind;
  checklistId: string;
  itemId: ?string;
};
```

</details>

<details>
<summary>2) info: Info</summary>

```ts
type ChecklistItem = {
  id: string;
  name: string;
};

type Checklist = {
  id: string;
  name: string;
  items: ChecklistItem[];
};

type Info = {
  checklist: Checklist;
  item: ?ChecklistItem;
};
```

</details>
:::

:::note
The listener receives the following arguments for hotspot events:

<details>
<summary>1) event: Event</summary>

```ts
type EventKind =
  | "hotspot_visited"
  | "hotspot_dismissed";

type Event = {
  kind: EventKind;
  hotspotId: string;
};
```

</details>

<details>
<summary>2) info: Info</summary>

```ts
type Hotspot = {
  id: string;
  name: string;
};

type Info = {
  hotspot: Hotspot;
};
```

</details>
:::

## `HelpHero.off([eventName], listenerFn, [context])`

Unregister a previously registered listener. Use the same arguments that you passed when registering the listener with `HelpHero.on`.
