Embed raid plans anywhere
Drop a Raidstrats.gg plan into any web page with an iframe. Pre-set the roster with URL parameters, then drive runtime updates, highlights, index badges, and spell badges via postMessage.
Quickstart #
Minimal iframe setup. Pre-fill the roster via URL parameters and listen for the ready event.
<iframe
id="raidplanEmbed"
src="https://raidstrats.gg/planner?embed=true&id=YOUR_PLAN_ID&animation=true&hidetrails=true"
width="100%"
height="600"
frameborder="0">
</iframe>
const iframe = document.getElementById('raidplanEmbed');
// Listen for the embed to tell us which slots it has
window.addEventListener('message', (event) => {
if (event.origin !== 'https://raidstrats.gg') return;
if (event.data.type === 'playerNamesLoaded') {
console.log('Slots:', event.data.slots);
}
if (event.data.type === 'embedEditSaved') {
document.getElementById('savedPlanId').value = event.data.planId;
iframe.src = event.data.embedUrl;
}
});
// Send a runtime update
iframe.contentWindow.postMessage({
type: 'updatePlayers',
players: {
'index1': { name: 'Alice', class: 'Mage' }
}
}, 'https://raidstrats.gg');
Index slots #
Every controllable token on the plan has a numeric embed index (set in the planner's properties panel). All messages target slots by indexKey (index1, index2, ...). This keeps targeting stable even when names change or duplicate names exist.
indexKey. Name-based targeting is supported for legacy flows but is ambiguous.URL parameters #
Append to the iframe URL to configure initial state.
true to enable embed mode.false.false.true.scene=3. Out-of-range values are clamped.Alice,Bob,CharlieAlice|Mage,Bob|WarriorembedEditSaved to the parent with the new plan link. Saving requires a logged-in Raidstrats account. Default false.editMode=true. When a guest tries to save, they are sent to /login on Raidstrats and returned here after login. If omitted, the embed uses document.referrer when it points to another site.URL examples #
https://raidstrats.gg/planner?embed=true&id=YOUR_PLAN_ID
&scene=3
https://raidstrats.gg/planner?embed=true&id=YOUR_PLAN_ID
&names=Alice,Bob,Charlie,Dave,Eve
https://raidstrats.gg/planner?embed=true&id=YOUR_PLAN_ID
&players=Alice|Warrior,Bob|Mage,Charlie|Priest,Dave|Paladin
https://raidstrats.gg/planner?embed=true&id=YOUR_PLAN_ID
&players=Nairy|Priest,Bob|Mage&circleMode=true
https://raidstrats.gg/planner?embed=true&id=YOUR_PLAN_ID
&editMode=true&returnUrl=https://your-site.com/raid-page
Listen to events #
The embed posts messages back to the parent window. Always verify event.origin.
playerNamesLoaded
Sent once the plan finishes loading. Contains names and slots.
animationStarted
Fires when embed animation playback starts.
animationStopped
Fires when embed animation playback stops.
assignSpellToIndexResult
Response to assignSpellToIndex. Single slot: ok, indexKey, spellId. Batch: batch: true and results[] per slot. Includes requestId when provided.
embedSceneChanged
Fires after a scene switch. Includes sceneIndex and requestRuntimeReplay.
embedEditSaved
Sent when a user saves in editMode=true. Includes planId (the saved plan — same as the embed when the user owns it, or a new ID when they forked a copy), plus plannerUrl and embedUrl.
embedEditSaveFailed
Sent when save fails in edit mode. Includes error.
embedEditLoginRequired
Sent when a guest clicks Save. Includes loginUrl, returnUrl, and usePopup: true. A centered login popup opens; after login it closes and save can be retried automatically.
embedEditLoginComplete
Sent to the parent page when popup login succeeds.
Edit mode save — capture the plan ID #
When a logged-in user clicks Save in editMode=true, the iframe posts embedEditSaved to your page. Use event.data.planId to read the saved plan — store it in a form field, your CMS, or local state.
planId change?
- Same ID — the logged-in user owns the plan and it was updated in place.
- New ID — the user forked a copy (they were not the owner, or the source plan had no owner). Your page should persist the new
planIdif you want later loads to use the saved layout.
<iframe
id="raidplanEmbed"
src="https://raidstrats.gg/planner?embed=true&id=ORIGINAL_PLAN_ID&editMode=true&returnUrl=https://your-site.com/raid-page"
width="100%"
height="600"
frameborder="0">
</iframe>
<!-- Example: hidden input your CMS or backend reads -->
<input type="hidden" id="savedPlanId" name="raidstrats_plan_id" value="ORIGINAL_PLAN_ID">
const iframe = document.getElementById('raidplanEmbed');
const planIdField = document.getElementById('savedPlanId');
const EMBED_ORIGIN = 'https://raidstrats.gg';
window.addEventListener('message', (event) => {
if (event.origin !== EMBED_ORIGIN) return;
if (!event.data || event.data.type !== 'embedEditSaved') return;
const { planId, embedUrl, plannerUrl } = event.data;
const previousId = planIdField.value;
// Persist for your CMS, API, or page state
planIdField.value = planId;
// Optional: reload iframe so the embed uses the saved plan URL
iframe.src = embedUrl;
if (planId !== previousId) {
console.log('User forked a new plan:', planId, plannerUrl);
// e.g. PATCH your backend: { raidstrats_plan_id: planId }
} else {
console.log('Owner updated plan in place:', planId);
}
});
src with the saved id= and your existing embed params (including editMode).Update names #
POSTupdatePlayerName
'index1'.maxCharacters.indexKey isn't available).iframe.contentWindow.postMessage({
type: 'updatePlayerName',
indexKey: 'index1',
newName: 'Nairyana'
}, 'https://raidstrats.gg');
Update classes #
POSTupdatePlayerClass
Warrior, Mage, Death Knight, ...). Use null to clear runtime override and restore that slot's baseline visual from load (class/spec/role).circleMode=true is on the iframe URL, class updates render as rings. Otherwise they render as class/spec icons. Baseline resets (newClass: null) persist across scene switches for that indexKey and restore non-class role visuals too (for example DPS/Tank icons).iframe.contentWindow.postMessage({
type: 'updatePlayerClass',
indexKey: 'index1',
newClass: 'Priest'
}, 'https://raidstrats.gg');
iframe.contentWindow.postMessage({
type: 'updatePlayerClass',
indexKey: 'index1',
newClass: null
}, 'https://raidstrats.gg');
Batch updates #
POSTupdatePlayers
Update name and/or class for many slots in a single message. Set class: null for a slot to reset its class back to baseline.
iframe.contentWindow.postMessage({
type: 'updatePlayers',
players: {
'index1': { name: 'Alice', class: 'Mage' },
'index2': { name: 'Bob', class: 'Warrior' },
'index3': { name: 'Chad' }
}
}, 'https://raidstrats.gg');
playersMap in the parent and re-send it when the embed emits embedSceneChanged. This ensures off-scene slots stay synchronized even if scene assets hydrate late.const ORIGIN = 'https://raidstrats.gg';
const playersMap = {
'index1': { name: 'Alice', class: 'Mage' },
'index2': { name: 'Bob' }
};
window.addEventListener('message', (event) => {
if (event.origin !== ORIGIN) return;
const data = event.data || {};
if (data.type === 'embedSceneChanged' && data.requestRuntimeReplay) {
iframe.contentWindow.postMessage({
type: 'updatePlayers',
players: playersMap
}, ORIGIN);
}
});
Highlight players #
POSThighlightPlayers
Dim all other players and apply a salmon glow to the targeted indices. Persists across scene switches until cleared with an empty array.
[] clears all highlights.// Single index
iframe.contentWindow.postMessage({ type: 'highlightPlayers', indices: 2 }, '*');
// Multiple
iframe.contentWindow.postMessage({ type: 'highlightPlayers', indices: [1, 3, 5] }, '*');
// Clear
iframe.contentWindow.postMessage({ type: 'highlightPlayers', indices: [] }, '*');
Index badges #
POSTtoggleIndexNumbers
Show or hide numeric index badges on player slots (for example 1, 2, 3). State persists across scene switches until changed again.
true shows badges, false hides badges.show.show.iframe.contentWindow.postMessage({
type: 'toggleIndexNumbers',
show: true
}, 'https://raidstrats.gg');
iframe.contentWindow.postMessage({
type: 'toggleIndexNumbers',
show: false
}, 'https://raidstrats.gg');
Spell badges #
POSTassignSpellToIndex
Attach Wowhead-backed spell icons to player slots. Badges have full Wowhead tooltips and persist across scene switches. Use a batch payload when applying the same spell to many slots — one message, one canvas update (avoids flicker).
index1). Alias: slotKey.spellId. Alias: slotKeys.[1,2,3] → index1, index2, … or comma-separated "1,2,3".[{ indexKey, spellId }, { indexKey, spellId, scale }, { indexKey, clear: true }].indexKeys / indices. Use 0 or null to clear. Aliases: spell_id, spellid.spellId: 0. For batch clear, use assignments: [{ indexKey, clear: true }, …].0.5. Overridable per entry in assignments.{ x: 0, y: -0.5 } (top center).assignSpellToIndexResult for correlation.iframe.contentWindow.postMessage({
type: 'assignSpellToIndex',
indexKey: 'index1',
spellId: 73920,
scale: 0.5
}, 'https://raidstrats.gg');
iframe.contentWindow.postMessage({
type: 'assignSpellToIndex',
requestId: 'raid-w1-heroic',
indexKeys: ['index1', 'index2', 'index3', 'index4', 'index5', 'index6'],
spellId: 451832,
scale: 0.5
}, 'https://raidstrats.gg');
// Or numeric indices:
iframe.contentWindow.postMessage({
type: 'assignSpellToIndex',
indices: [1, 2, 3, 4, 5, 6],
spellId: 451832
}, 'https://raidstrats.gg');
iframe.contentWindow.postMessage({
type: 'assignSpellToIndex',
requestId: 'assignments-demo',
assignments: [
{ indexKey: 'index1', spellId: 451832 },
{ indexKey: 'index2', spellId: 451832 },
{ indexKey: 'index3', spellId: 123456 }
]
}, 'https://raidstrats.gg');
// One slot
iframe.contentWindow.postMessage({
type: 'assignSpellToIndex',
indexKey: 'index1',
spellId: 0
}, 'https://raidstrats.gg');
// Many slots
iframe.contentWindow.postMessage({
type: 'assignSpellToIndex',
assignments: [
{ indexKey: 'index1', clear: true },
{ indexKey: 'index2', clear: true }
]
}, 'https://raidstrats.gg');
{
type: 'assignSpellToIndexResult',
requestId: 'raid-w1-heroic',
ok: true,
batch: true,
results: [
{ indexKey: 'index1', ok: true, spellId: 451832 },
{ indexKey: 'index2', ok: true, spellId: 451832 }
]
}
Animation #
Control embed animation playback. Requires animation=true on the iframe URL.
startAnimation
Begin playback of the current scene's animation.
stopAnimation
Stop playback and reset to frame 0.
Message types #
Complete reference of every supported message type.
Parent to embed
names: { index1: 'Alice', ... }newClass: null).null resets per slot).class: null resets).[] clears.indexKey) or batch (indexKeys, indices, assignments).Embed to parent
names, slots.batch: true and results[].sceneIndex and requestRuntimeReplay: true.planId (unchanged if owner updated in place, or a new UUID if forked), embedUrl, plannerUrl, sceneIndex. See Edit mode save.error.Security #
event.origin === 'https://raidstrats.gg' in your message listener before trusting payloads.- Prefer
indexKeytargeting over fragile name matching. - Only post messages after the iframe has loaded.
encodeURIComponentuser-provided values when composing URL parameters.- Handle embed load failures gracefully. Do not block on
playerNamesLoaded.