# Form Tracking Developer Guide

**Last Updated:** 2025-11-28

Guide for developers on how to add GTM form tracking to new forms or update existing form tracking.

## Quick Reference

### Tracking Utility Location

- **File:** `v2/js/gtm-form-tracking.js`
- **Global Object:** `window.GTMFormTracker`
- **Loaded In:** `v2/base/head.php` (loaded on all pages)

## Adding Tracking to New Forms

### 1. Custom HTML Forms

For standard HTML `<form>` elements:

```javascript
// In form submit handler, before form.submit() or fetch call
if (
  window.GTMFormTracker &&
  typeof window.GTMFormTracker.trackCustomHTMLForm === "function"
) {
  window.GTMFormTracker.trackCustomHTMLForm(formElement, {
    formName: "Your Form Name",
    formType: "form_subtype", // optional
    hubspotFormGuid: "your-hubspot-form-guid", // optional
    contentType: "content_type", // optional, for gated content
    step: 1, // optional, for multi-step forms
  });
}
```

**Example - Form with submit handler:**

```javascript
document.getElementById("my-form").addEventListener("submit", function (e) {
  e.preventDefault();

  // GTM Form Tracking
  if (
    window.GTMFormTracker &&
    typeof window.GTMFormTracker.trackCustomHTMLForm === "function"
  ) {
    window.GTMFormTracker.trackCustomHTMLForm(this, {
      formName: "My New Form",
      formType: "contact_form",
      hubspotFormGuid: "your-form-guid-here",
    });
  }

  // Continue with form submission
  this.submit();
});
```

### 2. HubSpot Embedded Forms

For HubSpot forms created with `hbspt.forms.create()`:

```javascript
hbspt.forms.create({
  portalId: "145133546",
  formId: "your-form-id",
  region: "eu1",
  target: "#form-container",
  onFormSubmit: function ($form) {
    // GTM Form Tracking - Track form submission
    if (
      window.GTMFormTracker &&
      typeof window.GTMFormTracker.trackHubSpotEmbeddedForm === "function"
    ) {
      window.GTMFormTracker.trackHubSpotEmbeddedForm(
        {
          formId: "your-form-id",
          portalId: "145133546",
          region: "eu1",
          target: "#form-container",
        },
        {
          formName: "Your HubSpot Form Name",
          additionalData: {
            // Optional additional data
          },
        }
      );
    }
  },
  onFormSubmitted: function ($form) {
    // GTM Form Tracking - Track successful submission
    if (
      window.GTMFormTracker &&
      typeof window.GTMFormTracker.trackHubSpotEmbeddedForm === "function"
    ) {
      window.GTMFormTracker.trackHubSpotEmbeddedForm(
        {
          formId: "your-form-id",
          portalId: "145133546",
          region: "eu1",
          target: "#form-container",
        },
        {
          formName: "Your HubSpot Form Name",
          additionalData: {
            submission_status: "success",
          },
        }
      );
    }
  },
});
```

### 3. API-Based Form Submissions

For forms that submit via API endpoints (fetch/XMLHttpRequest):

```javascript
// Before the API call
if (
  window.GTMFormTracker &&
  typeof window.GTMFormTracker.trackAPIForm === "function"
) {
  window.GTMFormTracker.trackAPIForm("your-endpoint.php", {
    formName: "Your API Form Name",
    formId: "your-form-id",
    hubspotFormGuid: "your-hubspot-form-guid",
    formGuidConstant: "YOUR_CONSTANT", // optional
    contentType: "content_type", // optional
    templateType: "template_type", // optional
    additionalData: {
      // Optional additional data
    },
  });
}

// Then make the API call
const response = await fetch("/v2/api/your-endpoint.php", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify(formData),
});
```

**Example - Template download form:**

```javascript
// GTM Form Tracking
if (
  window.GTMFormTracker &&
  typeof window.GTMFormTracker.trackAPIForm === "function"
) {
  window.GTMFormTracker.trackAPIForm("submit-template.php", {
    formName: "Template Download Form",
    formId: "template-download-form",
    hubspotFormGuid: "11e392f7-aece-4969-8c39-402ee6cb2330",
    formGuidConstant: "TEMPLATE",
    templateType: "Schichtplan Vorlage - Template",
    contentType: "Schichtplan Vorlage - Template",
  });
}

const response = await fetch("/v2/api/submit-template.php", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify(templateData),
});
```

## DataLayer Event Structure

All tracking functions push events with this structure:

```javascript
{
    event: 'form_submit',
    form_id: 'form-id',
    form_name: 'Form Name',
    form_type: 'custom_html' | 'hubspot_embedded' | 'api_based',
    form_subtype: 'optional_subtype',
    page_url: window.location.href,
    page_title: document.title,
    page_path: window.location.pathname,
    hubspot_form_guid: 'form-guid',
    utm_source: 'source',
    utm_medium: 'medium',
    utm_campaign: 'campaign',
    utm_term: 'term',
    utm_content: 'content',
    gclid: 'gclid',
    lead_source: 'lead_source',
    partner: 'partner',
    // Additional form-specific fields from additionalData
}
```

## Best Practices

### 1. Always Check for GTMFormTracker

Always check if `GTMFormTracker` exists before calling:

```javascript
if (
  window.GTMFormTracker &&
  typeof window.GTMFormTracker.trackCustomHTMLForm === "function"
) {
  // Safe to call
}
```

**Why:** Prevents errors if script fails to load or is blocked.

### 2. Track Before Submission

Always track **before** the form submission completes:

```javascript
// ✅ CORRECT - Track before submit
if (window.GTMFormTracker) {
  window.GTMFormTracker.trackCustomHTMLForm(form);
}
form.submit();

// ❌ WRONG - Track after submit (may not fire)
form.submit();
if (window.GTMFormTracker) {
  window.GTMFormTracker.trackCustomHTMLForm(form);
}
```

### 3. Use Descriptive Form Names

Use clear, descriptive form names:

```javascript
// ✅ GOOD
formName: "Main Lead Capture Form";
formName: "Template Download - Schichtplan";
formName: "Lead Capture Popup - Step 1";

// ❌ BAD
formName: "Form 1";
formName: "Contact";
formName: "Submit";
```

### 4. Include HubSpot Form GUID

Always include the HubSpot form GUID when available:

```javascript
hubspotFormGuid: "9b93ee13-fad2-4ce8-8ea2-4e588932af2a";
```

**Reference:** See `docs/forms/form-audit-inventory.json` for all form GUIDs.

### 5. Add Form-Specific Context

Use `additionalData` for form-specific information:

```javascript
additionalData: {
    form_step: 1, // for multi-step forms
    content_type: 'whitepaper', // for gated content
    template_type: 'Schichtplan Vorlage - Template', // for templates
    addon_name: 'Payroll', // for addon forms
    webinar_type: 'product_webinar' // for webinars
}
```

## Testing Checklist

When adding tracking to a new form:

- [ ] Tracking call added before form submission
- [ ] Form name is descriptive and unique
- [ ] HubSpot form GUID included (if applicable)
- [ ] Form-specific context added to `additionalData`
- [ ] Tested in GTM Preview mode
- [ ] Verified dataLayer push in browser console
- [ ] Verified trigger fires in GTM
- [ ] Verified GA4 event received
- [ ] Tested on multiple browsers
- [ ] Tested on mobile devices

## Common Patterns

### Pattern 1: Form with Prevent Default

```javascript
form.addEventListener("submit", function (e) {
  e.preventDefault();

  // Validation
  if (!validateForm()) {
    return;
  }

  // GTM Tracking
  if (window.GTMFormTracker) {
    window.GTMFormTracker.trackCustomHTMLForm(this, {
      formName: "My Form",
      hubspotFormGuid: "guid-here",
    });
  }

  // Submit via fetch
  fetch("/api/endpoint.php", {
    method: "POST",
    body: new FormData(this),
  });
});
```

### Pattern 2: Multi-Step Form

```javascript
// Step 1
if (window.GTMFormTracker) {
  window.GTMFormTracker.trackCustomHTMLForm(step1Form, {
    formName: "Multi-Step Form - Step 1",
    step: 1,
    hubspotFormGuid: "guid-here",
  });
}

// Step 2
if (window.GTMFormTracker) {
  window.GTMFormTracker.trackCustomHTMLForm(step2Form, {
    formName: "Multi-Step Form - Step 2",
    step: 2,
    hubspotFormGuid: "guid-here",
  });
}
```

### Pattern 3: Conditional Form Selection

```javascript
// Form handler selects HubSpot form based on form title
const formTitle = document.getElementById("formtitle").value;
let hubspotFormGuid = "";

if (formTitle === "Kostenlos und unverbindlich testen") {
  hubspotFormGuid = "9b93ee13-fad2-4ce8-8ea2-4e588932af2a";
} else if (formTitle === "Unverbindliche Demo vereinbaren") {
  hubspotFormGuid = "535143d6-9521-45b0-bea3-c13b078b8668";
}

if (window.GTMFormTracker) {
  window.GTMFormTracker.trackCustomHTMLForm(form, {
    formName: "Main Lead Capture Form",
    hubspotFormGuid: hubspotFormGuid || "handler-determined",
  });
}
```

## Updating Form Inventory

When adding a new form, update the form inventory:

1. **Update `docs/forms/form-audit-inventory.json`:**

   - Add form to appropriate category (hubspot_embedded, custom_html, api_based)
   - Include all metadata: form_id, form_name, hubspot_form_guid, etc.

2. **Update `docs/forms/form-ids-reference.md`:**

   - Add form to appropriate section
   - Include GTM tracking ID
   - Document trigger configuration

3. **Update `docs/forms/form-audit-report.md`:**
   - Add form to appropriate section
   - Update form counts

## Error Handling

The tracking utility includes error handling:

- **Silent failures:** Errors are caught and logged only in development
- **Graceful degradation:** If tracking fails, form submission continues normally
- **No blocking:** Tracking never blocks form submission

**You don't need to add try-catch blocks** - the utility handles errors internally.

## Debugging

### Enable Debug Logging

Debug logging is automatically enabled on localhost:

```javascript
// Automatically enabled if hostname is localhost or 127.0.0.1
// Check browser console for: [GTM Form Tracker] Form submission tracked
```

### Check DataLayer

In browser console:

```javascript
// View all dataLayer events
console.log(window.dataLayer);

// Filter form submission events
window.dataLayer.filter((e) => e.event === "form_submit");
```

### GTM Preview Mode

1. Open GTM Preview mode
2. Navigate to page with form
3. Submit form
4. Check:
   - **Tags Fired:** Should show GA4 event tag
   - **DataLayer:** Should show `form_submit` event
   - **Variables:** Should show populated values

## Reference

- **Tracking Utility:** `v2/js/gtm-form-tracking.js`
- **Form Inventory:** `docs/forms/form-audit-inventory.json`
- **Form IDs Reference:** `docs/forms/form-ids-reference.md`
- **Implementation Guide:** `docs/forms/GTM_FORM_TRACKING_GUIDE.md`
