Skip to content
TraceLead

HubSpot forms

Contact properties, hidden fields and the form API script that carry the attribution into HubSpot.

Overview: HubSpot

HubSpot forms can carry TraceLead's attribution into the contact record as ordinary contact properties. TraceLead never connects to your HubSpot account and holds no HubSpot credentials: the form you embed sends the values to HubSpot itself, alongside the visitor's answers.

Status: tested on every release against HubSpot's rendered markup and its documented form API (a stand-in for HubSpot's embed script, so the test needs no HubSpot account). Not yet verified on a live HubSpot portal; see the integrations ledger.

1. Create the contact properties

In HubSpot, open Settings → Properties, choose the Contact object and create one property per value you want on the record. A sensible set:

Label Internal name Field type
TraceLead channel tl_channel Single-line text
TraceLead source tl_source Single-line text
TraceLead medium tl_medium Single-line text
TraceLead campaign tl_utm_campaign Single-line text
TraceLead landing page tl_landing_page Single-line text
TraceLead first visit tl_first_touch_at Single-line text

HubSpot suggests an internal name from the label; change it to the tl_ name before saving, because an internal name cannot be edited afterwards. Any field TraceLead can fill works the same way (tl_gclid, tl_utm_term, tl_referrer_host and so on; the full list is in Installing the snippet). If you already have properties with other internal names, keep them and change the mapping on your site's page in TraceLead instead.

2. Add them to the form as hidden fields

In the form editor, add each property to the form and turn on Make this field hidden. Leave the default value empty. Publish the form.

3. Install the snippet on the page

Add the TraceLead script tag to the page that embeds the form, as in Installing the snippet, with your consent call. What happens next depends on how HubSpot renders the form.

Forms rendered into the page (raw HTML)

Legacy forms set to raw HTML render their inputs straight into your page. The snippet fills any input named tl_<field> itself, including forms HubSpot mounts after the page loads, and counts the submission as a lead with the form's id (hsForm_<form id>). No extra code is needed.

Forms in an iframe (the new forms editor)

Forms built in HubSpot's new forms editor render inside an iframe from HubSpot's domain, where no script on your page can reach the inputs. HubSpot provides a form API for exactly this. Paste this script before HubSpot's embed code, after the TraceLead tag:

<script>
// TraceLead → HubSpot (forms from the new forms editor). Paste before HubSpot's embed code.
(function () {
    var PREFIX = '0-1/tl_';

    window.addEventListener('hs-form-event:on-ready', function (event) {
        var form =
            window.HubSpotFormsV4 &&
            window.HubSpotFormsV4.getFormFromEvent(event);
        if (!form) {
            return;
        }
        window.tracelead('touch', function (fields) {
            if (!fields) {
                return;
            }
            Object.keys(fields).forEach(function (key) {
                try {
                    if (fields[key]) {
                        form.setFieldValue(PREFIX + key, fields[key]);
                    }
                } catch {
                    // The form has no property for this field; skip it.
                }
            });
        });
    });

    window.addEventListener(
        'hs-form-event:on-submission:success',
        function (event) {
            window.tracelead('lead', 'hubspot-' + event.detail.formId);
        },
    );
})();
</script>

When the form is ready, the script asks TraceLead for the attribution and sets each property through setFieldValue('0-1/tl_<field>', value). After a successful submission it reports the lead to your TraceLead dashboard as hubspot-<form id>; the report carries the form id and the stored attribution, never the visitor's answers. If your internal names do not start with tl_, change PREFIX.

Without consent, TraceLead hands the script nothing, the hidden properties stay empty and the form submits normally. If consent arrives while the form is open, the properties are set at that moment.

What appears in HubSpot

Each new contact created through the form has the TraceLead properties filled with the first touch: for example TraceLead channel paid_search, TraceLead source google, TraceLead campaign spring-launch. Add them to the contact record sidebar, filter lists by them, or build a report of contacts by TraceLead channel. This works on any HubSpot plan, including those without HubSpot's own attribution reports.

HubSpot keeps the value it received at submission. A later form submission by the same contact overwrites the properties with that submission's values, which is still that browser's first touch unless it has expired or the visitor used another device.

Troubleshooting

  • Properties stay empty: check that consent was given on the page, that the internal names match (tl_channel, not tracelead_channel), and that the fields are on the form as hidden fields. tracelead('diagnostics', console.log) in the browser console shows whether consent was given and whether a touch is stored.
  • Raw HTML forms not filled: the input names in the rendered form must match the site's mapping; inspect the form and look for name="tl_channel".
  • Leads counted twice: use the iframe script only for iframe forms. On raw HTML forms the snippet already counts the submission.