Set Up Advanced Tracking & Attribution for Your Priceguide Estimator
A step-by-step guide for web teams and digital agencies
By the end of this tutorial, your embedded Priceguide estimator will (1) attach full marketing attribution — UTMs and ad click IDs — to every lead, and (2) fire your GA4, Meta Pixel, and Google Ads conversion tags through your own Google Tag Manager container. Both setups are drop-in, generic, and reusable across every estimator you roll out.
- • Time required: ~15 minutes
- • Difficulty: Beginner to intermediate (you’ll paste one script and wire up a few GTM triggers)
- • Applies to: Every Priceguide estimator embed
What you’ll need before you start
Make sure you have these on hand:
- • Access to edit the parent page — the page on your own site where the estimator is embedded (in-house web team, CMS, or your tag manager)
- • Access to your Google Tag Manager container (only needed for Part 2)
- • A browser with DevTools (Chrome, Firefox, Safari, or Edge — all work)
- • The estimator already embedded and loading on your page
Good to know: The estimator works perfectly without any of this. These two enhancements simply unlock data that browser privacy rules would otherwise block. Nothing here changes how the estimator behaves for your customers.
Why this is needed (the 60-second version)
When a Priceguide estimator is embedded on your site, it runs inside an iframe on a different domain (app.priceguide.ai). That’s great for security and reliability, but it creates two gaps:
- Attribution gap — the campaign data in your page’s URL (UTMs, ad click IDs) does not automatically reach the estimator. Without a fix, leads arrive with no source attached.
- Conversion-tracking gap — because the iframe is cross-origin, the browser blocks it from reaching your page’s
dataLayer. So any tag fired from inside the estimator is invisible to your GTM container.
This tutorial closes both. We’ll do Part 1 (attribution) first — it’s the higher priority for most businesses — then Part 2 (conversion tracking).
Everything below is generic. The same snippets work for every location and every brand, with no per-estimator IDs to manage. Set them up once and reuse them across your whole rollout.
Part 1 — Pass UTMs and click IDs into the estimator
What this fixes
Imagine a visitor clicks a Google ad and lands on:
yoursite.com/pricing-estimator/?utm_source=google&utm_campaign=spring
The estimator iframe loads its own fixed URL and does not inherit that query string. So without this step, the lead is captured with no source, medium, or campaign.
The good news: Priceguide already reads and stores all standard UTM parameters on the lead record and passes them through to Zapier where Zapier is connected. The only missing link is getting those parameters from your page into the iframe URL. The script below does exactly that — once it runs, attribution flows all the way through to your lead data and your Zaps automatically.
You can skip Part 1 if… your site or agency already injects the campaign parameters into the estimator URL another way — for example, if your platform renders the iframe with the UTMs already on the
srcserver-side. The script is the universal client-side method for everyone else. It never overwrites a parameter that’s already present, so it’s safe to leave in place either way.
Step 1 — Copy the passthrough script
<!-- Priceguide: forward parent-page UTMs & click-IDs into the estimator iframe -->
<script>
(function () {
// Parameters forwarded from the parent page into the estimator
var FORWARD = ["utm_source","utm_medium","utm_campaign","utm_term","utm_content",
"gclid","gbraid","wbraid","fbclid","msclkid","ttclid","li_fat_id"];
var PG_HOST = "app.priceguide.ai"; // only change if you use a custom estimator domain
var parentParams = new URLSearchParams(window.location.search);
var pass = new URLSearchParams();
FORWARD.forEach(function (k) {
var v = parentParams.get(k);
if (v) pass.set(k, v);
});
if (!Array.from(pass).length) return; // nothing to forward, do nothing
function decorate(iframe) {
if (!iframe || iframe.dataset.pgUtmDone) return;
var src = iframe.getAttribute("src") || iframe.getAttribute("data-src");
if (!src || src.indexOf(PG_HOST) === -1) return;
var u;
try { u = new URL(src, window.location.href); } catch (e) { return; }
pass.forEach(function (v, k) {
if (!u.searchParams.has(k)) u.searchParams.set(k, v); // never overwrite
});
iframe.dataset.pgUtmDone = "1";
iframe.src = u.toString();
}
function scan() {
document
.querySelectorAll('iframe[src*="' + PG_HOST + '"], iframe[data-src*="' + PG_HOST + '"]')
.forEach(decorate);
}
if (document.readyState !== "loading") scan();
document.addEventListener("DOMContentLoaded", scan);
// Catch iframes injected later by page builders, tag managers or lazy-loaders
new MutationObserver(scan).observe(document.documentElement, { childList: true, subtree: true });
})();
</script>
This reads the campaign parameters from your page URL and forwards them into the Priceguide iframe. It also forwards the major ad-platform click IDs — Google (gclid, gbraid, wbraid), Meta (fbclid), Bing (msclkid), TikTok (ttclid), and LinkedIn (li_fat_id) — so paid attribution stays intact.
Step 2 — Place it on your estimator pages
Add the script to every page that has an estimator embed — ideally just before the closing </body> tag, or anywhere your tag manager can inject it site-wide. It finds the Priceguide iframe automatically, so it doesn’t matter whether it sits above or below the embed.
Step 3 (optional) — Enable the zero-flicker version
The script works with your standard embed exactly as Priceguide generates it. But by default the iframe may briefly load once without parameters, then reload with them.
To avoid that flicker: change the iframe’s src attribute to data-src. With no src, the browser waits until the script sets the final URL, so the estimator loads once with the parameters already attached. The script already reads data-src, so it supports both styles with no other change.
Step 4 — Test it (two minutes)
- Open an estimator page with test parameters on the end of the URL, e.g.
?utm_source=test&utm_campaign=demo - Right-click the estimator and choose Inspect, or open DevTools and find the
<iframe>element - Confirm its
srcnow ends with…?utm_source=test&utm_campaign=demo - Submit a test estimate and confirm the UTMs appear on the lead in Priceguide (and in your Zap, if connected)
✅ Part 1 complete. Every future lead now arrives with its full source attached.
Part 2 — Track conversion events in Google Tag Manager
Why GTM can’t see inside the iframe
Because the estimator runs on a different domain, the browser treats it as a cross-origin frame. Third-party cookies are blocked by default in Chrome, Safari, and Firefox, and JavaScript inside the iframe cannot reach your page’s dataLayer. So any tag fired from inside the estimator (GA4, Meta Pixel, conversion tags) is invisible to your GTM container. This is a browser privacy protection, not a bug.
The fix: let the estimator tell your page when something happens, and have your page push that into its own first-party dataLayer. The estimator already broadcasts an event at each key step using the browser’s postMessage API, and the listener that receives those events is already built into the embed code Priceguide gives you. So there’s nothing to add inside the iframe and no extra script to paste. Your only job is to wire the resulting dataLayer events to your tags in GTM.
For reference — the listener already in your embed. You don’t need to add this; it ships inside every Priceguide embed. It’s shown only so you know exactly what’s being pushed to your
dataLayer:<!-- Already included in your Priceguide embed — forwards estimator events to your dataLayer --> <script> window.addEventListener("message", function (e) { if (!e.data || e.data.type !== "priceguide-analytics") return; window.dataLayer = window.dataLayer || []; window.dataLayer.push({ event: "priceguide_" + e.data.event.toLowerCase().replace(/\s+/g, "_"), priceguide_event: e.data.event, priceguide_category: e.data.params.event_category || "", priceguide_label: e.data.params.event_label || "", priceguide_params: e.data.params }); }); </script>
What lands in your dataLayer
Each estimator step pushes one event whose name is priceguide_ followed by the step name in lowercase. Alongside each event, these variables are available for your tags:
| dataLayer key | What it contains |
|---|---|
event |
The trigger name, e.g. priceguide_lead |
priceguide_event |
The original step name from the estimator |
priceguide_category |
Event category, where provided |
priceguide_label |
Event label, where provided |
priceguide_params |
The full payload object for advanced use |
The typical events across a session are priceguide_started, priceguide_services_chosen, priceguide_step, priceguide_completed, and priceguide_lead (lead created and emails sent). The definitive list for your specific estimator is whatever appears in the console test at the end of this part — use that as the source of truth.
Step 1 — Create a Custom Event trigger
In GTM, go to Triggers → New → Custom Event.
- • To catch one specific event, enter its exact name, e.g.
priceguide_lead - • To catch every estimator event at once, tick Use regex matching and enter
priceguide_.*— handy while testing
Step 2 — Create Data Layer Variables (optional)
Go to Variables → New → Data Layer Variable and add any keys you want to pass to your tags — for example priceguide_label or priceguide_event.
Step 3 — Wire up your tags
Attach the trigger from Step 1 to your existing tracking tags. Common examples:
- • GA4 event — Tag type GA4 Event, event name e.g.
generate_lead, triggerpriceguide_lead - • Meta (Facebook) Pixel — Custom HTML tag firing
fbq("track", "Lead"), triggerpriceguide_lead - • Google Ads conversion — Google Ads Conversion Tracking tag, trigger
priceguide_completedorpriceguide_lead, with your Conversion ID and Label
Step 4 — Test it
- Open the estimator page, open DevTools → Console, and run an estimate all the way through
- Paste this to list the events as they fire:
window.dataLayer.filter(function (e) {
return e.event && e.event.indexOf("priceguide") === 0;
});
- Then use GTM Preview Mode to confirm your triggers fire and your tags execute
✅ Part 2 complete. Your estimator conversions now flow into GA4, Meta, and Google Ads through your own container.
Final checklist
- Passthrough script added to every estimator page (Part 1, Step 2)
- Test URL confirms UTMs land on the iframe
srcand on the lead record - (Optional) Zero-flicker
data-srcversion enabled - GTM Custom Event trigger created for the events you care about
- GA4 / Meta / Google Ads tags attached and confirmed in Preview Mode
Troubleshooting
UTMs aren’t reaching the lead. Confirm the script is actually on the page (check the page source), and that the iframe src points to app.priceguide.ai. Remember the script only forwards parameters that are present on the parent-page URL — if there are no UTMs on the URL, there’s nothing to forward.
A parameter looks “wrong” or isn’t overwritten. That’s by design — the script never overwrites a parameter that’s already on the iframe URL. If your platform injects UTMs server-side, those win.
No events appear in the dataLayer. Check that the estimator iframe is the Priceguide embed (its src is on app.priceguide.ai) and that the embed wasn’t pasted with the analytics listener removed. Re-copy a fresh embed if in doubt.
Still stuck? Send Priceguide the page URL and the team will take a look.
Need help?
If you’ve followed the steps and tracking still isn’t working, send us a message with the URL of your embed page and we’ll take a look. Or if you’d rather hand it off — Claude Cowork or any AI dev assistant can drop this in for you in about two minutes. Most agencies can do it even faster.
Five minutes of setup, accurate attribution forever. Worth it.
On This Page:
- Before you start
- Why it matters
- Part 1 · Attribution
- Part 2 · Conversion tracking
- Checklist
- Troubleshooting
Have More Questions?
We’d love to hear from you.
