NO BUG: GTM / Tag Assistant freezing when pushing AJAX search data to Data Layer

Browser: Chrome 110
OS: Windows 11
URL: https://www.axelils.com
Video: Jam

[Please describe this bug in as much detail as possible so we can replicate & debug this bug]

Hello community members,

I am looking for some help with a Google Tag Manager (GTM) implementation for an AJAX-based search feature on my website.

Current Setup & Goal

  • How it works: Users click a search icon in the header to go to the search page. The search is triggered either by clicking the icon or pressing Enter, loading results via AJAX.

  • The Goal: I want to send the search keyword and the results count to Google Analytics via GTM. If a search yields no results, it should still send the keyword with a 0 count.

The Problem

Right now, the tracking is not active. I previously tried a few AI-suggested code snippets to push this data to the dataLayer, but they broke the site. Whenever the data layer push code is active, both Google Tag Manager and Tag Assistant freeze completely.

Because of this freezing issue, the tracking event never fires successfully.

Below are the implementation details and the specific code that causes the crash. Any insights into why this freeze is happening or how to properly structure the AJAX data layer push would be greatly appreciated!

Implementation Details

Bricks Builder layout

Section
 Container
   Block 
     Filter-Search
     Filter- Submit/Reset

  Container (Results Wrapper)
    Block
       Query Results Summary
       Basic Text1   (to display search keyword)
    Code1  ( To populate dynamic search keyword due to live search) 
    Loop Block (Query loop for search)
        Block
           Image
        Block
           Post title
           Basic text2   ( to display author and time )
    Pagination
    Code2     ( Get search keyword)
    Code3     (to ensure search result does not vanish when clicked outside)

Basic Text 1

for

Code 1:

document.addEventListener(“DOMContentLoaded”, function () {
// Find the Bricks Filter-Search input element
const searchInput = document.querySelector(“.brxe-filter-search input, .brxe-filter-search textarea”);

if (!searchInput) return;

function updateSummaryKeyword() {
    // Find all span placeholders on the page
    const targets = document.querySelectorAll(".live-search-keyword");
    targets.forEach(span => {
        span.textContent = searchInput.value;
    });
}
// Update whenever the user types into the input box
searchInput.addEventListener("input", updateSummaryKeyword);

// Run on AJAX query loop complete to catch the text state
document.addEventListener("bricks/query/loop/refresh", function() {
    setTimeout(updateSummaryKeyword, 100); 
});

});

Code 2:

const urlParams = new URLSearchParams(window.location.search);
const searchKeyword = urlParams.get(‘search_term’);
console.log(searchKeyword);

Code 3:

document.addEventListener(‘bricks/ajax/query_result/displayed’, (event) => {
const queryId = event.detail?.queryId

if (!queryId) {
	return
}

const query = window.bricksData?.queryLoopInstances?.[queryId]

if (!query?.isLiveSearch) {
	return
}

const wrapper = document.querySelector(`[data-brx-ls-wrapper="${queryId}"]`)
const searchInput = Object.values(window.bricksData?.filterInstances || {}).find((filter) => {
	return filter.targetQueryId === queryId && filter.filterType === 'search'
})?.filterElement

if (wrapper && searchInput?.value.trim()) {
	wrapper.classList.add('keep-live-search-open')
}

if (wrapper && !searchInput?.value.trim()) {
	wrapper.classList.remove('keep-live-search-open')
}
})

Code in Code 1 which did not work

document.addEventListener(“DOMContentLoaded”, function () {

const searchInput = document.querySelector(“.brxe-filter-search input, .brxe-filter-search textarea”);

const summaryEl = document.querySelector(“.brxe-query-results-summary”);

if (!searchInput) return;

function updateSummaryKeyword() {

document.querySelectorAll(".live-search-keyword").forEach(span => {

  span.textContent = searchInput.value.trim();

});

}

function getResultsCount() {

if (!summaryEl) return 0;



try {

  const stats = summaryEl.getAttribute("data-brx-qr-stats-data");

  if (stats) {

    const parsed = JSON.parse(stats);

    return Number(parsed.total) || 0;

  }

} catch (e) {}



const text = summaryEl.textContent || "";

const match = text.match(/out of\\s+(\\d+)/i);

return match ? parseInt(match\[1\], 10) : 0;

}

let lastPushed = “”;

let pushTimer = null;

function pushSearchEvent() {

const term = searchInput.value.trim();

if (!term || term === lastPushed) return;



const results = getResultsCount();



window.dataLayer = window.dataLayer || \[\];

window.dataLayer.push({

  event: "internal_search",

  search_term: term,

  results_count: results,

  has_results: results > 0

});



lastPushed = term;

}

searchInput.addEventListener(“input”, updateSummaryKeyword);

document.addEventListener(“bricks/query/loop/refresh”, function () {

clearTimeout(pushTimer);

pushTimer = setTimeout(function () {

  updateSummaryKeyword();

  pushSearchEvent();

}, 150);

});

});

Best regards,

D. Mallick

Hey @adminar,

From the details provided, this looks like a custom GTM/dataLayer implementation issue rather than a Bricks bug, that’s why I’m marking it as a no bug.

Maybe you can try to use bricks/ajax/query_result/displayed event instead, but my main guess would be that there is some infinite trigger loop happening, so make sure to double check everything.

Matej

Hi Matej,

I am perfectly fine with marking this issue as “no bug.”

However, for future reference, I would highly appreciate it if we could proactively propose a robust solution for sending search keywords and the hit count to external systems via API. This implementation is quite complex due to the challenges of handling AJAX search triggers, page refreshes, and potential infinite loop risks.

Best regards,

D. Mallick