← Back to Metrics

Promotion Views

Also known as: Promotion Impressions, Internal Promotion Views, Promo Views, Banner Impressions, View Promotion

EngagementmetricE-commerce: Product Discovery & Merchandising (Search/Filters/PDP)E-commerce

Count of internal promotion impressions (GA4 view_promotion), one per promotion per page view once the slot is in view. It is the denominator of Promotion Click-Through Rate.

Business Use Case

1️⃣ Merchandising compares each banner's views with its clicks and swaps creatives whose CTR trails the slot average. 2️⃣ Marketing checks campaign promotion views on launch day and fixes slot targeting when views fall short of plan. 3️⃣ Merchandising moves high-priority offers to the creative_slot positions that deliver the most views per session.

Business Criticality

Medium

Journey / Navigation Area

Discovery

Owning Function

Merchandising

Scope

Event

Formula

COUNT of view_promotion impressions, one per distinct promotion_id per page view, by event timestamp in the reporting period

Calculation Notes

1️⃣ One view per promotion_id per page view; carousel rotations and scroll-back re-renders on the same page add no views. 2️⃣ Fire when at least 50% of the creative is in the viewport for 1 second; firing on page load for below-the-fold slots inflates the count. 3️⃣ Internal promotions only: hero banners, tiles and on-site offers. Third-party ad impressions and product list views are excluded. 4️⃣ When one view_promotion lists several promotions in items, each distinct promotion_id counts as one view. 5️⃣ Promotion identity is promotion_id, else promotion_name; events with neither report (not set) and stay in the total. 6️⃣ Internal traffic (traffic_type = internal) is excluded, the same filter Promotion Clicks applies, so the CTR ratio stays consistent.

Technical Details

Measure TypeCounter
Aggregation WindowDaily, Weekly, Monthly

Events

PlatformEvent
Google Analytics 4view_promotion
Adobeview_promotion

Data Mappings

W3 Data Layer
{
  "digitalData": {
    "page": {
      "category": {
        "pageType": "home"
      }
    },
    "event": [
      {
        "eventInfo": {
          "eventName": "view_promotion",
          "type": "promotion"
        },
        "attributes": {
          "trafficType": "external",
          "promotions": [
            {
              "promotionId": "PROMO-1",
              "promotionName": "promo",
              "creativeName": "banner",
              "creativeSlot": "slot-1"
            }
          ]
        }
      }
    ]
  }
}
GA4 Data Layer
{
  "event": "view_promotion",
  "promotion_id": "PROMO-1",
  "promotion_name": "promo",
  "creative_name": "banner",
  "creative_slot": "slot-1",
  "page_type": "home",
  "traffic_type": "external",
  "ecommerce": {
    "items": [
      {
        "item_id": "SKU-1",
        "item_name": "item",
        "promotion_id": "PROMO-1",
        "promotion_name": "promo"
      }
    ]
  }
}
Adobe Client Data Layer
{
  "event": "view_promotion",
  "eventInfo": {
    "path": "promotions"
  },
  "promotions": [
    {
      "promotionId": "PROMO-1",
      "promotionName": "promo",
      "creativeName": "banner",
      "creativeSlot": "slot-1"
    }
  ],
  "page": {
    "pageType": "home"
  },
  "trafficType": "external"
}
XDM Mapping
{
  "eventType": "view_promotion",
  "timestamp": "2026-01-01T00:00:00Z",
  "identityMap": {
    "ECID": [
      {
        "id": "ecid-1",
        "authenticatedState": "ambiguous",
        "primary": true
      }
    ]
  },
  "_tenantId": {
    "trafficType": "external",
    "promotions": [
      {
        "promotionId": "PROMO-1",
        "promotionName": "promo",
        "creativeName": "banner",
        "creativeSlot": "slot-1"
      }
    ]
  }
}

SQL Queries

Google Analytics 4 (BigQuery)
-- ==========================================
-- 1. GOOGLE BIGQUERY SQL
-- ==========================================
DECLARE start_date DATE DEFAULT DATE_SUB(CURRENT_DATE(), INTERVAL 90 DAY);
DECLARE end_date DATE DEFAULT DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY);

WITH events AS (
  -- Page views and promotion views in the period, internal traffic excluded, event-level promotion fields pivoted
  SELECT
    user_pseudo_id,
    event_timestamp,
    event_name,
    items,
    (SELECT NULLIF(ep.value.string_value, '') FROM UNNEST(event_params) AS ep WHERE ep.key = 'promotion_id') AS promotion_id,
    (SELECT NULLIF(ep.value.string_value, '') FROM UNNEST(event_params) AS ep WHERE ep.key = 'promotion_name') AS promotion_name
  FROM `your-project.analytics_123456789.events_*`
  WHERE _TABLE_SUFFIX BETWEEN FORMAT_DATE('%Y%m%d', start_date) AND FORMAT_DATE('%Y%m%d', end_date)
    AND event_name IN ('page_view', 'view_promotion')
    AND COALESCE((SELECT ep.value.string_value FROM UNNEST(event_params) AS ep WHERE ep.key = 'traffic_type'), '') != 'internal'
),
anchored AS (
  -- Tie each promotion view to the user's most recent page view, so re-renders on the same page share one page view key
  SELECT
    *,
    LAST_VALUE(IF(event_name = 'page_view', event_timestamp, NULL) IGNORE NULLS)
      OVER (PARTITION BY user_pseudo_id ORDER BY event_timestamp ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS page_view_ts
  FROM events
),
promotions AS (
  -- One row per promotion listed on the event: promotion_id (item, then event level), else promotion_name, else (not set)
  SELECT
    a.user_pseudo_id,
    a.page_view_ts,
    COALESCE(NULLIF(i.promotion_id, ''), a.promotion_id, NULLIF(i.promotion_name, ''), a.promotion_name, '(not set)') AS promotion_key
  FROM anchored AS a
  LEFT JOIN UNNEST(a.items) AS i
  WHERE a.event_name = 'view_promotion'
)
-- Promotion Views: each distinct promotion counts once per page view
SELECT
  COUNT(DISTINCT CONCAT(user_pseudo_id, '|', COALESCE(CAST(page_view_ts AS STRING), 'none'), '|', promotion_key)) AS promotion_views
FROM promotions;
Adobe Experience Platform (AEP Query Service)
-- ==========================================
-- 2. ADOBE AEP QUERY SERVICE SQL
-- ==========================================
WITH events AS (
  -- Page views and promotion views in the last 90 complete days, internal traffic excluded
  SELECT
    identityMap['ECID'][0].id AS ecid,
    timestamp,
    eventType,
    _tenantId.promotions AS promotions
  FROM aep_web_events_dataset
  WHERE timestamp >= date_sub(current_date(), 90)
    AND timestamp < current_date()
    AND eventType IN ('web.webpagedetails.pageViews', 'view_promotion')
    AND COALESCE(_tenantId.trafficType, '') != 'internal'
),
anchored AS (
  -- Tie each promotion view to the visitor's most recent page view, so re-renders on the same page share one page view key
  SELECT
    *,
    last(CASE WHEN eventType = 'web.webpagedetails.pageViews' THEN timestamp END, true)
      OVER (PARTITION BY ecid ORDER BY timestamp ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS page_view_ts
  FROM events
),
promotions AS (
  -- One row per promotion listed on the event: promotionId, else promotionName, else (not set)
  SELECT
    a.ecid,
    a.page_view_ts,
    COALESCE(NULLIF(p.promotionId, ''), NULLIF(p.promotionName, ''), '(not set)') AS promotion_key
  FROM anchored AS a
  LATERAL VIEW OUTER explode(a.promotions) AS p
  WHERE a.eventType = 'view_promotion'
)
-- Promotion Views: each distinct promotion counts once per page view
SELECT
  COUNT(DISTINCT CONCAT(ecid, '|', COALESCE(CAST(page_view_ts AS STRING), 'none'), '|', promotion_key)) AS promotion_views
FROM promotions;

Source Data

Digital Analytics (GA4)

Dependencies

Prerequisite: List the dependencies required for this Metric

Events:

promotion-view

Dimensions:

page-type

Report Attributes

promotion_id promotion_name creative_name creative_slot page-type device-category

Recommended Reporting Views

Views
Internal Promotion PerformanceMerchandising DashboardHomepage Performance

Segment Eligibility

true

Governance

Data SensitivityInternal

Derived KPIs

Governance

Created bydevyendarm
Created on10/12/2026
Last modified bydevyendarm
Last modified on10/12/2026
StatusPUBLISHED

GitHub

View related Pull Requestcatalog/metrics/promotion-views.yml

Community Discussion