Developer guide
Every demo on this site, in one page of code
The building blocks behind all nine demos. Copy them, replace the origins with your own, and check the result with the live inspector on any demo page.
01
Use the script embed. A plain iframe can't receive the data layer or send events to the page.
02
Fill the data layer first. Push your values before embedV2.js loads.
03
Name exact origins. Never post to '*', and check e.origin in every listener.
04
Test both readers. Logged in and guest, with and without an ad blocker.
1 · Embed
The script embed
Copy it from Publish → Embed in the Riddle Creator. The wrapper div tells embedV2.js which Riddle it is; the script resizes the iframe, forwards the data layer and relays events.
- Load embedV2.js once per page, even with several Riddles.
- Auto-scroll is on by default; switch it off with data-auto-scroll="false" if the page has its own layout around the quiz.
<div class="riddle2-wrapper"
data-rid-id="YOUR_RIDDLE_ID"
data-auto-scroll="true"
data-is-fixed-height-enabled="false">
<script src="https://www.riddle.com/embed/build-embedjs/embedV2.js"></script>
<iframe title="Riddle"
src="https://www.riddle.com/embed/a/YOUR_RIDDLE_ID?lazyImages=false&staticHeight=false"
allow="autoplay" referrerpolicy="strict-origin"></iframe>
</div>
2 · Data layer
Hand the Riddle what your page knows
Push key/value pairs into window.riddleDataLayer. Every key you want to use must also be listed under Publish → Data layer in the Riddle; then it is available as a variable in text, in logic conditions and in forms.
- Values are strings: send '1' and '0', not true and false.
- Render values on the server and escape them (esc_js in WordPress).
- Pushes made after the Riddle has loaded are forwarded too; the login demos rely on that.
- Pass the least you need. A first name greets; an email address rarely belongs here.
// before the embed
window.riddleDataLayer = window.riddleDataLayer || [];
window.riddleDataLayer.push(
{ key: 'is_logged_in', value: '1' },
{ key: 'display_name', value: 'Livia' }
);
<?php // WordPress: values from the login ?>
<script>
window.riddleDataLayer = window.riddleDataLayer || [];
window.riddleDataLayer.push(
{ key: 'is_logged_in', value: '<?php echo is_user_logged_in() ? 1 : 0; ?>' },
{ key: 'display_name', value: '<?php echo esc_js( wp_get_current_user()->first_name ); ?>' }
);
</script>
3 · Events
Listen to what readers do
Every script embed posts messages to the page. Tracking events carry isRiddle2Event plus an action; status messages carry a type instead. This is what the live inspector on the demo pages shows.
- action: Block_View, Block_Next, Block_Submit, CoreMetrics …
- name: for CoreMetrics, e.g. View or Start
- blockType, blockTitle, blockId, riddleId: where it happened
- type: status messages such as RiddleInited or HeightChanged
- isRiddleDataLayerEvent: Riddle confirms the data layer it received
window.addEventListener('message', function (e) {
if (e.origin !== 'https://www.riddle.com') return;
var d = e.data;
if (!d || !d.isRiddle2Event || d.type) return; // skip status messages
if (d.action === 'Block_Submit') {
// an answer was given in d.blockTitle
gtag('event', 'riddle_answer', { riddle: d.riddleId });
}
});
4 · Pages inside the Riddle
Login forms, launchers and creatives
An Ad block can frame any page you host instead of an ad slot. That page continues the Riddle with one message, and it can tell the article page what happened with another.
- ad-iframe-complete to https://www.riddle.com moves the Riddle to the next block.
- riddle-login-sync is this site's own name for “a reader signed in”; use any name, but check the origin.
- Hide the Ad block's next button when only your page should continue.
- The framed page must allow https://www.riddle.com as a frame ancestor.
// inside the framed page, when it is done
window.parent.postMessage(
{ 'ad-iframe-complete': true }, 'https://www.riddle.com');
// optional: tell the article page
window.top.postMessage(
{ type: 'riddle-login-sync', payload: { display_name: name } },
'https://your-site.com');
<?php // let Riddle frame this page (WordPress) ?>
add_action( 'template_redirect', function () {
if ( is_page( 'login-in-riddle' ) ) {
header_remove( 'X-Frame-Options' );
header( "Content-Security-Policy: frame-ancestors 'self' https://www.riddle.com" );
}
} );
5 · Ads
Your ad units, inside and around the Riddle
Inside the Riddle, ads come from project ad slots: add your Google Ad Manager ad units once per project, then place them with Ad blocks or the top and bottom banners. Around the Riddle, your page keeps its own GPT setup and reacts to Riddle events.
- Display and video slots both live in the project's ad settings.
- A delayed next button gives an ad a real view without trapping readers.
- Refresh page ads only after reader actions, with a cooldown, and check your Ad Manager agreements.
// an Ad block (Riddle Builder API)
{
"type": "Ad",
"title": "Advertisement",
"projectSlot": { "slotId": 1 },
"isShowNextButtonAfterDelayEnabled": true,
"showNextButtonDelay": 3
}
// refresh a page slot after answers
var last = 0;
window.addEventListener('message', function (e) {
if (e.origin !== 'https://www.riddle.com' || !e.data.isRiddle2Event) return;
if (!/Block_(Next|Submit)/.test(e.data.action) || Date.now() - last < 5000) return;
last = Date.now();
googletag.cmd.push(function () { googletag.pubads().refresh([slot]); });
});
Before you go live
The ten-minute launch checklist.
- Every data layer key you push is listed in the Riddle under Publish → Data layer.
- Values are escaped on the server and contain no more personal data than the Riddle needs.
- Every postMessage names an exact origin; every listener checks e.origin.
- Pages framed by the Riddle send frame-ancestors for https://www.riddle.com and nothing broader.
- Guests and members both reach a result, also with an ad blocker active.
- The consent setup covers the Riddle embed and the ads it loads.
- The Riddle is published again after every change, so the embed shows the latest version.