Login
ZappushZappush Docs
Reference

Data layer

The exact payload Zappush reads from window.dataLayer, with a copy-paste example for every ecommerce and lead event.

Once the tracker loads it wraps window.dataLayer.push and reads every push. One push reaches both GA4 and Zappush. There is no extra call and no GTM tag to add.

Zappush follows the GA4 recommended events schema. If you already send GA4 ecommerce, you are already sending Zappush ecommerce. If you do not use a data layer, call zappush.track() instead, which takes the same fields flattened and the Zappush event name rather than the GA4 one.

Push shape

window.dataLayer.push({
  event: "purchase",   // required, must be a string
  user_data: { ... },  // who the shopper is
  ecommerce: { ... },  // what it was worth, and which products
});
KeyWhat it carries
eventThe event name. A push without a string event is ignored.
user_dataContact details, used to match the conversion to a person.
ecommercevalue, currency, transaction_id, coupon, items.
Anything elsePassed through as event metadata.

Zappush flattens all three into one object. If the same key appears twice, the later one wins in this order: user_data, then top-level keys, then ecommerce.

Pushes made before the tracker finishes loading are replayed, so you never need a readiness check. On a visitor's first page load that replay happens once their consent state resolves, which takes a moment longer than the script loading. page_view is ignored, because the tracker fires its own page view. Anything starting with gtm. is ignored.

Contact fields

This is the part that decides whether a conversion matches a real person in Meta. Email and phone do most of the work. Send them on every event that has them.

Inside user_data, exactly these keys are read. This is the GA4 Enhanced Conversions shape.

KeyExampleNotes
emailalex@example.com
phone_number+61400000000E.164, including country code
address.first_nameAlex
address.last_nameSmith
address.citySydney
address.regionNSWState or province
address.postal_code2000
address.countryAUISO 3166-1 alpha-2

address is a single object, never an array. Keys inside user_data that are not on this list are dropped. To send anything else, put it at the top level of the push, where these names and aliases are read:

FieldAlso accepted as
email
phonephone_number
first_namefirstName
last_namelastName
city
stateregion
zippostal_code, zipcode
countrycountry_code
date_of_birthdob
gender
external_idexternal_customer_id

Send whatever you have, all fields are optional. Zappush persists them for the session and attributes later events in that session to the same person, so you only need to send them once.

Anything pushed to window.dataLayer is readable by every other script on the page. To keep contact details out of the shared data layer, call zappush.track() directly instead.

Items

FieldRequiredWhat it does
item_idYesIdentifies the product. Sent to Meta as content_ids.
item_nameNoProduct name in your dashboard. Used as the identity if item_id is missing.
quantityNoSummed into Meta's num_items. Defaults to 1.
priceNoUnit price in your dashboard and on order lines.
item_variantNoVariant name in your dashboard.
item_categoryNoProduct type in your dashboard.

Other GA4 item fields (item_brand, coupon, discount, index, affiliation, item_category2 and up) are accepted and stored on the event, but Zappush does not read them and does not forward them to Meta.

Put value and currency on ecommerce, not on items. The conversion value Meta receives is ecommerce.value exactly as you send it. It is never summed from item prices, so an event without a value reports a conversion worth nothing.

Ecommerce events

Fire these in order as the shopper moves through your funnel.

Product viewed

window.dataLayer.push({
  event: "view_item",
  ecommerce: {
    currency: "USD",
    value: 79.0,
    items: [
      {
        item_id: "SKU-001",
        item_name: "Running Shoes",
        item_variant: "Blue / 10",
        item_category: "Footwear",
        price: 79.0,
        quantity: 1,
      },
    ],
  },
});

Added to cart

window.dataLayer.push({
  event: "add_to_cart",
  ecommerce: {
    currency: "USD",
    value: 79.0,
    items: [
      { item_id: "SKU-001", item_name: "Running Shoes", price: 79.0, quantity: 1 },
    ],
  },
});

Checkout started

window.dataLayer.push({
  event: "begin_checkout",
  ecommerce: {
    currency: "USD",
    value: 158.0,
    coupon: "SUMMER10",
    items: [
      { item_id: "SKU-001", item_name: "Running Shoes", price: 79.0, quantity: 2 },
    ],
  },
});

Shipping info submitted

window.dataLayer.push({
  event: "add_shipping_info",
  user_data: { email: "alex@example.com", phone_number: "+61400000000" },
  ecommerce: {
    currency: "USD",
    value: 158.0,
    shipping_tier: "Ground",
    items: [
      { item_id: "SKU-001", item_name: "Running Shoes", price: 79.0, quantity: 2 },
    ],
  },
});

Payment info submitted

window.dataLayer.push({
  event: "add_payment_info",
  user_data: { email: "alex@example.com", phone_number: "+61400000000" },
  ecommerce: {
    currency: "USD",
    value: 158.0,
    payment_type: "Credit Card",
    items: [
      { item_id: "SKU-001", item_name: "Running Shoes", price: 79.0, quantity: 2 },
    ],
  },
});

Purchase

Fire on the order confirmation page, after payment succeeds.

window.dataLayer.push({
  event: "purchase",
  user_data: {
    email: "alex@example.com",
    phone_number: "+61400000000",
    address: {
      first_name: "Alex",
      last_name: "Smith",
      city: "Sydney",
      region: "NSW",
      postal_code: "2000",
      country: "AU",
    },
  },
  ecommerce: {
    transaction_id: "T-1234",
    currency: "USD",
    value: 158.0,
    coupon: "SUMMER10",
    items: [
      {
        item_id: "SKU-001",
        item_name: "Running Shoes",
        item_variant: "Blue / 10",
        item_category: "Footwear",
        price: 79.0,
        quantity: 2,
      },
    ],
  },
});

Two fields carry more weight here than anywhere else:

  • value must be a number greater than zero. Without it the purchase does not become an order in your dashboard and reports no revenue.
  • transaction_id identifies the order. It is what stops a refreshed confirmation page from counting twice, and it is sent to Meta as order_id.

Always send contact details on purchase. Without them Zappush cannot match the order to a shopper, and the conversion will not attribute in Meta.

Refund

window.dataLayer.push({
  event: "refund",
  ecommerce: {
    transaction_id: "T-1234",
    currency: "USD",
    value: 79.0,
    items: [{ item_id: "SKU-001", quantity: 1 }],
  },
});

Lead events

generate_lead is a GA4 event, so push it to the data layer. schedule and verify_lead are Zappush events with no GA4 name, so GTM will never emit them. Fire those two with zappush.track(), which takes contact fields flat rather than under user_data.

lead_generated and verify_lead are legacy events. They still work exactly as before, but they will be deprecated. Use generate_lead in place of lead_generated in anything new.

Lead captured

Fire when you collect contact details: a form, a quiz result, a lead magnet, an email opt-in.

window.dataLayer.push({
  event: "generate_lead",
  lead_source: "Quiz",
  user_data: {
    email: "alex@example.com",
    phone_number: "+61400000000",
    address: { first_name: "Alex", last_name: "Smith" },
  },
});

Add value and currency if the lead has a known worth. Both or neither.

Appointment booked

Fire schedule when someone books a call or an appointment. It is a stronger signal than a form submit, and it maps to Meta's standard Schedule event.

window.zappush.track("schedule", {
  email: "alex@example.com",
  phone: "+61400000000",
  first_name: "Alex",
  last_name: "Smith",
});

Lead contact fields

Use generate_lead when you want a Lead event to go to Meta. Send the four contact fields and nothing else. The SDK reference lists the format for each.

Do not add the service, treatment, consultation type, offer, or any other description of what the lead asked for. Meta has rules on what a lead event may say about a person, and Zappush filters those fields before sending. Extra fields make that filtering less predictable. Contact fields are all Meta needs to match the lead.

GoHighLevel

GoHighLevel ships no data layer of its own, so Zappush defines one. Install the tracker as a page element first, following Install the tracker, then use the shape below.

These arrive on their own, with no push and no code:

EventWhen it fires
page_viewedEvery page load, and every in-page funnel step change
funnel_step_viewedEach funnel step, carrying the page path and step number
A leadA funnel or survey form is submitted, carrying the contact fields it collected

Everything else you send yourself. Use zappush.track(), or this push:

window.dataLayer.push({
  zappush_event: "checkout_completed",
  zappush_properties: {
    transaction_id: "ORD-9F2A",
    total_price: 149.99,
    currency: "USD",
  },
});
KeyWhat it carries
zappush_eventAny event name from the reference below. Required.
zappush_propertiesFlat metadata, the same fields zappush.track() takes.

The push deliberately has no event key. That is what keeps it from also being read as a GA4 push, so one push can never produce two events. Your existing GA4 and GTM pushes, which do carry event, keep working exactly as documented above.

On a purchase, transaction_id must be the GoHighLevel order id. The same order also reaches Zappush from GoHighLevel directly, and matching ids is what keeps its revenue counted once instead of twice. A purchase sent without one is recorded as a conversion but reports no value, on purpose.

Event name reference

Use either the GA4 name or the Zappush name. Both resolve to the same event.

GA4 eventZappush eventMeta CAPI event
view_itemproduct_viewedViewContent
add_to_cartproduct_added_to_cartAddToCart
remove_from_cartproduct_removed_from_cartcustom
view_cartcart_viewedcustom
begin_checkoutcheckout_startedInitiateCheckout
add_shipping_infocheckout_shipping_info_submittedAddShippingInfo
add_payment_infopayment_info_submittedAddPaymentInfo
purchasecheckout_completedPurchase
add_to_wishlistproduct_added_to_wishlistAddToWishlist
searchsearch_performedSearch
loginuser_logged_incustom
sign_upuser_signed_upCompleteRegistration
view_item_listitem_list_viewedcustom
view_promotionpromotion_viewedcustom
select_promotionpromotion_selectedcustom
select_itemitem_selectedcustom
refundorder_refundedcustom
select_contentcontent_selectedcustom
sharecontent_sharedcustom
view_search_resultssearch_results_viewedcustom

Lead events use the same name in a push and in zappush.track():

EventMeta CAPI event
generate_leadLead
verify_leadLead
scheduleSchedule

Any name not on this list passes through as a custom event under the name you used, and reaches Meta as a custom event. Custom names appear in your dashboard once received, and you can give them a funnel stage on the analytics configure page.

What reaches Meta

On the seven product events (view_item, add_to_cart, add_to_wishlist, begin_checkout, add_shipping_info, add_payment_info, purchase), Zappush sends a fixed set and drops the rest: value, currency, content_ids from your item_ids, num_items from your quantities, content_type, order_id from transaction_id, and coupon.

On every other event, all metadata is forwarded except contact fields, which Zappush forwards separately as Meta's user data.

To confirm a push arrived, open Analytics → Events in the dashboard. Your event shows up within a couple of minutes.

On this page