Sign in

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:

  1. Captures the value from the URL on the first pageview
  2. Stores it in sessionStorage so it survives multi-page funnels
  3. Pushes it to dataLayer on 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

LayerKeyValue example
dataLayerad_placementAudience_Network_Native
sessionStoragemt_ad_placementAudience_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.

  1. Make sure you've installed GTM Core Config first
  2. In your mtConfig, set:
window.mtConfig = {
  ad_placement: true
};
  1. 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 (not DOM Ready) may race the script — set a default value on your DLV to handle this cleanly
  • Older browsers without URLSearchParams support (IE11 and earlier) will silently fall back to no value
  • sessionStorage is 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. Boggswhboggs.com → Free Meta Ads audit

The code

ad-placement.js
javascript
/*!
 * 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;
  }
}