Show Email Reading Time in Salesforce Marketing Cloud
Reading time indicators have become a common UX feature on blogs and news sites, but they can be just as valuable in email marketing. In this article, I’ll show you how to build one for your email campaigns using SSJS in Salesforce Marketing Cloud.
The benefits of adding this simple feature can be useful for:
- Longer newsletters, digests, or editorial content
- Time-sensitive users (think: executives, mobile readers)
- Improving engagement by setting expectations
- Encouraging scroll depth and click-throughs when used near a CTA
It’s a small touch, but it shows respect for your reader’s time — and in marketing, trust and clarity go a long way.
<script runat="server"> Platform.Load("Core", "1"); //trim polyfill if (!String.prototype.trim) { String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ''); }; } //get reading time label var getReadingTimeLabel = function(readingTime, longVariant) { if (readingTime == 0) return longVariant ? "less than a minute read" : "< 1 min"; if (readingTime == 1) return longVariant ? "1 minute read" : "1 min"; return longVariant ? readingTime + " minutes read" : readingTime + " min"; } try{ // Replace with your content block's key var contentBlockKey = "email-body", readingTime = 0, content, plainText, words, wordCount, readingLabel, avgReadingTime = 225 //Average adult reading speed: 200–250 words per minute (wpm) // Load content block content content = Platform.Variable.ContentBlockByKey(contentBlockKey); // Strip HTML tags if content is HTML plainText = content.replace(/<[^>]*>/g, ' '); // Replace multiple spaces/newlines with a single space plainText = plainText.replace(/\s+/g, ' ').trim(); // Split content into words words = plainText.split(" "); wordCount = words.length; readingTime = Math.round(Number(wordCount / avgReadingTime)); readingLabel = getReadingTimeLabel(readingTime, 1); //set value for later use Platform.Variable.SetValue("@readingLabel", readingLabel); }catch(e){ //handle error } </script> %%=v(@readingLabel)=%%
But you might have noticed a potential issue when the content we’re pulling contains personalization — its length can vary depending on the contact. To ensure the reading time is tailored for each individual, we should use TreatAsContent()
to render personalized content before calculating word count.
var personalized = Platform.Function.TreatAsContent(ContentBlockByKey("email-body")); var text = personalized.replace(/<[^>]+>/g, " ").replace(/\s+/g, " "); var wordCount = text.trim().split(" ").length;