Hi,
I’ve done something similar in the past using jQCloud. The way I had set up things was with multiple choices multiple answers questions for each category, and base the weight of a word on the number of items selected in its category. I don’t know if it fits your use case but it can be a good starting point.
Here’s an example:


Javascript to add to your results question (configure questionData with your IDs and don’t forget to load jQuery in your header if you’re using the new survey taking experience):
Qualtrics.SurveyEngine.addOnReady(function () {
// Load jQCloud
function loadResource(type, url) {
return new Promise(function (resolve, reject) {
var el;
if (type === "css") {
el = document.createElement("link");
el.rel = "stylesheet";
el.href = url;
} else {
el = document.createElement("script");
el.src = url;
}
el.onload = resolve;
el.onerror = reject;
document.head.appendChild(el);
});
}
Promise.all([
loadResource("css", "https://cdn.jsdelivr.net/npm/jqcloud2@2.0.3/dist/jqcloud.min.css"),
loadResource("js", "https://cdn.jsdelivr.net/npm/jqcloud2@2.0.3/dist/jqcloud.min.js")
])
.then(initCloud)
.catch(function (e) {
console.error("Failed to load jQCloud:", e);
});
function initCloud() {
if (typeof jQuery.fn.jQCloud !== "function") {
console.warn("jQCloud still not defined, retrying");
setTimeout(initCloud, 100);
return;
}
console.log("jQCloud plugin loaded");
// Configuration
var questionData = {
"QID1": "${q://QID1/ChoiceGroup/SelectedChoices}",
"QID3": "${q://QID3/ChoiceGroup/SelectedChoices}"
};
var colors = [
"#007bff", "#28a745", "#ff8800", "#6f42c1",
"#20c997", "#e83e8c", "#17a2b8", "#fd7e14",
"#6610f2", "#dc3545"
];
// Get data
var groups = [];
Object.keys(questionData).forEach(function (qid, idx) {
var raw = questionData[qid];
console.log("Raw data from", qid, ":", raw);
var list = raw ? raw.split(",").map(s => s.trim()).filter(Boolean) : [];
groups.push({
id: qid,
words: list,
count: list.length,
color: colors[idx % colors.length]
});
});
var totalWords = groups.reduce((a, g) => a + g.count, 0);
if (totalWords === 0) {
console.warn("No words selected across questions. Exiting.");
return;
}
// Weights
groups.forEach(g => g.weightRaw = g.count / totalWords);
var rawMin = Math.min(...groups.map(g => g.weightRaw));
var rawMax = Math.max(...groups.map(g => g.weightRaw));
var steps = 10;
function normalize(v) {
if (rawMax === rawMin) return Math.round(steps / 2);
return Math.round(steps - ((v - rawMin) * (steps - 1)) / (rawMax - rawMin));
}
groups.forEach(g => g.weight = normalize(g.weightRaw));
// Font size calculation
var clamped = Math.max(totalWords, 5);
var fFrom = 0.012 + (25 / clamped) * 0.004;
var fTo = fFrom + Math.max(0.02, 0.08 / clamped);
// Prepare words
var words = [];
groups.forEach(function (g) {
g.words.forEach(function (w) {
words.push({
text: w,
weight: g.weight,
html: {
style: "color:" + g.color
}
});
});
});
words.push({
text: "__min",
weight: 1,
html: {
style: "display:none;"
}
});
words.push({
text: "__max",
weight: steps,
html: {
style: "display:none;"
}
});
// Ensure container
if (jQuery("#wordCloudContainer").length === 0) {
jQuery("<div>", {
id: "wordCloudContainer",
css: {
width: "100%",
maxWidth: "600px",
height: "400px",
margin: "1em auto",
position: "relative"
}
}).appendTo("body");
}
// Render word cloud
jQuery("#wordCloudContainer").jQCloud(words, {
width: 600,
height: 400,
steps: steps,
autoResize: true,
removeOverflowing: false,
fontSize: {
from: fFrom,
to: fTo
}
});
console.log("Word cloud rendered.");
}
});
Add the wordcloud div in your results question source code:
Results :<br>
<br>
{q://QID1/ChoiceGroup/SelectedChoices}: ${q://QID1/ChoiceGroup/SelectedChoices}<br>
{q://QID1/SelectedChoicesCount}: ${q://QID1/SelectedChoicesCount}<br>
{q://QID3/ChoiceGroup/SelectedChoices}: ${q://QID3/ChoiceGroup/SelectedChoices}<br>
{q://QID3/SelectedChoicesCount}: ${q://QID3/SelectedChoicesCount}
<div style="width: 600px; height: 400px; position: relative; margin: auto;" id="wordCloudContainer"> </div>
That looks absolutely perfect - I’m going to have quite a few more words that might potentially go into the word cloud (as the parent can select out of over 500 words their child might know) so I may try and randomly choose a few words they know, out of each category.
I will give it a go and see how I get on!
Hi @vgayraud I have a couple more questions, though astonishingly this works almost immediately. Here is my result from my first two categories of words (I have about 15).

I had originally set up a Score for each choice section - as I couldn’t see how to pipe the Count from the question itself, but that seems to be something hidden that I can use without knowing how to use it.
I have worked out why the animal noises are oddly formatted (it’s to do with how the questions were set up, and I’m removing the odd formatting from the questions).
I also accidentally put an extra $ in front of the Animal Names category in the JS so that is where the $ came from.
I would now like to increase the number of categories (this shouldn’t be hard) but also to randomly select just a few words in each category. Here are 5 categories out of the 15. I am not sure why the wordcloud is displaying over the text (I could put the instructions for saving the wordcloud on the previous page, but I’d rather put the title of the wordcloud on the same page: the beginning of the title is cut off in this screenshot, but it was hard to read.)

Also, there are attention checks in the word list and I don’t want those to display. I can remove them from the scoring by adjusting the items that add up to each category score but I don’t want “please select this item” to appear in the word cloud. However, I DO still want it to appear in the list of words in the same format (so I can’t make it be a separate word to tick in a separate question).
Would you be able to suggest any changes that can help me with this?
Hi,
This is untested, but you could try to add 2 configuration variables (under the colors one, say).
var validationChecks = ['validation check 1', 'validation check 2'];
var maxWords = 5;
And modify the line where you define the lists:
var list = raw ? raw.split(",").map(s => s.trim()).filter(s => s && !validationChecks.includes(s)).sort(() => Math.random() - 0.5).slice(0, maxWords) : [];
This would remove any attention check you define before randomly selecting up to maxWords words for each category. Note that the word weights will now be based on the number of randomly selected words, and not on the number of words selected by the respondent.
For your title problem, it’s hard to say without seeing your question html code but I suspect you added it inside the wordCloudContainer. If so, try putting it outside.
I’m afraid my JS skills are so minimal that I’m not sure if I’ve edited the configuration variable section correctly, though it does seem to work!
var questionData = {
"QID50": "${q://QID50/ChoiceGroup/SelectedChoices}",
"QID52": "${q://QID52/ChoiceGroup/SelectedChoices}",
"QID54": "${q://QID54/ChoiceGroup/SelectedChoices}",
"QID56": "${q://QID56/ChoiceGroup/SelectedChoices}",
"QID58": "${q://QID58/ChoiceGroup/SelectedChoices}"
};
var colors = [
"#007bff", "#28a745", "#ff8800", "#6f42c1",
"#20c997", "#e83e8c", "#17a2b8", "#fd7e14",
"#6610f2", "#dc3545"];
var validationChecks = ['select this one to show you are reading', 'please tick this to show you are reading', 'choose this to show you are reading'];
var maxWords = 5;
;
I have changed the list section to
var list = raw ? raw.split(",").map(s => s.trim()).filter(s => s && !validationChecks.includes(s)).sort(() => Math.random() - 0.5).slice(0, maxWords) : [];
groups.push({
id: qid,
words: list,
count: list.length,
color: colors[idx % colors.length]
});
});
It eliminates the attention checks and also does not display too many words in each category. I still haven’t seen what happens when I check words in every category (there are about 15 categories, if it looks too busy I will just make the maximum number of words lower). I also haven’t increased the number of categories higher than the number of colours you have specified, maybe it will implode at that point but I guess I can add more colours!
My layout problem persists but oddly it looks lovely in Mobile view - nice spacing between the title “these are some words your child CHILD’S NAME can say on DATE”, no overlap.
In the desktop view, the previous text (instructions of what to do with the wordcloud) and the title text (these are some words….) are separate questions, because I thought that would help with overlap but it doesn’t. Here’s the HTML for the title text:
Words that ${q://QID1131/ChoiceTextEntryValue} can say on ${date://CurrentDate/PT}
And here’s the HTML for the wordcloud question:
(I just put in a space so it wouldn’t keep telling me to add a question.)
However, I now moved the title for the wordcloud back to the same question and it is looking better EXCEPT that my forward and back arrows are now over the wordcloud, which I suspect is a corporate/style issue so I shall fiddle around with that now.
Thanks so much for your help - this proved to be a lot simpler than I thought, and hopefully my parent-participants will be charmed and delighted with their toddler word clouds!