Documentation
Google Tag Manager & Analytics
Track booking conversions in GA4, Google Ads and Meta
Every step of the booking form sends an event to Google Tag Manager (GTM), so you can build GA4 funnels, report Google Ads conversions with the real booking value, and feed Meta or any other platform from one container. Where the events go depends on where the customer books. On your website, the embedded form delivers them to your page and your own GTM handles them; the form loads no tags of its own. On your hosted booking page, the page loads the container you enter in PestBooker. Each booking reports through exactly one of these paths, so the same container can cover both without double-counting.
Requirements
- A Google Tag Manager web container (GTM-XXXXXXX) that you can publish. GA4, Google Ads and Meta are set up as tags inside it.
- That container installed on the page where the booking form is embedded
- A GA4 property and/or a Google Ads account with a conversion action
- Admin access in PestBooker to enter the container ID (only needed for the hosted booking page)
Embedded on your website
Customer books
in the embedded form
Event delivered
to your page's dataLayer
Your GTM fires tags
GA4, Google Ads, Meta…
Conversion recorded
with value + order ID
On your hosted booking page
Customer books
from a link, email or Google
Booking page loads
the GTM ID from Settings
Same events, same GTM
same triggers fire
Conversion recorded
with value + order ID
| Where they book | What records it | What you need |
|---|---|---|
| Embedded form | The GTM container on your page. The form adds no tags of its own. | GTM installed on the page that holds the form |
| Hosted booking page | The GTM container entered in PestBooker | Container ID in Integrations → Google Analytics & Tag Manager |
Install GTM on the Page With the Booking Form
- Events are delivered to the exact page that holds the form. If the form lives on /schedule, GTM must be installed on /schedule, not just on your homepage.
- If your site already runs GTM site-wide, there is nothing to install. Booking events will start appearing in your container automatically.
- The booking form never loads tags inside itself when embedded, so it cannot double-count with your site. Your consent banner settings also apply to booking events, because they run through your container.
- Running GA4 through the gtag.js snippet without GTM? Booking events are Tag Manager events, and gtag.js alone ignores them. Install GTM (recommended) or add the forwarding snippet below to the same page.
<script>
// Forwards PestBooker booking events to GA4 as gtag events.
// Paste after your gtag.js snippet, on the page with the booking form.
window.addEventListener('message', function (e) {
if (e.origin !== 'https://getpestcontrol.services') return;
// Only accept messages from a booking form embedded on this page.
var frames = document.querySelectorAll('iframe[src^="https://getpestcontrol.services/"]');
var fromForm = Array.prototype.some.call(frames, function (f) {
return f.contentWindow === e.source;
});
if (!fromForm) return;
var msg = e.data;
if (!msg || msg.type !== 'getpestcontrol_analytics') return;
var p = msg.payload;
if (!p || typeof p !== 'object' || typeof p.event !== 'string') return;
var params = {};
// Contact details are deliberately left out (no personal data in GA4).
['step_name', 'step_number', 'planType', 'frequency',
'value', 'currency', 'transaction_id'].forEach(function (k) {
if (p[k] !== undefined) params[k] = p[k];
});
gtag('event', p.event, params);
});
</script>Add the Same Container ID to PestBooker
- Go to Dashboard → Integrations → Google Analytics & Tag Manager
- Paste your container ID (GTM-XXXXXXX) and click Save Changes
- Use the same container that runs on your website. One set of triggers and tags then covers every booking, wherever it happens.
- Why this matters even if you only embed: customers who come back through a "finish your booking" email or text, a Google listing, or a referral link book on the hosted page, not your website. Without this ID those bookings never reach your analytics.
- Embedded visits ignore this setting, so adding it never double-counts your website's bookings.
- Use a Tag Manager ID (GTM-…) if you can. A GA4 measurement ID (G-…) also works here, but it reports to GA4 only: no Google Ads or Meta conversions and no enhanced conversions.
Know the Events
registration_started: booking form loadedregistration_step_completed: a funnel step finished (step_name + step_number)registration_completed: booking confirmed. This is your conversion.- registration_completed fires only once the appointment actually exists. If you require a signed service agreement before booking, it waits until the customer signs.
- Bookings that start from a Google listing choose their plan first, so their step 3 arrives before steps 1 and 2. Build funnels on step_name rather than assuming the order.
- registration_completed carries value (the initial service price), currency (USD) and transaction_id (the order ID). On the Checkout design it also carries planType (plan name) and frequency (treatments per year).
- Use registration_completed as your one and only conversion. Step events are for funnels: billing_setup fires when the customer reaches payment on the Checkout design, before they have paid. checkout_booked fires at the same moment as registration_completed, so counting both doubles every sale.
- Contact details: once the customer has entered them, events also include email, phone_number (10 digits, US), first_name and last_name. They are there for Google Ads enhanced conversions and Meta advanced matching, and are always filled on registration_completed (step events before the contact step carry them empty). Never add them to GA4 tags, because Google prohibits personal data in GA4.
- Street address and payment details are never included in any event
| step_name | step_number | What happened |
|---|---|---|
| address_selection | 1 | Customer entered their address |
| customer_creation | 2 | Contact details submitted (a lead now exists) |
| appointment_scheduling | 3 | Plan step done (Checkout design: plan chosen / Classic design: time picked) |
| billing_setup | 4 | Reached payment (Checkout design) / paid (Classic design, same moment as registration_completed) |
| out_of_service_lead | 0 | Address outside your service area; contact saved as a lead |
| address_incomplete | 0 | Address was missing details and could not be priced |
| lead_created_no_api_keys | 0 | Online booking not connected yet; contact saved as a lead |
| Event | What happened |
|---|---|
| abandoned_cart_resumed | Customer came back to finish a booking from an email or text link |
| magic_link_accessed / _success / _expired / _error / _already_converted | A "finish your booking" link was opened, and how that went (hosted page) |
| referral_landing_view / referral_landing_cta_click | Customer-referral landing page viewed / clicked through (hosted page) |
| checkout_lead_captured / checkout_booked | Checkout-design twins of customer_creation / registration_completed. Do not count them as well. |
| checkout_sign_gate_shown / _signed, classic_sign_gate_shown / _signed | Service agreement shown / signed before the booking is confirmed |
| checkout_chat_opened / _message / _escalated | Booking assistant chat used |
| checkout_resumed_from_link | Checkout-design booking reopened from a saved link (alongside the magic_link events) |
| checkout_existing_customer_link | Existing customer sent to the customer portal instead |
| checkout_start_over | Customer cleared the form and started again |
| checkout_sign_prompt_clicked | Customer opened the service agreement from the confirmation |
{
event: 'registration_completed',
event_category: 'registration_form',
value: 149,
currency: 'USD',
transaction_id: '284715',
planType: 'Quarterly', // Checkout design
frequency: 4, // Checkout design
email: 'jane@example.com', // for ad matching only
phone_number: '5555550123',
first_name: 'Jane',
last_name: 'Doe'
}Create Triggers and Variables in GTM
- Triggers → New → Custom Event. Create one for registration_completed (your conversion) and one for registration_step_completed (your funnel). Add registration_started if you want funnel entry.
- Variables → New → Data Layer Variable. Create one each for value, currency, transaction_id, step_name and step_number, named like "DLV - value". Add planType and frequency if you use the Checkout design.
- For Google Ads enhanced conversions or Meta advanced matching, also create email, phone_number, first_name and last_name
- phone_number arrives as 10 US digits. Google expects +1 in front, so use the Custom JavaScript variable below for the phone field.
function () {
var p = {{DLV - phone_number}};
if (!p) return undefined;
var digits = String(p).replace(/\D/g, '').slice(-10);
return digits.length === 10 ? '+1' + digits : undefined;
}Send Events to GA4
- Make sure a Google tag with your GA4 measurement ID (G-XXXXXXXXXX) fires on all pages of your site
- Add a GA4 Event tag for the funnel: event name registration_step_completed, parameters step_name and step_number, triggered by the step trigger
- Add a GA4 Event tag for the sale, triggered by registration_completed. Name the event purchase so revenue shows in GA4's monetization reports, and add the parameters value, currency and transaction_id. GA4 uses transaction_id to ignore repeat sends of the same order.
- Do not add email, phone_number, first_name or last_name to any GA4 tag
- In GA4, go to Admin → Data display → Key events and mark purchase (or your chosen event name) as a key event
- Use Explore → Funnel exploration with step_number to see exactly where visitors drop off
Track Google Ads Conversions
- In Google Ads: Goals → Conversions → New conversion action → Website, set up manually with Google Tag Manager
- Category: Purchase. Value: "Use different values for each conversion". Count: Every.
- In GTM, add a Conversion Linker tag on All Pages if you do not already have one. It keeps the ad click attached to the visitor.
- Add a Google Ads Conversion Tracking tag with your Conversion ID and Label. Set Conversion Value to {{DLV - value}}, Transaction ID to {{DLV - transaction_id}} and Currency Code to {{DLV - currency}}, and trigger it on registration_completed.
- Enhanced conversions (recommended): in the same tag, turn on "Include user-provided data from your website", choose Manual configuration, and map email, the E.164 phone variable, first_name and last_name. Then accept the enhanced-conversions terms in Google Ads.
- Google Ads optimizes on the real booking value, so ROAS bidding works out of the box
Add Meta and Other Platforms (Optional)
- Meta Pixel: fire a Purchase event on registration_completed with value and currency, and use transaction_id as the event ID so Pixel and Conversions API events dedupe
- Fire a Lead event on registration_step_completed where step_name equals customer_creation to optimize for leads as well as sales
- With advanced matching on, pass email, phone and name from the variables above
- Any other platform (Microsoft Ads, LinkedIn, TikTok, a CRM) works the same way: trigger on registration_completed and read value and transaction_id
Verify Before You Go Live
- Open GTM Preview (Tag Assistant) on the page with the embedded form. Booking events appear in the event list on the left as the form is used.
- registration_started and the first two steps can be checked without booking. Just enter an address and contact details.
- Seeing registration_completed takes a real booking. Coordinate with the pest control company first so they can cancel it afterwards.
- Quick check without Preview: run this in the browser console on the host page.
dataLayer.filter(e => /^(registration|checkout)_/.test(e.event))- Check the hosted page too: in Tag Assistant, connect to your booking page URL (getpestcontrol.services/your-slug)
- In GA4, watch Admin → DebugView while Preview is connected. In Google Ads, a new conversion action can take a few hours to show a status.
Pro Tips
- • Make registration_completed your only conversion. Step events, billing_setup and checkout_booked will double-count sales if you count them too.
- • UTM tags and ad click IDs (gclid, gbraid, wbraid, fbclid, msclkid) on the URL of the page with the booking form are saved with each lead, and remembered for 30 days across pages that have the form, so a visitor who leaves and comes back later still credits the ad. If your ads land on a page without the form, make sure links into the booking page carry the UTM tags; the matching Google Ads or Meta click ID is then recovered automatically.
- • PestBooker records campaign attribution on its own, independent of your GTM setup. On Pro plans it shows on Dashboard → Analytics, which makes a good cross-check against your ad platforms.
- • The embedded form doesn't change your page's URL or send page views of its own. Use the step events, not page views, to build your funnel.
- • Recommended: add getpestcontrol.services to GA4 → Admin → Data streams → Configure tag settings → Configure your domains, so a visitor who clicks from your site to the hosted booking page stays one session
Need help with setup?
Email us and we'll walk you through any integration or setup process.
Contact Sales