Zum Inhalt springen
RentwareRentware
Demo

Tracking-Referenz für Entwickler: window.RTR_HOOKS

Zuletzt aktualisiert:

Diese Seite richtet sich an Entwickler und Agenturen, die die Rentware-Buchungswidgets mit ihren eigenen Tags verbinden. Sie beschreibt die Browser-Seite. Serverseitiges Tracking über Rentware (GA4, Google Ads und Meta von unserem Server) braucht keinen Code: siehe Conversion-Tracking: was du wo einrichtest.

Überblick

  • Das Widget sendet im Browser nichts an Tags, solange die Seite window.RTR_HOOKS nicht definiert. Der ältere Name window.RENTWARE_HOOKS funktioniert auch; gibt es beide, gilt RTR_HOOKS.
  • RTR_HOOKS wird bei jedem Ereignis neu gelesen. Es kann also spät gesetzt werden, zum Beispiel von einem GTM-Tag, solange es vor dem Ereignis existiert.
  • Das Widget lädt nie selbst ein Tag. gtag, fbq, umami und oaiq müssen schon auf der Seite sein; fehlt eine Funktion, wird dieser Kanal stillschweigend übersprungen. Nur der dataLayer wird angelegt, wenn er nicht existiert.
  • Das Widget prüft keine Einwilligung für deine Tags. Lade sie erst nach der Einwilligung (Aufgabe deines Cookie-Banners).
  • Alle Werte sind netto: Rabatte abgezogen, Kautionen weggelassen, MwSt. in tax. Beträge sind Zahlen in der Hauptwährungseinheit (49.5), sofern nicht anders angegeben.

Snippet

<script>
  window.RTR_HOOKS = Object.assign(window.RTR_HOOKS || {}, {
    // E-Commerce-Ereignisse im GA4-Format in window.dataLayer (Google Tag Manager; funktioniert auch ohne GTM)
    enableDataLayer: true,

    // gtag('event', …) direkt
    // enableGtagTracking: true,
    // zusätzlich gtag('event', 'conversion', …) beim Kauf
    // gtagAdsSendTo: 'AW-123456789/AbCdEfGhIj',
    // gtag('set', 'user_data', …) für Enhanced Conversions
    // enableGtagUserDataTracking: true,

    // fbq('track', …) auf deinem Meta-Pixel
    // enableMetaTracking: true,
    // zusätzlich fbq('init', id, {…}) mit Kundendaten (erweiterter Abgleich)
    // metaPixelId: '123456789012345',

    // umami.track(…)
    // enableUmamiTracking: true,
    // oaiq('measure', 'order_created', …)
    // enableOpenAiTracking: true,

    // onAddToCart: (data) => {},
    // onInitiateCheckout: (data) => {},
    // onCheckoutSuccess: (data) => {},
  })
</script>

Object.assign behält Schlüssel, die ein anderes Skript schon gesetzt hat.

Alle Optionen

Schlüssel Typ Wirkung
enableDataLayer boolean Schreibt add_to_cart, begin_checkout, add_shipping_info und purchase in window.dataLayer
enableGtagTracking boolean Ruft gtag('event', …) mit denselben vier Ereignissen auf
gtagAdsSendTo string Ruft beim Kauf zusätzlich gtag('event', 'conversion', {…, send_to}) auf, z. B. 'AW-123456789/AbCdEfGhIj'
enableGtagUserDataTracking boolean Ruft beim Speichern der Kundendaten gtag('set', 'user_data', {…}) auf
enableMetaTracking boolean Ruft fbq('track', …) auf: AddToCart, InitiateCheckout, Purchase
metaPixelId string Mit enableMetaTracking: Ruft beim Speichern der Kundendaten fbq('init', metaPixelId, {…}) mit Kundendaten auf
enableUmamiTracking boolean Ruft umami.track(…) auf: add_to_cart, begin_checkout, purchase
enableOpenAiTracking boolean Ruft beim Kauf oaiq('measure', 'order_created', …) auf
onAddToCart function Wird aufgerufen, nachdem ein Artikel hinzugefügt wurde
onInitiateCheckout function Wird aufgerufen, wenn sich der Checkout öffnet
onCheckoutSuccess function Wird aufgerufen, wenn die Buchung abgeschlossen ist

Ereignisse pro Schritt

Schritt dataLayer / gtag Meta-Pixel Umami OpenAI Wird ausgelöst, wenn
In den Warenkorb add_to_cart AddToCart add_to_cart – ein Artikel erfolgreich hinzugefügt wurde
Checkout geöffnet begin_checkout InitiateCheckout begin_checkout – sich der Checkout öffnet
Kundendaten gespeichert add_shipping_info – – – das Kontakt- und Rechnungsformular gespeichert wird
Buchung abgeschlossen purchase Purchase purchase order_created siehe „Wann purchase ausgelöst wird“

Es gibt kein Browser-Ereignis für die Wahl von Standort und Zeitraum, für das Ansehen eines Artikels oder für den Beginn der Zahlung (add_payment_info gibt es nur serverseitig). Es gibt keine DOM-CustomEvents.

Wann purchase ausgelöst wird

purchase wird ausgelöst, wenn die Buchung abgeschlossen ist. Das ist nicht immer der Zeitpunkt der Zahlung:

  • Reservierung, Vorkasse oder Überweisung, Gutschein: direkt nach dem Absenden (noch nicht bezahlt).
  • Kartenzahlung im Checkout: wenn die Zahlung erfolgreich ist.
  • Zahlungen mit Weiterleitung (PayPal, Zahlungsarten, die die Seite verlassen): erst, wenn der Besucher auf eine Seite mit dem Widget zurückkehrt. Kommt er nie zurück, gibt es kein purchase im Browser. Der serverseitige Kauf wird trotzdem gesendet.

dataLayer

Vor jedem Ereignis schreibt das Widget { ecommerce: null } in den dataLayer, um das vorherige E-Commerce-Objekt zu leeren, wie Google es empfiehlt.

// add_to_cart: jeder Artikel, dessen Menge gestiegen ist, automatisch hinzugefügte eingeschlossen
{ event: 'add_to_cart', ecommerce: {
  currency: 'EUR',
  value: 59.5,                      // Σ Preis × Menge
  items: [{ item_id: 'a1b2c3', item_name: 'SUP Board', price: 29.75, quantity: 2, index: 0 }]
} }

// begin_checkout und add_shipping_info: Nettowert des Warenkorbs
{ event: 'begin_checkout', ecommerce: { currency: 'EUR', value: 59.5 } }
{ event: 'add_shipping_info', ecommerce: { currency: 'EUR', value: 59.5 } }

// purchase
{ event: 'purchase', ecommerce: {
  transaction_id: 'SNLDX1',         // Bestellnummer
  currency: 'EUR',
  value: 59.5,                      // netto, Rabatte abgezogen, Kautionen weggelassen
  tax: 11.31,                       // MwSt.
  items: [{ item_id: 'a1b2c3', item_name: 'SUP Board', price: 29.75, quantity: 2 }]
} }
  • price ist der rabattierte Netto-Stückpreis. Kautionspositionen stehen nie in items.
  • transaction_id ist die Bestellnummer (z. B. SNLDX1). Der Server sendet denselben Wert als GA4-transaction_id, Google-Ads-order_id und Meta-order_id.
  • Der dataLayer enthält keine E-Mail, keine Telefonnummer und keine Event-ID.

gtag

Mit enableGtagTracking ruft das Widget gtag('event', name, params) mit denselben ecommerce-Objekten wie im dataLayer auf (die items von purchase tragen zusätzlich index).

Mit gtagAdsSendTo löst der Kauf zusätzlich Folgendes aus:

gtag('event', 'conversion', {
  transaction_id: 'SNLDX1', currency: 'EUR', value: 59.5, tax: 11.31,
  items: [/* wie oben */],
  send_to: 'AW-123456789/AbCdEfGhIj'
})

Mit enableGtagUserDataTracking, beim Speichern der Kundendaten:

gtag('set', 'user_data', {
  email: 'jane@example.com',
  phone_number: '+4915112345678',   // nur wenn gültiges E.164, sonst weggelassen
  address: { first_name: 'Jane', last_name: 'Doe', city: 'Berlin', postal_code: '10115', country: 'DE' }
})

Verwendet wird die Lieferadresse, wenn der Kunde eine eingegeben hat, sonst die Rechnungsadresse.

Meta-Pixel

fbq('track', 'AddToCart', { content_ids: ['a1b2c3'], content_type: 'product', currency: 'EUR', value: '29.75' })

fbq('track', 'InitiateCheckout', { value: '59.50', currency: 'EUR' })

fbq('track', 'Purchase', {
  order_id: 'SNLDX1',
  currency: 'EUR',
  value: '59.50',
  content_ids: ['a1b2c3'],
  content_type: 'product',
  contents: [{ id: 'a1b2c3', quantity: 2, price: '29.75', item_name: 'SUP Board' }],
  num_items: 1                      // Anzahl der Warenkorbzeilen
}, { eventID: 'purchase_SNLDX1' })
  • Beträge für Meta sind Strings mit zwei Nachkommastellen.
  • eventID ist purchase_ + Bestellnummer, dieselbe event_id wie beim serverseitigen Purchase über die Conversions API, damit Meta die beiden dedupliziert.
  • Mit metaPixelId, beim Speichern der Kundendaten: fbq('init', metaPixelId, { em, fn, ln, ct, zp, country }) (Klartextwerte; das Pixel hasht sie).

Umami

Mit enableUmamiTracking und dem Umami-Skript auf der Seite:

umami.track('add_to_cart', { item_id: 'a1b2c3', item_name: 'SUP Board', quantity: 1, currency: 'EUR', value: 29.75 })
umami.track('begin_checkout', { value: 59.5, currency: 'EUR' })
umami.track('purchase', { revenue: 59.5, currency: 'EUR', transaction_id: 'SNLDX1', num_items: 1 })

Nur purchase trägt revenue. Leere Felder werden weggelassen. Umami setzt keine Cookies; ob du eine Einwilligung einholst, entscheidest du.

OpenAI-Ads-Pixel

Mit enableOpenAiTracking und dem OpenAI-Pixel (oaiq) auf der Seite:

oaiq('measure', 'order_created', {
  type: 'contents',
  amount: 5950,                     // kleinste Währungseinheit (Cent), netto
  currency: 'EUR',
  contents: [{ id: 'a1b2c3', name: 'SUP Board', content_type: 'product', quantity: 2 }]
}, { event_id: 'purchase_SNLDX1' })

Du kannst die Option auch weglassen und oaiq in onCheckoutSuccess selbst aufrufen.

Callbacks

Fehler, die in einem Callback geworfen werden, werden abgefangen und in der Konsole ausgegeben, damit sie die Buchung nicht unterbrechen.

onAddToCart({ productId, quantity, currency, name })

productId ist die Artikel-ID, quantity die hinzugefügte Menge.

onInitiateCheckout({ transactionTotal, transactionId })

transactionTotal ist der zu zahlende Betrag (brutto, inklusive Kautionen), nicht der Netto-Warenkorbwert der anderen Ereignisse. transactionId ist die Bestellnummer.

onCheckoutSuccess({ ecommerceData, fbqData, eventID, price })
  • ecommerceData.purchase: das purchase-Objekt aus dem dataLayer (transaction_id, currency, value, tax, items).
  • fbqData: die Purchase-Parameter für Meta (ohne order_id).
  • eventID: purchase_ + Bestellnummer.
  • price: veraltetes Objekt { gross, net, vat } in Cent, inklusive Kautionen. Nutze stattdessen ecommerceData.

Beispiel, ein eigenes Pixel:

window.RTR_HOOKS = Object.assign(window.RTR_HOOKS || {}, {
  onCheckoutSuccess: ({ ecommerceData, eventID }) => {
    const p = ecommerceData.purchase
    myPixel('purchase', { order: p.transaction_id, value: p.value, currency: p.currency, dedup: eventID })
  },
})

Google Tag Manager

  1. Füge das Snippet mit enableDataLayer: true hinzu, entweder direkt in der Seite oder als GTM-Tag vom Typ Benutzerdefiniertes HTML (Custom HTML) mit dem Trigger Initialisierung – Alle Seiten (Initialization – All Pages).
  2. Lege Trigger vom Typ Benutzerdefiniertes Ereignis (Custom Event) für add_to_cart, begin_checkout, add_shipping_info und purchase an.
  3. Lege Variablen vom Typ Datenschichtvariable (Data Layer Variable, Version 2) an, zum Beispiel ecommerce.value, ecommerce.currency, ecommerce.transaction_id, ecommerce.items.
  4. GA4-Ereignis-Tags: Ereignisname {{Event}} oder der feste Name, und „E-Commerce-Daten senden“ mit der Datenquelle „Data Layer“.
  5. Meta-Purchase über GTM: Setze die Event-ID auf purchase_{{DLV - ecommerce.transaction_id}}. Sie passt dann zum serverseitigen Purchase, und Meta dedupliziert die beiden.

Nutzt du für dieselbe GA4-Property auch serverseitiges Tracking über Rentware, sende die dataLayer-Ereignisse nicht zusätzlich dorthin: GA4 dedupliziert nur purchase (anhand der transaction_id), „In den Warenkorb“ und die anderen Funnel-Ereignisse würden also doppelt gezählt.

Einwilligung

Das Widget liest die Einwilligung für das, was es an den Rentware-Server sendet (der entscheidet, was an GA4, Google Ads und Meta geht). Deine eigenen Tags steuert es nicht.

  • Es liest Google Consent Mode v2 aus window.dataLayer: Einträge gtag('consent', 'default' | 'update', {…}) und Objekte im GTM-Stil wie { event: 'consent_update', ad_storage: 'granted', … }. Es spielt sie der Reihe nach ab: Ein späteres update überschreibt frühere Werte.
  • Signale: ad_storage, analytics_storage, ad_user_data, ad_personalization. Jedes steht standardmäßig auf denied.
  • Hat die Seite gar keinen Consent-Mode-Eintrag, wird die Anfrage als „kein Einwilligungssignal“ markiert, und das Tracking-Protokoll zeigt skipped: no consent signal.
  • Regionsspezifische default-Einträge (mit region) lassen sich im Browser nicht dem Standort des Besuchers zuordnen: Nur ihre denied-Werte werden angewendet.
  • Späte Einwilligung funktioniert: Die Einwilligung wird bei jeder Anfrage neu gelesen. Ein Besucher, der zustimmt, nachdem das Widget geladen hat, ist ab der nächsten Anfrage erfasst, solange dein Banner ein Consent-Mode-update in window.dataLayer schreibt.
  • Das Widget liest nur den dataLayer namens dataLayer im selben Fenster. Ein umbenannter dataLayer oder ein Widget in einem iframe bedeutet: kein Einwilligungssignal.

So prüfst du eine Seite: Akzeptiere den Banner, öffne die Konsole und tippe dataLayer. Es muss einen consent-Eintrag (oder ein consent_update-Ereignis) geben, bevor der Besucher bucht.

Klick-IDs

  • Das Widget erfasst gclid, gbraid und wbraid aus der URL (gclid auch aus dem Linker-Parameter _gl von Google oder dem Cookie _gcl_aw) und fbclid aus der URL oder dem Cookie _fbc von Meta. Die URL hat Vorrang vor dem Cookie.
  • Erfasst wird nur mit ad_storage-Einwilligung. Vorher wird nichts aus Cookies gelesen und nichts gespeichert. Kommt die Einwilligung später, während die Klick-ID noch in der URL steht, wird sie dann erfasst.
  • Klick-IDs werden für den Tab im sessionStorage gehalten (gleicher Tab, gleiche Domain, weg, sobald der Tab geschlossen wird). Der erste Klick gilt.
  • Das Widget sendet sie mit seinen Anfragen an den Rentware-Server, der sie für Google Ads und Meta nutzt. Deinen Browser-Ereignissen werden sie nicht hinzugefügt.
  • Landingpage und Buchungsseite sind verschieden? Lass das Widget-Skript auch auf der Landingpage laufen, oder lass dein Google-Tag (mit url_passthrough) oder Meta-Pixel das Cookie _gcl_aw / _fbc schreiben. Für gbraid und wbraid gibt es keinen Cookie-Fallback.

Test-Checkliste

  1. Füge RTR_HOOKS hinzu, öffne die Seite, akzeptiere den Banner.
  2. Lege einen Artikel in den Warenkorb und tippe dann dataLayer in die Konsole: Die letzten Einträge sind { ecommerce: null } und { event: 'add_to_cart', … }.
  3. Schließe eine Buchung mit „Reservieren“ oder Vorkasse ab und prüfe den purchase-Eintrag; seine transaction_id ist die Bestellnummer.
  4. Storniere die Testbuchung danach in Rentware.