For developers who need complete control over UI and want to build custom search interfaces, the Switchfly JavaScript SDK provides direct access to location APIs and URL building without using pre-built widgets.
Use Pre-built Widgets when:
You want a ready-made, tested UI with minimal integration effort
Standard search functionality meets your needs
You prefer iframe or script embed without writing custom code
You need multi-product search (air, hotel, car, activities, bundles) out of the box
Use JavaScript SDK when:
You need complete UI control (custom forms, styling, frameworks)
Building a highly customized search experience
Integrating search into existing UI patterns or design systems
Want to compose search functionality with other features (e.g., combining with your own filters, recommendation engine, etc.)
Installation
ES Modules (recommended):
import { createClient } from 'https://your-cdn.com/packages/sdk/src/index.js' ;
NPM (when published):
npm install @switchfly/sdk
import { createClient } from '@switchfly/sdk' ;
Quick Start Example (Hotel Search)
Complete working example showing location autocomplete and search URL generation:
<! DOCTYPE html >
< html>
< head>
< title> Custom Hotel Search</ title>
</ head>
< body>
< form id = " hotelSearchForm" >
< input type = " text" id = " destination" placeholder = " Enter city" autocomplete = " off" required >
< div id = " autocompleteResults" > </ div>
< input type = " date" id = " checkin" required >
< input type = " date" id = " checkout" required >
< button type = " submit" > Search Hotels</ button>
</ form>
< script type = " module" >
import { createClient } from 'https://your-cdn.com/packages/sdk/src/index.js';
// Initialize SDK client
const sdk = createClient({
targetUrl: 'https://your-booking-site.com',
locale: 'en-US'
});
let selectedLocation = null;
let debounceTimer = null;
const destinationInput = document.getElementById('destination');
const autocompleteResults = document.getElementById('autocompleteResults');
const form = document.getElementById('hotelSearchForm');
// Location autocomplete
destinationInput.addEventListener('input', async (e) => {
const query = e.target.value.trim();
clearTimeout(debounceTimer);
selectedLocation = null;
if (query.length < 2) {
autocompleteResults.innerHTML = '';
return;
}
debounceTimer = setTimeout(async () => {
try {
const response = await sdk.locations.suggest({
query,
locationType: 'DESTINATION',
productTypes: 'ROOM' // Use 'ROOM' for hotel searches
});
const locations = response?.data?.locations || [];
// Render results
autocompleteResults.innerHTML = locations.map(loc => `
< div class = " autocomplete-item" data-location = ' ${JSON.stringify(loc)}' >
${loc.nameDisplayValue || loc.displayValue}
</ div>
`).join('');
// Handle selection
autocompleteResults.querySelectorAll('.autocomplete-item').forEach(item => {
item.addEventListener('click', () => {
const loc = JSON.parse(item.dataset.location);
selectedLocation = loc;
destinationInput.value = loc.nameDisplayValue || loc.displayValue;
autocompleteResults.innerHTML = '';
});
});
} catch (error) {
console.error('Autocomplete error:', error);
}
}, 300);
});
// Form submission
form.addEventListener('submit', (e) => {
e.preventDefault();
if (!selectedLocation) {
alert('Please select a destination');
return;
}
// Build search URL
const searchInfo = {
type: 'HOTEL',
location: selectedLocation.search, // Location token like '|city:7321'
fromDate: document.getElementById('checkin').value,
toDate: document.getElementById('checkout').value,
rooms: [{ adults: 2, childAges: [] }]
};
const url = sdk.search.buildUrl(searchInfo);
console.log('Search URL:', url.href);
window.location.href = url.href; // Navigate to search results
});
</ script>
</ body>
</ html>
API Reference
createClient(config)
Create an SDK client instance.
Parameters:
config.targetUrl (string, required): Target booking platform URL (e.g., 'https://your-booking-site.com')
config.locale (string, optional): Locale string (e.g., 'en-US', 'fr', 'es', 'ja')
config.cobrand (string, optional): Cobrand identifier for analytics/tracking
config.apiPathPrefix (string, optional): Custom API path prefix (default: '')
config.timeout (number, optional): Default request timeout in milliseconds (default: 10000)
config.headers (object, optional): Custom headers for API requests
config.fetch (function, optional): Custom fetch implementation
Returns: SDK client instance with locations, search, and utils modules
Example:
const sdk = createClient ( {
targetUrl : 'https://your-booking-site.com' ,
locale : 'en-US' ,
cobrand : 'partner123' ,
timeout : 15000
} ) ;
sdk.locations.suggest(options)
Search for location suggestions (autocomplete).
Parameters:
options.query (string, required): Search query (minimum 2 characters recommended)
options.locationType (string, required): Location type
'ORIGIN' - Departure locations (airports)
'DESTINATION' - Arrival/destination locations (cities, airports, hotels)
'ORIGIN_DESTINATION' - Both origin and destination
options.productTypes (string, required): Comma-separated product types
'AIR' - Flights/airports
'ROOM' - Hotels/accommodations (note: use ROOM, not HOTEL)
'CAR' - Car rentals
'ACTIVITY' - Activities/experiences
Examples: 'AIR', 'ROOM', 'AIR,ROOM'
options.includeHotels (boolean, optional): Include individual hotel properties in results
options.originLocation (string, optional): Origin location token for route-based filtering
options.crsName (string, optional): Filter by CRS system name
options.provider (string, optional): Filter by provider
options.signal (AbortSignal, optional): AbortSignal for request cancellation
Returns: Promise with structure:
{
data : {
locations : [
{
nameDisplayValue : "San Diego, California, United States" ,
displayValue : "San Diego, California, United States" ,
locationType : "CITY" ,
search : "|city:7321"
}
]
}
}
Example:
const results = await sdk. locations. suggest ( {
query : 'san diego' ,
locationType : 'DESTINATION' ,
productTypes : 'ROOM'
} ) ;
const locations = results. data. locations;
locations. forEach ( loc => {
console. log ( loc. nameDisplayValue, loc. search) ;
} ) ;
sdk.locations.resolve(options)
Resolve a prefilled location token to a full location object. Useful when you have a location token (e.g., from URL params) and need display information.
Parameters:
options.searchParam (string, required): Location token (e.g., '|city:7321', '|airport:LAX')
options.prefillLabel (string, optional): Display label for numeric city IDs (required for numeric IDs since typeahead API cannot resolve them)
options.locationType (string, required): Location type ('ORIGIN', 'DESTINATION', 'ORIGIN_DESTINATION')
options.productTypes (string, required): Product types (e.g., 'ROOM', 'AIR')
Returns: Promise<Object|null> - Resolved location object or null if not found
Example:
const location = await sdk. locations. resolve ( {
searchParam : '|airport:LAX' ,
locationType : 'DESTINATION' ,
productTypes : 'ROOM'
} ) ;
const location = await sdk. locations. resolve ( {
searchParam : '|city:7321' ,
prefillLabel : 'San Diego' ,
locationType : 'DESTINATION' ,
productTypes : 'ROOM'
} ) ;
sdk.search.buildUrl(searchInfo, config?)
Build a shopping platform deep-link URL for search results.
Parameters:
searchInfo object (required):
searchInfo.type (string, required): Product type
'AIR' - Flights only
'HOTEL' - Hotels only
'CAR' - Car rentals only
'ACTIVITY' - Activities only
'BUNDLE' - Multi-product bundles (requires bundleTypes)
searchInfo.bundleTypes (array, required if type='BUNDLE'): Array of bundle products (e.g., ['AIR', 'HOTEL'])
searchInfo.location (string, required): Destination location token from locations.suggest() (e.g., '|city:7321')
searchInfo.fromDate (string|Date, required): Start/check-in date (ISO format: '2026-03-15' or Date object)
searchInfo.toDate (string|Date, optional): End/check-out date (required for hotel, optional for one-way flights)
searchInfo.fromLocation (string, required for AIR/CAR): Origin location token (e.g., '|airport:LAX')
Traveler Configuration (Hotels/Bundles):
searchInfo.rooms (array, optional): Room configurationsrooms : [
{ adults : 2 , childAges : [ 8 , 5 ] } ,
{ adults : 1 , childAges : [ ] }
]
Traveler Configuration (Air/Car/Activities - flat structure):
searchInfo.numAdults (number, optional): Number of adults (default: 2)
searchInfo.childAges (array, optional): Array of child ages (e.g., [8, 5])
Air-specific:
searchInfo.serviceClass (string, optional): 'coach', 'premiumeconomy', 'business', 'first' (default: 'coach')
searchInfo.roundtrip (boolean, optional): true for roundtrip, false for one-way (default: true)
searchInfo.airline (string, optional): Airline code filter (e.g., 'UA')
searchInfo.directOnly (boolean, optional): Direct/non-stop flights only
Car-specific:
searchInfo.fromTime (string, optional): Pick-up time in 24hr format (e.g., '14' for 2pm, default: '12')
searchInfo.toTime (string, optional): Drop-off time in 24hr format (default: '12')
searchInfo.driverAgeDefault (boolean, optional): Use default driver age
searchInfo.driverAge (number, optional): Specific driver age
config object (optional): Additional parameters for analytics/tracking
Any additional properties are passed through as URL parameters
Returns: URL object (use .href property for full URL string)
Examples:
Hotel Search:
const url = sdk. search. buildUrl ( {
type : 'HOTEL' ,
location : '|city:7321' ,
fromDate : '2026-03-15' ,
toDate : '2026-03-20' ,
rooms : [
{ adults : 2 , childAges : [ 8 , 5 ] }
]
} ) ;
window. location. href = url. href;
Air Search (Roundtrip):
const url = sdk. search. buildUrl ( {
type : 'AIR' ,
fromLocation : '|airport:LAX' ,
location : '|airport:JFK' ,
fromDate : '2026-03-15' ,
toDate : '2026-03-22' ,
numAdults : 2 ,
childAges : [ 8 ] ,
serviceClass : 'business' ,
directOnly : true
} ) ;
Bundle Search (Flight + Hotel):
const url = sdk. search. buildUrl ( {
type : 'BUNDLE' ,
bundleTypes : [ 'AIR' , 'HOTEL' ] ,
fromLocation : '|airport:LAX' ,
location : '|city:7321' ,
fromDate : '2026-03-15' ,
toDate : '2026-03-20' ,
rooms : [
{ adults : 2 , childAges : [ ] }
] ,
serviceClass : 'coach'
} ) ;
Car Rental:
const url = sdk. search. buildUrl ( {
type : 'CAR' ,
fromLocation : '|airport:LAX' ,
location : '|airport:LAX' ,
fromDate : '2026-03-15' ,
toDate : '2026-03-20' ,
fromTime : '10' ,
toTime : '14' ,
driverAge : 25
} ) ;
sdk.locations.clearCache(options?)
Clear location autocomplete cache.
Parameters:
options.locale (string, optional): Clear specific locale only
options.locationType (string, optional): Clear specific location type only
Example:
sdk. locations. clearCache ( ) ;
sdk. locations. clearCache ( { locale : 'fr' } ) ;
sdk. locations. clearCache ( { locationType : 'DESTINATION' } ) ;
sdk.locations.getCacheStats()
Get cache statistics for debugging/monitoring.
Returns: Object with cache statistics
{
entries : 42 ,
sizeBytes : 125000 ,
enabled : true
}
sdk.utils.parseSearchToken(token)
Parse a location search token into its components.
Parameters:
token (string): Location token (e.g., '|city:7321', '|airport:LAX', '7321')
Returns: Object with parsed components
{
type : 'city' ,
value : '7321' ,
canonical : '|city:7321'
}
Example:
const parsed = sdk. utils. parseSearchToken ( '|city:7321' ) ;
console. log ( parsed. type) ;
console. log ( parsed. value) ;
console. log ( parsed. canonical) ;
sdk.utils.debounce(fn, delay)
Create a debounced function (useful for autocomplete).
Parameters:
fn (function): Function to debounce
delay (number): Delay in milliseconds
Returns: Debounced function
Example:
const debouncedSearch = sdk. utils. debounce ( async ( query ) => {
const results = await sdk. locations. suggest ( {
query,
locationType : 'DESTINATION' ,
productTypes : 'ROOM'
} ) ;
} , 300 ) ;
input. addEventListener ( 'input' , ( e ) => {
debouncedSearch ( e. target. value) ;
} ) ;
SDK Notes
Location tokens: Always use the search property from location objects (e.g., '|city:7321', '|airport:LAX') when building search URLs. These are the canonical identifiers expected by the booking platform.
Product type naming: Use 'ROOM' (not 'HOTEL') for hotel searches in locations.suggest(). The API expects ROOM as the product type.
Numeric city IDs: Cannot be resolved via typeahead API without a prefillLabel. If you have a numeric city token like '|city:7321', you must provide the display label separately.
Date formats: Dates can be provided as ISO strings ('2026-03-15') or Date objects. The SDK handles formatting for the booking platform.
Error handling: All async methods (suggest, resolve, buildUrl) can throw errors. Always wrap in try/catch blocks.
Caching: Location suggestions are cached in localStorage with a 30-day TTL to reduce API calls and improve performance.
Switchfly widgets support two integration methods:
Iframe embed (recommended): simplest integration and maximum isolation from host page styles/scripts.
Direct script embed (IIFE): renders inline on the host page for tighter visual integration.
Both methods are supported out of the gate. Hosting of the widget IIFE and the API proxy approach will be documented once finalized.
When users submit a search, the widget generates a deep-link URL to the booking platform with search parameters.
Traveler Representation:
All search URLs use room_info as the canonical traveler data format:
room_info is a JSON payload containing rooms, adults, children, child ages, seniors, and infants
The JSON is URL-encoded before being added to the search URL
Example structure: {"rooms":[{"numAdults":2,"numSeniors":0,"numInfantsInSeats":0,"numInfantsInLaps":0,"childAges":[8,12]}]}
Legacy traveler parameters (adults, children, child_ageN, infantN) are no longer used
Product Type Flags:
Search URLs also include product type flags to indicate the search intent:
air1=true - Air search
room1=true - Hotel search
car1=true - Car search
activity1=true - Activity search
Other Parameters:
See individual widget configuration parameters for marketing/tracking parameters (discount_code, utm_source, etc.)
Error Handling (PostMessage API)When a search fails on the booking platform, the user may be redirected back to the host page with an error parameter (e.g., ?ERROR_MESSAGE=NO_ROOMS_FOUND). The widget provides a postMessage API for the host page to inject and display these errors.
Flow Overview
Parent page detects error: Parse ERROR_MESSAGE from the URL query string
Parent sends error to widget: Use postMessage to send a swf.widgets.search.configure message with error payload
Widget displays error: Shows error message in a modal dialog using existing UI components
User dismisses error: Widget sends swf.widgets.search.error.dismissed message back to parent
Parent clears error: Remove ERROR_MESSAGE from URL using history.replaceState()
Message Types
Inject configuration including optional error display.
window. frames[ 0 ] . postMessage ( {
type : 'swf.widgets.search.configure' ,
payload : {
error : {
code : 'NO_ROOMS_FOUND' ,
searchUrl : 'https://...' ,
clearOnDismiss : true
}
}
} , '*' ) ;
Notification that the user dismissed the error dialog.
window. addEventListener ( 'message' , function ( event ) {
if ( event. data. type === 'swf.widgets.search.error.dismissed' ) {
const errorCode = event. data. payload. code;
const url = new URL ( window. location) ;
url. searchParams. delete ( 'ERROR_MESSAGE' ) ;
window. history. replaceState ( { } , '' , url) ;
}
} ) ;
Supported Error Codes
The widget maps error codes to localized user-facing messages. If an unknown code is provided, the DEFAULT message is shown.
Error Code
English Message
DATE_TOO_FAR_IN_ADVANCE
"The date is too far in advance. Please try again."
DEFAULT
"An unexpected error has occurred. Please try your search again."
INTERNAL_ERROR
"An unexpected error has occurred. Please try your search again."
SESSION_ERROR
"Your session has encountered an error. Please try your search again."
THIRD_PARTY_ERROR
"We are having problems communicating with our suppliers. Please try your search again."
NO_FLIGHTS_FOUND
"No available flights were found. Please adjust your search and try again."
NO_ROOMS_FOUND
"There are no rooms available during the dates you have selected. Please try different dates or destination."
NO_CARS_FOUND
"There are no cars available during the dates you have selected. Please try different dates or destination."
NO_ACTIVITIES_FOUND
"There are no activities available during the dates you have selected. Please try different dates or destination."
SEARCH_LOCATION_NOT_FOUND
"The search location was not found."
All error messages are translated for all widget-supported languages (en, fr, es, ja).
Parent Page Implementation Example
< iframe id = " search-widget-iframe" src = " https://your-cdn.com/widgets/search/" width = " 100%" height = " 600" > </ iframe>
< script>
// On page load, check for ERROR_MESSAGE parameter
const urlParams = new URLSearchParams(window.location.search);
const errorCode = urlParams.get('ERROR_MESSAGE');
if (errorCode) {
// Wait for iframe to load
const iframe = document.getElementById('search-widget-iframe');
iframe.addEventListener('load', function() {
// Send error to widget
iframe.contentWindow.postMessage({
type: 'swf.widgets.search.configure',
payload: {
error: {
code: errorCode,
clearOnDismiss: true
}
}
}, '*');
});
}
// Listen for error dismissal
window.addEventListener('message', function(event) {
if (event.data.type === 'swf.widgets.search.error.dismissed') {
// Clear ERROR_MESSAGE from URL
const url = new URL(window.location);
url.searchParams.delete('ERROR_MESSAGE');
window.history.replaceState({}, '', url);
}
});
</ script>
Replace the default Location API autocomplete with fixed location lists from your own JSON data. Useful for airlines with restricted route networks or when you want to limit search options to specific airports/cities.
Display Modes
Static locations support two display modes:
dropdown (default): Custom dropdown showing all items with icons. Best for small lists (5-15 items). Users click to open and scroll to find their location.
typeahead : Autocomplete-style input with client-side filtering. Best for larger lists (20+ items). Users type to filter locations instantly (no network calls).
Script Embed with JSON URL
< div id = " search-widget" > </ div>
< script src = " https://your-cdn.com/dist/switchfly-widgets.iife.js" > </ script>
< script>
SwitchflyWidgets.createSearchWidget({
containerId: 'search-widget',
targetUrl: 'https://your-booking-site.com',
staticLocationsUrl: 'https://cdn.example.com/locations.json',
staticLocationsDisplayMode: 'typeahead' // Optional: 'dropdown' (default) or 'typeahead'
});
</ script>
Script Embed with Inline JSON
< div id = " search-widget" > </ div>
< script src = " https://your-cdn.com/dist/switchfly-widgets.iife.js" > </ script>
< script>
SwitchflyWidgets.createSearchWidget({
containerId: 'search-widget',
targetUrl: 'https://your-booking-site.com',
staticLocationsDisplayMode: 'dropdown', // Optional: 'dropdown' or 'typeahead'
staticLocations: {
origins: [
{ displayValue: "Tokyo (TYO)", search: "|airport:TYO", locationType: "AIRPORT" },
{ displayValue: "Osaka", search: "|city:27562", locationType: "CITY" }
],
destinations: [
{ displayValue: "Los Angeles (LAX)", search: "|airport:LAX", locationType: "AIRPORT" },
{ displayValue: "San Francisco (SFO)", search: "|airport:SFO", locationType: "AIRPORT" }
]
}
});
</ script>
Iframe Embed with JSON URL
< iframe
src = " https://your-cdn.com/widgets/search/?targetUrl=https%3A%2F%2Fyour-booking-site.com&staticLocationsUrl=https%3A%2F%2Fcdn.example.com%2Flocations.json&staticLocationsDisplayMode=typeahead"
width = " 100%"
height = " 600"
frameborder = " 0" >
</ iframe>
Note: staticLocationsDisplayMode is optional. Defaults to dropdown if omitted.
Iframe Embed with postMessage (Dynamic)
< iframe id = " search-widget" src = " https://your-cdn.com/widgets/search/?targetUrl=https%3A%2F%2Fyour-booking-site.com" width = " 100%" height = " 600" frameborder = " 0" > </ iframe>
< script>
window.addEventListener('load', () => {
document.getElementById('search-widget').contentWindow.postMessage({
type: 'swf.widgets.search.configure',
payload: {
staticLocationsDisplayMode: 'typeahead', // Optional: 'dropdown' or 'typeahead'
staticLocations: {
origins: [
{ displayValue: "Tokyo (TYO)", search: "|airport:TYO", locationType: "AIRPORT" }
],
destinations: [
{ displayValue: "Los Angeles (LAX)", search: "|airport:LAX", locationType: "AIRPORT" }
]
}
}
}, 'https://your-cdn.com');
});
</ script>
{
"origins" : [
{
"displayValue" : "Tokyo Haneda (HND)" ,
"search" : "|airport:HND" ,
"locationType" : "AIRPORT"
} ,
{
"displayValue" : "Osaka" ,
"search" : "|city:27562" ,
"locationType" : "CITY"
}
] ,
"destinations" : [
{
"displayValue" : "Los Angeles (LAX)" ,
"search" : "|airport:LAX" ,
"locationType" : "AIRPORT"
}
]
}
Field Descriptions:
origins: Array of origin locations (optional - if omitted, origin field uses autocomplete)
destinations: Array of destination locations (optional - if omitted, destination field uses autocomplete)
displayValue: Text shown to user (e.g., "Tokyo (TYO)" or "Osaka")
search: Search token sent to Core Shopping (format: "|airport:CODE" or "|city:ID")
locationType: Must be "AIRPORT" or "CITY" (determines icon shown)
Display Mode Behavior:
dropdown (default): Custom dropdown with SVG icons. Shows all items at once. Best for small lists (5-15 items).
typeahead : Autocomplete-style input with client-side filtering. User types to filter. Best for larger lists (20+ items). No network calls - instant filtering.
Notes:
You can provide only origins, only destinations, or both
Fields not in staticLocations fall back to autocomplete
For car rentals, both pickup and dropoff use destinations array
Invalid location items are logged to console and skipped
Display mode applies to all static location fields in the widget
Static locations are NOT filtered by product type - The same location list is shown for all product types (air, hotel, car, activity, bundle). This differs from API autocomplete mode, which filters results based on product type. Ensure your static locations are appropriate for all product types you're offering, or consider using API autocomplete for product-specific filtering.
Feature a specific hotel on search results or redirect directly to hotel details page. Useful for marketing campaigns, email newsletters, or partner sites promoting individual properties.
Feature Hotel on Search Results
Pass hotel_id to highlight/feature a specific hotel in search results:
Script Embed:
< div id = " search-widget" > </ div>
< script src = " https://your-cdn.com/dist/switchfly-widgets.iife.js" > </ script>
< script>
SwitchflyWidgets.createSearchWidget({
containerId: 'search-widget',
targetUrl: 'https://your-booking-site.com',
hotel_id: '12345'
});
</ script>
Iframe Embed:
< iframe
src = " https://your-cdn.com/widgets/search/?targetUrl=https%3A%2F%2Fyour-booking-site.com&hotel_id=12345"
width = " 100%"
height = " 600"
frameborder = " 0" >
</ iframe>
Redirect to Hotel Details Page
Combine hotel_id with redirect_to_hotel_details to bypass search results and go directly to the hotel details page:
Script Embed:
< div id = " search-widget" > </ div>
< script src = " https://your-cdn.com/dist/switchfly-widgets.iife.js" > </ script>
< script>
SwitchflyWidgets.createSearchWidget({
containerId: 'search-widget',
targetUrl: 'https://your-booking-site.com',
hotel_id: '12345',
redirect_to_hotel_details: true
});
</ script>
Iframe Embed:
< iframe
src = " https://your-cdn.com/widgets/search/?targetUrl=https%3A%2F%2Fyour-booking-site.com&hotel_id=12345&redirect_to_hotel_details=true"
width = " 100%"
height = " 600"
frameborder = " 0" >
</ iframe>
Notes:
hotel_id is passed through to the booking URL as hotel_id parameter
redirect_to_hotel_details only works when hotel_id is also provided
These parameters work for all search types (not just hotel searches)
The hotel ID format should match your booking platform's hotel identifier format
Feature a specific activity on search results or redirect directly to activity details page. Activities require both an activity ID and a CRS (provider/system identifier) such as "viator", "expedia", "getyourguide", etc.
Feature Activity on Search Results
Pass activity_id and activity_crs to highlight/feature a specific activity in search results:
Script Embed:
< div id = " search-widget" > </ div>
< script src = " https://your-cdn.com/dist/switchfly-widgets.iife.js" > </ script>
< script>
SwitchflyWidgets.createSearchWidget({
containerId: 'search-widget',
targetUrl: 'https://your-booking-site.com',
activity_id: '12345',
activity_crs: 'viator'
});
</ script>
Iframe Embed:
< iframe
src = " https://your-cdn.com/widgets/search/?targetUrl=https%3A%2F%2Fyour-booking-site.com&activity_id=12345%3Aviator"
width = " 100%"
height = " 600"
frameborder = " 0" >
</ iframe>
Redirect to Activity Details Page
Combine activity_id, activity_crs, and redirect_to_activity_details to bypass search results and go directly to the activity details page:
Script Embed:
< div id = " search-widget" > </ div>
< script src = " https://your-cdn.com/dist/switchfly-widgets.iife.js" > </ script>
< script>
SwitchflyWidgets.createSearchWidget({
containerId: 'search-widget',
targetUrl: 'https://your-booking-site.com',
activity_id: '12345',
activity_crs: 'viator',
redirect_to_activity_details: true
});
</ script>
Iframe Embed:
< iframe
src = " https://your-cdn.com/widgets/search/?targetUrl=https%3A%2F%2Fyour-booking-site.com&activity_id=12345%3Aviator&redirect_to_activity_details=true"
width = " 100%"
height = " 600"
frameborder = " 0" >
</ iframe>
Notes:
CRS is required: Unlike hotels, activities always require a CRS (provider identifier)
In iframe mode , combine ID and CRS using colon format: activity_id=12345:viator
In script embed mode , provide activity_id and activity_crs as separate properties
activity_id is passed through to the booking URL as activity_id parameter in id:crs format
redirect_to_activity_details only works when activity_id is also provided
These parameters work for all search types (not just activity searches)
Common CRS values: "viator", "expedia", "getyourguide", etc.
The notes below call out CMS-specific considerations. Unless stated otherwise, iframe embed is the recommended approach.
HubSpot
Recommended: Iframe embed in a Custom HTML module
Supported: Direct script embed (subject to HubSpot script/CSP restrictions)
Allowlist the widget host domain (for example, your-cdn.com) in Content Security Policy (CSP) if needed
Listen for SWF_WIDGET_HEIGHT to resize iframe dynamically
URL-encode all color parameters (# → %23)
Wix
Recommended: Iframe embed via HTML Embed or Custom Element
Supported: Direct script embed
For iframe: Set an explicit height (for example, 600px) or use an auto-height script
Ensure the iframe src domain (or script source domain) is allowlisted
URL-encode all color parameters (# → %23)
Webflow
Recommended: Iframe embed via Custom Code component
Supported: Direct script embed
For iframe: Set an explicit height or add a resize listener via postMessage
URL-encode all color parameters (# → %23)
Squarespace
Recommended: Iframe embed using a Code Block
Supported: Direct script embed
For iframe: Set an explicit height (Squarespace does not support dynamic iframe resizing)
Ensure the iframe src domain (or script source domain) is allowlisted
URL-encode all color parameters (# → %23)
WordPress
Recommended: Iframe embed using Custom HTML block
Supported: Direct script embed
For script embeds, some themes or security plugins may block inline scripts
For iframe: Set an explicit height or handle resizing via postMessage
URL-encode all color parameters (# → %23)
Shopify
Recommended: Iframe embed using Custom HTML section or Liquid template
Supported: Direct script embed
Script embeds may require adding the widget domain to Shopify’s allowed script sources
For iframe: Set an explicit height or implement postMessage-based resizing
URL-encode all color parameters (# → %23)
custom",{"_index":438,"title":{},"description":{"3":{}}}],["todat",{"_index":502,"title":{},"description":{"3":{}}}],["token",{"_index":78,"title":{},"description":{"1":{},"2":{},"3":{},"8":{}}}],["tokyo",{"_index":838,"title":{},"description":{"8":{}}}],["tool",{"_index":694,"title":{"4":{}},"description":{"4":{}}}],["totim",{"_index":649,"title":{},"description":{"3":{}}}],["translat",{"_index":41,"title":{},"description":{"1":{},"7":{}}}],["travel",{"_index":5,"title":{},"description":{"0":{},"1":{},"3":{},"6":{},"12":{}}}],["tri",{"_index":288,"title":{},"description":{"2":{},"3":{},"7":{}}}],["true",{"_index":243,"title":{},"description":{"2":{},"3":{},"7":{},"9":{},"10":{}}}],["truncat",{"_index":178,"title":{},"description":{"2":{}}}],["try/catch",{"_index":686,"title":{},"description":{"3":{}}}],["ttl",{"_index":690,"title":{},"description":{"3":{}}}],["two",{"_index":187,"title":{},"description":{"2":{},"5":{},"8":{}}}],["tyo",{"_index":839,"title":{},"description":{"8":{}}}],["type",{"_index":31,"title":{},"description":{"1":{},"2":{},"3":{},"6":{},"7":{},"8":{},"9":{},"10":{}}}],["type=\"d",{"_index":448,"title":{},"description":{"3":{}}}],["type=\"modul",{"_index":454,"title":{},"description":{"3":{}}}],["type=\"submit\">search",{"_index":452,"title":{},"description":{"3":{}}}],["type=\"text",{"_index":443,"title":{},"description":{"3":{}}}],["type='bundl",{"_index":587,"title":{},"description":{"3":{}}}],["typeahead",{"_index":367,"title":{},"description":{"2":{},"3":{},"8":{}}}],["ua",{"_index":620,"title":{},"description":{"3":{}}}],["ui",{"_index":46,"title":{"3":{}},"description":{"1":{},"2":{},"3":{},"7":{}}}],["unexpect",{"_index":792,"title":{},"description":{"7":{}}}],["unit",{"_index":566,"title":{},"description":{"3":{}}}],["unknown",{"_index":785,"title":{},"description":{"7":{}}}],["unless",{"_index":911,"title":{},"description":{"11":{}}}],["unlik",{"_index":904,"title":{},"description":{"10":{}}}],["up",{"_index":379,"title":{},"description":{"2":{}}}],["url",{"_index":133,"title":{"6":{}},"description":{"2":{},"3":{},"6":{},"7":{},"8":{},"9":{},"10":{}}}],["url(iframe.src).origin",{"_index":290,"title":{},"description":{"2":{}}}],["url(window.loc",{"_index":310,"title":{},"description":{"2":{},"7":{}}}],["url-encod",{"_index":201,"title":{},"description":{"2":{},"6":{},"11":{}}}],["url.href",{"_index":508,"title":{},"description":{"3":{}}}],["url.searchparams.delete('error_messag",{"_index":311,"title":{},"description":{"2":{},"7":{}}}],["urlparam",{"_index":272,"title":{},"description":{"2":{},"7":{}}}],["urlparams.get('error_messag",{"_index":276,"title":{},"description":{"2":{},"7":{}}}],["urlsearchparams(window.location.search",{"_index":274,"title":{},"description":{"2":{},"7":{}}}],["us",{"_index":77,"title":{},"description":{"1":{},"2":{},"3":{},"6":{},"7":{},"8":{},"9":{},"10":{},"11":{}}}],["usag",{"_index":719,"title":{},"description":{"4":{}}}],["useparentnavig",{"_index":345,"title":{},"description":{"2":{}}}],["user",{"_index":28,"title":{},"description":{"1":{},"2":{},"6":{},"7":{},"8":{}}}],["user-fac",{"_index":784,"title":{},"description":{"7":{}}}],["util",{"_index":535,"title":{},"description":{"3":{}}}],["utm_sourc",{"_index":767,"title":{},"description":{"6":{}}}],["ux",{"_index":104,"title":{},"description":{"1":{}}}],["valid",{"_index":51,"title":{},"description":{"1":{},"2":{}}}],["valu",{"_index":667,"title":{},"description":{"3":{},"4":{},"10":{}}}],["var",{"_index":268,"title":{},"description":{"2":{}}}],["variabl",{"_index":83,"title":{},"description":{"1":{}}}],["variou",{"_index":252,"title":{},"description":{"2":{}}}],["via",{"_index":251,"title":{},"description":{"2":{},"3":{},"11":{}}}],["viator",{"_index":896,"title":{},"description":{"10":{}}}],["visual",{"_index":35,"title":{},"description":{"1":{},"5":{}}}],["vs",{"_index":182,"title":{},"description":{"2":{},"3":{}}}],["wait",{"_index":811,"title":{},"description":{"7":{}}}],["walk",{"_index":710,"title":{},"description":{"4":{}}}],["want",{"_index":361,"title":{},"description":{"2":{},"3":{},"8":{}}}],["webflow",{"_index":927,"title":{},"description":{"11":{}}}],["whether",{"_index":778,"title":{},"description":{"7":{}}}],["widget",{"_index":1,"title":{"0":{},"13":{},"15":{}},"description":{"0":{},"1":{},"2":{},"3":{},"4":{},"5":{},"6":{},"7":{},"8":{},"11":{},"12":{},"13":{},"14":{},"15":{}}}],["widget-support",{"_index":807,"title":{},"description":{"7":{}}}],["widgets/hoteld",{"_index":945,"title":{},"description":{"15":{}}}],["widgets/hoteldeals/?locale=en&maxitems=6&accentcolor=%23dc2626",{"_index":944,"title":{},"description":{"15":{}}}],["widgets/search",{"_index":942,"title":{},"description":{"13":{}}}],["widgets/search/?customtab1label=cruises&customtab1url=https://example.com/cruises&customtab1position=last",{"_index":941,"title":{},"description":{"13":{}}}],["widgets/search/?locale=fr&cobrand=partner123&accentcolor=%230a66c2&bgcolorwidget=%23ffffff",{"_index":939,"title":{},"description":{"13":{}}}],["widgets/search/?searchparam=%7ccity:7321&prefilldestinationlabel=san%20diego",{"_index":940,"title":{},"description":{"13":{}}}],["width",{"_index":173,"title":{},"description":{"2":{}}}],["width=\"100",{"_index":234,"title":{},"description":{"2":{},"7":{},"8":{},"9":{},"10":{}}}],["wildcard",{"_index":354,"title":{},"description":{"2":{}}}],["window",{"_index":250,"title":{},"description":{"2":{}}}],["window.addeventlistener('load",{"_index":854,"title":{},"description":{"8":{}}}],["window.addeventlistener('messag",{"_index":284,"title":{},"description":{"2":{},"7":{}}}],["window.frames[0].postmessag",{"_index":773,"title":{},"description":{"7":{}}}],["window.history.replacest",{"_index":312,"title":{},"description":{"2":{},"7":{}}}],["window.location.assign",{"_index":337,"title":{},"description":{"2":{}}}],["window.location.assign(targeturl",{"_index":308,"title":{},"description":{"2":{}}}],["window.location.href",{"_index":509,"title":{},"description":{"3":{}}}],["window.open(targeturl",{"_index":306,"title":{},"description":{"2":{}}}],["window.self",{"_index":333,"title":{},"description":{"2":{}}}],["window.top",{"_index":334,"title":{},"description":{"2":{}}}],["window.top.location.href",{"_index":322,"title":{},"description":{"2":{}}}],["within",{"_index":69,"title":{},"description":{"1":{},"2":{}}}],["without",{"_index":319,"title":{},"description":{"2":{},"3":{}}}],["wix",{"_index":921,"title":{},"description":{"11":{}}}],["wordpress",{"_index":930,"title":{},"description":{"11":{}}}],["work",{"_index":155,"title":{},"description":{"2":{},"3":{},"9":{},"10":{}}}],["workflow",{"_index":699,"title":{},"description":{"4":{}}}],["wrap",{"_index":685,"title":{},"description":{"3":{}}}],["write",{"_index":411,"title":{},"description":{"3":{}}}],["you'r",{"_index":874,"title":{},"description":{"8":{}}}],["your-cdn.com",{"_index":188,"title":{},"description":{"2":{},"11":{}}}],["yy/mm/dd",{"_index":393,"title":{},"description":{"2":{}}}],["yyyy/mm/dd",{"_index":394,"title":{},"description":{"2":{}}}]],"pipeline":[]}},"options":{}};
var container = document.getElementById('redoc');
Redoc.hydrate(__redoc_state, container);