Skip to content

Install the capture script

When someone clicks an ad, the network adds a click ID to your landing page’s URL. A conversion that carries that ID can be matched to the exact click. The capture script saves the ID when the visitor lands, and fills it into hidden fields on your HubSpot forms. When the form is submitted, the click ID lands on the contact, where Ledion reads it at send time.

It’s free on every plan. It’s under 3 KB gzipped, has no dependencies and makes no network requests: nothing it reads reaches Ledion. The click IDs go to HubSpot with the form, like any other field.

1. Add the script to your site

Paste this tag before </head> on every page of your site:

html
<script src="https://ledion.io/c/v1.js" async></script>

Keep it as its own <script> tag, as above: not type="module", and not bundled into another script. The script reads its options from its own tag, so in any other form it doesn’t see them and runs with the defaults, without waiting for consent.

Two optional attributes go on the same tag:

  • data-consent="wait": read and write nothing until the visitor agrees (consent).
  • data-days="90": how many days to keep a click ID in the visitor’s browser. Anything that isn’t a positive number means 90.
With both options
<script src="https://ledion.io/c/v1.js" async
      data-consent="wait" data-days="90"></script>

2. Add the hidden fields to your forms

The script can only fill fields the form has, so each form needs Ledion’s properties as hidden fields. Ledion created them when you installed it, in the property group Ledion. In HubSpot, open each form that collects leads from ads, add the properties for your networks, and mark each one hidden.

Network Hidden fields
Google Ads ledion_gclid, ledion_gbraid, ledion_wbraid
Meta ledion_fbc, ledion_fbp
Microsoft Ads ledion_msclkid
Reddit ledion_rdt_cid, ledion_rdt_uuid
LinkedIn (next) ledion_li_fat_id
TikTok (saved only: Ledion doesn’t send to TikTok) ledion_ttclid
Every form ledion_click_at

In the form editor they’re labelled like Ledion: Google click ID (gclid). ledion_click_at is Ledion: Ad click time: when the script saw the most recent ad click, which Ledion uses to check each network’s window.

Screenshot to come: HubSpot form editor: the property Ledion: Google click ID (gclid) added to a lead form and set as a hidden field

3. Which forms it fills

  • Forms from HubSpot’s new forms editor: the script fills them when they render, whenever that is.
  • Your own fields: any <input name="ledion_gclid"> (or another ledion_ name) on the page, for example on a form you post to HubSpot’s Forms API yourself.
  • Forms with older HubSpot embed code, and forms on pages HubSpot hosts: the script tries, but run the check below before you rely on it.

When the visitor clicks a newer ad, the newer click ID replaces the older one for that network.

Without data-consent, the script runs on every page view as soon as it loads. With data-consent="wait", it reads and writes nothing (no cookies, no storage, no form fields) until your page calls window.ledion.consent(true).

Sites with visitors in the EEA, the UK or Switzerland usually need data-consent="wait". Whether the script runs before consent is your decision.

Call it from your consent banner’s code, on every page view where the visitor has agreed. The script doesn’t remember consent.

js
// When the visitor agrees to advertising cookies:
if (window.ledion) window.ledion.consent(true);

// When they say no, or take it back:
if (window.ledion) window.ledion.consent(false);
  • consent(true) captures the click ID from the URL the page loaded with, even if your site changed the URL since, and fills the forms already on the page.
  • consent(false) deletes what the script stored, empties the fields it filled on this page, and stops for the rest of the page view. Without data-consent="wait", the next page view captures again.
  • window.ledion exists once the script has run. Calls made before that are lost, so keep the check.

What it stores, for your cookie list: one first-party cookie, _ldn_c, and one localStorage entry, ldn_c, both kept for 90 days or your data-days. It also reads cookies that the networks’ own tags set: _fbc, _fbp, li_fat_id and _rdt_uuid.

5. Check it works

Do this once for each kind of form you use.

  1. Open a page of your site with a test click ID on the URL, like https://www.example.com/?gclid=TeSt_123 (with your own domain).

  2. Open the browser’s console and run:

    js
    window.ledion.get()

    You should see the click ID, the time the script first saw it, and click_at:

    { gclid: { value: "TeSt_123", at: 1792488600000 }, click_at: "2026-10-20T09:30:00.000Z" }
    

    With data-consent="wait", it shows {} until consent(true) is called.

  3. Submit a test form on that page. In HubSpot, open the new contact and check that Ledion: Google click ID (gclid) and Ledion: Ad click time have values. If either is empty, email santi@ledion.io with the page’s address.

  4. Delete the test contact, or keep it out of workflows that send conversions: its click ID is made up.

From then on, Ledion’s Tracking health page shows the share of new contacts from paid traffic that carry each network’s click ID. It checks new contacts once a day (Read Tracking health). Get started marks Install the capture script done once a new contact from the last 30 days has a Ledion click ID.

Known limits

  • Non-HubSpot forms: HubSpot’s capture of non-HubSpot forms ignores hidden fields (“The tool doesn’t collect information from any hidden fields”). It also misses forms in iframes, forms sent by JavaScript, single-page apps and forms added after the page loads. So the script can’t carry click IDs through those forms.
  • Fields it can’t reach: fields inside an iframe from another domain or inside a shadow DOM, and plain inputs added more than 2 seconds after the page loads (single-page apps, pop-ups). Forms from HubSpot’s new forms editor are always reached.
  • Safari:
    • In Private Browsing, and on links opened from Mail and Messages, Safari removes gclid, fbclid and msclkid from the URL. gbraid, wbraid and UTM parameters get through. In regular browsing they still pass, as of Safari 26.
    • Safari deletes what scripts store, cookies and localStorage, after 7 days without the visitor interacting with your site. Cookies a script sets on a page opened from an ad link last 24 hours at most. The capture script’s storage falls under both.
    • So in Safari, the click ID is safest when the visitor fills in a form on the visit that came from the ad. That’s one reason Ledion also matches on email and phone.

Something missing or wrong? Email santi@ledion.io.