Koala Smartblock docs

This section is not public yet. Enter the password you received from Koala.

Skip to main content

Fresh integration

For a new integration, you add three things to your pages:

  1. a custom HTML element where the widget appears,
  2. a window.CTStore global object that carries the trip data and your event handlers,
  3. a loader script on the pages where Smartblock appears.

Before you start

Koala provides you with two elements:

  • your partner slug, used in the custom HTML element's data attribute data-config-name,
  • the loader script URLs, one for staging and one for production.

The loader script URL determines which Koala environment the widget talks to. Build your integration against the staging URL and switch to production at the last step (see Testing and going live).

Set up the widget

Place the custom HTML element

Put the following custom HTML element where the protection offer should appear. It inherits the available width from its container; you do not size it.

<koala-smartblock-sb4 data-config-name="your-slug"></koala-smartblock-sb4>

Set up window.CTStore before the loader

Create the global object with two properties:

  • dataSource: the trip context Koala prices against (currency, language, the trip, travellers).
  • koala: the Koala namespace. It must exist before the loader runs; its presence is also how the widget knows it belongs on the page. Register your event handlers on koala.events.
<script>
window.CTStore = {
dataSource: {
currency: 'EUR',
language: 'en-GB',
residence: 'IE',
custom: { context: 'checkout' },
tripPrice: 640,
segments: [
{
mode: 'FLIGHT',
airlineIata: 'FR',
number: '22',
departureAirportIata: 'DUB',
arrivalAirportIata: 'BGY',
departureDate: '2026-07-11T06:25:00',
departureTimezone: 'Europe/Dublin',
arrivalDate: '2026-07-11T09:50:00',
arrivalTimezone: 'Europe/Rome',
},
{
mode: 'FLIGHT',
airlineIata: 'FR',
number: '29',
departureAirportIata: 'BGY',
arrivalAirportIata: 'DUB',
departureDate: '2026-07-18T22:45:00',
departureTimezone: 'Europe/Rome',
arrivalDate: '2026-07-18T23:20:00',
arrivalTimezone: 'Europe/Dublin',
},
],
travelers: [
{ ageRange: 'ADULT', numberOfCheckedBags: 1 },
{ ageRange: 'CHILD', numberOfCheckedBags: 1 },
],
},
koala: {
events: {
onReady: [(status) => console.log('koala ready:', status)],
onAvail: [(status, data) => console.log('koala quotes:', status, data)],
onBundle: [(status, data) => console.log('koala bundle:', status, data.bundle)],
onBasket: [(status, data) => console.log('koala basket:', status, data)],
onError: [(status, data) => console.error('koala error:', data.message)],
},
},
};
</script>

Provide every date-time as a local ISO 8601 string with no UTC offset (for example 2026-07-11T06:25:00) together with its IANA timezone. The full field-by-field contract, the other trip shapes (stays, trains, buses, ferries), and the cross-field rules are documented in the reference page Trip context. This guide shows a flights-only trip as the worked example.

warning

The data and basket payload contracts are still evolving while Koala completes its integration with CarTrawler. Expect small changes before the final guide is published.

Set up the loader script

Include the following script tag once, after the custom HTML element is present in the DOM and window.CTStore is defined. It is asynchronous and does not block your page render.

<script async src="[koala-loader-staging-url]"></script>

If you cannot guarantee the order of static tags, create the loader script from code instead, once the element and the global object are both set up:

<script>
const loader = document.createElement('script');
loader.async = true;
loader.src = '[koala-loader-staging-url]';
document.head.append(loader);
</script>

That is all the wiring. The widget boots, fetches its configuration from Koala's CDN, prices the trip, and renders. See Widget loading for a detailed explanation of the load sequence.

Full page example

<section class="protection">
<koala-smartblock-sb4 data-config-name="your-slug"></koala-smartblock-sb4>
</section>

<script>
window.CTStore = {
dataSource: {
currency: 'EUR',
language: 'en-GB',
residence: 'IE',
custom: { context: 'checkout' },
tripPrice: 640,
segments: [
{
mode: 'FLIGHT',
airlineIata: 'FR',
number: '22',
departureAirportIata: 'DUB',
arrivalAirportIata: 'BGY',
departureDate: '2026-07-11T06:25:00',
departureTimezone: 'Europe/Dublin',
arrivalDate: '2026-07-11T09:50:00',
arrivalTimezone: 'Europe/Rome',
},
],
travelers: [{ ageRange: 'ADULT', numberOfCheckedBags: 1 }],
},
koala: {
events: {
onReady: [(status) => {}],
onAvail: [(status, data) => {}],
onBundle: [(status, data) => {}],
onBasket: [(status, data) => updateOrderSummary(data.selectedBundles)],
onError: [(status, data) => console.error(data.message)],
},
},
};
</script>

<script async src="[koala-loader-url]"></script>

Reacting to events

To react to events from the widget, like the widget loading or the customer interacting with it, register event handlers on window.CTStore.koala.events. For each event, an array of callbacks can be provided and will be called when the event occurs. Each callback is a function that receives (status, data):

EventWhen it firesdata
onReadythe widget started loading (START), then rendered (END)none
onAvailthe quote responded (SUCCESS or ERROR){ count, response }, or the reason
onBundlea bundle is selected, declined, or opened{ bundle }
onBasketthe basket changes (ADD or REMOVE)the Koala basket
onErroran integration failure: configuration, startup, or an unquotable trip context (ERROR){ message, code?, details?, error? }

The onBasket data is the Koala basket itself, so you read it directly:

window.CTStore.koala.events.onBasket = [
(status, data) => {
updateOrderSummary(data.selectedBundles); // your own function
},
];

The full event reference, statuses, and basket shape are documented in the reference page Events.

Updating the trip after page load

The widget quotes once at page load. If the trip changes afterwards (dates, travellers, currency), update window.CTStore.dataSource and call window.CTStore.koala.restart() to re-quote.

Create the subscription after booking

One last call completes the integration. After a booking ends with a sale on your side, your backend makes one HTTP POST to Koala, whether or not the traveller selected protection:

  • protection selected: the call creates the subscription, the traveller's policy;
  • nothing selected: the call deletes the quote, so Koala measures conversion against all bookings.

You never build this request yourself: the widget prepares it and keeps it up to date as the basket changes. The prepared request is the book object on window.CTStore.koala.basketPayload (also delivered with every onBasket event as data.book). It carries two properties:

  • msgRaw: the request body to send. When protection was selected, it contains [TOKEN] placeholders for the few values only your system knows: the booking number, the policyholder's details, and each traveller's name. When nothing was selected, only [BOOKINGNUMBER] is left to fill.
  • fullUrl: the URL to POST it to. The widget always points it at the right endpoint for the current basket.

Step 1, on your page: when the traveller submits the booking, pass the prepared book to your backend along with the booking:

// The prepared payload lives on the page. Send it to your backend with the booking.
const { book } = window.CTStore.koala.basketPayload;

await myApi.submitBooking({
// ...your own booking data...
koalaBook: { msgRaw: book.msgRaw, fullUrl: book.fullUrl },
});

Step 2, on your backend: once the booking is confirmed and paid, replace every [TOKEN] placeholder in msgRaw with the real values, then POST it to fullUrl as JSON:

// On your backend, after the booking is confirmed and paid.
const { msgRaw, fullUrl } = booking.koalaBook;

// Every token is unique, so replacing them across the whole body is safe.
const body = fillPlaceholders(msgRaw, {
'[BOOKINGNUMBER]': booking.reference,
'[CUSTOMER_FIRSTNAME]': booking.customer.firstName,
'[CUSTOMER_LASTNAME]': booking.customer.lastName,
'[CUSTOMER_EMAIL]': booking.customer.email,
'[CUSTOMER_LANGUAGE]': 'en-GB',
// One pair per traveller, in the order you quoted them.
'[TRAVELER_1_FIRSTNAME]': booking.travellers[0].firstName,
'[TRAVELER_1_LASTNAME]': booking.travellers[0].lastName,
});

await fetch(fullUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});

fillPlaceholders is your own helper: no token appears twice in the payload, so a replace over the serialized body is enough. If the booking is never completed, send nothing. The payload shape and the full placeholder list are documented in the reference page Request template; when to send it, a sample helper and the endpoint responses in Creating the subscription.

Checklist

Checklist0/6