SDK
The window.zappush API. Send standard and custom events with the full payload, manage consent, and read shopper identity.
Once a Zappush script is installed it exposes window.zappush. Your own code
calls it to send events, manage consent, and read the current shopper identity.
Use the SDK when you do not have a data layer, when the event has no GA4
equivalent, or when you want contact details to stay out of
window.dataLayer, where every other script on the page can read them.
What is available where
Zappush serves two scripts and they expose different methods. The tracker runs on your store, the gate runs on a compliant page.
| Method | Tracker | Gate |
|---|---|---|
track | Yes | Yes |
setConsent, withdrawConsent | Yes | No |
getIdentity | No | Yes |
redirect | No | Yes |
track is safe to call at any time. The install snippet buffers calls made
before the script loads and replays them once it is ready. Every other method
needs the script loaded first. If you have not installed it yet, follow
Install the tracker.
Payload shape
window.zappush.track(eventName, metadata);Everything goes in one flat object. There is no ecommerce or user_data
wrapper, unlike a data layer push.
window.zappush.track("checkout_started", {
currency: "USD", // conversion value
value: 158.0,
email: "alex@example.com", // who the shopper is
phone: "+61400000000",
items: [ ... ], // which products
});| Group | Keys |
|---|---|
| Value | value, currency, transaction_id, coupon |
| Contact | email, phone, first_name, and the rest below |
| Products | items |
| Anything else | Passed through as event metadata |
value must be a number greater than zero, and currency an ISO 4217 code.
The conversion value Meta receives is the value you send. It is never summed
from item prices, so an event without one reports a conversion worth nothing.
Event names
This is the one place the SDK differs from the data layer. A data layer push
accepts the GA4 name and translates it. track does not translate anything, so
pass the Zappush name. Leads are the exception: a captured lead follows the
GA4 schema, so send generate_lead.
window.zappush.track("checkout_completed", { ... }); // correct
window.zappush.track("purchase", { ... }); // a custom event named "purchase"Calling track("purchase") is not an error and the event will arrive, but it
does not become an order, and it reaches Meta as a custom event rather than the
standard Purchase.
| Zappush event | Meta CAPI event | Fire when |
|---|---|---|
product_viewed | ViewContent | A product page or prominent product modal opens |
product_added_to_cart | AddToCart | A product is added to the cart |
cart_viewed | custom | The cart page or drawer opens |
checkout_started | InitiateCheckout | The shopper reaches the first checkout step |
checkout_shipping_info_submitted | AddShippingInfo | Shipping details are submitted |
payment_info_submitted | AddPaymentInfo | Payment details are submitted |
checkout_completed | Purchase | Payment succeeded |
order_refunded | custom | An order is refunded |
generate_lead | Lead | Contact details are captured |
schedule | Schedule | A call or appointment is booked |
verify_lead | Lead | A captured lead is confirmed or qualified |
search_performed | Search | A search is run |
user_signed_up | CompleteRegistration | An account is created |
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.
The full list, including the GA4 name each one maps from, is in the event name reference.
Contact fields
These decide whether a conversion matches a real person in Meta. Email and phone do most of the work. Send them flat, on every event that has them.
| Field | Also accepted as |
|---|---|
email | |
phone | phone_number |
first_name | firstName |
last_name | lastName |
city | |
state | region |
zip | postal_code, zipcode |
country | country_code |
date_of_birth | dob |
gender | |
external_id | external_customer_id |
All optional, send whatever you have. Phone in E.164 with the country code, country as ISO 3166-1 alpha-2. Zappush persists them for the session, so later events in that session attribute to the same person without resending.
A nested user_data object is also accepted, for when you are porting a data
layer payload, but flat keys are the recommended shape.
Items
| Field | Required | What it does |
|---|---|---|
item_id | Yes | Identifies the product. Sent to Meta as content_ids. |
item_name | No | Product name in your dashboard. Used as the identity if item_id is missing. |
quantity | No | Summed into Meta's num_items. Defaults to 1. |
price | No | Unit price in your dashboard and on order lines. |
item_variant | No | Variant name in your dashboard. |
item_category | No | Product type in your dashboard. |
Ecommerce events
Product viewed
window.zappush.track("product_viewed", {
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.zappush.track("product_added_to_cart", {
currency: "USD",
value: 79.0,
items: [
{ item_id: "SKU-001", item_name: "Running Shoes", price: 79.0, quantity: 1 },
],
});Checkout started
window.zappush.track("checkout_started", {
currency: "USD",
value: 158.0,
coupon: "SUMMER10",
items: [
{ item_id: "SKU-001", item_name: "Running Shoes", price: 79.0, quantity: 2 },
],
});Payment info submitted
window.zappush.track("payment_info_submitted", {
currency: "USD",
value: 158.0,
email: "alex@example.com",
phone: "+61400000000",
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.zappush.track("checkout_completed", {
transaction_id: "T-1234",
currency: "USD",
value: 158.0,
coupon: "SUMMER10",
email: "alex@example.com",
phone: "+61400000000",
first_name: "Alex",
last_name: "Smith",
city: "Sydney",
state: "NSW",
zip: "2000",
country: "AU",
items: [
{
item_id: "SKU-001",
item_name: "Running Shoes",
item_variant: "Blue / 10",
item_category: "Footwear",
price: 79.0,
quantity: 2,
},
],
});valuemust be a number greater than zero. Without it the purchase does not become an order in your dashboard and reports no revenue.transaction_ididentifies the order. It is what stops a refreshed confirmation page from counting twice, and it is sent to Meta asorder_id.- Contact details matter most here. Without them Zappush cannot match the order to a shopper, and the conversion will not attribute in Meta.
Lead events
Lead captured
window.zappush.track("generate_lead", {
lead_source: "Quiz",
email: "alex@example.com",
phone: "+61400000000",
first_name: "Alex",
last_name: "Smith",
});Appointment booked
Fire schedule when someone books a call or an appointment. It is a stronger
signal than a form submit.
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:
| Field | Format |
|---|---|
first_name | The first word of the name the person entered |
last_name | Everything after the first word |
email | As entered. Leave the key out if the form has no email field |
phone | E.164, with + and the country code |
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.
Custom events
Any name that is not a standard event passes through as a custom event. Nothing to register first.
window.zappush.track("quiz_completed", {
quiz_id: "skin-type",
result: "combination",
});Custom events appear in your dashboard once the first one arrives. They start unclassified, so give them a funnel stage on the analytics configure page to make them count in your funnel.
They reach Meta as a custom event under the same name, carrying every key you
sent except items, which is dropped, and contact fields, which Zappush forwards
separately as user data. So quiz_id and result above arrive as custom
properties you can build an audience on.
Attach value and currency if the action is worth something, and the custom
event can be optimized against like any other conversion.
Keep names lowercase with underscores, like quiz_completed, and stay
consistent so the same action always reports under one name. A name is created
the first time it arrives, so a typo becomes a second event you then have to
ignore.
From a third-party tool
If you send events from a script that loads independently of Zappush, a quiz
platform or a booking widget for example, call track from its custom
JavaScript field. Buffered calls are replayed, so there is no readiness check to
write.
window.zappush.track("quiz_completed", { result: "type-a" });From a Kommo web form
Kommo forms post straight to Kommo, so the lead arrives there with nothing tying it to the visit that produced it. When a Kommo form is present on the page, Zappush notices the submission and records it as a lead automatically. There is nothing to add to the page and nothing to configure.
Only successful submissions count. A validation error is not a lead, so it is not recorded as one.
Manage consent
Tracker only, and only on a store with Consent management turned on.
Most consent banners, Cookiebot for example, support Google Consent Mode v2, Google's standard format for passing on a shopper's cookie choices. If yours does, Zappush picks up each shopper's choice on its own and you do not need these methods. Use them only when your banner does not support it. Both take effect immediately.
window.zappush.setConsent({
analytics_storage: "granted",
ad_storage: "granted",
ad_user_data: "granted",
ad_personalization: "granted",
});
window.zappush.withdrawConsent();setConsent takes the four Google Consent Mode v2 choices: analytics_storage,
ad_storage, ad_user_data, and ad_personalization. Set each one to
"granted" or "denied" to match what the shopper agreed to on your banner.
You can pass only the choices that changed, and the others keep their previous
value.
withdrawConsent is the same as calling setConsent with all four set to
"denied". From then on, Zappush follows your After a shopper withdraws
setting on this page and on the shopper's later visits, until they agree again.
Anything recorded before the withdrawal is kept.
Only call setConsent once the shopper has actually agreed. Calling it without
real consent defeats the purpose of the banner.
Read the current identity
Gate only. Returns what Zappush has resolved for the visitor on a compliant page.
const identity = window.zappush.getIdentity();| Field | What it is |
|---|---|
persistent_id | Long-lived ID for this shopper |
session_id | ID for the current session |
route_id | The route this compliant page belongs to |
fbc, fbp, fbclid | Meta click and browser identifiers |
click_ids | Ad click identifiers picked up from the landing page (Google, Microsoft, TikTok, and others) |
consent | Current analytics and marketing grants |
Contact fields, page URL, referrer, and user agent are also on the object. Any
field Zappush has not resolved yet is null.
Trigger a compliant redirect
Gate only. Sends the visitor to your store and carries their identity across, including any ad click identifiers picked up on the landing page. The gate script already wires this to the page's call to action, so most stores never call it. Use it if you build your own button.
window.zappush.redirect("https://your-store.example/products/best-seller");Repeat calls within half a second are ignored, so a double click cannot fire two redirects. If building the identity-carrying URL fails for any reason, the visitor is still sent to the plain destination URL rather than being stranded.