> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hightouch.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Browser (Javascript) SDK

> Hightouch's browser Javascript SDK for collecting events

The Browser SDK makes it easy to track events in webpages.

## Installation

The Browser SDK can be installed by loading the Javascript via a `script` tag, or directly bundled via a `npm` package.

To install using a `script` tag, add the following snippet to your site, replacing WRITE\_KEY with the write key from your Event Source:

```
<script type="text/javascript">
!function(){var e=window.htevents=window.htevents||[];if(!e.initialize)if(e.invoked)window.console&&console.error&&console.error("Hightouch snippet included twice.");else{e.invoked=!0,e.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","debug","page","once","off","on","addSourceMiddleware","addIntegrationMiddleware","setAnonymousId","addDestinationMiddleware"],e.factory=function(t){return function(){var n=Array.prototype.slice.call(arguments);return n.unshift(t),e.push(n),e}};for(var t=0;t<e.methods.length;t++){var n=e.methods[t];e[n]=e.factory(n)}e.load=function(t,n){var o=document.createElement("script");o.type="text/javascript",o.async=!0,o.src="https://cdn.hightouch-events.com/browser/release/v1-latest/events.min.js";var r=document.getElementsByTagName("script")[0];r.parentNode.insertBefore(o,r),e._loadOptions=n,e._writeKey=t},e.SNIPPET_VERSION="0.0.1",
e.load('WRITE_KEY',{apiHost:'us-east-1.hightouch-events.com'}),
e.page()}}();
</script>
```

To install using `npm`:

1. Install the SDK by running `npm install @ht-sdks/events-sdk-js-browser`
2. Import and initialize the SDK with the following:

```jsx theme={null}
import { HtEventsBrowser } from "@ht-sdks/events-sdk-js-browser";
export const htevents = HtEventsBrowser.load(
  { writeKey: "WRITE_KEY" },
  { apiHost: "us-east-1.hightouch-events.com" }
);
```

## API

### Identify

The `identify` method is used to send an `identify` event.

If `identify` is called multiple times for the same user, the `traits` are
merged together.

**Method signature**:

```
htevents.identify(userId, [traits], [context], [callback])
```

**Method parameters**:

| Parameter | Type | Description |
| - | - | - |
| `userId` | String | The user's persistent ID. |
| `traits` | Object | Additional traits about the user, such as `email` and `name`. |
| `context` | Object | Overrides to values in the event `context`. By default, `context` contains information autocollected by the SDK. |
| `callback` | Function | A callback that's invoked after the event is sent. |

### Track

The `track` method is used to send a `track` event.

**Method signature**:

```
htevents.track(event, [properties], [context], [callback])
```

**Method parameters**:

| Parameter | Type | Description |
| - | - | - |
| `event` | String | The event name (for example "Checked Out"). |
| `properties` | Object | Additional properties about the event, such as `product_id`. |
| `context` | Object | Overrides to values in the event `context`. By default, `context` contains information autocollected by the SDK. |
| `callback` | Function | A callback that's invoked after the event is sent. |

### Page

The `page` method is used to send a `page` event.

**Method signature**:

```
htevents.page(category, name, [properties], [context], [callback])
```

**Method parameters**:

| Parameter | Type | Description |
| - | - | - |
| `category` | String | The page's category. For example, "Docs". |
| `name` | String | The page's name. For example, "Getting started". |
| `properties` | Object | Additional properties about the event, such as `url`. By default, the SDK autocollects properties such as page referrer. |
| `context` | Object | Overrides to values in the event `context`. By default, `context` contains information autocollected by the SDK. |
| `callback` | Function | A callback that's invoked after the event is sent. |

### Group

The `group` method sends a `group` event.

**Method signature**:

```
htevents.group(groupId, [traits], [context], [callback])
```

**Method parameters**:

| Parameter | Type | Description |
| - | - | - |
| `groupId` | String | The id for the group. |
| `traits` | Object | Additional traits about the group, such as `company_name`. |
| `context` | Object | Overrides to values in the event `context`. By default, `context` contains information autocollected by the SDK. |
| `callback` | Function | A callback that's invoked after the event is sent. |

### Reset

The `reset` method resets the `identify` and `group` for the local session.
Specifically, it resets the `anonymousId`, `userId`, `groupId`, and `traits`.

The `reset` method should be called when users log out. This way, if the user
logs back in with another account, the userIds and traits from the different
sessions remain separate.

**Method signature**:

```
htevents.reset()
```

## Single page applications

While Single Page Apps (SPAs) are great for many reasons, they do require some extra consideration in order to set up client-side tracking than with a traditional webpage.

By default, the Hightouch htevents.js library doesn't generate or store the referrer value. Instead, the referrer value you see in the payload is the value returned by `document.referrer` directly from the browser, and the URL value is the canonical URL on the page.

When a user navigates between pages on an SPA website, there won't be a referrer because there is no concept of a new page since it's all a single page load. This means that the referrer will always be the same as it was on the first page call where someone was first directed to your site. However, in order to circumvent this, you can manually set the referrer and URL in your Hightouch calls by updating the context object.

For example, a Page call with the referrer and URL manually set looks like this:

```js theme={null}
htevents.page({
  referrer: "https://hightouch.com/",
  url: "https://hightouch.com/pricing/?ref=nav",
});
```

A Track call with these fields manually updated looks like this:

```js theme={null}
htevents.track(
  "Example Event",
  {},
  {
    page: {
      referrer: "https://hightouch.com/",
      url: "https://hightouch.com/pricing/?ref=nav",
    },
  }
);
```

### Tracking emulated page views

Your application should update the URL in the address bar to emulate traditional webpage navigation. Full page requests aren't made in most of these instances since the resources are loaded on initial page load. This means that the Page call in the traditional htevents.js snippet won't fire again as a user navigates around your site.

You should still place the snippet in the head of your site, but you should remove the Page call and fire it whenever you're emulating a page load. Hightouch recommends that you call [Page](https://docs.hightouch.com/events/sdks/browser.md#page) from the same block of logic that updates the view and URL path like below:

```js theme={null}
// The new view has been called to render
htevents.page("Home");
```

To track more than the page field, pass those fields in as additional properties. Hightouch recommends that you use variables to set information about page properties, rather than hard-coding. In most SPA frameworks, you can automate this by attaching the Page call to the routing service.

## QueryString API

The Browser SDK can trigger `track` and `identify` events based on the URL query string. You can use this when tracking email click-throughs, social media clicks, and digital advertising.

**Query parameters**:

| Parameter | Description | Triggers |
| - | - | - |
| `ajs_uid` | The `userId` for the `identify` event. | This triggers an `identify` event. |
| `ajs_event` | The `name` for the `track` event. | This triggers a `track` event. |
| `ajs_aid` | The `anonymousId` for the user. | This sets the `anonymousId`, by itself does not trigger any event. |
| `ajs_prop_<property>` | A property to set on the `track` event. | This sets a property on the resulting `track` event, by itself does not trigger any event. |
| `ajs_trait_<trait>` | A trait to set on the `identity` event. | This sets a trait on the resulting `identify` event, by itself does not trigger any event. |

### Example

The following URL:

```
https://hightouch.com/?ajs_uid=123&ajs_event=Clicked%20Email&ajs_aid=abc123&ajs_prop_emailCampaign=First+Touch&ajs_trait_name=John
```

would result in these calls:

```js theme={null}
htevents.identify("123", { name: "John" });
htevents.track("Clicked Email", { emailCampaign: "First Touch" });
htevents.user().anonymousId("abc123");
```

### Configuration

The `useQueryString` option allows you to control the behavior of the query parameters. For example, you can entirely disable query string processing by setting `useQueryString` to `false`:

```js theme={null}
htevents.load("WRITE_KEY", {
  useQueryString: false,
});
```

You can also keep query string processing on, but enforce validation rules. For example:

```js theme={null}
htevents.load("WRITE_KEY", {
  useQueryString: {
    // set a pattern for anonymous id
    aid: /([A-Z]{10})/,
    // set a pattern for user id
    uid: /([A-Z]{6})/,
  },
});
```

## Cross Domain Tracking

Using the [QueryString API](#querystring-api) you can easily track users across different domains. For example, if you have the following sites:

* Site 1: `www.landing-page.com`
* Site 2: `www.product-page.com`

To track a user who starts on Site 1 and navigates to Site 2, you just need to pass the `userId` from Site 1 to Site 2 using the `ajs_uid` query parameter.

```
https://www.product-page.com/?ajs_uid=123
```

This will automatically trigger an `identify` event on Site 2 with `userId: 123`.

If you want to track anonymous users across domains, you can access the `anonymousId` on Site 1 using:

```js theme={null}
htevents.user().anonymousId();
```

You can then pass the `anonymousId` from Site 1 to Site 2 using the `ajs_aid` query parameter. Note that the `ajs_aid` parameter does not automatically trigger an `identify` event.

## Autocollected fields

The browser SDK autocollects the following fields within the `context` of each event:

| Field | Description |
| - | - |
| `page.path` | The current page's sanitized path, i.e. with search parameters and the site domain removed. |
| `page.referrer` | The referrer to the current page. An empty string denotes a direct referrer. |
| `page.search` | The search parameter of the current page, if any |
| `page.title` | The current page's title |
| `page.url` | The current page's full URL |
| `sessionId` | An identifier for the visitor's current session. |
| `userAgent` | The raw user agent string |
| `userAgentData` | Parsed information on the user agent. This includes whether the visitor's device is a mobile device, and the platform of the device. |
| `locale` | The browser's locale |
| `library` | Information about the SDK version used to send the event. |
| `timezone` | The visitor's local timezone. |

## Session tracking

A session is a group of "uninterrupted" events that were performed by the same visitor.
The session resets once the session's timeout has expired, and automatically refreshes when a new event is sent.
For example, if the visitor views a couple pages, and then returns to your site after a day, the next day's events will be considered a new session.

The browser SDK automatically tracks a `sessionId` field to track what events occurred in the same session. If two events occurred in the same session, they
will have the same session ID.

The session timeout can be adjusted from the default of **30 minutes** when the SDK is initialized:

```js theme={null}
e.load("YOUR_WRITE_KEY", {
  apiHost: "us-east-1.hightouch-events.com",
  user: {
    sessions: {
      autoTrack: true,
      // Set the timeout to 60 minutes.
      timeout: 60 * 60 * 1000,
    },
  },
});
```

## Campaign Attribution (UTM)

Hightouch automatically captures UTM parameters that you pass in URLs. You can also manually pass UTMs into the `context.campaign` field.

UTM parameters are only used when linking to your site from outside of your domain. When a visitor arrives to your site using a link containing UTM parameters, Hightouch's Browser SDK will automatically parse the URL query string and store UTM parameters within the `context.campaign` object as outlined here. These parameters do not persist to subsequent calls unless you pass them explicitly.

**UTM parameters**:

| Parameter | Mapping | Description |
| - | - | - |
| `utm_campaign` | `campaign.name` | This is the name of your campaign. All marketing activities that support this campaign need to have the same `utm_campaign` so that downstream analysis to measure performance for this specific campaign can be done off this primary key. |
| `utm_medium` | `campaign.medium` | How the traffic is coming to your site. Is it through email, a display ad, or an online forum? This ensures downstream analysis can easily see which channel performs the best. eg. `email`, `paid-display`, `paid-social`, `organic-social` |
| `utm_source` | `campaign.source` | Where the traffic is specifically coming from. You can be specific here. This ensures downstream analysis can measure which specific source brings the most conversions. eg. `x`, `facebook`, `adroll` |
| `utm_content` | `campaign.content` | For multiple calls to action on a single page, `utm_content` indicates which one. For example, on a website, there may be three different display ads. While the link on each display ad will have the same `utm_campaign`, `utm_medium`, and `utm_source`, the `utm_content` will be different. eg. `banner`, `left-side`, `bottom-side` |
| `utm_term` | `campaign.term` | This is the parameter suggested for paid search to identify keywords for your ad. If you’re using Google Adwords and have enabled “autotagging”, then you don’t need to worry about this. Otherwise, you can manually pass the keywords from your search terms through this parameter so that you can see which keywords convert the most. Note that this parameter is reserved explicitly for search. eg. `toast`, `butter`, `jam` |

If you’d like UTM parameters to persist in subsequent calls, you’ll need to manually set those fields in `context.campaign`. For example:

```js theme={null}
htevents.page(
  "My Page",
  {},
  {
    campaign: {
      name: "TPS Innovation Newsletter",
      source: "Newsletter",
      medium: "email",
      term: "tps reports",
      content: "image link",
    },
  }
);
```

## Cookies and LocalStorage

Hightouch stores cookies to track information about website visitors across multiple visits.

* `htjs_user_id`: ID tracking known or identified users as defined [here](https://docs.hightouch.com/events/event-spec.md#identify-events).
* `htjs_anonymous_id`: ID tracking anonymous website visitors as defined [here](https://docs.hightouch.com/events/event-spec.md#identify-events).
* `htjs_group_id`: ID tracking the group a user is associated with as defined [here](https://docs.hightouch.com/events/event-spec.md#group-events).
* `htjs_sesh`: Information about the user's current session as defined [here](https://docs.hightouch.com/events/sdks/browser.md#session-tracking).

In addition to tracking this information in cookies, we use localStorage to track this as well. In localStorage, we also track:

* `htjs_user_traits`: Traits defined about the user being tracked
* `htjs_group_properties`: Properties defined about the group being tracked

For more information on measures to increase persistence of cookies, please refer to our guide on [proxying and server-side cookies](https://docs.hightouch.com/events/first-party-tracking.md).

## Overriding messageId

If you need control over the `messageId` format, you can override it using a `before` plugin. A `before` plugin runs before the event is sent and lets you mutate the event object directly:

Example:

```js theme={null}
import { HtEventsBrowser } from "@ht-sdks/events-sdk-js-browser";

export const htevents = HtEventsBrowser.load(
  { writeKey: "WRITE_KEY" },
  { apiHost: "us-east-1.hightouch-events.com" }
);

let seq = 0;

function generateMessageId() {
  return `msg_${Date.now().toString(36)}_${String(++seq).padStart(5, "0")}`;
}

htevents.register({
  name: "Custom MessageId",
  type: "before",
  version: "1.0.0",
  isLoaded: () => true,
  load: () => Promise.resolve(),
  track: (ctx) => {
    ctx.event.messageId = generateMessageId();
    return ctx;
  },
  identify: (ctx) => {
    ctx.event.messageId = generateMessageId();
    return ctx;
  },
  page: (ctx) => {
    ctx.event.messageId = generateMessageId();
    return ctx;
  },
  group: (ctx) => {
    ctx.event.messageId = generateMessageId();
    return ctx;
  },
});
```

Add a handler for each event type you want to override, since a plugin only runs for the methods it defines. Only use alphanumeric characters, `-`, and `_` in your custom `messageId` values. Other special characters aren't supported.

## Prebuilt plugins

Use Hightouch's prebuilt plugins to add integrations without writing a plugin yourself. Each plugin is optional and must be enabled in your SDK configuration.

### Enrich events with Facebook parameters

The Facebook Parameters plugin collects Meta's `fbc` and `fbp` values and attaches them to the `context` of every event. When you forward those events to Meta's Conversions API, these parameters improve how well Meta matches events to people.

* `context.fbc`: The Facebook click ID, derived from the `fbclid` URL parameter and stored in the `_fbc` cookie.
* `context.fbp`: The Facebook browser ID, stored in the `_fbp` cookie.

Hightouch collects these values using [Meta's client-side ParamBuilder SDK](https://developers.facebook.com/docs/marketing-api/conversions-api/parameter-builder-feature-library/client-side-onboarding).

The plugin is opt-in. To turn it on, add `facebook-params` to the `plugins` option when you load the SDK.

If you installed with a `script` tag, add the option to the load call in the snippet:

```js theme={null}
htevents.load("WRITE_KEY", {
  apiHost: "us-east-1.hightouch-events.com",
  plugins: ["facebook-params"],
});
```

If you installed with `npm`, add the same option:

```jsx theme={null}
export const htevents = HtEventsBrowser.load(
  { writeKey: "WRITE_KEY" },
  {
    apiHost: "us-east-1.hightouch-events.com",
    plugins: ["facebook-params"],
  }
);
```

> [!NOTE]
>
> ParamBuilder writes the `_fbc`, `_fbp`, or `_fbi` first-party cookies when the
> SDK loads. If your site requires consent before setting tracking cookies, turn
> on this plugin only after the visitor consents.

Hightouch loads the plugin as a critical enrichment step, so the SDK waits for ParamBuilder to initialize before sending the first events. If ParamBuilder fails to load, Hightouch still sends events, without the `fbc` and `fbp` values.

### Braze

Use the Braze plugin to forward Hightouch calls to the Braze Web SDK in the browser. This lets Braze evaluate in-app message triggers while the visitor is active, alongside normal event collection in Hightouch.

Use version `1.7.0` or later of the Hightouch Browser SDK. Install the Braze Web SDK alongside it:

```bash theme={null}
npm install @ht-sdks/events-sdk-js-browser @braze/web-sdk@^6
```

Configure the destination with your Braze SDK API key and SDK endpoint. The plugin initializes Braze and opens its session:

```js theme={null}
import { HtEventsBrowser } from "@ht-sdks/events-sdk-js-browser";

const htevents = HtEventsBrowser.load(
  { writeKey: "YOUR_WRITE_KEY" },
  {
    apiHost: "us-east-1.hightouch-events.com",
    destinations: {
      Braze: {
        apiKey: "YOUR_BRAZE_SDK_API_KEY",
        baseUrl: "YOUR_BRAZE_SDK_ENDPOINT",
        sdk: () => import("@braze/web-sdk"),
        pageTracking: "name",
      },
    },
  }
);
```

The plugin forwards `identify` calls as user updates and `track` calls as custom events. By default, `Order Completed` and `Completed Order` become purchases, with one purchase per product. Page forwarding is off by default; `pageTracking: "name"` forwards `page` calls as custom events.

When the plugin initializes Braze, `automaticallyShowInAppMessages` defaults to `true`. Set it to `false` if your application provides custom in-app message presentation. Your application configures Content Cards and push notifications.

If Braze is already initialized, pass `instance: braze` instead of `apiKey`, `baseUrl`, and `sdk` to reuse it. With an existing instance, your application manages message presentation and sessions. The `automaticallyShowInAppMessages` option does not apply.

See the [Braze example](https://github.com/ht-sdks/events-sdk-js-mono/tree/master/examples/braze) for an application setup. If you're replacing an mParticle kit, follow Migrate the mParticle Braze kit to preserve your existing mappings.
