Ancillaries Component

About

The ancillaries component is a JavaScript component you can use to allow your customers to add ancillaries to their order. It's simple to add to your website and can be customised to fit your brand.
This guide explains how to integrate it, along with examples and sample code.
Logo for undefined

See it on GitHub

You can find the source code and release notes for this component on GitHub.

Logo for undefined

See it on npm

This component is available to be installed with npm.

Why sell ancillaries?

Ancillaries in air travel refer to additional products and services that airlines offer beyond the basic ticket price, for example seat selection or extra baggage.
Ancillaries have higher profit margins than the base ticket price, so selling them can increase your revenue and profit. Selling ancillaries also helps you provide more value to your customers, differentiating you from your competitors.
Our component makes it easy to apply a markup to the ancillaries you sell, so you can increase your revenue even further.

Live demo

Below is an interactive demo of the ancillaries component in a test environment.

Step-by-step guide

The following instructions are aimed at people using React, but the component can be used in any JavaScript environment with a few tweaks. To learn more, see Using the component in non-React environments.
For a working example of this setup, see the example in the repository.

1. Install the component

Shell (using yarn)

yarn add @duffel/components

⒉ Add the component to your page

The components expects a few properties: either an offer or offer ID, passengers, and an array of which ancillaries to display. For this example, we'll use the offer ID "fixture_off_1", which will tell the component to load a pre-made example offer. We'll also add debug={true} which enables debug mode, which will show you more information about what's happening in the component in your browser's console.
Other properties can be supplied too, but they aren't used in this guide. For a full list of all properties, see configuration options below.

React

import { DuffelAncillaries } from '@duffel/components'
const MyComponent = () => (
<DuffelAncillaries
debug={true}
offer_id="fixture_off_1"
services={['bags', 'seats', 'cancel_for_any_reason']}
passengers={[
{
id: 'pas_0000AUde3KY1SptM6ABSfU',
given_name: 'Mae',
family_name: 'Jemison',
gender: 'F',
title: 'dr',
born_on: '1956-10-17',
email: 'm.jemison@nasa.gov',
phone_number: '+16177562626',
},
{
id: 'pas_0000AUde3KY1SptM6ABSfT',
given_name: 'Dorothy',
family_name: 'Green',
gender: 'F',
title: 'dr',
born_on: '1942-10-17',
},
]}
onPayloadReady={console.log}
/>
)

3. Handling selection

Every time a user selects ancillaries, the component emits an onPayloadReady event, which is an object containing two properties:
  • data: A JSON object matching the Duffel API's order creation payload schema that you can then use to create the order from your server.

  • metadata: An object with helpful information about the selected ancillaries, which can be used to enrich your price breakdown or order summary with the description and price of the selected ancillaries.

This event is emitted every time a user completes each separate ancillaries flow. For example, if the user selects additional baggage, then selects seats, the event will be sent twice. Because of this, you should only create the order once the user has indicated they're ready to place the order, for example by pressing a Book button in your booking flow.

React

<DuffelAncillaries
debug={true}
offer_id="fixture_off_1"
services={["bags", "seats", "cancel_for_any_reason"]}
passengers={[ ... ]}
onPayloadReady={(data: CreateOrderPayload, metadata: OnPayloadReadyMetadata) => {
/**
* In a real environment, instead of logging the data, you'd post the payload
* to your server so it can be used to
* create an order with the Duffel API.
*
* For more information on creating orders, see
* https://duffel.com/docs/guides/quick-start#creating-a-booking-using-the-selected-offer
*/
console.log('Ancillaries selected. Order payload:', data)
console.log('Ancillaries selected. Ancillary services chosen:', metadata)
}}
/>

Using real data

By now you should have a working example of the ancillaries component, using a pre-made example offer. There are two ways you can make the component use real offers retrieved from the Duffel API.

Option A: Using an offer ID and client key

By passing in an offer ID, the component can use the Duffel API to retrieve information about the offer, like which ancillaries are available and the plane's seat maps. When using this method, you must include a client key for authentication. The client key is returned with a create offer request to the Duffel API.

React

<DuffelAncillaries
debug={true}
offer_id='offer_id_here'
client_key='client_key_here'
services={["bags", "seats", "cancel_for_any_reason"]}
passengers={[ ... ]}
onPayloadReady={console.log}
/>

Option B: Using a full offer

If you already have an offer object retrieved from a create offer request to the Duffel API, you can pass this into the component instead of an offer ID.
Because the component needs to know the seat maps of the plane, you have two options for supplying it. You can pass in a client key that was returned with your initial create offer request to the Duffel API, in which case the component will retrieve the seat maps using the Duffel API on your behalf, or if you've already retrieved the seat maps for this offer, you can pass it in yourself.

React

// Using a client key so that the component retrieves the seat map itself.
<DuffelAncillaries
debug={true}
services={['bags', 'seats', 'cancel_for_any_reason']}
offer={ ... }
client_key='client_key_here'
passengers={[ ... ]}
/>
// You may include the seat map, so the component won't retrieve it.
<DuffelAncillaries
debug={true}
services={['bags', 'seats', 'cancel_for_any_reason']}
offer={ ... }
seat_maps={ ... }
passengers={[ ... ]}
/>

Adding a markup

Duffel helps you make money from selling travel, and adding markups is one of the best tools you have to do this. The component offers two ways to add markups to the ancillaries you sell.

Note

Option A: Simple markup

Pass a markup object as a property when initialising the component, with a key for each ancillary you want to mark up. Each ancillary has an amount and a rate property. The amount property is a fixed amount to add to the price of each ancillary, and the rate property is a percentage to add to the price of each ancillary.

JavaScript

markup: {
bags: {
amount: 1, // Add 1.00 to the price of each bag
rate: 0.01, // Also add 1% to the price of each bag
},
seats: {
amount: 2, // Add 2.00 to the price of each seat
rate: 0, // Don't add any percentage markup
},
cancel_for_any_reason: {
amount: 0, // Don't add any amount markup
rate: 0.25, // Add 25% to Cancel For Any Reason.
},
}
When calculating prices, rate is applied first, followed by amount. For example, if a bag costs 10.00, and you have a markup of amount: 1 and rate: 0.1, the final price will be 12.00 (10 increased by 10% is 11, plus 1 to make 12).

Option B: Advanced markup

This is aimed at those who need more control over how the markup is calculated. For example, you might want to mark up some bags more than others. If you don't need this level of control, we recommend using the simpler markup option instead.

JavaScript

priceFormatters: {
bags: (amount, currency, service) => {
// If the bag costs less than $20, add a 20% markup.
// Otherwise, add a 10% markup.
const percentageMarkup = amount < 20 ? 0.2 : 0.1
return { amount: amount * (1 + percentageMarkup) }
}
}
You can also use this option to display prices in bespoke currencies, like loyalty scheme points. To do this, include a currency property in the object you return from the price formatter.

JavaScript

priceFormatters: {
bags: (amount, currency, service) => {
const moneyToPointsExchangeRate = 100 // $1.00 = 100 points
return {
amount: amount * moneyToPointsExchangeRate,
currency: 'Duffel Points',
}
}
}

Using the component in non-React environments

If you're not using React, there are two methods you can use to add the component to your website.

Option A: Using npm or yarn

For a working example of this setup, see the example in the repository.
Install the component:

Shell (using yarn)

yarn add @duffel/components
Import it into your page:

JavaScript

import {
onDuffelAncillariesPayloadReady,
renderDuffelAncillariesCustomElement,
} from '@duffel/components'
Add it to the place on your page you want it to appear:

HTML

<duffel-ancillaries></duffel-ancillaries>
Finally, call renderDuffelAncillariesCustomElement to render it. The function accepts an object with the same properties as the React component, so see the React guide for more details.

JavaScript

window.onload = function () {
renderDuffelAncillariesCustomElement({
debug: true,
offer_id: 'fixture_off_1',
services: ['bags', 'seats', 'cancel_for_any_reason'],
passengers: [ ... ]
}
A callback function can be passed to onDuffelAncillariesPayloadReady to receive the payload when the user selects ancillaries. This function executes every time a user completes each separate ancillaries flow. For example, if the user selects additional baggage, then selects seats, the event will be sent twice.

JavaScript

onDuffelAncillariesPayloadReady((data, metadata) => {
/**
* In a real environment, instead of logging the data, you'd post the payload
* to your server so it can be used to
* create an order with the Duffel API.
*
* For more information on creating orders, see
* https://duffel.com/docs/guides/quick-start#creating-a-booking-using-the-selected-offer
*/
console.log('Ancillaries selected. Order payload:', data)
console.log('Ancillaries selected. Ancillary services chose:', metadata)
})

Option B: Using the Duffel CDN

For a working example of this setup, see the example in the repository.
Load the component by adding a script to your page's <head> element.

HTML

<!--
Replace <VERSION> with the version you want to use. See
https://github.com/duffelhq/duffel-components/releases
for a list of versions.
-->
<script
type="text/javascript"
src="https://assets.duffel.com/components/ancillaries/<VERSION>/index.js"
></script>
Add it to the place on your page you want it to appear:

HTML

<duffel-ancillaries></duffel-ancillaries>
Finally, select the component on your page and call render to render it. The function accepts an object with the same properties as the React component, so see the React guide for more details.

JavaScript

window.onload = function () {
document.querySelector('duffel-ancillaries').render({
debug: true,
offer_id: 'fixture_off_1',
services: ['bags', 'seats', 'cancel_for_any_reason'],
passengers: [ ... ],
})
}
An event is emitted every time the user selects ancillaries, allowing you to receive the order creation payload. This event is emitted every time a user completes each separate ancillaries flow. For example, if the user selects additional baggage, then selects seats, the event will be sent twice.

JavaScript

document
.querySelector('duffel-ancillaries')
.addEventListener('onPayloadReady', (event) => {
/**
* In a real environment, instead of logging the data, you'd post the payload
* to your server so it can be used to
* create an order with the Duffel API.
*
* For more information on creating orders, see
* https://duffel.com/docs/guides/quick-start#creating-a-booking-using-the-selected-offer
*/
console.log('Ancillaries selected. Order payload:', event.detail.data)
console.log(
'Ancillaries selected. Ancillary services chose:',
event.detail.metadata
)
})

Render options

All possible properties that can be included when initialising the component.

debug

Whether to print extra information about how the component is being set up to your browser's console. Defaults to false.
**Note: ** We advise setting this to true when you're first setting up the component, but to set it to false in production.

services

Which ancillaries to include when displaying the component. The possible values are bags, seats and cancel_for_any_reason, and you must include at least one ancillary.

client_key

A client key for authentication. This is returned under the attribute client_key with a create offer request to the Duffel API. This field is required if offer or seat_maps are not part of the configuration options.

offer

An offer retrieved from Duffel's API. You can pass in either this or offer_id, but not both.

offer_id

The ID of an offer retrieved from Duffel's API. You can pass in either this or offer, but not both. If you include offer_id, client_key is required.

seat_maps

A seat map from The Duffel API's get seat map endpoint. This is optional, but if you don't supply it you must supply client_key so that the component can retrieve the seat maps from the Duffel API itself.

passengers

An array of passengers. Below are some example passengers you can use.

JavaScript

passengers: [
{
id: 'pas_001',
given_name: 'Mae',
family_name: 'Jemison',
gender: 'F',
title: 'dr',
born_on: '1956-10-17',
email: 'm.jemison@nasa.gov',
phone_number: '+16177562626',
},
{
id: 'pas_002',
given_name: 'Amelia',
family_name: 'Earhart',
gender: 'F',
title: 'mrs',
born_on: '1987-07-24',
email: 'amelia@duffel.com',
phone_number: '+442080160509',
},
]

markup

An object that can be used to add markups to the ancillaries you sell. See the Adding a markup section for more details.
markup is an object with the following structure:

JavaScript

{
// The service you want to add a markup to.
// Possible values are 'bags', 'seats' and 'cancel_for_any_reason'.
[service]: {
// A fixed amount to add to the price of each ancillary, e.g. 1
amount: number,
// A percentage to add to the price of each ancillary, e.g. 0.1 for 10%
rate: number,
},
}
You cannot supply both markup and priceFormatters at the same time for the same service.

priceFormatters

An object that can be used to customise the prices displayed in the component. See the Adding a markup section for more details.
priceFormatters is an object with the following structure:

JavaScript

{
// The service you want to add a markup to.
// Possible values are 'bags', 'seats' and 'cancel_for_any_reason'.
[service]: (amount, currency, service) => {
// A function that takes the amount, currency and service as arguments
// and returns an object with the following structure:
return {
// The new amount to display.
amount: number,
// The currency to display, e.g. "GBP", or "Points".
// Currency is optional, and if not supplied the original currency will be used.
// If currency is a valid ISO 4217 currency code, the amount will be formatted automatically.
// For example, if currency is "GBP" and amount is 1.23, the amount will be formatted as "£1.23".
currency: string,
}
},
}
You cannot supply both priceFormatters and markup at the same time for the same service.

styles

An object that can be used to make the component match your brand. It includes:
  • accentColor: A comma-separated string of RGB values to customise the component's UI, for example "34,139,34".

  • buttonCornerRadius: A string with the corner radius to apply to buttons, for example "8px".

  • fontFamily: A string with the name of the font family to use, for example "Menlo".

JavaScript

styles: {
accentColor: "34,139,34",
buttonCornerRadius: "8px",
fontFamily: "Menlo, Courier, Monospace",
}

Note