# HubSpot Meeting Booking Widget Attribution Guide

**Last Updated:** 2026-03-25

## Overview

HubSpot's native meeting booking widget (embedded via iframe) has known limitations with UTM parameter and Google Ads attribution tracking. This document outlines the limitations, impact, and recommended workarounds.

## Problem Statement

When users book meetings through HubSpot's embedded meeting booking widget:

1. **UTM Parameters Are Lost**: UTM parameters from the landing page URL are not automatically passed to the iframe
2. **Google Ads Attribution Issues**: `gclid` and `hsa_*` parameters are not preserved, causing Google Ads traffic to be misattributed as "Direct Traffic"
3. **Iframe Isolation**: The iframe environment doesn't have access to parent page URL parameters or cookies in the same way as regular form submissions

## Impact

Based on audit results (Contact 667905998044), contacts who book meetings via HubSpot's widget may show:

- **Lead Source**: "Direct Traffic" instead of "Google"
- **Missing UTM Parameters**: No `utm_source`, `utm_medium`, `utm_campaign`, etc.
- **Missing Google Ads Indicators**: No `gclid` or `hsa_*` parameters stored

## Root Cause

HubSpot's meeting booking widget operates in an iframe, which creates isolation from the parent page:

1. **URL Parameters**: The iframe URL doesn't automatically include query parameters from the parent page
2. **Cookie Access**: Cross-origin iframe restrictions may prevent access to UTM tracking cookies
3. **HubSpot's Native Tracking**: HubSpot tracks the meeting booking link itself as the source, not the original referral

## Workarounds

### Option 1: Add UTM Parameters to Meeting Booking Links (Recommended)

**Implementation**: Add UTM parameters directly to meeting booking URLs in CTAs and links.

**Example**:

```html
<!-- Before -->
<a href="https://meetings-eu1.hubspot.com/lukas17/ordio-vorstellung"
  >Demo vereinbaren</a
>

<!-- After -->
<a
  href="https://meetings-eu1.hubspot.com/lukas17/ordio-vorstellung?utm_source=adwords&utm_medium=ppc&utm_campaign=google_ads_campaign"
  >Demo vereinbaren</a
>
```

**Pros**:

- Simple to implement
- UTM parameters are preserved in HubSpot
- Works for all traffic sources

**Cons**:

- Requires manual UTM parameter management
- Doesn't capture dynamic parameters like `gclid` automatically
- May not work for embedded iframes (depends on HubSpot configuration)

### Option 2: JavaScript Parameter Passing

**Implementation**: Use JavaScript to pass UTM parameters from parent page to iframe.

**Example**:

```javascript
// Get UTM parameters from current URL or cookies
const utmParams = new URLSearchParams();
if (window.utmTracker) {
  const utmData = window.utmTracker.getAllUTMData();
  if (utmData.gclid) utmParams.append("gclid", utmData.gclid);
  if (utmData.utm_source) utmParams.append("utm_source", utmData.utm_source);
  if (utmData.utm_medium) utmParams.append("utm_medium", utmData.utm_medium);
  if (utmData.utm_campaign)
    utmParams.append("utm_campaign", utmData.utm_campaign);
}

// Append to iframe src
const iframe = document.querySelector(
  'iframe[src*="meetings-eu1.hubspot.com"]',
);
if (iframe && utmParams.toString()) {
  const separator = iframe.src.includes("?") ? "&" : "?";
  iframe.src += separator + utmParams.toString();
}
```

**Pros**:

- Captures dynamic parameters like `gclid`
- Works with existing UTM tracking system
- Can be automated

**Cons**:

- Requires iframe access (may be blocked by CORS)
- More complex implementation
- May not work if HubSpot blocks parameter modification

### Option 3: Post-Booking Attribution Correction

**Implementation**: Use HubSpot API to correct attribution after meeting booking.

**Example**:

```php
// After meeting booking, check for Google Ads indicators in contact's first URL
$contactId = getContactIdFromMeetingBooking($meetingId);
$contact = fetchContactFromHubSpot($contactId);
$firstUrl = $contact['properties']['hs_analytics_first_url'] ?? '';

// Extract gclid or hsa_* from first URL
if (hasGoogleAdsIndicators($firstUrl)) {
    updateContactLeadSource($contactId, 'Google');
}
```

**Pros**:

- Can retroactively fix attribution
- Works regardless of iframe limitations
- Can be automated via webhook or cron job

**Cons**:

- Requires API access and development
- May have delays in attribution correction
- Doesn't prevent the initial misattribution

### Option 4: Use Alternative Booking Solutions

**Considerations**:

- **Calendly**: Better UTM parameter support, can be configured to pass parameters
- **Orbianca**: Custom booking solution with full control over parameter passing
- **Custom Booking Form**: Full control but requires more development

**Current Implementation**: The thank-you page `/kostenlos-testen/danke` ([`v2/pages/typ.php`](../../../v2/pages/typ.php)) embeds **one** HubSpot meeting widget (Lukas): `https://meetings-eu1.hubspot.com/lukas17/ordio-vorstellung`. Legacy per-`seller` calendar routing was removed.

## `seller` query parameter on `/kostenlos-testen/danke` (audit)

### In-repo behavior

- **Only producer**: [`html/form-hs.php`](../../../html/form-hs.php) — after a successful (or consent-skipped) demo-class POST to `/form-hs`, the redirect uses `form_hs_build_kostenlos_testen_danke_url()`.
- **`seller` on the thank-you URL**: Only when the **landing page had an explicit `?seller=`** query. The demo modal copies that into hidden field `seller_passthrough` (see [`v2/base/include_form-hs.php`](../../../v2/base/include_form-hs.php)). **`seller` is never copied from `utm_campaign`** or other UTM fields.
- **UTM / `gclid` on the thank-you URL**: The redirect may append **`utm_source`, `utm_medium`, `utm_campaign`, `utm_term`, `utm_content`, `gclid`** (when non-empty) from the same POST values used for HubSpot — as **separate** query keys, RFC 3986–encoded. That does not duplicate into `seller`.
- **Interaction with [`v2/js/utm-tracking.js`](../../../v2/js/utm-tracking.js)**: The tracker does not read or store a `seller` param. It **does** strip `utm_*`, `gclid`, etc. from the visible URL after load on most pages, but **`seller` is not in that cleanup list**, so it can remain visible. When the user lands on `/kostenlos-testen/danke` with `utm_*` / `gclid` in the redirect URL, the next page load can re-ingest those params (and cookies already set on the first touch remain). No code conflict.
- **Not set in-repo by**: `.htaccess` rules for `/kostenlos-testen/danke`, `retURL` in [`v2/base/include_form.php`](../../../v2/base/include_form.php) (no query string), or other API redirects — verified by searching for `Location:.*danke` and `danke?seller`.

### HubSpot portal (manual check)

Ordio’s main demo modal posts to **`/form-hs`** ([`v2/base/include_form-hs.php`](../../../v2/base/include_form-hs.php)); there is **no** in-repo HubSpot embedded form configuration that redirects to `danke` with `seller` independently.

**Recommended one-time verification in HubSpot (Settings → Marketing → Forms / legacy forms):**

- [ ] No form “Thank you” / redirect URL points to `ordio.com/.../danke` with hard-coded or dynamic `seller=` unless intentional.
- [ ] Any standalone HubSpot-hosted forms used in production either use the same `/form-hs` flow or a documented redirect pattern.

## Current Status

### Meeting Booking Widgets in Use

1. **HubSpot Meeting Widget**: Used on `/kostenlos-testen/danke` (`typ.php`) and potentially in CTAs
   - URL Pattern: `https://meetings-eu1.hubspot.com/lukas17/ordio-vorstellung`
   - Status: **No UTM parameter passing implemented** (iframe isolation; see workarounds above)

2. **Orbianca / Calendly (legacy)**: No longer used on `/kostenlos-testen/danke` for per-rep routing; other pages may still link to Orbianca or third-party calendars separately.

### CTA Buttons

CTA buttons (`include_ctabuttons.php`) currently open:

- **"Kostenlos testen"**: Opens lead-capture-popup modal (uses `/v2/api/lead-capture.php` - **attribution works correctly** ✓)
- **"Demo vereinbaren"**: Opens lead-capture-popup modal (uses `/v2/api/lead-capture.php` - **attribution works correctly** ✓)

**Note**: CTA buttons do NOT directly link to meeting booking widgets, so attribution should work correctly for these flows.

## Recommendations

### Short-Term (Immediate)

1. **Document Limitation**: Accept that meeting bookings via HubSpot widget may have imperfect attribution
2. **Monitor Impact**: Track how many leads come through meeting bookings vs. forms
3. **Manual Correction**: For high-value leads, manually correct attribution in HubSpot

### Medium-Term (Next Sprint)

1. **Implement JavaScript Parameter Passing**: Add script to pass UTM parameters to HubSpot meeting booking iframes
2. **Test Alternative Solutions**: Evaluate if Orbianca or Calendly can better preserve attribution
3. **Add UTM to Booking Links**: Manually add UTM parameters to meeting booking links in CTAs (if applicable)

### Long-Term (Future)

1. **Post-Booking Attribution Correction**: Implement automated script to correct attribution after meeting bookings
2. **Unified Booking Solution**: Consider consolidating to a single booking solution with better attribution support
3. **HubSpot Configuration**: Work with HubSpot support to enable better UTM parameter passing in iframes

## Testing

To test meeting booking attribution:

1. **Create Test Meeting Booking**:
   - Visit landing page with Google Ads parameters: `https://www.ordio.com/gastro/?gclid=test123`
   - Book a meeting via HubSpot widget
   - Check HubSpot contact attribution

2. **Verify Attribution**:
   - Check `leadsource` property
   - Check `hs_analytics_first_url` for UTM parameters
   - Check `gclid__c` and `hsa_*__c` properties

3. **Compare with Form Submission**:
   - Submit form on same page
   - Compare attribution between form and meeting booking

## Related Documentation

- [Google Ads Attribution Audit 2026-01](./GOOGLE_ADS_ATTRIBUTION_AUDIT_2026-01.md)
- [Attribution Debugging Guide](../../development/ATTRIBUTION_DEBUGGING_GUIDE.md)
- [Lead Capture Integration Guide](../lead-capture/INTEGRATION_GUIDE.md)

## References

- [HubSpot Community: UTM in CTA to Meeting Link](https://community.hubspot.com/t5/Lead-Capture-Tools/UTM-in-CTA-to-Meeting-Link/m-p/783623)
- [HubSpot Community: Passing UTM Code via Meeting Booking Form](https://community.hubspot.com/t5/Sales-Hub-Tools/Passing-UTM-Code-via-Meeting-Booking-Form/m-p/549021)
- [HubSpot Community: Meetings Tools Stealing Attribution](https://community.hubspot.com/t5/Lead-Capture-Tools/Meetings-Tools-Stealing-Attribution/m-p/921411)
