A copy-paste iframe, with real tracking.
No plugin needed — just an iframe embed and one small helper function, so Google Ads and Meta can still attribute bookings correctly.
Helper function
Add this once, in a shared include:
<?php
function fb_tracking_query() {
$keys = ['gclid','gbraid','wbraid','utm_source','utm_medium','utm_campaign','utm_term','utm_content','fbclid'];
$qs = '';
foreach ($keys as $k) {
$val = '';
if (!empty($_GET[$k])) {
$val = $_GET[$k]; // 1st: this page's own URL
} elseif (!empty($_COOKIE['fb_' . $k])) {
$val = $_COOKIE['fb_' . $k]; // 2nd: sitewide cookie (see below)
}
if ($val !== '') {
$qs .= '&' . $k . '=' . rawurlencode($val);
}
}
return $qs;
}
?>
Let the iframe resize itself
An iframe doesn't grow when its content grows — without telling it to, the form gets cut off the moment its content expands (opening the Options panel, for example). Both embeds below already include this, but the pattern is always the same three pieces, in this order:
- The resizer script — before the iframe
- The iframe itself, with a fixed
id - A small script that activates the resize — after the iframe, targeting that same
id
Use FareBookings' own copy of the script
app.farebookings.com/iframe-resizer/iframeResizer.min.js — not a third-party CDN. Ad blockers, corporate firewalls, and site-optimisation plugins sometimes block external CDNs but not the domain the widget already lives on.
Compact widget
<script src="https://app.farebookings.com/iframe-resizer/iframeResizer.min.js"></script>
<iframe
id="fb-booking-widget"
src="https://app.farebookings.com/booking-widget.php?k=YOUR_COMPANY_KEY&lng=gb<?php echo fb_tracking_query(); ?>"
width="100%" height="640" frameborder="0" scrolling="no" style="border:none">
</iframe>
<script>
if (window.iFrameResize) {
iFrameResize({checkOrigin: false, heightCalculationMethod: 'lowestElement'}, '#fb-booking-widget');
}
</script>
Full booking form
The most important fix on this page
If a compact widget elsewhere on the site (the homepage, say) submits and sends the visitor to this page, everything they already typed — origin, destination, date, passengers, plus any gclid/utm_* — arrives in this page's own URL. If this page doesn't read that and forward it into the iframe, all of it is lost and the form loads blank. This only applies when the widget sends visitors to a page of your own with the form embedded — if the widget links straight to app.farebookings.com instead, it builds that URL itself and none of this is needed.
The fix — forward this page's entire query string into the iframe, without listing each parameter by hand:
<script src="https://app.farebookings.com/iframe-resizer/iframeResizer.min.js"></script>
<?php
// Forward everything this page's own URL was given — this is what
// carries the widget's data through when it redirects here.
$ownParams = $_SERVER['QUERY_STRING'] ?? '';
?>
<iframe
id="fb-booking-form"
src="https://app.farebookings.com/step1sslv3.php?k=YOUR_COMPANY_KEY&d=pp&lng=gb<?php echo $ownParams ? '&' . $ownParams : ''; ?>"
width="100%" scrolling="no" style="border:none;min-height:1400px">
</iframe>
<script>
if (window.iFrameResize) {
iFrameResize({checkOrigin: false, heightCalculationMethod: 'lowestElement'}, '#fb-booking-form');
}
</script>
Replace YOUR_COMPANY_KEY with the real key from the Frontend tab of your panel. Forwarding $_SERVER['QUERY_STRING'] wholesale already carries through anything the widget sent — including gclid/utm_* — so fb_tracking_query() isn't needed again on this specific page.
Sitewide tracking
Add this to the shared footer/template of every page:
<script>
(function(){
var keys = ['gclid','gbraid','wbraid','utm_source','utm_medium','utm_campaign','utm_term','utm_content','fbclid'];
keys.forEach(function(k){
var m = new RegExp('[?&]'+k+'=([^&#]*)').exec(window.location.href);
if(m){
document.cookie = 'fb_' + k + '=' + m[1] + ';max-age=7776000;path=/;SameSite=Lax';
}
});
})();
</script>
This stores the campaign data as soon as it's seen on any page, so fb_tracking_query() can still pick it up even if the visitor browsed a few pages before reaching the widget.
&dark=1 to the iframe URL.&opts_open=1.lng=gb to lng=es, lng=fr, etc.&layout=inline to the widget iframe URL (widget only, not the full form). Needs ~1000px of width and stacks on its own under 900px — no separate markup for mobile. Set the iframe's starting height to 200 instead of 640 when using this layout, or there's a visible gap under the bar for the first moment before iframeResizer measures it.Verifying tracking works
- Visit any page with
?gclid=test123on the end of the URL. - Open the browser console (F12) → type
document.cookie. fb_gclid=test123should be there.- Navigate to another page (without the parameter) and confirm the cookie is still there before reaching the widget/form.
Building on a different platform?
There are dedicated guides for WordPress and sites with no backend at all.