Skip to content

view_item

The view_item event fires when a user views a product detail page. This is your product demand signal — it tells you which products get attention, how variant selection affects engagement, and where in the funnel users drop off before adding to cart.

view_item is the destination event for select_item. The item data you push here should be the most complete version of the product record you have: full category hierarchy, brand, variant, and price. The detail page is where you have all this data available, so use it.

Fire view_item when:

  • The product detail page loads (for traditional multi-page sites)
  • The product detail view renders in a SPA (after component mount, not on route change)
  • A quick-view modal opens with product detail content

Fire it once per product view, not on every render. For SPAs, use a ref guard or check to prevent re-firing on component re-renders.

// Always clear previous ecommerce data first
dataLayer.push({ ecommerce: null });
dataLayer.push({
event: 'view_item',
ecommerce: {
currency: 'USD',
value: 89.99,
items: [
{
item_id: 'SKU-001-BLK',
item_name: 'Classic Leather Jacket',
item_brand: 'Heritage Co.',
item_category: 'Apparel',
item_category2: 'Outerwear',
item_category3: 'Jackets',
item_category4: 'Leather',
item_variant: 'Black / Large',
price: 89.99,
quantity: 1,
index: 0,
affiliation: 'Online Store',
coupon: '',
discount: 0,
// List context — preserve from select_item if navigated from a list
item_list_id: 'mens_outerwear',
item_list_name: "Men's Outerwear"
}
]
}
});

The value on view_item is the price of the product being viewed — the same value as items[0].price. For a standard single-product view, value = price.

Event Schema view_item
Parameter Type Required Description
event string Required Must be "view_item"
ecommerce.currency string Required ISO 4217 currency code. Required for GA4 to attribute monetary value.
ecommerce.value number Required Monetary value — the product price. Must be a number.
ecommerce.items[] Array<Item> Required Array containing one item — the product being viewed.
items[].item_id string Required SKU or unique product identifier.
items[].item_name string Required Product name.
items[].item_brand string Optional Brand or manufacturer.
items[].item_category string Optional Primary product category.
items[].item_category2 string Optional Second-level category.
items[].item_category3 string Optional Third-level category.
items[].item_category4 string Optional Fourth-level category.
items[].item_variant string Optional Currently selected variant (color, size, style). Update when user changes variant selection.
items[].price number Optional Current price of the selected variant. Must match the ecommerce.value.
items[].quantity number Optional Always 1 for view_item.
items[].affiliation string Optional Store affiliation for marketplace scenarios.
items[].coupon string Optional Active coupon code if one is applied to this item.
items[].discount number Optional Discount amount if item is on sale.
items[].item_list_id string Optional The list the user navigated from — preserves funnel path context.
items[].item_list_name string Optional Human-readable name of the list the user navigated from.

When a product has variants (color, size, material) and the user changes the selected variant, you have two options:

Option A: Fire once on page load with the default variant. Simpler to implement. Loses the information about which variant the user actually considered.

Option B: Fire again when the variant selection changes. More work, but captures variant-level demand signal. Which color is most viewed? Which size runs out of stock because it’s most desired?

// Option B: re-fire when variant changes
function trackVariantView(product, selectedVariant) {
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
event: 'view_item',
ecommerce: {
currency: product.currency,
value: selectedVariant.price,
items: [{
item_id: selectedVariant.sku, // variant-level SKU
item_name: product.name,
item_brand: product.brand,
item_category: product.category,
item_variant: selectedVariant.label, // e.g., 'Navy / Medium'
price: selectedVariant.price,
quantity: 1
}]
}
});
}
// Fire on page load with default variant
trackVariantView(product, product.defaultVariant);
// Re-fire when user changes variant
colorSelector.addEventListener('change', () => {
const variant = getSelectedVariant();
trackVariantView(product, variant);
});

If the user navigated to this product detail page from a list (via select_item), carry the list context forward in item_list_id and item_list_name. This enables GA4 to build path reports showing “users who viewed items from Men’s Outerwear are X% more likely to purchase.”

For server-rendered pages, pass the list context via a query parameter or session storage, and read it back on the product page.

// On select_item (list page) — store context for the product page
sessionStorage.setItem('last_item_list', JSON.stringify({
item_list_id: 'mens_outerwear',
item_list_name: "Men's Outerwear"
}));
// On view_item (product detail page) — restore context
const listContext = JSON.parse(sessionStorage.getItem('last_item_list') || '{}');
dataLayer.push({ ecommerce: null });
dataLayer.push({
event: 'view_item',
ecommerce: {
currency: 'USD',
value: 89.99,
items: [{
item_id: 'SKU-001-BLK',
item_name: 'Classic Leather Jacket',
price: 89.99,
quantity: 1,
item_list_id: listContext.item_list_id || '',
item_list_name: listContext.item_list_name || ''
}]
}
});
  1. Create a Custom Event trigger. Event name: view_item. Name it CE - view_item.

  2. Create Data Layer Variables. Variables for ecommerce.currency, ecommerce.value, and ecommerce.items.

  3. Create the GA4 Event tag. Event name: view_item. Enable Send Ecommerce data. Add currency and value as explicit event parameters (they don’t flow through the ecommerce checkbox automatically).

  4. Test in Preview mode. Load a product page. Confirm one view_item fires with all parameters populated.

Firing on component re-render in SPAs. In React, a useEffect without a ref guard fires on every render. Wrap the push in a useRef(false) guard, or use useEffect with a dependency array that only changes when the product ID changes.

Sending the cart quantity instead of 1. view_item describes viewing the product, not purchasing a quantity. quantity: 1 on this event. The actual purchase quantity goes on add_to_cart and purchase.

Missing currency. Without currency, GA4 ignores the value parameter entirely. Your product performance reports will show views but zero revenue contribution.

Not updating the push when variant changes. If you implement Option A and fire only on page load, accept that you’re losing variant-level demand data. Don’t half-implement Option B by firing the initial push with a default variant but never re-firing — that’s worse than Option A because it looks like you have variant data but it’s unreliable.