Riddle Integration Guide: Embedding a Login Form in an Ad/Iframe Step

This guide explains how to:

  1. Load a login form in a Riddle ad/iframe block.
  2. Pass login state data back to Riddle.
  3. Advance the Riddle step programmatically.
  4. 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

  1. The user logs in inside the inner iframe.
  2. The iframe sends a postMessage to 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.
  3. The top page:
    • Pushes login state into window.riddleDataLayer for Riddle.
    • Optionally calls a first-party URL on the publisher’s domain to set real auth cookies.
  4. The inner iframe also sends an ad-iframe-complete message 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-endpoint with your actual authentication URL.
  • sso_token is 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:

  • payload is pushed into window.riddleDataLayer → Riddle sees the login state.
  • If sso_token is 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-sync message (top page listener pushes to data layer)
    • ad-iframe-complete message (Riddle advances to next step)

Important: Both postMessage calls are needed for full functionality.


Step 5 — Security considerations

  • Always lock down postMessage origins (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

  1. Embed your Riddle quiz in a test page on your site.
  2. Visit the step with the login iframe.
  3. Log in and check browser console:
    • Confirm riddle-login-sync message is sent.
    • Confirm window.riddleDataLayer now contains your login data.
    • Confirm ad-iframe-complete message advances the quiz.
  4. If using SSO bridge:
    • Confirm /sso-bridge is called (check network tab).
    • After navigating to another page on your site, confirm you are logged in.

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 postMessage from that iframe.
  • Optionally handle a short-lived token to set real auth cookies.