Ninja Docs
Search…
Misc options
Platform Specific Issues
Newly Added Parameters
Powered By GitBook
Embed into a site with iFrames
How to embed VDO.Ninja into your own website with the IFRAME API
VDO.Ninja (VDON) is offers here a simple and free solution to quickly enable real-time video streaming in their websites. VDON wishes to make live video streaming development accessible to any developer, even novices, yet still remain flexible and powerful.
While VDO.Ninja does offer source-code to customize the application and UI at a low level, this isn't for beginners and it is rather hard to maintain. As well, due to the complexity of video streaming in the web, typical approaches for offering API access isn't quite feasible either.
The solution decided on isn't an SDK framework, but rather the use of embeddable IFrames and a corresponding bi-directional iframe API. An iframe allows us to embed a webpage inside a webpage, including VDO.Ninja into your own website.
Modern web browsers allow the parent website to communicate with the child webpage, giving a high-level of control to a developer, while also abstracting the complex code and hosting requirements. Functionality, we can make an VDON video stream act much like an HTML video element tag, where you can issue commands like play, pause, or change video sources with ease.
Creating an VDON iframe can be done in HTML or programmatically with Javascript like so:
1
const iframe = document.createElement("iframe");
2
iframe.allow = "autoplay;camera;microphone;fullscreen;picture-in-picture;display-capture;";
3
iframe.src = "https://vdo.ninja/?push=vhX5PYg&cleanoutput&transparent";
Copied!
You can also make an VDO.Ninja without Javascript, using just HTML, like
<iframe allow="autoplay;camera;microphone;fullscreen;picture-in-picture;display-capture;" src="https://vdo.ninja/?push=vhX5PYg&cleanoutput&transparent"></iframe>
Adding that iframe to the DOM will reveal a simple page for accessing for a user to select and share their webcam. For a developer wishing to access a remote guest's stream, this makes the ingestion of that stream into production software like OBS Studios very easy. The level of customization and control opens up opportunities, such as a pay-to-join audience option for a streaming interactive broadcast experience.
An example of how this API is used by VDO.Ninja is with its Internet Speedtest, which has two VDO.Ninja IFrames on a single page. One iframe feeds video to the other iframe, and the speed at which it does this is a measure of the system's performance. Detailed stats of the connection are made available to the parent window, which displays the results. https://vdo.ninja/speedtest​
More community-contributed IFRAME examples can be found here: https://github.com/steveseguin/vdoninja/tree/master/examples​
A sandbox of options is available at this page, too: https://vdo.ninja/iframe You can enter an VDO.Ninja URL in the input box to start using it. For developers, viewing the source of that page will reveal examples of how all the available functions work, along with a way to test and play with each of them. You can also see here for the source-code on GitHub: https://github.com/steveseguin/vdoninja/blob/master/iframe.html​
I also have an example of how you can transfer virtually any data (JSON, text, small images) via the IFRAME API with just a few lines of code here: https://gist.github.com/steveseguin/15bba03d1993c88d0bd849f7749ea625 It's a pretty awesome example of how you can securely communicate peer to peer online with virtually zero effort and with no cost.
Please note that since VDO.Ninja requires SSL to be strictly enabled site wide, any website you embed a VDO.Ninja iframe into also will require SSL enabled site wide. Using a service like Cloudflare can provide SSL-enabled caching for websites to make this fairly easy to do.
Something else to note about this iframe API is that it can not only be controlled via URL parameters given to the iframe src URL, but also using postMessage and addEventListener methods of the browser. The later is used to dynamically control VDO.Ninja, while the former is used to initiate the instance to a desired state.
Some of the more interesting ones primarily for iframe users might include:
    &webcam
    &screenshare
    &videodevice=1 or 0
    &audiodevice=1 or 0
    &autostart
    &chroma
    &transparency
    As for API, allow for dynamic messaging, below are examples of the options available:
    Mute Speaker
    Mute Mic
    Disconnect
    Change Video Bitrate
    Reload the page
    Change the volume
    Request detailed connection stats
    Access the loudness level of the audio
    Send/Recieve a chat message to other connected guests
    Get notified when there is a video connection
As for the actually details for methods and options available to dynamically control child VDON iframe, they are primarily kept up to via the iframe.html file that is mentioned previously. see: iframe.html. Below is a snippet from that file:
1
let button = document.createElement("button");
2
button.innerHTML = "Mute Speaker";
3
button.onclick = () => {
4
iframe.contentWindow.postMessage({
5
"mute": true
6
}, '*');
7
};
8
iframeContainer.appendChild(button);
9
​
10
button = document.createElement("button");
11
button.innerHTML = "Un-Mute Speaker";
12
button.onclick = () => {
13
iframe.contentWindow.postMessage({
14
"mute": false
15
}, '*');
16
};
17
iframeContainer.appendChild(button);
18
​
19
button = document.createElement("button");
20
button.innerHTML = "Toggle Speaker";
21
button.onclick = () => {
22
iframe.contentWindow.postMessage({
23
"mute": "toggle"
24
}, '*');
25
}
26
iframeContainer.appendChild(button);
27
​
28
button = document.createElement("button");
29
button.innerHTML = "Mute Mic";
30
button.onclick = () => {
31
iframe.contentWindow.postMessage({
32
"mic": false
33
}, '*');
34
};
35
iframeContainer.appendChild(button);
36
​
37
button = document.createElement("button");
38
button.innerHTML = "Un-Mute Mic";
39
button.onclick = () => {
40
iframe.contentWindow.postMessage({
41
"mic": true
42
}, '*');
43
};
44
iframeContainer.appendChild(button);
45
​
46
button = document.createElement("button");
47
button.innerHTML = "Toggle Mic";
48
button.onclick = () => {
49
iframe.contentWindow.postMessage({
50
"mic": "toggle"
51
}, '*');
52
};
53
iframeContainer.appendChild(button);
54
​
55
button = document.createElement("button");
56
button.innerHTML = "Disconnect";
57
button.onclick = () => {
58
iframe.contentWindow.postMessage({
59
"close": true
60
}, '*');
61
};
62
iframeContainer.appendChild(button);
63
​
64
button = document.createElement("button");
65
button.innerHTML = "Low Bitrate";
66
button.onclick = () => {
67
iframe.contentWindow.postMessage({
68
"bitrate": 30
69
}, '*');
70
};
71
iframeContainer.appendChild(button);
72
​
73
button = document.createElement("button");
74
button.innerHTML = "High Bitrate";
75
button.onclick = () => {
76
iframe.contentWindow.postMessage({
77
"bitrate": 5000
78
}, '*');
79
};
80
iframeContainer.appendChild(button);
81
​
82
button = document.createElement("button");
83
button.innerHTML = "Default Bitrate";
84
button.onclick = () => {
85
iframe.contentWindow.postMessage({
86
"bitrate": -1
87
}, '*');
88
};
89
iframeContainer.appendChild(button);
90
​
91
button = document.createElement("button");
92
button.innerHTML = "Reload";
93
button.onclick = () => {
94
iframe.contentWindow.postMessage({
95
"reload": true
96
}, '*');
97
};
98
iframeContainer.appendChild(button);
99
​
100
button = document.createElement("button");
101
button.innerHTML = "50% Volume";
102
button.onclick = () => {
103
iframe.contentWindow.postMessage({
104
"volume": 0.5
105
}, '*');
106
};
107
iframeContainer.appendChild(button);
108
​
109
button = document.createElement("button");
110
button.innerHTML = "100% Volume";
111
button.onclick = () => {
112
iframe.contentWindow.postMessage({
113
"volume": 1.0
114
}, '*');
115
};
116
iframeContainer.appendChild(button);
117
​
118
button = document.createElement("button");
119
button.innerHTML = "Request Stats";
120
button.onclick = () => {
121
iframe.contentWindow.postMessage({
122
"getStats": true
123
}, '*');
124
};
125
iframeContainer.appendChild(button);
126
​
127
button = document.createElement("button");
128
button.innerHTML = "Request Loudness Levels";
129
button.onclick = () => {
130
iframe.contentWindow.postMessage({
131
"getLoudness": true
132
}, '*');
133
};
134
iframeContainer.appendChild(button);
135
​
136
button = document.createElement("button");
137
button.innerHTML = "Stop Sending Loudness Levels";
138
button.onclick = () => {
139
iframe.contentWindow.postMessage({
140
"getLoudness": false
141
}, '*');
142
};
143
iframeContainer.appendChild(button);
144
​
145
button = document.createElement("button");
146
button.innerHTML = "Say Hello";
147
button.onclick = () => {
148
iframe.contentWindow.postMessage({
149
"sendChat": "Hello!"
150
}, '*');
151
};
152
iframeContainer.appendChild(button);
153
​
154
button = document.createElement("button");
155
button.innerHTML = "previewWebcam()";
156
button.onclick = () => {
157
iframe.contentWindow.postMessage({
158
"function": "previewWebcam"
159
}, '*');
160
};
161
iframeContainer.appendChild(button);
162
​
163
button = document.createElement("button");
164
button.innerHTML = "CLOSE IFRAME";
165
button.onclick = () => {
166
iframeContainer.parentNode.removeChild(iframeContainer);
167
};
168
iframeContainer.appendChild(button);
169
​
170
// As for listening events, where the parent listens for responses or events from the VDON child frame:
171
​
172
// ////////// LISTEN FOR EVENTS
173
​
174
const eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
175
const eventer = window[eventMethod];
176
const messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";
177
​
178
eventer(messageEvent, function (e) {
179
if (e.source !== iframe.contentWindow) {
180
return
181
} // reject messages send from other iframes
182
​
183
if ("stats" in e.data) {
184
const outputWindow = document.createElement("div");
185
​
186
let out = `<br />total_inbound_connections:${
187
e.data.stats.total_inbound_connections
188
}`;
189
out += `<br />total_outbound_connections:${
190
e.data.stats.total_outbound_connections
191
}`;
192
​
193
for (const streamID in e.data.stats.inbound_stats) {
194
out += `<br /><br /><b>streamID:</b> ${streamID}<br />`;
195
out += printValues(e.data.stats.inbound_stats[streamID]);
196
}
197
​
198
outputWindow.innerHTML = out;
199
iframeContainer.appendChild(outputWindow);
200
}
201
​
202
if ("gotChat" in e.data) {
203
const outputWindow = document.createElement("div");
204
outputWindow.innerHTML = e.data.gotChat.msg;
205
outputWindow.style.border = "1px dotted black";
206
iframeContainer.appendChild(outputWindow);
207
}
208
​
209
if ("action" in e.data) {
210
const outputWindow = document.createElement("div");
211
outputWindow.innerHTML = `child-page-action: ${
212
e.data.action
213
}<br />`;
214
outputWindow.style.border = "1px dotted black";
215
iframeContainer.appendChild(outputWindow);
216
}
217
​
218
if ("loudness" in e.data) {
219
console.log(e.data);
220
if (document.getElementById("loudness")) {
221
outputWindow = document.getElementById("loudness");
222
} else {
223
const outputWindow = document.createElement("div");
224
outputWindow.style.border = "1px dotted black";
225
iframeContainer.appendChild(outputWindow);
226
outputWindow.id = "loudness";
227
}
228
outputWindow.innerHTML = "child-page-action: loudness<br />";
229
for (const key in e.data.loudness) {
230
outputWindow.innerHTML += `${key} Loudness: ${
231
e.data.loudness[key]
232
}\n`;
233
}
234
outputWindow.style.border = "1px black";
235
​
236
}
237
});
Copied!
This VDO.Ninja API is developed and expanded based on user feedback and requests. It is by no means complete, but it is getting better every week.

Advanced IFrame functionality

There's some users who wish to have an SDK instead of an IFRAME API. While an SDK may happen eventually, currently the IFRAME API is surprisingly capable.
If you wish to use your own video mixer logic for example, you can disable the existing auto-mixer logic that currently exists using the &manual flag. You can then access the srcObject of each of the video elements in VDO.Ninja and pull those streams into the parent frame to manipulate or to connect to the parent DOM.
If you aren't self-hosting the code, you may run into cross origin permission issues. This concept works with different subdomains though, and if you ask, the option to directly reference the VDO.Ninja servers with your own DNS servers is available. Self-hosting the code in a sub-domain of your own works too.
See the video below for an advanced demo of the IFRAME API and how videos hosted within VDO.Ninja can be accessed and manipulated by the parent window. Video works well in this fashion; pulling audio from the IFRAME is a bit trickier however.
​

All to happy to support the IFRAME API

Please feel free to follow me in the VDO.Ninja Discord channel (discord.vdo.ninja) where I post news about updates and listen to requests. The upcoming version of VDO.Ninja is also often hosted at https://vdo.ninja/beta, where you can explore new features and help crush any unexpected bugs. I am keen to continue to support the IFRAME API, so please reach out if you have questions or requests.
-steve
Last modified 12d ago