# Forms and tracking code

Facts checked against HubSpot's live docs on 2026-10-17. For the event contract and GA4 side, use the tracking-plan-builder skill if installed; for campaign values, utm-convention-and-registry.

## Tracking code

- HubSpot-hosted pages already load the HubSpot tracking code. Do not add it again through GTM or header HTML on those pages.
- On external sites, install it before the closing body tag on every page, or as a Google Tag Manager Custom HTML tag on an All Pages trigger. A GTM tag without a firing rule collects nothing.
- Add every externally hosted domain and subdomain in HubSpot settings (Settings > Tracking & Analytics > Tracking code; accounts with only free tools or Marketing Starter see Tracking Code in the left sidebar instead).
- Each portal has its own code. Install one HubSpot tracking code per page: if two load, only the first fires. Check the rendered page for a second portal's code left by an agency or an old site.
- Decide how the code behaves under the site's consent banner with the privacy owner, and test with consent denied. Collection that follows the configured permissions is the goal, not maximum volume.
- GA4 on HubSpot-hosted pages: pick one install route per page type and check the rendered page for a second GA4 tag. The Measurement ID field in the content settings (Settings > Content > Pages > Integrations) runs GA4 only for visitors who opt in when an opt-in consent banner is used; GA4 pasted into header HTML is not controlled by HubSpot's banner. A GTM container on the same pages is a third route and the usual source of double collection.

Gate: a test page view on each domain appears for a known test contact; a page on each domain with consent denied behaves as agreed; each page type loads one GA4 tag.

## Identity: what links a visit to a contact

- HubSpot tracks visitors with a browser cookie and links earlier page views to a contact when that visitor submits a HubSpot form (or clicks a tracked HubSpot marketing email).
- Imported, manually created and synced contacts have no page-view history until one of those events happens. Do not promise attribution history for an imported database.
- If a form is submitted server-side or through a proxy without passing the HubSpot tracking cookie, HubSpot may not link the visit to the contact. Custom form handlers must forward it; check the current Forms API docs for the field name.

## Form design

For each form record in the brief:

- Purpose and the workflow it feeds (demo request, newsletter, support). Different purposes need different forms or a purpose field, so a newsletter signup never becomes a sales request.
- Fields mapped to internal property names from the property register.
- The "Set new contacts as marketing contacts" switch for HubSpot forms (on by default). With it on, an existing non-marketing contact who submits the form is also set to marketing, however that contact was created. Non-HubSpot forms follow an account-wide setting, on by default, with the same effect.
- Who will submit the form. If imported non-marketing contacts are likely submitters, either turn the switch off or budget them against the tier and the maximum cap.
- Subscription types and consent fields agreed with the privacy owner, for any form that collects marketing permission.
- Default lifecycle stage, if the form sets one.
- What happens when an existing customer submits it (the must-not-happen case from the brief).

Unique-value properties are not supported in forms, so a form cannot enforce an internal ID. Match on email and let the integration attach the internal ID.

Form submissions with company properties associate the contact with that company whatever the automatic company association setting says. Test a submission from a shared domain.

## Capturing UTMs and campaign context

- Hidden fields populate from query-string parameters whose names equal the property's internal name. Dropdown, radio and checkbox values must match option values exactly (multiple checkboxes separated by semicolons, single checkbox `true` or `false`, dates as YYYY-MM-DD, spaces encoded as `%20`).
- Hidden fields capture only the URL of the page holding the form. A visitor who lands on an article with UTMs and then navigates to the pricing page has lost them unless the site preserves them (first-party storage, then written into the form).
- With "Pre-populate fields for returning visitors" on, a hidden field's value can be overwritten by the stored value depending on the field type. Test a returning visitor.
- Define three separate behaviours, each with its own properties:
  - First observed acquisition: written once, with observed time.
  - Latest eligible acquisition: updated by a documented rule (how direct visits and missing parameters behave).
  - Conversion context: what was known at this submission.
- Never clear a known source because the next submission lacks UTMs, and never present an old campaign as the current request's source.
- Do not put emails, names or form text in URLs or analytics parameters.

## Counting a successful submission

- Count the conversion on the success event for the form editor version actually embedded (updated and legacy forms expose different event interfaces). The event contract belongs in tracking-plan-builder if installed; otherwise read HubSpot's global form events page.
- Use the success event, not the submit-button click (validation can still fail) or a thank-you-page view (reloads and bookmarks).
- Restrict analytics conversions to the intended forms. Test a repeated submission and a failed one.
- Exclude test and internal submissions by one documented rule (test email domain, internal IP or a test flag) applied the same way in HubSpot reports and in analytics.

Gate: for each form, one test submission produces the expected contact (or update), marketing status, lifecycle, hidden-field values and exactly one success event; an existing-customer submission follows its own rule; the marketing contact count before and after the form goes live is recorded.
