Implementing a Custom Data Layer for First-Party and Business Data Collection

Created by Todd Belcher, Modified on Tue, 10 Sep at 5:24 PM by Todd Belcher

When collecting first-party data and/or business data, a custom data layer enables a truly tech-agnostic approach to proprietary data collection. The custom data layer may represent a core component of a data contract between site developers and marketing analysts.

Below is an example that accomplishes the following:


  1. It establishes a proprietary data layer, called "layer1pd". That's the first thing you see in the code. A few variables are added to the data layer immediately, and others will be injected after it is established.

  2. It categorizes pages-- this example is from a WordPress site-- using basic content site page types of home, page, section, and post.

  3. It enables tracking of viewable page sections. Sections may be labeled with an attribute: data-viewable-section-name, and when that section is viewable it is added to a list of sections that were viewable during page engagement.

  4. When blog posts are viewed, post tags are collected in a variable that can be utilized for reporting and personalization.



var layer1pd = {
    url: window.location.href,
    title: document.title,
    timestamp: Date.now(),
    viewableSections: [],
    // pageType and postTerms will be added later
};

function determinePageType() {
    const url = window.location;
    let pageType = 'page'; // Default to 'page'

    if (url.pathname === '/') {
        pageType = url.hash === '' ? 'home' : 'page';
    }

    if (document.querySelector('[data-viewable-section-name="section links"]')) {
        pageType = 'section';
    }

    if (document.querySelector('article')) {
        pageType = 'post';
    }

    return pageType;
}

function updateDataLayerWithViewableSection(sectionName) {
    if (!layer1pd.viewableSections.includes(sectionName)) {
        layer1pd.viewableSections.push(sectionName);
    }
}

function collectTerms() {
    if (layer1pd.pageType === 'post') {
        const termsListElement = document.querySelector('.elementor-post-info__terms-list');
        if (termsListElement) {
            const termsItems = termsListElement.querySelectorAll('.elementor-post-info__terms-list-item');
            const terms = Array.from(termsItems).map(item => item.innerText.trim());
            layer1pd.postTerms = terms;
        }
    }
}

function observeViewableSections() {
    let observer = new IntersectionObserver((entries, observer) => {
        entries.forEach(entry => {
            if (entry.isIntersecting) {
                let sectionName = entry.target.getAttribute('data-viewable-section-name');
                updateDataLayerWithViewableSection(sectionName);
            }
        });
    }, { threshold: 0.1 });

    document.querySelectorAll('[data-viewable-section-name]').forEach(element => {
        observer.observe(element);
    });

    document.querySelectorAll('[data-viewable-section-name]').forEach(element => {
        if (element.getBoundingClientRect().top < window.innerHeight && element.getBoundingClientRect().bottom >= 0) {
            updateDataLayerWithViewableSection(element.getAttribute('data-viewable-section-name'));
        }
    });
}

function initializeLayer1pd() {
    layer1pd.pageType = determinePageType();
    collectTerms();
    observeViewableSections();
}

if (document.readyState === 'complete') {
    initializeLayer1pd();
} else {
    window.addEventListener('DOMContentLoaded', initializeLayer1pd);
}

Was this article helpful?

That’s Great!

Thank you for your feedback

Sorry! We couldn't be helpful

Thank you for your feedback

Let us know how can we improve this article!

Select at least one of the reasons
CAPTCHA verification is required.

Feedback sent

We appreciate your effort and will try to fix the article