Tracking WhatsApp, Call and Map Clicks in GA4: GTM Recipes for Arab Websites
To track WhatsApp clicks in GA4 properly, build your own GTM triggers. Enhanced measurement logs a wa.me tap as a generic outbound click, and Google’s definition (a link to another website) says nothing about tel: links. In our 2 October 2026 check of 29 Arab brand homepages, only 4 of the 16 we could read had a WhatsApp link in their HTML.
Key takeaways
- Of 16 readable Arab homepages, 4 had a WhatsApp link, 5 had tel: links and none linked to Google Maps or Apple Maps.
- Only 1 of 5 WhatsApp links prefilled a message. Only 2 of 11 tel: links used an international number, and both contained a space.
- GA4 has no recommended event for WhatsApp or calls. Send whatsapp_click, phone_click and directions_click from anchored Click URL regex triggers.
- Split every report by device, and reconcile with real chats through a reference token in the prefilled text.
What did we find in the contact links of 29 Arab homepages?
Contact links in the server HTML were thin. On 2 October 2026 we could read the HTML of 16 of the 29 homepages. Of those 16, 4 linked to WhatsApp, 5 had tel: links and none linked to a map app. Only 1 of 5 WhatsApp links prefilled a message, in English on an Arabic page.
| Signal in server-rendered HTML (2 Oct 2026) | Sites | Base |
|---|---|---|
| Homepage returned readable link markup | 16 | 29 homepages |
| WhatsApp link (wa.me, api.whatsapp.com, wa.link) | 4 (25%) | 16 readable |
| tel: link | 5 (31%) | 16 readable |
| Google Maps or Apple Maps link | 0 | 16 readable |
| Store locator or contact page instead of a map link | 5 | 16 readable |
| Page sets format-detection telephone=no | 5 | 16 readable |
The five WhatsApp links used four formats. An Egyptian hospital and a UAE developer used wa.me with digits only, the documented form. A Kuwaiti bank put a plus sign inside the wa.me path. A UAE property portal used api.whatsapp.com/send/ with a 238-character prefilled message carrying a “Ref:” line. The UAE developer’s header used a wa.link shortener, which hides the number. A Qatari telecom’s “available via WhatsApp” link pointed to google.com.
How we checked
The sample comes from the VOCTOS crawl of 2 October 2026 (desktop Chrome, logged out, connection in Cairo, live DOM read within a 4.5-second window). Of 37 homepages tried, 8 (22%) returned a bot challenge or blank page. Later that day we fetched each of the 29 Arabic homepages once, without running JavaScript, and counted distinct WhatsApp, tel:, map, Telegram and mailto: links.
Limits: only server-rendered links are seen, so widgets injected by JavaScript are missed. 11 of 29 returned an error, a timeout or an empty shell, 2 returned text without links, and 4 of the 16 readable pages were cut off before the footer. One page per site, homepage only, no Core Web Vitals field data.
What is wrong with the phone and map links we found?
Most tel: links were written for callers inside the country. Of 11 tel: links on 5 sites, 5 were short hotlines and 4 were Saudi 800 or 920 numbers without +966. Only 2 used an international number, and both contained a literal space. No homepage linked to a maps app; branch details sat behind store locators and contact pages.
One Saudi bank labelled a 920 number for customers calling from abroad, yet the link had no country code. Two Qatari links read tel:+974 44200700. MDN’s anchor element reference writes its tel: examples with a plus sign and country code, such as tel:+49.157.0156. Write yours the same way with no spaces, such as tel:+97444200700, so the link and your tracking variables read one clean string.
Five of the 16 pages set <meta name="format-detection" content="telephone=no">, which Apple’s Safari reference says stops Safari on iOS from turning phone-like text into call links. On a Kuwaiti bank’s homepage the hotline is plain text, so an iPhone visitor cannot tap it and GTM has nothing to count. Keep that tag only if every number is a real tel: link.
Why does a default GA4 setup miscount WhatsApp and call clicks?
Out of the box, GA4 records a wa.me tap as an outbound click, the same event it logs for any link to another website, and Google’s definition does not mention tel: links. Custom events fix the naming, but three things still distort the count: desktop clicks that open nothing, widgets that fire twice, and consent choices that block the tag.
- Enhanced measurement sends an event named click, with link_domain and link_url, when a visitor clicks a link that leads away from the current domain. A WhatsApp lead and a partner link land in one event. Check tel: behaviour in DebugView before relying on it.
- On a desktop, a wa.me link hands off to WhatsApp Web or the desktop app, so a visitor who is not signed in records a tap and starts no chat. For tel:, MDN says: “Cellular devices autodial the number.” Desktops depend on whatever calling app is installed.
- Keep enhanced measurement on and add a custom event, and every tap sends two events. Some widgets fire once on the bubble and again on the link inside it.
- In basic Consent Mode, tags wait for consent, so taps by visitors who decline never arrive. Only 3 of the 20 homepages running a Google tag in our crawl declared a default; our Consent Mode check of the same 29 homepages covers the fix.
Which GTM triggers catch WhatsApp, tel: and map links?
Use three triggers of type Click, Just Links, each firing on Some Link Clicks where Click URL matches a regular expression. Start every pattern with ^, because Google’s own example shows matches RegEx matching anywhere in the string. Make the WhatsApp pattern require a phone number, so share buttons stay out.
// Trigger: Click - Just Links | Some Link Clicks | Click URL matches RegEx
// whatsapp_click (wa.me, api/web.whatsapp.com with phone=, whatsapp://, wa.link)
^(https?://(wa\.me/\+?[0-9]|(api|web)\.whatsapp\.com/send/?\?(.*&)?phone=|wa\.link/)|whatsapp://send/?\?(.*&)?phone=)
// phone_click
^tel:
// directions_click (Google Maps, Apple Maps, Waze)
^https?://((www\.)?google\.[a-z.]+/maps|maps\.google\.[a-z.]+|goo\.gl/maps|maps\.app\.goo\.gl|maps\.apple\.com|(www\.)?waze\.com/ul)
We tested these patterns in Node.js on 2 October 2026 against every contact link we collected, after normalising each URL with the WHATWG URL parser, which lowercases scheme and host as a browser does. Google does not document GTM’s regex engine, so confirm in Preview mode too.
| Link tested | Source | Result |
|---|---|---|
| wa.me/ plus digits (2), wa.me/+ plus digits (1) | Our sample | whatsapp_click |
| api.whatsapp.com/send/?phone=…&text=… | Our sample | whatsapp_click |
| wa.link/ shortener | Our sample | whatsapp_click, number unknown |
| 11 tel: links, including two with spaces | Our sample | phone_click |
| api.whatsapp.com/send?text=… share button | Synthetic | No match |
In Google’s click trigger docs, Wait for Tags holds navigation until tags fire or a timeout passes, which matters only for same-tab links. Check Validation fires only when the click counts as a valid action, so a widget that cancels the default click silences the trigger. Leave it off for contact links.
Want these triggers built and tested in your own container? Set up my WhatsApp and call tracking.
How should you name the GA4 events and parameters?
Use one event per channel, whatsapp_click, phone_click and directions_click, and send the same parameters with each: link_location, page_language, branch and contact_number. GA4 has no recommended event for WhatsApp or calls, so custom names are right. Keep event names within 40 characters and parameter values within 100.
Google’s recommended events include generate_lead and qualify_lead but nothing named contact and nothing for calls. The naming rules require a leading letter, only letters, numbers and underscores, and treat names as case-sensitive. Parameter names cannot begin with an underscore, firebase_, ga_, google_ or gtag.
The collection limits allow 100 characters per parameter value and 25 parameters per event. The property portal’s prefilled link ran to 238 characters, so send a cleaned number, not the raw Click URL.
// Custom JavaScript variable: CJS - link_location
function () {
var el = {{Click Element}};
if (!el || !el.closest) return 'unknown';
var zone = el.closest('[data-track-zone]');
if (zone) return zone.getAttribute('data-track-zone');
if (el.closest('header')) return 'header';
if (el.closest('footer')) return 'footer';
return 'body';
}
// Custom JavaScript variable: CJS - contact_number (digits only)
function () {
var url = {{Click URL}} || '';
try { url = decodeURIComponent(url); } catch (e) {}
var m = url.match(/(?:wa\.me\/|phone=|^tel:)([^?&\/]+)/);
return m ? m[1].replace(/[^0-9]/g, '') : undefined;
}
Register each parameter as an event-scoped custom dimension. Standard properties get 50, and reporting starts after 24 to 48 hours.
How do you track a JavaScript widget without double counting?
Have the widget push a dataLayer event from its own click handler, fire the GA4 tag on a Custom Event trigger, and exclude the widget from your link triggers. Click triggers only see real anchor elements, and many floating widgets open WhatsApp with window.open from a button. One push per open action gives one event per tap.
// Inside the widget's click handler, just before it opens WhatsApp
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'whatsapp_click',
link_location: 'floating_widget',
page_language: /^\/([a-z]{2,3}-)?ar(-[a-z]{2})?(\/|$)/i.test(location.pathname) ? 'ar' : 'en',
branch: widgetConfig.branch || 'all',
contact_number: widgetConfig.number // digits only, e.g. '9665XXXXXXXX'
});
- Create a Custom Event trigger named whatsapp_click and a GA4 event tag that reads the values through Data Layer Variables.
- Add a condition to the WhatsApp link trigger: Click Element does not match CSS selector
.wa-widget, .wa-widget *. - Mark only your custom events as key events. Leave enhanced measurement’s click event unmarked.
- Tap each contact link once in Tag Assistant preview and confirm one GA4 event per tap in DebugView.
Report Total users next to Event count, so three taps by one visitor do not read as three leads.
How do you split Arabic and English pages and multiple branches?
Take page_language from the URL path, not the html lang attribute, and take branch from the link itself. In our crawl, 3 of 27 Arabic homepages declared a wrong or empty lang, so a lang-based split misfiles some Arabic sessions. One RegEx Table row on Page Path covers /ar/, /ar-sa/ and /sa-ar/.
A RegEx Table variable matches the full input and ignores case by default. Set Input to {{Page Path}}, add ^/([a-z]{2,3}-)?ar(-[a-z]{2})?(/.*)?$ with output ar, and default to en. In our test it matched /ar, /ar-sa, /sa-ar, /uae-ar and /ar-AE, and rejected /arabic/ and /web/ar, so prefixed paths need their own row. Our hreflang, lang and dir audit lists the lang errors.
For branches, add data-branch="riyadh-olaya" to each branch page’s contact buttons and read it with a Custom JavaScript variable. If every branch has its own number, a Lookup Table keyed on contact_number works without template changes. Our guide to multi-branch local SEO in Saudi Arabia and the UAE explains why each branch needs its own page and number.
Should WhatsApp and call clicks be key events and Google Ads conversions?
Mark whatsapp_click and phone_click as key events in GA4, but import them into Google Ads as secondary actions until you know how many taps become conversations. A tap shows intent; it is not yet a lead. Google draws the same line for its phone number click conversion, which tracks clicks on the number, not actual calls.
Google renamed GA4 conversions to key events so “conversion” means one thing across Analytics and Ads. To mark one, open Admin, Data display, Events, and click the star; standard properties allow 30. When you import key events into Google Ads, Google sets them to secondary if the account already has goals from an Analytics property.
For ad traffic, calls from website conversions measure real calls through Google forwarding numbers, counting only calls above a minimum length you set. The phone number click action is the same kind of signal as phone_click.
How do you reconcile GA4 clicks with real WhatsApp chats?
Put a short reference token in the prefilled message, such as Ref: web-ar-home, and have the team count the chats that arrive with it. Compare that weekly count with mobile whatsapp_click events for the same pages. Treat the ratio as a floor, because visitors can delete prefilled text before they send.
WhatsApp requires the text parameter to be URL-encoded, so build the link in code:
var number = '9665XXXXXXXX'; // international format, digits only
var greeting = greetings[lang]; // your Arabic or English opening line
var ref = 'Ref: web-' + lang + '-' + pageSlug;
var href = 'https://wa.me/' + number + '?text=' + encodeURIComponent(greeting + '\n' + ref);
Write the greeting in the page’s language; the only prefilled link in our sample sent English from an Arabic page. A short Arabic greeting plus a token came to 176 characters once encoded, another reason to keep full links out of GA4 parameters.
Click-to-WhatsApp ads from Meta never touch your website, so GA4 cannot see them. Meta reports them in Ads Manager, not in GA4. On the WhatsApp Business Platform, the incoming message webhook carries the ad ID and a ctwa_clid, which a CRM can return through Meta’s Conversions API for Business Messaging.
How do you build the GA4 exploration?
Build one free-form exploration with Event name in rows and Device category in columns, filtered to the three contact events, then break it down by page_language and branch. That table shows which pages and branches produce taps, and how many taps came from desktops, where a chat or call is unlikely.
- Register link_location, page_language, branch and contact_number as event-scoped custom dimensions and wait 24 to 48 hours.
- Open Explore and start a Free form exploration.
- Import Event name, Device category, Page path and screen class, page_language, link_location and branch, plus the metrics Event count and Total users.
- Put Event name in Rows, Device category in Columns and both metrics in Values.
- Filter: Event name matches regex
^(whatsapp_click|phone_click|directions_click)$. - Duplicate the tab with branch and page_language in Rows, then again with Page path and screen class.
Read these events next to acquisition data. Our study of how GA4 files AI traffic for Arab sites shows why links shared through WhatsApp often arrive as Direct.
Our read
The click is not the lead. A WhatsApp tap starts a conversation GA4 never sees, so the GA4 number is a top-of-funnel signal. Bid and report on chats you can match to a token or a CRM record, and use whatsapp_click to find the pages and branches that start them.
Ship contact links as real anchors in the server HTML. Eleven of 29 homepages returned nothing usable to a plain fetch, and a link that exists only after JavaScript runs makes Just Links triggers fragile. A plain anchor to wa.me or tel: costs nothing.
Format numbers once: wa.me with digits only, tel: with a plus sign and no spaces, and an international option beside every short hotline. Then the regex, the contact_number variable and your branch lookup all read one string. Not sure where your container stands? Audit my contact tracking from tap to chat.
FAQ
Why does GA4 show our WhatsApp button as an outbound click?
Enhanced measurement sends an event named click whenever a visitor follows a link to another domain, and wa.me is another domain. GA4 does not know it is a lead. Add a GTM trigger on Click URL for WhatsApp links, send a whatsapp_click event, and mark that event, not click, as the key event.
Our WhatsApp button comes from a plugin and GTM does not see the clicks.
Most floating widgets open WhatsApp from a button with JavaScript, so a Just Links trigger has no anchor to catch. Use the widget’s click callback, if it has one, to push a whatsapp_click event to the dataLayer. Then fire your GA4 tag on a Custom Event trigger and exclude the widget from link triggers.
Should we count desktop WhatsApp and call clicks as leads?
No. WhatsApp links start a chat only where WhatsApp is signed in, on a phone, WhatsApp Web or the desktop app, and a tel: link on a desktop depends on whatever calling app is installed. Keep desktop taps as an engagement signal. Report leads from mobile taps, and from chats or calls you can verify.
Why don’t our GA4 WhatsApp clicks match the chats our team receives?
Some taps never become chats: desktop clicks, visitors who change their mind, and double fires from overlapping triggers. Some chats, such as those from click-to-WhatsApp ads, never pass through your site. Add a reference token to the prefilled text, count the chats that arrive with it each week, and compare against mobile whatsapp_click events.
GA4 can count WhatsApp clicks. What matters is whether those clicks match the conversations your team has. If your contact links are real anchors with international numbers, add the triggers, the token and the exploration this week. If they are JavaScript-only or local-only, fix the markup first. Either way, build my GA4 contact events properly, or connect lead tracking to my SEO reporting.
Everything else we have run on Analytics & Measurement
Written by whoever ran the work, not a content team
6 articlesRead also
All Analytics & Measurement
Server-Side Tagging for Arab Websites: Hosting Regions, First-Party Domains and Data Laws

Consent Mode on Arab Websites: What 29 Brand Homepages Actually Run

Tracking ChatGPT Ads Conversions in the Gulf: What OpenAI Measures, What GA4 Sees, and How to Set It Up (2026)

How GA4 Classifies AI Traffic for Arab Websites: What Saudi, UAE and Egyptian Sites Lose (2026 Study)
