Link
Skip to main content

Track IDRViewer page views and events with Google Analytics 4

<!-- Google tag (gtag.js) - Google Analytics 4 -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script>
    (function () {
        window.dataLayer = window.dataLayer || [];

        function gtag() {
            dataLayer.push(arguments);
        }

        gtag('js', new Date());
        gtag('config', 'G-XXXXXXXXXX');

        function trackPageView(page, pagecount) {
            gtag('event', 'idrviewer_page_view', {
                'page_number': page,
                'page_count': pagecount,
                'document_title': document.title
            });
        }

        IDRViewer.on('ready', function (data) { // The page the document opens on
            trackPageView(data.page, data.pagecount);
        });

        var THRESHOLD = 1000; // Time (in millis) a page must stay on screen to count as viewed

        var lastPage;
        IDRViewer.on('pagechange', function (data) { // Every page navigated to afterwards
            lastPage = data.page;
            setTimeout(function () { // Wait until the page stops changing before sending the event
                if (lastPage === data.page) {
                    trackPageView(data.page, data.pagecount);
                }
            }, THRESHOLD);
        });

        var searchTimeout;
        IDRViewer.on('search', function (data) {
            clearTimeout(searchTimeout);
            searchTimeout = setTimeout(function () { // Wait until the user stops typing
                gtag('event', 'idrviewer_search', {
                    'search_term': data.searchTerm,
                    'result_count': data.results.length
                });
            }, 1500);
        });
    })();
</script>
<!-- Google tag ends -->

Applies to output generated in the idrviewer view mode (the default).

Add it before IDRViewer.setup():

Paste the snippet at the end of the generated index.html, immediately before the script that calls IDRViewer.setup(), and replace both G-XXXXXXXXXX placeholders with your GA4 measurement ID (how to find it).

In the Complete, Clean and Simple viewer UIs that call is a line of its own:

<script src="config.js" type="text/javascript"></script>
<script type="text/javascript">IDRViewer.setup();</script>

In SlideShow it sits inside a larger script alongside a mobile check, so paste the snippet above that whole block.

Position matters: IDRViewer.setup() fires ready as it runs and the viewer does not replay events, so a listener added below that line, or above the closing </body> tag, never hears it and the opening page goes uncounted.

Events this records in GA4:

idrviewer_page_view is sent for the opening page (ready) and each page navigated to afterwards (pagechange), and idrviewer_search for each search. idrviewer_search only fires in the Complete viewer UI, the only one with a search box; on Clean, Simple and SlideShow the listener registers without error but never reports anything. Both appear under Reports > Engagement > Events; register the parameters as custom dimensions to break the reports down by page number or search term.

THRESHOLD holds a page for one second before counting it, so flicking through ten pages to reach page eleven records one view rather than eleven. Searches wait 1.5 seconds after the last keystroke, because the Complete UI searches on every keypress and would otherwise report i, in and inv as separate terms.

Pushing the same events to Google Tag Manager:

If GTM already loads on the page, do not add gtag.js as well. Keep your container snippet and add this before the IDRViewer.setup(); line:

<!-- IDRViewer dataLayer events -->
<script>
    window.dataLayer = window.dataLayer || [];

    (function () {
        function pushPageView(page, pagecount) {
            window.dataLayer.push({
                'event': 'idrviewer_page_view',
                'pageNumber': page,
                'pageCount': pagecount,
                'documentTitle': document.title
            });
        }

        IDRViewer.on('ready', function (data) { // The page the document opens on
            pushPageView(data.page, data.pagecount);
        });

        var THRESHOLD = 1000; // Time (in millis) a page must stay on screen to count as viewed

        var lastPage;
        IDRViewer.on('pagechange', function (data) { // Every page navigated to afterwards
            lastPage = data.page;
            setTimeout(function () { // Wait until the page stops changing before pushing the event
                if (lastPage === data.page) {
                    pushPageView(data.page, data.pagecount);
                }
            }, THRESHOLD);
        });

        var searchTimeout;
        IDRViewer.on('search', function (data) {
            clearTimeout(searchTimeout);
            searchTimeout = setTimeout(function () { // Wait until the user stops typing
                window.dataLayer.push({
                    'event': 'idrviewer_search',
                    'searchTerm': data.searchTerm,
                    'resultCount': data.results.length
                });
            }, 1500);
        });
    })();
</script>
<!-- IDRViewer dataLayer events end -->

Then create a Custom Event trigger per event name, data layer variables for the values you pushed, and a GA4 Event tag to forward them to your measurement ID.

Keeping page views from being double counted:

GA4 can already record page views for the document without any code of yours:

  • gtag('config', 'G-XXXXXXXXXX') sends a page_view when the tag loads.
  • The viewer keeps the current page in the address bar (?page=3) and updates it through the History API. Enhanced measurement’s Page changes based on browser history events is enabled by default, so each update can be counted as another page_view.

These all land on the same document, so sending your own page_view per page leaves the metric measuring pages flicked through rather than documents opened. The snippets above use custom event names to keep the two apart. Check Admin > DebugView to see what your property already records.

To report viewer pages as page views instead, change two things inside the snippet above, not in a separate <script> (gtag is scoped to that snippet). Replace the config call with:

gtag('config', 'G-XXXXXXXXXX', {
    'send_page_view': false
});

and send a page_view from trackPageView:

function trackPageView(page, pagecount) {
    gtag('event', 'page_view', {
        'page_location': location.origin + location.pathname + '?page=' + page,
        'page_title': document.title + ' - page ' + page
    });
}

send_page_view only suppresses the hit sent at load. If enhanced measurement is counting the history updates too, turn it off under Admin > Data streams > your stream > Enhanced measurement, otherwise each page is still counted twice.

Tracking zoom, layout and other viewer events:

Any event in the IDRViewer JavaScript API works the same way, such as zoomchange, layoutchange, rotationchange and searchresultselected: attach a listener, read the values from data, and send them with gtag('event', ...) or a data layer push. Only ready has to be registered before IDRViewer.setup() runs.


What's included in your BuildVu trial?

  • Access to download the SDK and run it locally.
  • Access to the cloud trial to convert documents in the IDR cloud.
  • Access to the Docker image to set up your own trial server in the cloud.
  • Communicate with IDR developers to ask questions & get expert advice.
  • Plenty of time to experiment and build a proof of concept.
  • Over 100 articles to help you get started and learn about BuildVu.
  • An exceptional PDF to HTML converter that took over 20 years to build!

Learn more about BuildVu

Start Your Free Trial

Trial License Type