Trustpilot reviews on the 1-day course page
A VWO test for Red Cross First Aid Training that surfaced real customer reviews high on the Emergency First Aid at Work course page, above the main content, filtered to four- and five-star reviews tagged for the course. Add to basket and conversion both rose against control.
I build and QA tests like this for brands and CRO agencies. Start a test brief →
Result
Rolled out to 100% of traffic.
The challenge
Visitors landing on the Emergency First Aid at Work course page were weighing up whether to book, with little on the page to reassure them that the training was trusted by other buyers. The reviews existed, but they were not shown where people were deciding.
Social proof had earned its place elsewhere on the site, so the question was simple: would surfacing strong, course-specific reviews near the top of the page move more people towards booking?
The hypothesis
What we changed
The variation injected a Trustpilot review module high on the course page, above the main content, filtered to strong reviews tagged for this specific course. Everything sat behind VWO's bucketing, scoped so nothing leaked to control.
- Module: Trustpilot carousel (TrustBox), loaded through the official Trustpilot script
- Reviews shown: four- and five-star, course-tagged, English
- Placement: inserted above the main content, near the top of the page
- Width: full width and centred, spaced above and below
- Measurement: GA4, an experimentation event per interaction
- Browsers: modern only, legacy IE and old Edge excluded
How it loads
The test ships as one script. It waits for <body>, switches on GA4, wires up the CTA tracking, makes sure the Trustpilot script is present, then injects the module only once everything it needs is ready.
The module depends on three things that arrive at different times: the content it sits above, the Trustpilot bootstrap script, and the render API. A single poll waits for all three before injecting, so there is no race and no half-rendered widget.
// Inject only once the content, the script, and the API are all ready
poll([
'main .component.rich-text',
function () {
return document.querySelector('[src*="tp.widget.bootstrap.min.js"]');
},
function () {
return window.Trustpilot && typeof window.Trustpilot.loadFromElement === 'function';
},
], injectModule);
Where it lands in the DOM
The insertion point is beforebegin on main .component.rich-text, so the module lands directly above the main content near the top of the page. The rendered markup is a standard TrustBox carousel, configured for this course's tag and locked to four- and five-star reviews. Client identifiers are redacted below.
<div class="trustpilot-module-container">
<div class="wrapper">
<div id="trustbox-carousel" class="trustpilot-widget"
data-locale="en-GB"
data-template-id="53aa8912dec7e10d38f59f36"
data-businessunit-id="•••••••• (client)"
data-style-height="140px" data-style-width="100%"
data-tags="CT-FA1"
data-stars="4,5" data-review-languages="en">
<a href="https://uk.trustpilot.com/review/redcrossfirstaidtraining.co.uk">Trustpilot</a>
</div>
</div>
</div>
var content = document.querySelector('main .component.rich-text');
content.insertAdjacentHTML('beforebegin', moduleHtml); // module lands above the content
window.Trustpilot.loadFromElement(document.getElementById('trustbox-carousel'));
Instrumentation
Every interaction sends a GA4 gtag event named experimentation, tagged with an experiment id and a readable label. Four labels track the journey from first view through to the course-finder CTA.
| Event label | Fires on | Frequency |
|---|---|---|
| Conditions Met | User is bucketed into the experiment | Per load |
| Sees the module | Module at least 20% in the viewport | Once, gated by a body class |
| Scrolls below the module | Module fully scrolled past | Once, gated by a body class |
| Clicks the course-finder CTA | Course finder submitted with a location | Per submit |
// Two scroll observers, each fires once
// Sees module: fires once at 20% visible.
observe(document.querySelector('#trustbox-carousel'), 0.2, function (entry) {
if (entry.isIntersecting && !document.body.classList.contains('trustpilot-module__seen')) {
track('user sees trustpilot module');
document.body.classList.add('trustpilot-module__seen');
}
});
// Scrolled past: fires once when the module is fully above the viewport.
observe(document.querySelector('.trustpilot-module-container'), 1, function (entry) {
if (!entry.isIntersecting && entry.boundingClientRect.top < 0 &&
!document.body.classList.contains('trustpilot-module__below')) {
track('user scrolls below trustpilot module');
document.body.classList.add('trustpilot-module__below');
}
});
// The course-finder CTA only counts a real search
poll(['#form-course-finder'], function () {
var form = document.querySelector('#form-course-finder');
if (!form) return;
form.addEventListener('submit', function (e) {
if (e.target.querySelector('input#location').value) {
track('user clicks the course-finder CTA'); // empty submits are ignored
}
});
});
Scoping and guards
Styling is scoped to the experiment's classes on <html>, so nothing leaks to control. A single regex skips IE and legacy Edge before anything runs, the Trustpilot bootstrap is only added if it is not already present, the injection waits on the readiness gate above, and both scroll events are gated by a body class so they fire exactly once.
/* Scoped to .trustpilot-module, added to <html> for bucketed users. */
.trustpilot-module #trustbox-carousel { width: 100%; }
.trustpilot-module-container { margin: 50px auto 20px; }
@media screen and (max-width: 768px) {
.trustpilot-module-container {
width: 100%; padding: 0 12px; margin: 30px auto auto; box-sizing: border-box;
}
.trustpilot-module-container
[title="Customer reviews powered by Trustpilot"] { height: 320px !important; }
}
The result, and what it means
Add to basket rose 15.08% and conversion 9.08% against control. Course search fell 4.12%, the one metric that moved the other way. One reading is that users needed fewer searches before booking, though the fuller picture sits in the segment analysis.
The decision was to roll out to 100% of traffic on this course page, then extend the same course-tagged module to comparable high-intent course pages, since course-tagged reviews travel well. The course-search dip is worth a closer look using the module view and scroll events, to confirm people are converting sooner rather than skipping a step they still need.