Setup guide and documentation

How to set up the GTM template for B2B websites

Import, configure and test the MILOWSKI.EU B2B GTM TEMPLATE v1.0 container step by step. Below you will also find the full documentation: events, GA4 parameters, Google Ads conversions, tags, triggers and variables.

Version 1.0, October 2026About 14 min readAuthor: Marcin Miłowski

What the template measures

The template adds contact tracking to Google Tag Manager for B2B websites without a shop: email and phone clicks, copied email addresses or phone numbers, and engaged time. Once you import it and enter your GA4 ID, more than 5 GA4 events work straight away. The remaining elements are paused, because they need your decision or an adjustment to your website.

EventWhen it firesParametersStatus after import
CLICK_EMAILclick on a mailto: linklink_textactive
CLICK_TELclick on a tel: or callto: linklink_textactive
COPY_TEL_OR_MAILan email address or phone number copied from the pagelink_text, CONTACT_TYPEactive
MORE_THAN_1_MINUTE60 s of active time in a session (summed across pages, visible tab only), once per sessionnoneactive
generate_leadsuccessful form submissionform_id, form_name, lead_sourcepaused, needs adjustment
Google Ads conversions: CLICK_EMAIL, CLICK_TEL, COPY_TEL_OR_MAILsame as the GA4 events, at most once per page viewnonepaused, need conversion labels
GO_TO_MAPclick on a Google Maps or OpenStreetMap linklink_url, link_textactive

The full email address or phone number never reaches GA4 or Google Ads. Details are in the “Privacy and consent” section.

Requirements before import

For basic tracking you only need a GTM container, a GA4 property and a consent banner with Consent Mode v2. The other requirements apply only to the elements you want to switch on.

RequirementWhat it is forRequired
A correctly installed Web GTM container and permission to publishimporting and publishing the templateyes
A GA4 property and its measurement ID (G-…)receiving the eventsyes
A consent banner (CMP) with Consent Mode v2GDPR-compliant tag firingyes, for EU traffic
A Google Ads account with 3 Website conversion actionsCLICK_EMAIL, CLICK_TEL and COPY_TEL_OR_MAIL conversionsif you run Google Ads campaigns
Forms built with Contact Form 7, or a developerthe generate_lead eventif you want to track forms
A CRM that receives hidden form fieldsfirst and last visit source on each leadoptional
Don’t have the file yet?
The template is free.
Download the template

Import into GTM step by step

Always import with the “Merge” option into a new workspace. The “Overwrite” option deletes everything in the workspace that is not in the file, which means your website’s existing tags.

  1. In GTM, open Admin → Import Container.
  2. Choose the file MILOWSKI.EU_B2B_GTM_TEMPLATE_v1.0_EN.json.
  3. Choose a New workspace, for example “Import B2B template”. You will see the changes before publishing and can discard them in one click if needed.
  4. Choose the Merge import option, then Rename conflicting tags, triggers and variables.
  5. Confirm the import. All elements land in the MILOWSKI.EU B2B GTM TEMPLATE v1.0 folder.
  6. Go to “Configuration after import”. Do not publish the container before running the tests from “Testing before you publish”.

Configuration after import

Two steps are enough for GA4 tracking alone: enter your GA4 ID and decide what to do with the main tag. You only set up the Google Ads elements and contact labels if you need them.

Element in GTMWhat to doWhen
Variable “ENTER YOUR GA4 MEASUREMENT ID HERE”enter the measurement ID that starts with G-always
Tag “GA4 – MAIN TAG – …”you already have a Google tag for GA4 → delete this tag; you don’t → enable italways
Variable “ENTER YOUR GOOGLE ADS CONVERSION ID HERE”enter only the digits from the AW-123456789 IDif you use Google Ads
Tag “Google Ads – MAIN TAG – …”you already have a Google tag with this AW- ID → delete this tag; you don’t → enable itif you use Google Ads
Tags “Google Ads – CLICK_EMAIL”, “- CLICK_TEL”, “- COPY_TEL_OR_MAIL”in the Conversion Label field replace ENTER_YOUR_CONVERSION_LABEL_FROM_GOOGLE_ADS with the label from your account, then enableif you use Google Ads
Tag “Google Ads – Conversion Linker”enable it if the container has no other Conversion Linkerif you use Google Ads
Variable “LT – CONTACT_LABEL”give names to your contacts and delete the 2 example rowsoptional

You will find the measurement ID in GA4 under Admin → Data streams → your stream. Do not enter the GA4 account ID, which consists of digits only, because the events will not reach anywhere.

Google Ads shows the conversion ID and label when you set up the conversion tag and choose Google Tag Manager. In AW-123456789/AbC-D_efG the ID is 123456789 and the label is AbC-D_efG.

In the contact label table, enter email addresses in lowercase ([email protected]) and phone numbers as digits only, including the country code and without + or spaces (442071234567). Polish numbers are the exception: enter them as 9 digits without 48 (600100200). Contacts that are not in the table are sent to GA4 masked.

GA4 events and parameters

Wherever possible, the template uses parameters that are built into GA4, so it does not use up your custom dimension quota. Only 2 parameters need registering: CONTACT_TYPE and lead_source. Do it in GA4 under Admin → Custom definitions → Create custom dimension, scope “Event”.

Event parameterDimension in GA4Example valuesEvents
link_textbuilt-in “Link text”, no registrationOffice, in***(at)company.com, ***789, DirectionsCLICK_EMAIL, CLICK_TEL, COPY_TEL_OR_MAIL, GO_TO_MAP
link_urlbuilt-in “Link URL”, no registration; GA4 also derives “Link domain” from ithttps://maps.app.goo.gl/AbC123GO_TO_MAP
form_idbuilt-in “Form ID”, no registration123generate_lead
form_namebuilt-in “Form name”, no registrationContact formgenerate_lead
CONTACT_TYPEneeds registeringemail, phoneCOPY_TEL_OR_MAIL
lead_sourceneeds registeringwebsite_form (default), quote, demogenerate_lead

For email and phone clicks, link_text holds the label from the “LT – CONTACT_LABEL” table or a mask, not the link text from the page, because that text is often the address itself. For the same reason, the contact tags do not send link_url. CONTACT_TYPE is only sent with COPY_TEL_OR_MAIL, because for clicks the type is already in the event name. You can read the map provider for GO_TO_MAP from “Link domain”. Data appears in reports with a delay of up to 48 hours, and in DebugView immediately.

Mark CLICK_EMAIL, CLICK_TEL and COPY_TEL_OR_MAIL as key events, and generate_lead too once you switch forms on. MORE_THAN_1_MINUTE is meant for segments and audiences, so do not import it into Google Ads as a primary conversion.

Uppercase marks the events and parameters of this template, so you can tell them apart from the names in Google’s documentation. Google’s names, meaning generate_lead, link_url, link_text, form_id, form_name and lead_source, are lowercase. Register CONTACT_TYPE in uppercase, because GA4 is case-sensitive.

Each conversion tag fires at most once per page view. Two clicks on the same email address therefore do not create two conversions, even if Google Ads is set to count “Every”.

  • In Google Ads, create 3 Website conversion actions, one each for CLICK_EMAIL, CLICK_TEL and COPY_TEL_OR_MAIL.
  • Set counting to “One” for each, meaning one conversion per ad click. That is the standard for leads.
  • In B2B, an email or phone contact is a weaker signal than a submitted form or a sale from your CRM. Set these conversions as secondary if you have a better primary conversion. Make them primary only when they are your only signal.
  • Do not count the same action from two sources. If you import GA4 key events with the same names into Google Ads and also enable the template’s tags, only one source can be the primary conversion. Otherwise every conversion is counted twice.
  • Google Ads tags check the ad_storage consent from Consent Mode v2 on their own, so they need no extra consent settings in GTM.

Paused elements: forms and visit source for your CRM

Form tracking and passing the source to your CRM depend on the CMS and CRM of each website. That is why these elements are paused and will not work just by enabling them.

Forms: generate_lead

The “GA4 – generate_lead” tag fires on the formSubmitSuccess event in the dataLayer. The form has to push it after a successful submission, not when someone clicks “Send”, because then submissions with errors would count too.

  • Contact Form 7 (WordPress): enable the “cHTML – listener Contact Form 7” tag together with the generate_lead tag. form_id is the CF7 form ID, form_name is its title.
  • Other forms (Elementor, Gravity Forms, HubSpot, custom): a developer adds this code after a successful submission:
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({ event: 'formSubmitSuccess', formId: 'contact', formName: 'Contact form', leadSource: 'website_form' });
  • Exclude your recruitment form in the “formSubmitSuccess” trigger with a condition on the “DLV – formName” variable, for example does not contain “CV”, “Careers” or “Jobs”. Check your form names in GTM Preview. Without this, job applications inflate your lead count.

First and last visit source for your CRM

The “cHTML – first and last visit source to CRM” tag stores in the visitor’s browser where they came from and writes that data into hidden form fields. You then see the source of every lead in your CRM, and the gclid lets you import offline conversions into Google Ads, such as a signed contract.

Hidden fieldContentExample
FIRST_SOURCE_MEDIUMsource / medium of the first visit within 90 dayslinkedin / paid_social
LAST_SOURCE_MEDIUMthe last source other than directgoogle / organic
LAST_CAMPAIGNutm_campaign of the last sourceautumn_2026
GCLIDthe last Google Ads click IDCj0KCQjw…

The source is determined in this order: UTM parameters, gclid (google / cpc), msclkid (bing / cpc), fbclid (facebook / social), the referring site (search engines as organic, others as referral) and finally (direct) / (none). Navigation within your domain and its subdomains does not change the source. The data expires after 90 days, and you can change that period in the script (VALID_DAYS).

Before you enable it:

  1. Add hidden fields to the form in your CMS, with the names or ids from the table. Names such as form_fields[GCLID] from Elementor work too.
  2. Map those fields in your CRM.
  3. The tag requires analytics_storage and ad_storage consent. Add a second trigger on the consent update event from your CMP. Without it, the source from the first page view is not saved for a visitor who only gives consent on that page.
  4. Add to your privacy policy that the visit source is sent to your CRM together with the form.
Would you rather hand off forms, CRM and the consent banner?
I implement the template from €125 net. On request I add Consent Mode v2, Microsoft Clarity, LinkedIn Insight Tag and Meta Pixel.
See the implementation scope

Privacy and consent

GA4 and Google Ads only receive the contact label or its mask in the link_text parameter, plus the contact type for copies, never the full email address or phone number. Google Analytics policies forbid sending personal data to GA4, and named sales reps’ addresses are personal data.

  • Emails are masked to the first 2 characters and the domain, for example in***(at)company.com. The value sent contains no @ sign.
  • Phone numbers are masked to the last 3 digits, for example ***789.
  • The full value exists only in the browser, in the “DLV – copiedText” and “JS – CONTACT_NORMALIZED” variables. Do not use these variables in any tag that sends data.
TagConsent setting in GTMWhy
GA4 and Google Ads tags, including the main tags and the Conversion LinkerNo additional consent requiredGoogle tags check analytics_storage and ad_storage from Consent Mode v2 on their own
cHTML – contact copy listener, cHTML – listener Contact Form 7No additional consent requiredthey only pass an event to the dataLayer and store or send nothing
cHTML – active time counteranalytics_storagestores the session counter in localStorage
cHTML – first and last visit source to CRManalytics_storage and ad_storagestores visit sources and gclid in localStorage

Without a consent banner with Consent Mode v2, Google tags send data without the user’s consent. For EU traffic that breaks the GDPR and the ePrivacy rules.

Settings outside GTM (in GA4)

Three things that are useful on B2B websites are set up in GA4, not in the container, so the template does not include them.

WhatWhere in GA4Notes
File downloads (PDF, PPTX, DOCX, XLSX, ZIP and others)Admin → Data streams → your stream → Enhanced measurementonly works for links that end with a file extension; event file_download
Site searchEnhanced measurement → Site searchGA4 recognises the q, s, search, query and keyword parameters; WordPress (s) works straight away, in other CMSs check the parameter in the results URL and add it if needed
Excluding your company’s own trafficYour stream → Configure tag settings → Define internal traffic, then Admin → Data filtersonly with a fixed company IP address; test the “Internal traffic” filter in testing mode first, then activate it

Testing before you publish

Before publishing, start GTM Preview, accept consent in the banner and tick off the scenarios below. Check the GA4 events in DebugView at the same time (GA4: Admin → DebugView).

Ticked 0 of 10

When everything checks out, click Submit and publish a version, for example “MILOWSKI.EU B2B GTM TEMPLATE v1.0”.

Common problems

SymptomMost common causeFix
No events reach DebugViewthe GA4 ID variable holds the account ID (digits only) instead of G-…, or no Google tag loads GA4correct the ID; enable the GA4 main tag or check your existing one
Two page_views on every page viewthe template’s GA4 main tag runs alongside another Google tag or pluginkeep a single GA4 implementation
CLICK_EMAIL or CLICK_TEL does not firethe button is not a mailto: or tel: link but a scriptcheck the Click URL variable in Preview; such a button needs its own trigger
COPY_TEL_OR_MAIL does not firemore than 120 characters were selected, the number has neither 9 digits nor a country code with + or 00, or the page blocks copyingcopy just the address or number; check whether the copyContact event appears in Preview
MORE_THAN_1_MINUTE does not fireno analytics_storage consent, or consent was given on the current pagethe counter starts from the next page view after consent
CONTACT_TYPE does not show in reportsthe parameter is not registered as a custom dimension, or less than 48 hours have passedregister the dimension and wait
Google Ads conversions counted twicethe template’s tags and key events imported from GA4 are both primary conversionskeep one source as primary
Duplicate events after updating the templateelements from an older version remain in the containerdelete the old elements before publishing

Container contents

The container holds 16 tags, 6 triggers and 10 variables, all in the MILOWSKI.EU B2B GTM TEMPLATE v1.0 folder. After import, 7 tags are active and 9 are paused.

Tags

TagTypeStatus after importTrigger
GA4 – MAIN TAG – IF YOU ALREADY HAVE A GOOGLE TAG FOR GA4 IN GTM, DELETE THIS ONE. IF NOT, SET YOUR GA4 ID IN THE VARIABLES AND ENABLEGoogle tagpausedAll Pages
Google Ads – MAIN TAG – IF YOU ALREADY HAVE A GOOGLE ADS TAG IN GTM, DELETE THIS ONE. IF NOT, SET YOUR CONVERSION ID IN THE VARIABLES AND ENABLEGoogle tagpausedAll Pages
GA4 – CLICK_EMAILGA4 eventactivemailto click
GA4 – CLICK_TELGA4 eventactivetel click
GA4 – COPY_TEL_OR_MAILGA4 eventactivecopyContact
GA4 – MORE_THAN_1_MINUTEGA4 eventactiveactiveTime60s
GA4 – generate_leadGA4 eventpausedformSubmitSuccess
Google Ads – CLICK_EMAILGoogle Ads conversion, once per page viewpausedmailto click
Google Ads – CLICK_TELGoogle Ads conversion, once per page viewpausedtel click
Google Ads – COPY_TEL_OR_MAILGoogle Ads conversion, once per page viewpausedcopyContact
Google Ads – Conversion LinkerConversion LinkerpausedAll Pages
cHTML – contact copy listenerCustom HTMLactiveAll Pages
cHTML – active time counterCustom HTMLactive, requires analytics_storage consentAll Pages
cHTML – listener Contact Form 7Custom HTMLpausedAll Pages
cHTML – first and last visit source to CRMCustom HTMLpaused, requires analytics_storage and ad_storage consentAll Pages
GA4 – GO_TO_MAPGA4 eventactivemap click

Triggers

TriggerTypeCondition
mailto clickClick – Just LinksClick URL starts with mailto:, case-insensitive
tel clickClick – Just LinksClick URL starts with tel: or callto:
copyContactCustom Eventpushed by the copy listener tag
formSubmitSuccessCustom Eventpushed by the Contact Form 7 listener or the developer’s code
activeTime60sCustom Eventpushed by the active time counter
map clickClick – Just LinksClick URL contains a Google Maps address (google.*/maps, maps.google., maps.app.goo.gl, goo.gl/maps) or OpenStreetMap (openstreetmap.org, osm.org)

Variables

VariableTypeWhat it is for
ENTER YOUR GA4 MEASUREMENT ID HEREConstantGA4 measurement ID for the main tag and all GA4 events
ENTER YOUR GOOGLE ADS CONVERSION ID HEREConstantdigits from AW-… for the main tag and Google Ads conversions
DLV – copiedTextData Layer Variablethe copied contact, browser only
JS – CONTACT_NORMALIZEDCustom JavaScriptthe contact in a uniform format for the label table; do not send
JS – CONTACT_TYPECustom JavaScriptemail or phone for CONTACT_TYPE
JS – CONTACT_MASKEDCustom JavaScriptmask such as in***(at)company.com or ***789
LT – CONTACT_LABELLookup Tablecontact label or mask, sent as link_text
DLV – formIdData Layer Variableform ID for form_id
DLV – formNameData Layer Variableform name for form_name
DLV – leadSourceData Layer Variablelead source for lead_source, website_form by default

The template also enables these built-in variables: Click URL, Click Text, Event, Page URL, Page Hostname, Page Path and Referrer.

Limitations, version history and help

The template covers tracking that works the same way on every website. Anything that depends on your CMS, CRM or third-party tools needs adjusting.

  • Copied phone numbers are recognised as Polish numbers (9 digits) or international numbers written with + or 00. A local number copied without a country code, such as 020 7123 4567, is not recognised.
  • Forms other than Contact Form 7, chats and booking calendars are not tracked without adjustment.
  • The time counter treats a visible tab as activity, even when the user does not move the mouse.
  • Contact buttons that work through JavaScript rather than a mailto: or tel: link need their own trigger.
  • GO_TO_MAP only tracks clicks on a link to a map. GTM cannot see clicks inside a map embedded on the page (iframe).
VersionDateChanges
v1.02 October 2026 (English edition 13 October 2026)first release

MILOWSKI.EU implements the template with form tracking adjusted to your site, visit source passed to your CRM and full testing, from €125 net. See the implementation scope.

Would you rather I did it for you?
Template implementation from €125 net. The complete package also covers Consent Mode v2, Microsoft Clarity, LinkedIn Insight Tag and Meta Pixel.
See scope and prices

Ta strona jest dostępna również po polsku.

Przejdź do wersji polskiej