# Kibble installation contract: section 16 of 29 (guide version 3)

> This is **one section only**, not the whole contract. Complete document: https://www.usekibble.dev/AI/guide.md

## 16. Outcomes {#outcomes}

An outcome is a confirmed business result: a purchase, a booking or a lead. A form submit, a checkout start, a click, a confirmation-looking URL or a thank-you heading alone is **never** a confirmed conversion. A form submit is an attempt (`form_submit`); only `form_accepted` is a confirmed success.

> **Note:** Always use the command form: `kibble('outcome', {...})`, `kibble('formAccepted', ...)`. Dotted calls such as `kibble.outcome(...)` or `kibble.formAccepted(...)` exist only after the SDK has loaded. The snippet's queue supports only the command form.

### The signals that confirm an outcome

1. `kibble('outcome', {type, ref, value?, currency?, items?})` from the confirmation step. `ref` is SHA-256 hashed in the browser with the property key; the raw value is never sent.
2. `kibble('formAccepted', formId, {ref?})` once the server accepted the submission (also sent by the Contact Form 7 hook). Pass a stable submission reference when the site has one (hashed in the browser). Without a reference, repeat submissions of the same form in one tab within 60 seconds count once; later submissions count separately.
3. Recognized dataLayer events: GA4 `purchase` with `transaction_id`, and `booking_confirmed` with `booking_ref`. **Hotels:** a booking engine that pushes GA4 `purchase` is recorded as a purchase, not a booking. Do not change the meaning in code; report it to the human, who maps that signal per host in Kibble (Data tracking → Events, where a hotel purchase is listed under Needs a decision; a gift-card purchase on the main site can stay a purchase).
4. Adapters: Shopify `checkout_completed`, BigCommerce `orderPurchased` ([Shopify](https://www.usekibble.dev/AI#shopify), [BigCommerce](https://www.usekibble.dev/AI#bigcommerce)).
5. A dataLayer message (the generic way for a tag manager or any backend-rendered page):

```js
dataLayer.push({ event: 'kibble_outcome', outcome_type: 'lead' /* or 'purchase' | 'booking' */, reference: 'ORDER-OR-BOOKING-OR-LEAD-REF', value: 120, currency: 'EUR' });
```

`purchase` and `booking` require `reference` to be confirmed. A `lead` without a reference is still recorded as a lead; see the counting rules below. A missing reference for a purchase or booking produces only an outcome candidate. Requires `data-datalayer="on"`.

Or markup on a confirmation page, read on page view including client-side navigation (same reference rules):

```html
<div data-kibble-confirmation="lead|purchase|booking" data-kibble-ref="ORDER-OR-BOOKING-REF" data-kibble-value="120" data-kibble-currency="EUR" hidden></div>
```

- The markup accepts `data-kibble-ref`, `data-kibble-value`, `data-kibble-currency` (three uppercase letters, otherwise dropped) and `data-kibble-form`.
- The element is re-read on every page view. An element that stays on the page across client-side navigation fires again on each one. A reference makes the repeat harmless. A lead without a reference does not; remove the element after it has fired.

Explicit call:

```js
await kibble('outcome', {
  type: 'booking',          // 'purchase' | 'booking' | 'lead'
  ref: 'BK-48213',          // your business reference; hashed in the browser before sending
  value: 612.0,             // optional
  currency: 'USD',          // optional, ISO 4217
  items: 1                  // optional
});
```

Emit it once, from the confirmed step, with a stable business reference. Without a reference nothing is sent. Never emit one on page load of a generic thank-you page, on click or on submit. Two outcomes with the same reference count once.

### How repeats are counted

- With a reference: the same reference counts once. If two signals disagree about the type for one reference, the first one observed wins.
- A lead **without** a reference (a `formAccepted` call without `ref`, or a `kibble_outcome` lead without `reference`): repeat submissions of the same form in one tab within 60 seconds count once. Later submissions count separately.
- A purchase or booking without a reference is never confirmed. It becomes a candidate.

### Outcome candidates (automatic, never confirmed)

By default the SDK emits `outcome_candidate` events for ambiguous signals. Set `data-auto-candidates="false"` to turn that off. A candidate is never a confirmed outcome. The signals:

- `url_confirmation_path`: a confirmation-looking URL path (the URL itself is never sent).
- `dl_generate_lead` and `dl_sign_up`: GA4 `generate_lead` and `sign_up`.
- `dl_purchase_no_ref` and `dl_booking_no_ref`: `purchase` without `transaction_id`, `booking_confirmed` without a reference.
- `dl_kibble_outcome_no_ref`: `kibble_outcome` for a purchase or booking without a reference.
- `markup_purchase_no_ref` and `markup_booking_no_ref`: confirmation markup without a reference.

Staff review candidates in Data tracking → Events (`/manage/data-tracking/events`, under Needs a decision): discovered, then approved with an outcome type, or ignored; an approved one can be changed or stop counting. Changes are prospective by default, with an optional bounded 30-day repair of past data. Approved candidates count at most once per type per visit and never on top of a confirmed outcome of that type; a booking or purchase candidate never adds a second transaction to a visit that already has one. As an installer you do not approve candidates; mention any you triggered in the report.

Outcomes come only from the browser signals documented here. There is no server-side outcome confirmation API.

END OF SECTION outcomes
