Embed SDK

Embed SDK

The Embed SDK lets publishers embed a RewardedMedia video wall directly on their own pages via a lightweight JavaScript snippet. The video wall loads in a secure iframe — no CSS or JS conflicts with your page.

Setup

  1. In your promotion settings, go to the Embed SDK tab and add each origin (e.g. https://yoursite.com) that is allowed to embed the promotion.
  2. Copy the embed code snippet from the same tab into your publisher page.
  3. Implement a signing URL endpoint on your server (see below), or pass static mid/ts/sig params.

Quick Start (with Signing URL)

The recommended approach is to provide a signingUrl — a URL on your server that returns fresh signing parameters. The SDK calls this endpoint automatically on load and whenever reload() is called, so you never hardcode credentials in your frontend.

<div id="rewarded-container"></div>
<script src="https://rewardedmedia.com/js/rewarded-sdk.js"></script>
<script>
  var rm = new RewardedMedia({
    slug: 'your-promotion-slug',
    container: '#rewarded-container',
    signingUrl: '/api/rewarded-sign',  // your endpoint
    hideCompletionModal: true,         // you control the completion UX
    onReady: function() {
      console.log('Video wall is ready');
    },
    onComplete: function(data) {
      console.log('Earned:', data.points_earned, 'Member:', data.member_id);
      // Show your own success UI, credit the user, etc.

      // Optionally start a new activity:
      // rm.reload();
    },
    onError: function(err) {
      console.error('SDK error:', err.message);
    }
  });
</script>

Quick Start (with Static Params)

If you prefer to generate signing params server-side and inject them into the page template, you can pass them directly:

<div id="rewarded-container"></div>
<script src="https://rewardedmedia.com/js/rewarded-sdk.js"></script>
<script>
  var rm = new RewardedMedia({
    slug: 'your-promotion-slug',
    container: '#rewarded-container',
    mid: 'USER_123',         // server-rendered
    ts: '1709500000',        // server-rendered
    sig: 'hmac_signature',   // server-rendered
    onComplete: function(data) {
      console.log('Earned:', data.points_earned);
    }
  });
</script>

Constructor Options

Option Type Required Description
slug string Yes Your promotion's URL slug
container string | Element Yes CSS selector or DOM element to render the iframe in
signingUrl string No* URL on your server that returns { mid, ts, sig } as JSON. Called on init and on every reload(). * Either signingUrl or static mid/ts/sig should be provided.
mid string No* Member ID — your user's unique identifier (static alternative to signingUrl)
ts string No* Unix timestamp in seconds (static alternative to signingUrl)
sig string No* HMAC signature (static alternative to signingUrl)
hideCompletionModal boolean No When true, suppresses the built-in congrats modal after completion. The onComplete callback still fires so you can show your own UI. Default: false
onReady function No Called when the video wall has initialized. Receives { slug }
onComplete function No Called when the user completes the promotion. Receives { points_earned, member_id, slug }
onResize function No Called when the iframe content height changes. Receives { height }
onError function No Called if the signing URL request fails. Receives { error, message }

Methods

Method Description
reload() Start a new activity. If signingUrl is configured, fetches fresh signing params first. Otherwise reloads with the original static params. Useful for letting the user do another round after completion.
destroy() Remove the iframe and clean up event listeners

Signing URL Endpoint

When you provide a signingUrl, the SDK makes a GET request to that URL (with cookies/credentials for same-origin) and expects a JSON response:

{
  "mid": "USER_123",
  "ts": "1709500000",
  "sig": "a1b2c3d4e5f6..."
}

Your endpoint authenticates the current user, generates a fresh timestamp, and computes the HMAC signature — the same three steps as the redirect flow. The full per-language signing code lives on Signing The Request; an endpoint just wraps that output as a JSON response. The SDK calls your endpoint once on init and again on every reload().

Implementation outline

  1. Authenticate the request (session, JWT, etc.) — return 401 if missing.
  2. Compute mid, ts, sig per Gather inputs + Sign the request.
  3. Return them as the JSON above ({ mid, ts, sig }) instead of redirecting.

Minimal endpoint shapes

For reference — the auth + JSON wrapper around the canonical signing logic:

app.get('/api/rewarded-sign', (req, res) => {
  if (!req.user) return res.status(401).json({ error: 'unauthorized' });

  // Compute mid, ts, sig per /docs/signing.
  const { mid, ts, sig } = computeRewardedSig(req.user.id);

  res.json({ mid, ts, sig });
});
<?php
session_start();
if (!($user_id = $_SESSION['user_id'] ?? null)) {
    http_response_code(401);
    echo json_encode(['error' => 'unauthorized']);
    exit;
}

// Compute mid, ts, sig per /docs/signing.
[$mid, $ts, $sig] = compute_rewarded_sig($user_id);

header('Content-Type: application/json');
echo json_encode(['mid' => $mid, 'ts' => $ts, 'sig' => $sig]);
@app.route('/api/rewarded-sign')
def rewarded_sign():
    user_id = session.get('user_id') or abort(401)

    # Compute mid, ts, sig per /docs/signing.
    mid, ts, sig = compute_rewarded_sig(user_id)

    return jsonify(mid=mid, ts=ts, sig=sig)
class Api::RewardedController < ApplicationController
  before_action :authenticate_user!

  def sign
    # Compute mid, ts, sig per /docs/signing.
    mid, ts, sig = RewardedSigner.call(current_user.id)

    render json: { mid:, ts:, sig: }
  end
end

Full Integration Example

This example shows a typical publisher integration: the signing URL provides credentials, the completion modal is hidden so the publisher controls the UX, and reload() lets the user do another round.

<div id="rewarded-container" style="max-width: 640px; margin: 0 auto;"></div>
<div id="reward-banner" style="display: none; padding: 16px; background: #d4edda; text-align: center;">
  <span id="reward-message"></span>
  <button id="play-again" style="margin-left: 12px;">Play Again</button>
</div>

<script src="https://rewardedmedia.com/js/rewarded-sdk.js"></script>
<script>
  var rm = new RewardedMedia({
    slug: 'my-promotion',
    container: '#rewarded-container',
    signingUrl: '/api/rewarded-sign',
    hideCompletionModal: true,
    onComplete: function(data) {
      // Show your own completion UI
      document.getElementById('reward-message').textContent =
        'You earned ' + data.points_earned + ' points!';
      document.getElementById('reward-banner').style.display = 'block';
    },
    onError: function(err) {
      alert('Could not load the activity: ' + err.message);
    }
  });

  // "Play Again" reloads with fresh signing params
  document.getElementById('play-again').addEventListener('click', function() {
    document.getElementById('reward-banner').style.display = 'none';
    rm.reload();
  });
</script>

Sizing & Styling

  • The iframe automatically resizes its height to fit the video wall content.
  • Width is always 100% of the container element.
  • For best results, set a max-width on the container (e.g. max-width: 640px).
  • The minimum height is 400px.

Event Lifecycle

Event When Data
onReady Iframe loaded, signing verified (if applicable) { slug }
onComplete User finished all required videos (+ survey if configured) { slug, member_id, points_earned }
onResize Iframe content height changed { height }
onError Signing URL fetch failed { error, message }

Security

  • Only origins added to the promotion's allowed origins list can embed the video wall.
  • The iframe uses sandbox="allow-scripts allow-same-origin allow-popups allow-forms" to restrict capabilities.
  • The SDK validates the origin of all postMessage events.
  • Reward delivery is server-to-server via webhooks — the client-side onComplete callback is for UI updates only and should not be trusted for crediting users.
  • When using signingUrl, signing params never appear in your page source — they are fetched at runtime via an authenticated request to your own server.