Sorry for the late response. I was able to handle it by my own with the following approach (assuming you are using Spring). With it, you are able to track page visits and any specific click action performed on your page:
- Create a custom BootstrapListener which will append the needed JavaScript to your Vaadin page:
public class GoogleTagManagerListener implements BootstrapListener {
private final String tagManagerId;
private static final String HEAD = "head";
GoogleTagManagerListener(String tagManagerId) {
this.tagManagerId = tagManagerId;
}
@Override
public void modifyBootstrapFragment(BootstrapFragmentResponse bootstrapFragmentResponse) {
bootstrapFragmentResponse
.getFragmentNodes()
.add(getBodyIFrame());
}
@Override
public void modifyBootstrapPage(BootstrapPageResponse bootstrapPageResponse) {
bootstrapPageResponse
.getDocument()
.getElementsByTag(HEAD)
.get(0)
.appendChild(getDataLayer())
.appendChild(getHeaderScript(bootstrapPageResponse.getDocument()));
}
private Node getHeaderScript(Document document) {
@Language("JavaScript")
String js = "(function (w, d, s, l, i) {\n" +
" w[l]
= w[l]
|| [];\n" +
" w[l]
.push({\n" +
" 'gtm.start':\n" +
" new Date().getTime(), event: 'gtm.js'\n" +
" });\n" +
" var f = d.getElementsByTagName(s)[0]
,\n" +
" j = d.createElement(s), dl = l != 'dataLayer' ? '&l=' + l : '';\n" +
" j.async = true;\n" +
" j.src =\n" +
" 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;\n" +
" f.parentNode.insertBefore(j, f);\n" +
"})(window, document, 'script', 'dataLayer', " + "'" + tagManagerId + "');";
return document.createElement("script")
.append(js);
}
private Node getDataLayer() {
return new Element(Tag.valueOf("script"), "")
.append("var dataLayer = dataLayer || []");
}
private Node getBodyIFrame() {
return new Element(Tag.valueOf("noscript"), "")
.append("<iframe src=\"https://www.googletagmanager.com/ns.html?id=" + tagManagerId + "\"\n" +
" height=\"0\" width=\"0\" style=\"display:none;visibility:hidden\"></iframe>");
}
}
-
Extend from SpringVaadinServlet and override the servletInitialized method in which you add your custom BootstrapListener:
...
@Override
protected void servletInitialized() throws ServletException {
super.servletInitialized();
getService().addSessionInitListener(this::addBootStrapListenerOnSessionInit);
}
private void addBootStrapListenerOnSessionInit(SessionInitEvent sessionInitEvent) {
sessionInitEvent.getSession().addBootstrapListener(new GoogleTagManagerListener(tagManagerId));
}
-
Create the following JavaScriptExtensions to be able to fire the events to Google Tag Manager. I’ve mainly reused the code from the already existing Vaadin Google Analytics Plugin:
public class GoogleTagManagerState extends JavaScriptExtensionState {
public boolean allowAnchor = true;
public String trackerId;
public String pageId = "none";
}
@JavaScript({"vaadin://tag_extension.js"})
public class GoogleTagManager extends AbstractJavaScriptExtension implements ViewChangeListener {
private static final String TRACK_EVENT = "trackEvent";
private static final String TRACK_PAGE_VIEW = "trackPageView";
private static final String SET_PAGE_ID = "setPageId";
/**
* Instantiate new Google Tag Manager by id.
*
* @param trackerId The tracking id from Google Tag Manager. Something like
* 'GTM-123456'.
*/
public GoogleTagManager(String trackerId) {
setTrackerId(trackerId);
}
/**
* Instantiate new Google Tag Manager by id and pageId.
*
* @param trackerId The tracking id from Google Analytics. Something like
* 'GTM-123456'.
* @param pageId The name of the pageId which can be used to push pageView events. Something like 'app/home'
*/
public GoogleTagManager(String trackerId, String pageId) {
this(trackerId);
setPageId(pageId);
}
/**
* Get the page id associated with this tracker.
*
* @return The page id.
*/
public String getPageId() {
return getState().pageId;
}
/**
* Sets the domain name you are tracking
*
* @param pageId The page id.
*/
public void setPageId(String pageId) {
getState().pageId = pageId;
callFunction(SET_PAGE_ID, pageId);
}
@Override
protected GoogleTagManagerState getState() {
return (GoogleTagManagerState) super.getState();
}
/**
* Sets the Google Tag Manager Id.
*
* @param trackerId The tracking id like 'GTM-123456'
*/
public void setTrackerId(String trackerId) {
getState().trackerId = trackerId;
}
/**
* Gets the Google Tag Manager Id.
*
* @return Tracking id like 'GTM-123456'.
*/
public String getTrackerId() {
return getState().trackerId;
}
/**
* This method sets the # sign as the query string delimiter in campaign
* tracking.
* <p>
* https://developers.google.com/analytics/devguides/collection/gajs/methods/
*
* @param allowAnchor Are anchors allowed in URIs. This is the default.
*/
public void setAllowAnchor(boolean allowAnchor) {
getState().allowAnchor = allowAnchor;
}
/**
* This method sets the # sign as the query string delimiter in campaign
* tracking.
* <p>
* https://developers.google.com/analytics/devguides/collection/gajs/methods/
*
* @return true if anchors are allowed in the URIs
*/
public boolean isAllowAnchor() {
return getState().allowAnchor;
}
/**
* Track a single page view. This effectively invokes the 'trackPageview' in
* ga.js file.
*
* @param pageId The page id. Use a scheme like '/topic/page' or
* '/view/action'.
*/
public void trackPageview(String pageId) {
callFunction(TRACK_PAGE_VIEW, pageId);
}
/**
* Track an event. See the Google Tag Manager documentation for more information.
*
* @param eventCategory Typically the object that was interacted with (e.g. 'Video')
* @param eventAction The type of interaction (e.g. 'play')
* @see <a href="https://developers.google.com/tag-manager/devguide#events">Google Tag Manager documentation</a>
*/
public void trackEvent(String eventCategory, String eventAction) {
callFunction(TRACK_EVENT, eventCategory, eventAction);
}
/**
* Track an event. See the Google Tag Manager documentation for more information.
*
* @param eventCategory Typically the object that was interacted with (e.g. 'Video')
* @param eventAction The type of interaction (e.g. 'play')
* @param eventLabel Useful for categorizing events (e.g. 'Fall Campaign'). Optional.
* @param eventValue A numeric value associated with the event (e.g. 42). Optional.
* @see <a href="https://developers.google.com/tag-manager/devguide#events">Google Tag Manager documentation</a>
*/
public void trackEvent(String eventCategory, String eventAction, String eventLabel, int eventValue) {
callFunction(TRACK_EVENT, eventCategory, eventAction, eventLabel, eventValue);
}
/**
* Track an event. See the Google Tag Manager documentation for more information.
*
* @param eventCategory Typically the object that was interacted with (e.g. 'Video')
* @param eventAction The type of interaction (e.g. 'play')
* @param eventLabel Useful for categorizing events (e.g. 'Fall Campaign'). Optional.
* @see <a href="https://developers.google.com/tag-manager/devguide#events">Google Tag Manager documentation</a>
*/
public void trackEvent(String eventCategory, String eventAction, String eventLabel) {
callFunction(TRACK_EVENT, eventCategory, eventAction, eventLabel);
}
/**
* Attach this Tag Manager component to a UI to enable tracking
*
* @param target The UI to track
*/
public void extend(UI target) {
super.extend(target);
}
@Override
public boolean beforeViewChange(ViewChangeEvent event) {
return true;
}
@Override
public void afterViewChange(ViewChangeEvent event) {
trackPageview(event.getViewName());
}
}
- Create an instance of the GoogleTagManager with your custom tagId in your SpringView :
GoogleTagManager gtm = new GoogleTagManager(tagManagerId);
- To track something (e.g select something in a ComboBox, do the following)
....
ComboBox<String> comboBox = new ComboBox<>()
comboBox.addValueChangeListener(this::timeRangeChange);
....
private void timeRangeChange(HasValue.ValueChangeEvent<String> event) {
String value = event.getValue();
gtm.trackEvent("yourEventCategory", "yourEventAction", "yourEventLabel");
}
Additionally to that, you need to put the following JavaScript inside your /webapp/VAADIN folder:
window.com_foo_bar_GoogleTagManager = function () {
this.setPageId = function (pageId) {
dataLayer = [{
pageName: pageId
}]
};
this.trackEvent = function (category, action, label, value) {
console.debug("trackingEvent: {" +
"eventCategory: " + category + ", \n" +
"eventAction: " + action + ", \n" +
"eventLabel: " + label + ", \n" +
"eventValue: " + value + "\n" +
"}");
console.debug("dataLayer: " + dataLayer);
dataLayer.push({
event: 'event',
eventCategory: category,
eventAction: action,
eventLabel: label,
eventValue: value
})
};
this.trackPageView = function (pageId) {
console.debug("trackPageView: " + pageId);
console.debug(dataLayer);
dataLayer.push({
pageName: pageId
})
};
};