Loading content dynamically based on the segment a visitor belongs to¶
It is possible to show personalized content to a visitor, based on their segment (let's call this 'segment related content'), purely via front-end code and HTML. For this we need: - content wrapped in HTML with some specific attributes on it - some Javascript to read the visitor's profile data - optionally, some CSS (either inline or externally loaded)
HTML¶
In order to properly target our segment related content, we'll need to wrap it in HTML containing some specific data-attributes and attributes to set the visibility.
data-attributes¶
data-dsdc-visible="true": mark a piece of content as initially hidden. This will remain hidden until validated by the Javascript (see further down).data-dsdc-placeholder="true": (optional) mark a piece of content as a placeholder. Meaning it will be visible from the start of the page loading up until segment related content is made visible. Don't use it if you don't need a placeholder (or set it to "false").data-dsdc-segment="segment-uuid-goes-here": This will determine that the piece of content will be made visible for the targetted segment. Fill in the segment UUID of the segment you want to target and the Javascript will make sure it is displayed to those visitors.
attributes¶
hidden: ensures the browser doesn't render the element, essentially hiding it completely- since this is set directly on the html, it will get picked up faster than
display: noneset via CSS
- since this is set directly on the html, it will get picked up faster than
aria-hidden: explicitly hides content from screen-readers and accessibility tools- this may seem redundant with
hidden(and other ways of hiding content) in place, but we set it in casehidden(or other methods) break due to a site's own CSS or JS or even a 3rd party tool (eg. a text reader) reading the page.
- this may seem redundant with
<!-- Example of a placeholder block: visible until segment specific content is loaded -->
<div class="dynamic-content" data-dsdc-placeholder="true" data-dsdc-visible="true">
This is a generic placeholder. <br />
Laoreet sit amet cursus sit amet dictum sit. Elit duis tristique sollicitudin nibh sit. Congue eu consequat ac felis donec et odio pellentesque diam
</div>
<!-- Example of a block meant for a segment based on UUID -->
<div class="dynamic-content dynamic-content--first-time-visitors" data-dsdc-segment="758da07b-de5a-4b70-8472-85acea9452b3" data-dsdc-visible="false" aria-hidden="true" hidden>
This is some content to be shown to 'First time visitors' segment
</div>
CSS¶
Besides using HTML to hide the dynamic content, as a best practice, we should also set the blocks' display to none. This hides an element from view as well as text readers, so it functions as a fallback in case some external CSS or JS has overwritten the display or or messes with the hidden attribute.
Luckily this is not a must-have, since the Javascript below can also set display. It just executes faster if you can set it yourself using inline CSS or in a stylesheet/style-tag.
Example: using Inline CSS
<div style="display:none;" data-dsdc-visible="false" aria-hidden="true">
Example: using a style tag or in an external stylesheet
[data-dsdc-visible="false"] {
display: none !important;
}
Javascript¶
Now that our content is hidden from view and readers, we need to use Javascript to dynamically toggle their visibility.
Using existing capture methods, we want the script to read the capture data as it comes back from the capture API. This has to happen AFTER an initial capture has been sent out, so the machine learning algorithms on the other end has been able to categorize our visitor and assign them to a segment. So we'll have to use the afterResponse method.
What is also important, is that the Javascript responsible for showing or hiding content, is only executed AFTER the proper HTML has loaded on the page. So we check the response after DOM has loaded by using the dom event trigger.
<script>
// ** initialize the namespace we need to access capture script methods
window.dsdcSettings = window.dsdcSettings || {};
// enable namespace that handles the queue and methods
window.dsdc = window.dsdc || function () { (dsdc.q = dsdc.q || []).push(arguments) }; dsdc.l = +new Date;
// ** Re-enable 'dom' event capture, that is blocked by default
// We want to make use of the DOMloaded event,
// to guarantee the HTML is loaded before trying to toggle the content
window.dsdcSettings.preventCapture = window.dsdcSettings.preventCapture || {};
window.dsdcSettings.preventCapture.dom = false;
// ** We use 'afterResponse' because we need to get to the data that is sent back by the API
// so we can see what Segments exist to match
// -- We also want to make use of the DOMloaded event,
// to guarantee the HTML is loaded before trying to toggle the content
var afterResponseLoadHandler = function(response) {
// This is where our code will go
};
window.dsdc('afterResponse', 'dom', afterResponseLoadHandler);
</script>
Now that the Javascript setup is done, we need to add some scripting to target our content, based on segment UUID.
This goes inside the afterResponseLoadHandler function:
// check for segment related content, based on data-attributes
var elements = document.querySelectorAll('[data-dsdc-visible]');
var placeholders = document.querySelectorAll('[data-dsdc-placeholder]');
// if segment related content is found
if (elements.length > 0 ) {
// get the names of Segments (optional, we can use this as fallback)
var segmentNames = response.responseData.profile.profileSegmentNames;
// more important, get the segment UUIDs active for this project
var segmentsUUIDs = response.responseData.profile.profileSegments;
// a function to match our dynamic content with existing segment UUIDs
function matchSegments(elements, segments) {
// loop our hidden content
Array.prototype.forEach.call(elements, function(el, i){
var visible = el.getAttribute('data-dsdc-visible');
var segmentId = el.getAttribute('data-dsdc-segment');
var hide = true;
// see if their segment UUID matches one from the profile segments
// so we can show that element
// otherwise, hide (or keep hidden)
for (var i in segments) {
if (typeof segments[i] !== 'undefined' && segmentId === segments[i]) {
// mark element as to be shown
hide = false;
}
}
// if there were no segment matches, no need to show the element
if (hide) {
// if visible, set the variables/style to hide the element
if (visible || visible === 'true') {
// in case inline styles are used, turn off display here
el.style.display = 'none';
// set the related (data) attributes
el.setAttribute('data-dsdc-visible', false);
el.setAttribute('aria-hidden', true);
el.setAttribute('hidden', true);
// hide the placeholders, if there are any
Array.prototype.forEach.call(placeholders, function(placeholder, j) {
// in case inline styles are used, turn off display here
el.style.display = 'none';
// set the related (data) attributes
placeholder.setAttribute('data-dsdc-visible', false);
placeholder.setAttribute('aria-hidden', true);
placeholder.setAttribute('hidden', true);
});
}
// if a match was found, need to show the element
} else {
// if not already visible, set the correct attributes & style to reveal the element
if (typeof visible === 'undefined' || !visible || visible === 'false' || visible === null) {
// in case inline styles are used, remove display here
el.style.removeProperty('display');
// reset & remove the related (data) attributes
el.setAttribute('data-dsdc-visible', true);
el.removeAttribute('aria-hidden');
el.removeAttribute('hidden');
}
}
});
}
// ** We can make use of the Segment UUID, to check for matches
// we can also fall back on trying segment names, but that is not recommended
// because names change while UUID's do not
if (segmentsUUIDs.length) {
matchSegments(elements, segmentsUUIDs);
} else {
if (segmentNames.length) {
matchSegments(elements, segmentNames);
}
}
}
Now, with all this in place, your visitors will see the placeholder block, unless they belong to a segment that is linked to a block of content (using the data attribute data-dsdc-segment).
Because a large part of the functionality is done by Javascript, you might get a flash of the placeholder block before the targetted content is made visible.
Note
Note¶
if this is your visitor's first visit to a project where data is being captured, they will not have been assigned to a segment yet. This is to be expected, as our machine learning algorithms needs to process some capture data first, before they can categorize. This is the case regardless if the showing of segment related content happens in the front-end or via the back-end.