You are viewing a non-production environment — the API surface may differ from production.

Booking attribution

Capture marketing discovery, booking acquisition and guest-reported sources separately from booking and ordering channels.

Booking attribution is an optional built-in attribution object, available to every venue without custom-field entitlements. It is recorded atomically when a booking is created and remains unchanged when the booking is edited, seated, cancelled or completed. Historical bookings have attribution: null; Karma does not reconstruct past marketing journeys.

Channel versus marketing source

bookingSource describes how the reservation was made (website, app, phone, walkin, etc.). A purchase/order channel such as QR or POS describes how an order was placed. Neither identifies the original marketing source.

attribution.firstTouch records the earliest observed entry in the current venue-scoped session. attribution.bookingTouch records the most recent observed campaign or external referral before booking; it is not necessarily the booking page itself. Untagged internal navigation does not replace acquisition. reportedSource is an optional source explicitly reported by a guest or staff member. Missing UTMs do not prove a direct visit: a referrer can be unavailable.

Capturing attribution

The Karma storefront automatically captures UTM parameters and external referrers before authentication. Venue-scoped session storage preserves the first touch through login and booking steps, with a maximum age of 24 hours; blocked storage falls back to memory. The Karma app captures venue-specific campaign deep links within the app session. No tracking identifier or cross-session browsing history is created.

A custom website or API integration must collect attribution itself and send it with POST /api/v1/bookings:

{
  "locationId": 17099,
  "bookingDate": "2026-11-01",
  "startTime": "18:00:00",
  "endTime": "19:30:00",
  "timezone": "Europe/Stockholm",
  "guestCount": 2,
  "bookingSource": "website",
  "attribution": {
    "firstTouch": {
      "capturedAt": "2026-10-11T12:00:00Z",
      "utmSource": "instagram",
      "utmMedium": "social",
      "utmCampaign": "autumn",
      "landingPage": "https://gp.example/menu"
    },
    "bookingTouch": {
      "capturedAt": "2026-10-11T13:00:00Z",
      "utmSource": "google",
      "utmMedium": "cpc",
      "utmCampaign": "dinner",
      "referrer": "https://www.google.com/",
      "landingPage": "https://gp.example/book"
    }
  }
}

Touches support utmSource, utmMedium, utmCampaign, utmContent, utmTerm, referrer and landingPage, plus the required ISO capturedAt. Campaign and reported-source strings are limited to 500 characters. Karma strips URL queries, fragments and credentials and adds its own recordedAt timestamp. These observations are client-reported, not independently verified evidence of an ad click. Record only values your website actually observed.

The creation permission is sufficient to submit attribution; no generic metadata update or custom-field write is needed. A separate read-only analytics key can read it using normal booking-read permissions. Public confirmation-code lookups omit attribution.

Embedding the booking flow

Use the embed script hosted by the same Karma storefront environment as your booking URL:

<script async src="https://store.karma.life/booking-widget.js"
  data-karma-booking="https://store.karma.life/guiltypleasure/book"></script>

The script inserts the booking iframe after itself and passes the merchant page's session-scoped attribution to the frame. The bridge checks both message origin and sender. This matters because an iframe cannot read its cross-origin parent page's campaign parameters. A bare iframe only observes its own URL and browser-provided referrer; use this script or include UTMs explicitly in the iframe URL.

To preserve discovery before the booking page, install the same script on your landing/menu pages in attribution-only mode, with the same booking URL:

<script async src="https://store.karma.life/booking-widget.js"
  data-karma-booking="https://store.karma.life/guiltypleasure/book"
  data-karma-attribution-only></script>

This captures the session without displaying an iframe. On the booking page, use the embed snippet without data-karma-attribution-only. Capture starts on pages where the script runs; Karma cannot see uninstrumented third-party pages.

Walk-ins and phone bookings

Staff can enter “How did the guest hear about you?” when creating a booking. API integrations can send attribution: { "reportedSource": "A friend" }. An unknown source remains unknown. QR orders without an associated booking do not gain booking attribution automatically.

Reading the journey and revenue

Merchant booking lists show the marketing source below the booking channel. Booking details show first discovery, booking touch, reported source and expandable campaign details. Normal merchant/API booking list and detail responses include attribution; webhooks carrying a full booking include the same snapshot.

Link tabs using their bookingId, then purchases using their tabId. Include all tabs for a multi-resource booking and confirmed payments, subtract confirmed refunds, and avoid double-counting deposits or split payments. A booking's tabId can be absent once its tab is closed; retain the tab-to-booking relationship rather than relying on that active-tab convenience field. Estimated revenue is not actual paid revenue. See Reading sales data.

Deployment

Requires database migration 20261011230000_booking_marketing_attribution.ts from the central database repository before deploying the updated common API. Client capture alone does not enable storage in an environment running the older API.

On this page