# HubSpot Form Tracking

> How AnyTrack tracks each type of HubSpot form, and what you do so the AnyTrack Click ID reaches the HubSpot contact.

AnyTrack attributes a HubSpot contact to an ad click when the AnyTrack [Click ID](/docs/anytrack-click-id) reaches the contact. The type of form decides how the Click ID gets there. Find your form in the table, then follow its section. To connect HubSpot first, see the [HubSpot integration guide](/docs/hubspot).

<Table variant="specs">

| Form type | How the Click ID reaches HubSpot | What you do |
| :-------- | :------------------------------- | :---------- |
| [Standard embed code](#standard-embed-code) | The Tracking Tag fills in the AnyTrack Click ID field | Add the field to the form one time |
| [Developer embed code](#developer-embed-code) | The Tracking Tag fills in the AnyTrack Click ID field | Add the field to the form one time |
| [Legacy form](#legacy-forms) | AnyTrack adds the field. The Tracking Tag fills it in | Click **Sync with HubSpot** after you create a form |
| [Custom form](#custom-forms) (API, Zapier, Make) | Your form sends the Click ID with the lead | Add a hidden field and map it to the HubSpot property |
| [Typeform](#typeform-and-hubspot) | Typeform sends `at_click_id` to HubSpot | Map `at_click_id` to the HubSpot property |

</Table>

<Prerequisites
  title="Before you begin"
  items={[
    { label: "You connected HubSpot to AnyTrack", done: true },
    { label: "The AnyTrack Tracking Tag is on each page that shows a form", done: true },
    { label: "You can edit forms and contact properties in your HubSpot account", done: true },
    { label: "For a custom form, you can edit the code of the form or the automation that sends the lead", done: true },
  ]}
/>

<Callout icon="❗" theme="error">
**AnyTrack Tag required**

The HubSpot integration only works when the AnyTrack Tracking Tag is installed in the `head` section of your website, funnel, or landing pages. Learn how to [Install the AnyTrack Tag](/docs/install-anytrack-tag) on your website.
</Callout>

## How AnyTrack Matches a HubSpot Contact

When you connect HubSpot, AnyTrack creates the **AnyTrack Click ID** contact property. The internal name of the property is `atclid`. AnyTrack reads this property each time HubSpot reports an event for the contact.

AnyTrack matches the contact to a visit in this order:

1. **The AnyTrack Click ID property.** AnyTrack matches the contact to the visitor and to the ad click behind the visit.
2. **The email address.** If the property is empty, AnyTrack tries to match the email address of the contact to a visitor. If the contact has no email address, AnyTrack uses the phone number.

If AnyTrack finds no match, the conversion shows as [Unknown](/docs/conversions-showing-as-unknown). The Click ID gives the most reliable match, so each section below shows how to get it into the property.

## Standard Embed Code

The standard embed code is the default for a form from the updated form editor of HubSpot. HubSpot loads the form in an iframe.

```html
<script src="https://js.hsforms.net/forms/embed/PORTAL_ID.js" defer></script>
<div class="hs-form-frame" data-region="na1" data-form-id="FORM_ID" data-portal-id="PORTAL_ID"></div>
```

The Tracking Tag cannot read an iframe. It does not need to: HubSpot publishes form events on the page, and the Tracking Tag listens to them.

* **When the form loads**, the Tracking Tag fills in the AnyTrack Click ID field, if the form has the field.
* **When the visitor submits the form**, the Tracking Tag sends a `FormSubmit` event to AnyTrack. The event includes the email address, the name, and the phone number from the form.
* **When HubSpot creates the contact**, AnyTrack reads the AnyTrack Click ID property. By default, AnyTrack tracks the new contact as a `Lead`.

The Tracking Tag sends the `FormSubmit` event with or without the field. The field is what puts the Click ID on the HubSpot contact.

<Callout icon="⚠️" theme="warning">
**Load the Tracking Tag before the form**

The Tracking Tag fills in the field at the moment the form loads. If the Tracking Tag starts after the form loads, the field stays empty for that page view. This can occur when a tag manager loads the Tracking Tag. Install the Tracking Tag in the `head` section of the page, above the embed code of the form. When the field is empty, AnyTrack tries to match the contact by email address.
</Callout>

To add the field, open the form in HubSpot and add the **AnyTrack Click ID** property as a hidden field. The steps are in [Add the AnyTrack Click ID to Your Forms](/docs/hubspot#step-3-add-the-anytrack-click-id-to-your-forms).

### Test the Standard Embed Code

The form below is a live HubSpot form with the standard embed code. This page has the Tracking Tag, and the form has the AnyTrack Click ID field. The line under the form shows the value that the Tracking Tag writes to the field.

<HubSpotFormDemo embed="standard" portalId="6180478" formId="e1f91e90-ef0d-448d-871a-876cf8a85823" />

The field is hidden, so the form does not show it. The value under the form is the Property ID joined to your Client ID (26 characters). If you submit the form, HubSpot saves this value in the **AnyTrack Click ID** property of the contact. The form belongs to AnyTrack: a submission sends your details to the AnyTrack team.

## Developer Embed Code

The developer embed code is on the **Developer code (Advanced)** tab of the embed dialog in HubSpot. HubSpot makes it for custom CSS, and it needs a Marketing Hub or Content Hub Professional or Enterprise subscription. HubSpot writes the form into your page, with no iframe.

```html
<script src="https://js.hsforms.net/forms/embed/developer/PORTAL_ID.js" defer></script>
<div class="hs-form-html" data-region="na1" data-form-id="FORM_ID" data-portal-id="PORTAL_ID"></div>
```

AnyTrack works the same as with the standard embed code. The form comes from the same form editor and publishes the same form events. The Tracking Tag fills in the AnyTrack Click ID field when the form loads, and sends the `FormSubmit` event when the visitor submits the form. The same load order applies: the Tracking Tag must start before the form loads.

The setup is also the same: add the **AnyTrack Click ID** property to the form as a hidden field. If you change the embed code of a form from standard to developer, you do not add the field again. The field belongs to the form, not to the embed code.

### Test the Developer Embed Code

The form below is the same HubSpot form with the developer embed code. The Tracking Tag writes the same value to the field.

<HubSpotFormDemo embed="developer" portalId="6180478" formId="e1f91e90-ef0d-448d-871a-876cf8a85823" />

## Legacy Forms

A legacy form comes from the legacy form editor of HubSpot. Its embed code calls `hbspt.forms.create`.

```html
<script charset="utf-8" type="text/javascript" src="//js.hsforms.net/forms/embed/v2.js"></script>
<script>
  hbspt.forms.create({
    portalId: "PORTAL_ID",
    formId: "FORM_ID",
    region: "na1"
  });
</script>
```

AnyTrack adds the AnyTrack Click ID field to your legacy forms through the HubSpot API. AnyTrack does this when you connect HubSpot, and each time you click **Sync with HubSpot** in your HubSpot integration.

* **When the form loads**, the Tracking Tag fills in the AnyTrack Click ID field.
* **When the visitor submits the form**, the Tracking Tag sends a `FormSubmit` event to AnyTrack.

On a legacy form, the Tracking Tag does both actions only when the form has the field. After you create a legacy form, click **Sync with HubSpot**.

<Callout icon="⚠️" theme="warning">
**Legacy forms that appear later**

The Tracking Tag looks for legacy forms while the page loads. A legacy form can appear later, for example in a popup that opens on a click. The Tracking Tag does not fill in the Click ID on that form. AnyTrack then tries to match the contact by email address. A form from the updated form editor does not have this limit.
</Callout>

## Custom Forms

A custom form is a form that HubSpot did not make. Examples are an HTML form, a form in a React app, and a form from another form builder. The lead reaches HubSpot through the HubSpot API, Zapier, Make, or another automation tool.

HubSpot creates this contact from a server, with no tracked visit behind it. The Tracking Tag has no HubSpot form to fill in. Your form must carry the Click ID, and your automation must write it to the HubSpot property.

1. Add a hidden field to the form, inside the `<form>` element. Set its value to `--CLICK-ID--`.

   ```html
   <input type="hidden" name="click_id" value="--CLICK-ID--">
   ```

2. Load the page. The Tracking Tag replaces `--CLICK-ID--` with the Click ID of the visitor.
3. Send the value of the hidden field with the lead.
4. In the tool that sends the lead to HubSpot, map the value to the **AnyTrack Click ID** property (`atclid`).

Use the table to find the place of step 4 in your tool.

<Table variant="specs">

| How the lead reaches HubSpot | Where you map the Click ID |
| :--------------------------- | :------------------------- |
| HubSpot forms API (form submission) | Add the AnyTrack Click ID field to the HubSpot form that receives the submission. Send a field with the name `atclid` and the object type `0-1` |
| HubSpot contacts API | Set the `atclid` property when you create or update the contact |
| Zapier or Make | In the HubSpot action, map the hidden field of your form to **AnyTrack Click ID** |

</Table>

For the hidden field rules and the forms that the Tracking Tag cannot fill in, see [Form Tracking](/docs/form-tracking). For the same pattern with other CRMs, see [Pass the Click ID from External Forms to Your CRM](/docs/external-form-to-crm).

### When the HubSpot Tracking Code Collects Your Form

If the HubSpot tracking code is on your website, HubSpot can collect submissions from forms that it did not make. HubSpot calls them non-HubSpot forms. HubSpot then creates the contact itself, and AnyTrack tracks the contact as a `Lead`.

<Callout icon="⚠️" theme="warning">
**HubSpot does not collect hidden fields**

HubSpot states that the non-HubSpot forms tool does not collect information from hidden fields. The Click ID in your hidden field does not reach the contact. AnyTrack then tries to match the contact by email address. To put the Click ID on the contact, use the steps above: send the lead through the API or an automation tool.
</Callout>

HubSpot also states three more limits. The tool does not collect a form in an iframe, on a single-page app, or added after the page loads. An app from an AI coding tool such as Lovable is a single-page app. Read [Use non-HubSpot forms](https://knowledge.hubspot.com/forms/use-non-hubspot-forms) in the HubSpot knowledge base for the full list.

### Prompt for AI Coding Tools

If you build your website with Lovable, Claude, or another AI coding tool, give the tool this prompt. The prompt adds the hidden field to your form and sends the Click ID to HubSpot. Install the Tracking Tag first: see [Single Page App Tracking](/docs/single-page-tracking).

```text
My site uses AnyTrack for conversion tracking. The AnyTrack Tracking Tag is
already in the <head> of index.html. Do not remove or change that script tag.

Update my lead form so that it sends the AnyTrack Click ID to HubSpot:

1. Inside the <form> element, add this hidden input. Keep it uncontrolled
   (in React, use defaultValue, not value plus state):
   <input type="hidden" name="click_id" defaultValue="--CLICK-ID--" />
   The AnyTrack Tracking Tag replaces --CLICK-ID-- with the real value in the
   browser.

2. In the submit handler, read the value from the DOM input at submit time,
   not from React state.

3. Send that value to HubSpot together with the other form fields, as the
   contact property with the internal name "atclid":
   - If the form posts to the HubSpot forms API, add this object to the
     "fields" array: { "objectTypeId": "0-1", "name": "atclid", "value": <the value> }
   - If a backend function creates the contact through the HubSpot contacts
     API, add "atclid": <the value> to the "properties" object.

4. If the value is empty or is still the text "--CLICK-ID--", do not send the
   atclid field.

5. Do not call AnyTrack('trigger', 'FormSubmit'). AnyTrack tracks the form
   submission automatically.

6. Never put a HubSpot private app token in browser code.
```

After the tool makes the change, do the checks in [Verify the Click ID in HubSpot](#verify-the-click-id-in-hubspot).

## Typeform and HubSpot

With Typeform, two integrations work together:

* **The [Typeform integration](/docs/typeform)** tracks the form. The Tracking Tag adds the Click ID to your Typeform links and embeds as the `at_click_id` parameter. Typeform sends each submission to AnyTrack, and AnyTrack tracks it as a `Lead`.
* **The HubSpot integration** tracks what comes after the form: lead status, lifecycle stage, meetings, and deals. For these events, the Click ID must be on the HubSpot contact.

To put the Click ID on the HubSpot contact:

1. In Typeform, add `at_click_id` as a URL parameter of the form. See the [Typeform setup guide](/docs/typeform#setup-guide).
2. In Typeform, open the HubSpot integration of the form.
3. Map the `at_click_id` URL parameter to the **AnyTrack Click ID** contact property.
4. Save the mapping.

Typeform calls hidden fields URL parameters. Its HubSpot integration creates or updates the contact by email address, and it can map a URL parameter to a contact property. If Zapier or Make sends your Typeform leads to HubSpot, map `at_click_id` to **AnyTrack Click ID** in the HubSpot action.

### Test the Typeform Link

The link below opens a live Typeform form of AnyTrack. The Tracking Tag on this page adds your Click ID to the link. Open the link, then read the address of the form: the address contains `at_click_id=` and your Click ID.

[Open the live Typeform form](https://anytrack.typeform.com/to/apmPsghW)

<Callout icon="📘" theme="info">
**One lead, two events**

Each integration records its own event for the same lead: the Typeform submission, and **Contact created** in HubSpot. By default, AnyTrack tracks both as `Lead`. To count each lead one time, open **HubSpot Integration Events** in your HubSpot integration. Then clear the **Contact created** checkbox, or map **Contact created** to a different event name.
</Callout>

## Verify the Click ID in HubSpot

1. Open the page with your form in a private browser window.
2. Submit the form with an email address that is not in HubSpot.
3. In HubSpot, open the new contact.
4. Find the **AnyTrack Click ID** property. Verify that the property has a value.
5. In AnyTrack, open your HubSpot integration.
6. Click the **Events Log** tab. Verify that the contact shows as a `Lead` event.

If the **AnyTrack Click ID** property is empty, the form did not send the Click ID. Read the section for your form type again.

The Events Log can show an error that says the contact is not related to your Property ID. The Click ID then comes from a different AnyTrack Property. Verify that the page with the form has the Tracking Tag of the Property that you connected to HubSpot.

To read the status of each event, see [Events Log](/docs/integration-event-log).

<Cards columns={2}>
  <Card title="Integration Setup" href="/docs/hubspot" logo="hubspot">
    Connect your account, add the Click ID field, and map your events.
  </Card>
  <Card title="Click ID Parameter" href="/docs/typeform" logo="typeform">
    Add the at_click_id parameter and send your leads to a CRM.
  </Card>
  <Card title="Form Tracking" href="/docs/form-tracking" icon="fa-pen" iconColor="blue-500">
    Hidden field and action URL rules for every HTML form.
  </Card>
  <Card title="Single Page App Tracking" href="/docs/single-page-tracking" icon="fa-code" iconColor="green-500">
    Install the Tracking Tag in React, Next.js, and apps from AI coding tools.
  </Card>
</Cards>

<FaqAccordion
  title="HubSpot Form Tracking - Frequently Asked Questions"
  icon="fa-duotone fa-circle-question"
  items={[
    {
      question: "Does AnyTrack track a HubSpot form that loads in an iframe?",
      answer: "Yes. The standard embed code of HubSpot loads the form in an iframe, and the Tracking Tag cannot read an iframe. The Tracking Tag does not need to read it. HubSpot publishes form events on the page for each form from the updated form editor. The Tracking Tag listens to these events. It fills in the AnyTrack Click ID field when the form loads, and it sends a <code>FormSubmit</code> event when the visitor submits the form. Add the AnyTrack Click ID property to the form as a hidden field one time."
    },
    {
      question: "What is the difference between the standard and the developer embed code for AnyTrack?",
      answer: "For AnyTrack, there is no difference. The standard embed code loads the form in an iframe. The developer embed code writes the form into your page, so that you can style it with your own CSS. Both embed codes show a form from the updated form editor, and both publish the same HubSpot form events. The Tracking Tag fills in the AnyTrack Click ID field and sends the <code>FormSubmit</code> event with each one. The hidden field belongs to the form, so you add it one time."
    },
    {
      question: "How do I send the Click ID to HubSpot from a custom form?",
      answer: "Add a hidden field with the value <code>--CLICK-ID--</code> inside the form. The Tracking Tag replaces this value with the Click ID of the visitor. Send the value with the lead. Then map it to the AnyTrack Click ID contact property, which has the internal name <code>atclid</code>. You do this in the HubSpot forms API call, in the HubSpot contacts API call, or in the HubSpot action of Zapier or Make. See <a href='/docs/form-tracking'>Form Tracking</a> for the hidden field rules."
    },
    {
      question: "What happens if the HubSpot tracking code collects my custom form?",
      answer: "HubSpot creates the contact, and AnyTrack tracks the contact as a <code>Lead</code>. HubSpot states that its non-HubSpot forms tool does not collect hidden fields, so the Click ID does not reach the contact. AnyTrack then tries to match the contact to a visitor by email address. If AnyTrack finds no match, the conversion shows as Unknown. To put the Click ID on the contact, send the lead to HubSpot through the API or an automation tool, and map the hidden field to the AnyTrack Click ID property."
    },
    {
      question: "How do I pass the Click ID from Typeform to HubSpot?",
      answer: "Add <code>at_click_id</code> as a URL parameter of your Typeform form. The Tracking Tag adds the Click ID to your Typeform links and embeds with this parameter. Then open the HubSpot integration of the form in Typeform, and map the <code>at_click_id</code> URL parameter to the AnyTrack Click ID contact property. If Zapier or Make sends the leads, map the same value in the HubSpot action. See the <a href='/docs/typeform'>Typeform integration guide</a>."
    },
    {
      question: "Why is the AnyTrack Click ID property empty on my HubSpot contact?",
      answer: "The form did not send the Click ID. On a form from the updated form editor, add the AnyTrack Click ID property as a hidden field. On a legacy form, click <b>Sync with HubSpot</b> in your HubSpot integration. On a custom form, verify that the hidden field is inside the form and that your API call or automation maps it to the property. A contact that you create by hand in HubSpot has no Click ID. AnyTrack then tries to match the contact by email address."
    }
  ]}
/>
