# Custom goals

URL: https://docs.ablyft.com/developers/tracking-and-events/custom-goals/

> Trigger conversions from your own JavaScript with ablyft.push().



A **custom goal** counts something that ABlyft cannot detect on its own: a form submission, a video played to the
end, a newsletter signup, a completed step in a configurator. Your website tells ABlyft when it happens with one
JavaScript call.

## Step 1: Create the goal in ABlyft

1. Go to **Targeting & Goals → Goals** and create a goal.
2. Choose the type **Custom** ("Trigger a conversion/value via JavaScript").
3. Check the **API Name**. It is filled in from the name and identifies the goal in your code, for example
   `newsletter-signup`.
4. Choose the **Measurement type**: **Conversion** (did the visitor do it or not?) or **Value** (a numeric value that you
   send with the call), see [Goal types](https://docs.ablyft.com/guides/goals-and-measurement/goal-types/#custom-goals).
5. Set the counting method and winning direction in **Statistic Settings**, then save.
6. [Assign the goal to your experiment](https://docs.ablyft.com/guides/goals-and-measurement/configure-goals/#assign-goals-to-an-experiment).

The form shows an **API Code** box with a ready-made call for your goal. Click to copy it.

## Step 2: Send the event from your website

```html
<script>
window['ablyft'] = window['ablyft'] || [];
window['ablyft'].push({
    eventType: 'custom',
    eventName: 'newsletter-signup'
});
</script>
```

All push parameters are listed in the [`push()` reference](https://docs.ablyft.com/developers/reference/javascript-api/push/#custom). The
`eventName` must match the **API Name** of the goal exactly.

For a goal with the measurement type **Value**, the API Code box adds `eventValue`:

```js
window['ablyft'] = window['ablyft'] || [];
window['ablyft'].push({
    eventType: 'custom',
    eventName: 'video-watched-seconds',
    eventValue: 42
});
```

> **Unknown names are ignored silently:** If `eventName` does not match the API Name of a goal, nothing happens and no error is shown. Compare the name letter by
> letter, and remember that new goals reach your visitors only after the project has been published.

## Calling it before the snippet has loaded

The line `window['ablyft'] = window['ablyft'] || [];` is important. If the snippet has not loaded yet, the call is stored
in a list. When the snippet starts, it replays all stored calls. You can therefore place goal calls anywhere on your page,
independent of the position of the snippet. Details: [queueing](https://docs.ablyft.com/developers/reference/javascript-api/#use-the-api-before-the-snippet-has-loaded).

## What gets counted

* The event is sent together with the variations the visitor is assigned to at that moment.
* How often repeated calls are counted depends on the counting method, see
  [Counting method](https://docs.ablyft.com/guides/goals-and-measurement/goal-types/#counting-method).
* In **preview mode**, goals are recorded for checking but not counted in the results.
* If tracking is not allowed yet, for example because the visitor has not given consent, the event is kept in the
  session and sent as soon as tracking is allowed. See [Consent manager](https://docs.ablyft.com/developers/consent-and-security/consent-manager/).

## Examples

**On a button click**

```js
document.querySelector('#download-brochure').addEventListener('click', () => {
  window.ablyft = window.ablyft || [];
  window.ablyft.push({ eventType: 'custom', eventName: 'brochure-download' });
});
```

For a plain click you do not need code: use a [click goal](https://docs.ablyft.com/developers/tracking-and-events/click-and-pageview-goals/) instead.

**When a form was sent successfully**

```js
document.querySelector('#contact-form').addEventListener('submit', () => {
  window.ablyft = window.ablyft || [];
  window.ablyft.push({ eventType: 'custom', eventName: 'contact-form-sent' });
});
```

If your form validates first, trigger the call in the success handler of your form instead of the `submit` event.

**Interaction goal (the visitor engaged with the page)**

Counts a visitor as "interacted" on the first click anywhere on the page, or after 10 seconds on the page, whichever
comes first. This is a low-barrier engagement goal.

Create a **Custom** goal with the API name `interaction`, the measurement type **Conversion** and the counting method
**One**. With **Every**, each click would be counted. Add the code to your [project JavaScript](https://docs.ablyft.com/developers/application-integration/custom-javascript/)
or to your page.

```js
function triggerInteractionGoal() {
  window['ablyft'] = window['ablyft'] || [];
  window['ablyft'].push({
    eventType: 'custom',
    eventName: 'interaction' // change if you use another API name
  });
}

// On every click
document.addEventListener('click', function () {
  triggerInteractionGoal();
});

// After 10 seconds
setTimeout(function () {
  triggerInteractionGoal();
}, 10 * 1000);
```

**In a single-page app, after a route change**

```js
function onThankYouViewRendered() {
  window.ablyft = window.ablyft || [];
  window.ablyft.push({ eventType: 'custom', eventName: 'order-confirmed' });
}
```

**From a tag manager**

Create a *Custom HTML* tag with the script from the API Code box and fire it on the trigger that matches your event, for example
a "form submission" trigger. Load the ABlyft snippet before or independent of it, both orders work.

**From a data layer event**

Use [`watchDataLayerEntry`](https://docs.ablyft.com/developers/tracking-and-events/datalayer-events/#run-code-when-an-entry-is-pushed) to push a goal when your data layer receives an event.

## Check that it works

1. Turn on [debug mode](https://docs.ablyft.com/developers/debugging/preview-and-live-log/#debug-mode) and open the console. A call logs
   `Triggered GOAL "<name>" (custom)`.
2. In preview mode, [`ablyft.get('pingedGoals')`](https://docs.ablyft.com/developers/reference/javascript-api/get/#pingedgoals) returns the goals sent in the current session.
3. Open the **Live Log** of your project to see the incoming events.

## Next steps

- [Revenue tracking](https://docs.ablyft.com/developers/tracking-and-events/revenue-tracking/): Send an order value.
- [Data layer events](https://docs.ablyft.com/developers/tracking-and-events/datalayer-events/): React to data layer entries.
- [Verify measurement](https://docs.ablyft.com/guides/goals-and-measurement/verify-measurement/): Check that goals arrive.

