Building a custom tracking script
This page is for the developer or marketing agency writing the snippet that goes in a form's Custom tracking HTML box. The non-technical side — where that box lives and who can edit it — is in Tracking & analytics.
Do you actually need one?
If the tool you are wiring up is Meta Pixel or Google Tag Manager, you almost certainly don't. Both have their own field in the Tracking panel, and InsurGrid loads and fires them for you — Meta gets a PageView on open and a Lead on submission; a GTM container receives all three events below, pushed to the standard window.dataLayer under their insurgrid_ names, ready to hang Custom Event triggers on.
A custom script is for everything else: a call-tracking product, an ad network that isn't Meta, your own analytics endpoint.
What the box accepts
Worth reading before you write anything — these limits shape the snippet:
<script>tags only, with either asrcor inline JavaScript. At least one script is required.A
srcmust be HTTPS.Allowed script attributes:
async,crossorigin,defer,id,integrity,referrerpolicy,src,type. Everything else — including everyon*handler — is rejected.10,000 bytes total.
Inline JavaScript is parsed (never executed) and refused if it uses eval, Function, setTimeout, setInterval, atob, document.write, document.writeln, Worker, WebAssembly, with, or debugger. Most vendor snippets pass. A few that self-schedule with setTimeout do not — load those from a src URL instead of inlining them.
Validation happens on save: a rejected snippet fails the whole save with an error naming what was refused, and nothing is partially applied.
Load order is guaranteed. A <script src> with neither async nor defer finishes loading before the next script is added, so a second script can rely on what the first one defined. Scripts marked async or defer get no such guarantee.
The events you can hook into
The form publishes its lifecycle to a plain array at window.insurgridDataLayer. Three events, each at most once per form, per browser session:
insurgrid_form_view
The public form page loads.
insurgrid_form_started
The consumer completes the first step and it saves successfully. A step that fails to save does not count as a start.
insurgrid_form_completed
The final step is accepted by the server — a real submission, not an attempt.
Every entry has the same two fields:
Only the event name and the form's public ID — the same identifier that appears in the form's public URL, and the same for every visitor of that form. Answers are never published: no names, addresses, or uploaded files. If you need the submission data itself, that is server-to-server — the form-submission webhook or the Submissions API.
On forms that hand the consumer to a carrier login, insurgrid_form_completed fires on the confirmation page they return to, not at the moment they leave.
Writing the script
The one thing to get right: an event may already have fired before your script runs. insurgrid_form_view is published in the same tick that installs your snippet, so anything fetched over the network arrives too late to witness it. A listener that only watches for future pushes will silently miss the view event on every single visit.
So do both — replay what is already in the array, then intercept later pushes:
That wrapper is the whole pattern. Everything below is what you put inside handle.
A complete example
Two scripts: the vendor's tag, then your wiring. Because the first has a src and no async/defer, it is finished loading before the second is added — so window.exampleTracker exists by then. The guard is there for the case where the vendor's CDN fails, which lets loading continue rather than stalling the chain.
Posting a conversion to your own endpoint instead, with no vendor script at all:
Note there is no setTimeout anywhere in either example — it would be rejected on save. If your vendor's snippet retries or defers on a timer, host that logic in the file you load over src rather than inlining it.
Testing
Publish the form and open its public link with the browser console open.
Inspect
window.insurgridDataLayer— it lists what has fired so far.Step through the form and submit it. You should see exactly one entry per event, and your own handler firing on each.
If an event never reaches your handler, the usual cause is the timing problem above: confirm your snippet replays the existing array rather than only wrapping push.
Because events deduplicate per session, a second run in the same window produces nothing. Use a new incognito window for each test pass, not a page refresh.
Related
Tracking & analytics — setting tracking up, and the Meta and GTM fields.
Webhook events & payloads — the
form-submissionevent, which carries the answers.Submissions API — pull submissions on demand.
Embed a form — putting the form in your own app.
