Ad Placement
Ad Placement
Captures the utm_placement URL parameter on a visitor's first pageview and persists it across the session, so it's available when the conversion happens later.
What it does
Most ad platforms expose a placement-level breakdown (e.g., Meta's Audience Network vs. Facebook Mobile Feed, Google's top-of-page vs. Display Network). When you tag your ad URLs with utm_placement=Audience_Network_Native, this script:
- Captures the value from the URL on the first pageview
- Stores it in
sessionStorageso it survives multi-page funnels - Pushes it to
dataLayeron every pageview where a value is available
The result: when a lead form fires on page 4 of the funnel, your conversion still knows the original placement.
What this script outputs
| Layer | Key | Value example |
|---|---|---|
| dataLayer | ad_placement | Audience_Network_Native |
| sessionStorage | mt_ad_placement | Audience_Network_Native |
The script is platform-agnostic — utm_source already tells you which platform sent the visitor. This just captures whatever placement string was passed.
Installation
This script is loaded by the Marketing Toolkit bootstrap. You don't install it directly.
- Make sure you've installed GTM Core Config first
- In your
mtConfig, set:
window.mtConfig = {
ad_placement: true
};
- Save, preview, and publish your GTM container
Setting up the Data Layer Variable
In GTM, create a new variable:
- Type: Data Layer Variable
- Name:
DLV - Ad Placement - Data Layer Variable Name:
ad_placement - Set Default Value:
(not set)(recommended)
Using the value
In a GA4 Event tag
Add an event parameter:
- Parameter Name:
ad_placement - Value:
{{DLV - Ad Placement}}
In a Meta Conversions API tag
Add to the custom_data object:
- Property Name:
ad_placement - Property Value:
{{DLV - Ad Placement}}
How to tag your ads
For this script to capture anything, your ad URLs need to include utm_placement. Recommended values:
Meta Ads — use Meta's placement macros in your URL parameters:
utm_placement={{placement}}
Google Ads — use ValueTrack parameters:
utm_placement={network}_{adgroupid}
Set this up at the campaign or ad set level so all click-throughs get tagged.
Known limitations
- Tags that fire on initial
Page View(notDOM Ready) may race the script — set a default value on your DLV to handle this cleanly - Older browsers without
URLSearchParamssupport (IE11 and earlier) will silently fall back to no value sessionStorageis blocked in some private browsing modes — script gracefully falls back to URL-only attribution
Disclaimer
This script is provided as-is under the MIT License. Test thoroughly in your own setup before relying on it for revenue attribution.
Created by W.H. Boggs — whboggs.com → Free Meta Ads audit
The code
/*!
* Marketing Toolkit — Ad Placement v1.0.0
* https://github.com/whboggs/marketing-toolkit
*
* Captures utm_placement from URL on first pageview, persists via sessionStorage.
* Pushes value to dataLayer silently (no event) for use via Data Layer Variables.
*
* DataLayer key: ad_placement
* Storage key: mt_ad_placement
*
* Created by W.H. Boggs — https://whboggs.com
* → Free Meta Ads audit: https://whboggs.com/audit
*
* MIT License | Copyright (c) 2026 W.H. Boggs
*/
function() {
// Captures utm_placement from URL on first pageview, persists via sessionStorage.
// Handles both Meta placements (e.g. "Audience_Network_Native", "Facebook_Mobile_Feed")
// and Google Ads placements (e.g. "g_1t1" for top-of-page search, "gmb_" for Business Profile,
// "d_" for Display Network). The variable doesn't care which platform set the value —
// utm_source already tells you that. This just captures whatever placement was passed.
var STORAGE_KEY = 'ad_placement';
try {
// First, check if utm_placement is in the current URL.
// If yes, this is the freshest signal — overwrite anything stored.
var urlParams = new URLSearchParams(window.location.search);
var placementFromUrl = urlParams.get('utm_placement');
if (placementFromUrl) {
try { sessionStorage.setItem(STORAGE_KEY, placementFromUrl); } catch(e) {}
return placementFromUrl;
}
// No utm_placement in current URL — fall back to whatever we stored
// earlier in this session (e.g. from the original landing page).
try {
var stored = sessionStorage.getItem(STORAGE_KEY);
if (stored) return stored;
} catch(e) {}
// No URL value, no stored value — return undefined.
// GA4 will simply omit the parameter rather than send an empty string.
return undefined;
} catch (e) {
// URLSearchParams unavailable (very old browsers) or other failure
return undefined;
}
}