Guest rewards widget

Integrate Kicbak

Kicbak is a guest rewards and account layer for travel operators’ direct-booking sites: guests join the operator’s rewards programme with one email, get a Kicbak account along the way, and see their exact cashback on every rate, at checkout, and on the booking confirmation. Integrating adds the widget to your site — one script tag (or one React provider) plus small anchor elements where the offers should appear. Your booking flow is never blocked or altered.

Tier 1 — the script tag

Works on any site. Add the tag once, before </body>, on every page of the booking funnel. The wallet chip appears on every page with no further markup; the other surfaces render into the anchor elements below.

html
<!-- Layer 1: once, before </body>. The chip appears on every page. -->
<script
  src="https://kicbak.co/widget/v1.js"
  data-kicbak-operator="wayfarer-demo"
  data-kicbak-property="The Wayfarer"
  data-kicbak-percent="5"
  data-kicbak-key="YOUR_API_KEY"
  data-kicbak-theme="slate"
  data-kicbak-chip-shape="pill"
  data-kicbak-tag-style="card"
></script>
FieldTypeRequiredDescription
data-kicbak-operatorstringrequiredYour operator id, as issued by Kicbak. Sent with capture and booking events.
data-kicbak-propertystringrequiredThe property name, used verbatim in the widget's copy (“Earn at The Wayfarer…”).
data-kicbak-percentnumberrequiredThe cashback percentage your programme offers. Reward amounts on rates are computed from it.
data-kicbak-keystringrequiredYour publishable widget key. Browser-safe by design — see Keys below. Leave unset to run against the mock.
data-kicbak-theme"slate" | "light" | "graphite"optionalWhich of the three named finishes the whole widget family wears. Default: slate.
data-kicbak-chip-shape"pill" | "round"optionalWallet chip shape: horizontal pill with the label visible (default), or a round icon-only button.
data-kicbak-tag-style"card" | "pill"optionalReward-tag style on each rate: a reward card with a button (default), or a one-line pill beside the price.

Anchor elements (script tag)

Each surface renders into an anchor you place in your own markup. The script tag stays identical; only the anchors change per page. Amounts are the stay total with two decimals.

Join banner (homepage and rates page)

The programme offer on the homepage and rates page, with the join form. It turns into the confirmation where the guest joined; a member never sees it.

html
<!-- Where the banner renders: directly under the hero. -->
<div data-kicbak-banner></div>

Reward tag on each rate

Layer 2. Hand it the stay total and it shows the exact amount back for that rate — the same number in both states, only the owner changes. Every anonymous offer carries a button.

html
<!-- Per room: the stay total, two decimals. -->
<div data-kicbak-rate="518.00"></div>

Checkout offer

Layer 2. Pre-filled from the booking form's own email field so the opt-in is one tap; a member sees the reward as a line item, locked to this booking.

html
<!-- The booking form's email field, so the offer is prefilled. -->
<input type="email" name="email" data-kicbak-booking-email="" />
<!-- Above the confirm button: the checkout total, two decimals. -->
<div data-kicbak-checkout-total="518.00"></div>

Confirmation

Layer 2's conversion event, plus the last offer in the funnel: a member sees the reward pending their stay; a guest who booked without joining can still claim it with the booking email.

html
<!-- On the confirmation page: the booking total, two decimals. -->
<div data-kicbak-confirmation="518.00"></div>
<script>
  window.kicbak.bookingConfirmed({ reference: "WYF-40182", total: 518, room: "Forest Suite" });
</script>

Tier 2 — React components

For a React site, wrap the app once in the provider — it renders the wallet chip on every page — then place a component per surface. The package name is provisional.

tsx
import { KicbakRewards } from "@kicbak/rewards-react";

export default function Layout({ children }) {
  return (
    <KicbakRewards
      operator="wayfarer-demo"
      property="The Wayfarer"
      percent={5}
      apiKey="YOUR_API_KEY"
      variants={{ theme: "slate", chipShape: "pill", tagStyle: "card" }}
    >
      {children}
    </KicbakRewards>
  );
}

Join banner

tsx
import { RewardsBanner } from "@kicbak/rewards-react";

// Directly under the hero, and again on the rates page.
<RewardsBanner className="mt-6" />

Reward on a rate

tsx
import { RateTag } from "@kicbak/rewards-react";

// Per room, beside the price. The total is nightly × nights for the chosen dates.
<RateTag total={stayTotal} />

Checkout offer

tsx
import { CheckoutRewards } from "@kicbak/rewards-react";

// Tag the booking form's email field so the offer follows it:
<input type="email" data-kicbak-booking-email {...register("email")} />

// Then, above the confirm button:
<CheckoutRewards total={total} prefill={email} />

Confirmation

tsx
import { ConfirmationRewards } from "@kicbak/rewards-react";

<ConfirmationRewards
  booking={{ reference, total, room: room.name }}
  bookingEmail={email}
/>

Keys

There are two credentials and they never trade places. The publishable widget key (data-kicbak-key / apiKey) is browser-safe: it only identifies your programme to the widget endpoints. The server credential (client key and client secret) is used by your server for booking-amount enrollment quotes and booking hand-off, and must never appear in the browser, in client bundles, or in this widget’s attributes. With no key configured the widget runs against the mock — see verification below.

Themes

The widget ships in exactly three finishes, chosen by name with data-kicbak-theme: slate (the default), light for pale sites, and graphite for dark ones. One pick re-themes the whole family — chip, mini wallet, banner, and reward tags together. The widget is a brand-locked element: pick a finish, never recolor or restyle it.

Verify the integration

With no key configured the widget runs against the in-process mock — the mode this demo runs in by default — so every check below works before any credential exists. Each check is pass/fail:

  1. The chip renders on every page. document.querySelector('button[aria-haspopup="dialog"]') returns an element fixed to the bottom-right corner, on the homepage, rates, checkout, and confirmation pages alike. Null on any page means the script tag (or provider) is missing there.
  2. Joining flips the chip to its active state. Click the chip, submit any well-formed email in the panel’s form, and the chip re-renders in the active state — its text now contains “Kicbak active” instead of the join prompt. In mock mode this is on-site state only; no real account is created.
  3. Rate tags show a computed amount. An anchor with a stay total — e.g. <div data-kicbak-rate="518.00"> or <RateTag total={518} /> at 5% — renders a currency amount (“$26”) in its offer text. A tag with a non-numeric, zero, or negative total renders nothing, by design.
  4. Checkout and confirmation anchors render. With the anchors from this page in place, the checkout page shows the offer prefilled from the data-kicbak-booking-email field, and the confirmation page shows the claim (anonymous) or pending-reward (joined) state for the booking total.

Paste this to your AI assistant

Working with an AI coding agent? Copy this prompt; it points the agent at this page and scopes the work correctly.

text
Integrate the Kicbak guest rewards widget into this site.
Fetch https://kicbak.co/docs/integrate and follow it exactly — it is the
single source of truth. Use the script-tag integration unless this site is
React, in which case use the React components. Add the script tag (or
provider) once, then place the anchor elements: the join banner under the
hero and on the rates page, a rate tag beside every room price with the stay
total, the booking-email and checkout-total anchors on the checkout page,
and the confirmation anchor plus the bookingConfirmed call on the
confirmation page. Keep our existing markup and styles untouched; the widget
is brand-locked and must not be restyled. Leave the key unset for now and
run the page's verification checks before telling me it works.