Riddle Integration Guide: Embedding a Login Form in an Ad/Iframe Step
This guide explains how to:
- Load a login form in a Riddle ad/iframe block.
- Pass login state data back to Riddle.
- Advance the Riddle step programmatically.
- Log the user in “for real” in the publisher’s system (SSO or custom auth).
It is CMS-agnostic — you can adapt it to WordPress, Drupal, custom PHP, Node.js, Java, etc.
Architecture Overview
When you place a login form inside a Riddle ad/iframe block:
- Inner iframe: The login form (hosted on your site or an SSO endpoint you control).
- Riddle iframe: The quiz container (on
riddle.com). - Top page: The publisher’s page where the Riddle embed lives.
Flow
- The user logs in inside the inner iframe.
- The iframe sends a
postMessageto the top page containing:- Login state (e.g.,
is_logged_in,display_name,email). - Any token/session ID needed to authenticate the user on the publisher’s site.
- Login state (e.g.,
- The top page:
- Pushes login state into
window.riddleDataLayerfor Riddle. - Optionally calls a first-party URL on the publisher’s domain to set real auth cookies.
- Pushes login state into
- The inner iframe also sends an
ad-iframe-completemessage to the Riddle iframe so the quiz advances.
Step 1 — Create the login form page
Host this on your own domain so you control the login flow. This can be in your CMS, app, or a standalone HTML/PHP/Node page.
Key requirements:
- Accept username/password (or SSO flow).
- Authenticate the user.
- Return structured user info (JSON) to the frontend script.
Example login page (simplified, no styling):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<form id="login-form">
<input type="text" name="username" placeholder="Username" required>
<input type="password" name="password" placeholder="Password" required>
<button type="submit">Login</button>
</form>
<script>
const TOP_TARGET_ORIGIN = '*'; // set to publisher site origin in production
const PARENT_TARGET_ORIGIN = '*'; // Riddle iframe origin
document.getElementById('login-form').addEventListener('submit', async function(e) {
e.preventDefault();
const formData = new FormData(e.target);
try {
const res = await fetch('/auth-endpoint', {
method: 'POST',
credentials: 'include',
body: formData
});
const result = await res.json();
if (result.success) {
const payload = {
is_logged_in: '1',
display_name: result.display_name,
email: result.email
};
// Send login info to the TOP page for Riddle
window.top.postMessage({
type: 'riddle-login-sync',
payload: payload,
sso_token: result.sso_token || ''
}, TOP_TARGET_ORIGIN);
// Tell Riddle to advance
window.parent.postMessage({ 'ad-iframe-complete': true }, PARENT_TARGET_ORIGIN);
document.body.innerHTML = '<p>✅ Login successful. Advancing…</p>';
} else {
alert('Login failed: ' + result.message);
}
} catch (err) {
console.error('Login error', err);
}
});
</script>
</body>
</html>
Notes:
- Replace
/auth-endpointwith your actual authentication URL. sso_tokenis optional — only needed if you will log the user into your main site in first-party context.
Step 2 — Top page listener
The publisher’s page where the Riddle is embedded needs a listener to handle the postMessage from the login iframe.
<script>
(function () {
const allowedChildOrigins = ['https://login.example.com']; // origin where the login iframe is hosted
let ssoDone = false;
window.addEventListener('message', function (e) {
if (!allowedChildOrigins.includes(e.origin)) return;
const msg = e.data;
if (!msg || msg.type !== 'riddle-login-sync') return;
// Push payload into Riddle data layer
if (msg.payload && typeof msg.payload === 'object') {
window.riddleDataLayer = window.riddleDataLayer || [];
for (const [key, value] of Object.entries(msg.payload)) {
window.riddleDataLayer.push({ key, value });
}
}
// Optional: complete login on the publisher site via first-party call
if (!ssoDone && msg.sso_token) {
ssoDone = true;
const iframe = document.createElement('iframe');
iframe.style.display = 'none';
iframe.src = '/sso-bridge?token=' + encodeURIComponent(msg.sso_token)
+ '&redirect=' + encodeURIComponent(location.href);
document.body.appendChild(iframe);
}
});
})();
</script>
What happens here:
payloadis pushed intowindow.riddleDataLayer→ Riddle sees the login state.- If
sso_tokenis provided, it is sent to a first-party bridge URL on the publisher’s domain to set the actual session cookies.
Step 3 — Implement the SSO bridge on the publisher site (optional)
If you want the login to persist beyond the Riddle iframe (so the user is logged in across the site), you need a first-party endpoint.
Example in pseudocode (works in any backend language):
route /sso-bridge:
token = get_query_param('token')
if valid_token(token):
user_id = consume_token(token) // mark as used
set_session_cookie_for(user_id)
redirect to get_query_param('redirect') or home
else:
return 403 "Invalid or expired token"
valid_token()should verify the token issued by your/auth-endpoint.consume_token()should prevent reuse.set_session_cookie_for()should use your CMS’s standard login/session mechanism.
Step 4 — Embedding the Riddle with the login step
- In your Riddle quiz, create an ad/iframe block that loads your login page URL.
- After successful login, your login page sends:
riddle-login-syncmessage (top page listener pushes to data layer)ad-iframe-completemessage (Riddle advances to next step)
Important: Both postMessage calls are needed for full functionality.
Step 5 — Security considerations
- Always lock down
postMessageorigins (replace'*'with your real domains). - Only accept messages from iframes you control.
- Make SSO tokens short-lived (1–2 minutes) and single-use.
- Use HTTPS for all communication.
Step 6 — Testing
- Embed your Riddle quiz in a test page on your site.
- Visit the step with the login iframe.
- Log in and check browser console:
- Confirm
riddle-login-syncmessage is sent. - Confirm
window.riddleDataLayernow contains your login data. - Confirm
ad-iframe-completemessage advances the quiz.
- Confirm
- If using SSO bridge:
- Confirm
/sso-bridgeis called (check network tab). - After navigating to another page on your site, confirm you are logged in.
- Confirm
Summary
With this setup:
- The login form inside your Riddle step updates Riddle’s data layer immediately.
- Riddle can adapt the experience based on login state.
- The quiz advances without requiring extra clicks.
- If desired, the login also persists across your site via a secure first-party bridge.
This approach is flexible and works with any CMS or custom site that can:
- Serve a login page inside an iframe.
- Accept
postMessagefrom that iframe. - Optionally handle a short-lived token to set real auth cookies.

