# Vision video player MJPEG via websocket

**URL:** <https://forum.inductiveautomation.com/t/vision-video-player-mjpeg-via-websocket/112164>\
**Category:** Ignition\
**Tags:** vision\
**Created:** [November 13, 2025, 5:05pm UTC](https://forum.inductiveautomation.com/t/vision-video-player-mjpeg-via-websocket/112164 "2025-11-13T17:05:11Z")\
**Posts on this page:** 19\
**Page:** 1

<div class="post-metadata">

**Author:** ![alex.ferrell](https://avatars.discourse-cdn.com/v4/letter/a/958977/32.png) [@alex.ferrell](https://forum.inductiveautomation.com/u/alex.ferrell)\
**Post date:** [November 13, 2025, 5:05pm UTC](https://forum.inductiveautomation.com/t/vision-video-player-mjpeg-via-websocket/112164/1 "2025-11-13T17:05:11Z")

</div>

We have a Vision project that has pop-up windows with the video player component showing live video stream from an industrial camera. We recently changed cameras to a new one with better resolution and image capture. However, we started testing and realized this new one supports MJPEG but only via websocket. It has a connection url of “ws://:8888/ws”. The older one had an actual http url. I got some example html code from the manufacturer for using the websocket in html (below). Is there a way in Ignition to use this html to display the video feed?

 MJPEG Livestream #mjpeg-stream { width: 100%; height: auto; max-width: 1280px; /\* Adjust as needed \*/ } 
# MJPEG Livestream
 ![MJPEG Stream]()

```
<script>
    const img = document.getElementById('mjpeg-stream');
    const ws = new WebSocket('[ws://192.168.136.100:8888/ws](ws://192.168.136.100:8888/ws)');

    ws.binaryType = 'blob';

    ws.onmessage = function(event) {
        const url = URL.createObjectURL(event.data);
        img.src = url;
    };

    ws.onerror = function(error) {
        console.error('WebSocket Error: ', error);
    };

    ws.onclose = function() {
        console.log('WebSocket connection closed');
    };
</script>

```

---

<div class="post-metadata">

**Author:** ![alex.ferrell](https://avatars.discourse-cdn.com/v4/letter/a/958977/32.png) [@alex.ferrell](https://forum.inductiveautomation.com/u/alex.ferrell)\
**Post date:** [November 13, 2025, 5:09pm UTC](https://forum.inductiveautomation.com/t/vision-video-player-mjpeg-via-websocket/112164/2 "2025-11-13T17:09:17Z")

</div>

![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/a/2/a2537ea45b0c2c43852765aad04e1c5ebd100621.png)

Here is the actual full html code that I received.

---

<div class="post-metadata">

**Author:** ![ryan.white](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/ryan.white/32/73193_2.png) [@ryan.white](https://forum.inductiveautomation.com/u/ryan.white)\
**Post date:** [November 13, 2025, 5:17pm UTC](https://forum.inductiveautomation.com/t/vision-video-player-mjpeg-via-websocket/112164/3 "2025-11-13T17:17:01Z")

</div>

If you have the web browser component for Vision, maybe try setting it to HTML mode and placing the example HTML in the `startingHTML` property?

> **[Vision - Web Browser Component | Ignition User Manual](https://www.docs.inductiveautomation.com/docs/8.1/appendix/components/vision-components/web-browser/web-browser-component#properties)**
>
> The Web Browser component in Designer allows you to embed a full web browser inside of an Ignition Client.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [November 13, 2025, 5:21pm UTC](https://forum.inductiveautomation.com/t/vision-video-player-mjpeg-via-websocket/112164/4 "2025-11-13T17:21:02Z")

</div>

We didn't communicate it out much, but as part of an effort to simplify our module lineup in 8.3 the Vision module now automatically includes the Web Browser component.

---

<div class="post-metadata">

**Author:** ![alex.ferrell](https://avatars.discourse-cdn.com/v4/letter/a/958977/32.png) [@alex.ferrell](https://forum.inductiveautomation.com/u/alex.ferrell)\
**Post date:** [November 13, 2025, 7:31pm UTC](https://forum.inductiveautomation.com/t/vision-video-player-mjpeg-via-websocket/112164/5 "2025-11-13T19:31:35Z")

</div>

Thank you! This worked perfectly. We are also developing a Perspective version of this application. Does the Perspective Video Player support MJPEG via websocket, or is there a way to embed an html webpage with the same html code?

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [November 13, 2025, 7:36pm UTC](https://forum.inductiveautomation.com/t/vision-video-player-mjpeg-via-websocket/112164/6 "2025-11-13T19:36:33Z")

</div>

You can't embed the same HTML exactly, but you could use the Markdown component with the 'escape HTML' option turned off to embed that Javascript onto the page. It's _very_ simple code: just creating a websocket and immediately dropping each returned message onto an image. An LLM should be able to do it with some prompting.

---

<div class="post-metadata">

**Author:** ![alex.ferrell](https://avatars.discourse-cdn.com/v4/letter/a/958977/32.png) [@alex.ferrell](https://forum.inductiveautomation.com/u/alex.ferrell)\
**Post date:** [November 13, 2025, 8:02pm UTC](https://forum.inductiveautomation.com/t/vision-video-player-mjpeg-via-websocket/112164/7 "2025-11-13T20:02:27Z")

</div>

What is the best way to make the html code dynamic and pass in the IP via a parameter? I have the Web Browser object on a pop-up window that can get called for different cameras. I tried an Expression binding on the startingHTML property, but it does not like the formatting of the html text and gives me unterminated string errors.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [November 13, 2025, 8:11pm UTC](https://forum.inductiveautomation.com/t/vision-video-player-mjpeg-via-websocket/112164/8 "2025-11-13T20:11:34Z")

</div>

Take your sample HTML and put it into a text editor. Replace all single quotes `'` with double quotes `"`, including inside the actual script body.

Use an expression binding and the `stringFormat` function, wrapping the entire HTML text as a string literal using **single** quotes.

That is, your 'raw' HTML would be something like:

```python
<html lang="en">
<script>
const img = document.getElementById("mjpeg-stream");
const ws = new WebSocket("%s");

```

And then your Ignition expression is:

```python
stringFormat('
<html lang="en">
<script>
const img = document.getElementById("mjpeg-stream");
const ws = new WebSocket("%s");
',
{path/to/property/with/ip}
)

```

That should work:

1. HTML requires double quotes
2. JS treats single quotes and double quotes the same
3. Ignition's expression language treats single and double quotes the same

So as long as you're consistent about the outermost layer being single quotes, everything within it will be a single string to the expression language.

---

<div class="post-metadata">

**Author:** ![alex.ferrell](https://avatars.discourse-cdn.com/v4/letter/a/958977/32.png) [@alex.ferrell](https://forum.inductiveautomation.com/u/alex.ferrell)\
**Post date:** [November 13, 2025, 8:38pm UTC](https://forum.inductiveautomation.com/t/vision-video-player-mjpeg-via-websocket/112164/9 "2025-11-13T20:38:30Z")

</div>

I’m still getting the “unterminated string at end of line” error, line 1 character 15- basically the end of the stringFormat(‘ line.

---

<div class="post-metadata">

**Author:** ![alex.ferrell](https://avatars.discourse-cdn.com/v4/letter/a/958977/32.png) [@alex.ferrell](https://forum.inductiveautomation.com/u/alex.ferrell)\
**Post date:** [November 13, 2025, 10:06pm UTC](https://forum.inductiveautomation.com/t/vision-video-player-mjpeg-via-websocket/112164/10 "2025-11-13T22:06:30Z")

</div>

For some reason the editor is not allowing a string to get split to multiple lines. I got it to work by going back to the originally formatted html code and splitting it into 3 custom string properties. I have the html right up to the URL, then a property for the URL, then one for the code after it. The URL property gets passed into the popup window. The startingHTML property of the Web Browser object has an expression that is simply concatenating them all together.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [November 13, 2025, 11:16pm UTC](https://forum.inductiveautomation.com/t/vision-video-player-mjpeg-via-websocket/112164/11 "2025-11-13T23:16:22Z")

</div>

Oh, right, duh. I'm too used to Java/Kotlin, forgot our expression language doesn't do multiline strings like that. Glad you got something working.

---

<div class="post-metadata">

**Author:** ![alex.ferrell](https://avatars.discourse-cdn.com/v4/letter/a/958977/32.png) [@alex.ferrell](https://forum.inductiveautomation.com/u/alex.ferrell)\
**Post date:** [November 14, 2025, 3:29pm UTC](https://forum.inductiveautomation.com/t/vision-video-player-mjpeg-via-websocket/112164/12 "2025-11-14T15:29:37Z")

</div>

I started testing this in Perspective. I could not get the Markdown component to actually run my javascript, so I took a different approach. I created an html file in WebDev and put the same code that I got to work in the Vision Web Module. If I browse to that page with my browser, it works. However, with an Inline Frame object pointing to the same URL, I just get a blank page.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [November 14, 2025, 3:33pm UTC](https://forum.inductiveautomation.com/t/vision-video-player-mjpeg-via-websocket/112164/13 "2025-11-14T15:33:05Z")

</div>

Check the browser console when you're looking at that view - there might be errors in the console or network tabs.

---

<div class="post-metadata">

**Author:** ![alex.ferrell](https://avatars.discourse-cdn.com/v4/letter/a/958977/32.png) [@alex.ferrell](https://forum.inductiveautomation.com/u/alex.ferrell)\
**Post date:** [November 14, 2025, 3:42pm UTC](https://forum.inductiveautomation.com/t/vision-video-player-mjpeg-via-websocket/112164/14 "2025-11-14T15:42:53Z")

</div>

It might be an issue caused by https vs http. I see an error:

1. Even though the initial HTML page is loaded over a secure HTTPS connection, some resources like images, stylesheets or scripts are being accessed over an insecure HTTP connection. Usage of insecure resources is restricted to strengthen the security of your entire site.

undefined|----|----|  
| Camera1.html | blocked |  
undefined|----|----|

---

<div class="post-metadata">

**Author:** ![alex.ferrell](https://avatars.discourse-cdn.com/v4/letter/a/958977/32.png) [@alex.ferrell](https://forum.inductiveautomation.com/u/alex.ferrell)\
**Post date:** [November 14, 2025, 3:44pm UTC](https://forum.inductiveautomation.com/t/vision-video-player-mjpeg-via-websocket/112164/15 "2025-11-14T15:44:05Z")

</div>

I tried changing the source of the iFrame to https://… instead, but now I get a sad-faced paper icon.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [November 14, 2025, 4:41pm UTC](https://forum.inductiveautomation.com/t/vision-video-player-mjpeg-via-websocket/112164/16 "2025-11-14T16:41:25Z")

</div>

Hm. That'll probably also impact the markdown route, since you've got a `ws` endpoint, not a `wss` one.

Unfortunately that'll be tricky to deal with if the camera doesn't serve up a secure websocket.

Does the server where the gateway is actually running have access to this camera over the network?  
The protocol is **extremely** simple, so you could in theory do one of:

1. Set up a 'reverse proxy' on the gateway host that makes the WS connection and re-serves it via WSS. If you're already using HTTPS for your gateway you should be able to tie it into the same certificate.
2. Use a script on the gateway to make the persistent websocket connection. The `system.net.httpClient` function gives you access to the underlying Java `HttpClient` (`system.net.httpClient.javaClient`) which has a [`newWebSocketBuilder` method](https://docs.oracle.com/en/java/javase/17/docs/api/java.net.http/java/net/http/HttpClient.html#newWebSocketBuilder()) you could in theory use to make an outgoing WS connection. Then you could fetch the image data and put it into a memory tag or store it in `system.util.globals` or something else.

Neither option is _great_, to be honest - you're going to burn some engineering time here.

---

<div class="post-metadata">

**Author:** ![alex.ferrell](https://avatars.discourse-cdn.com/v4/letter/a/958977/32.png) [@alex.ferrell](https://forum.inductiveautomation.com/u/alex.ferrell)\
**Post date:** [November 14, 2025, 5:06pm UTC](https://forum.inductiveautomation.com/t/vision-video-player-mjpeg-via-websocket/112164/17 "2025-11-14T17:06:43Z")

</div>

Is there a way to have the WebDev module serve up the html over https?

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [November 14, 2025, 5:13pm UTC](https://forum.inductiveautomation.com/t/vision-video-player-mjpeg-via-websocket/112164/18 "2025-11-14T17:13:15Z")

</div>

Yes, there's a setting at the top of the route. I don't know if it'll help, though - even if the HTML is secure content, the WS connection it tries to make will not be.

---

<div class="post-metadata">

**Author:** ![alex.ferrell](https://avatars.discourse-cdn.com/v4/letter/a/958977/32.png) [@alex.ferrell](https://forum.inductiveautomation.com/u/alex.ferrell)\
**Post date:** [November 14, 2025, 6:58pm UTC](https://forum.inductiveautomation.com/t/vision-video-player-mjpeg-via-websocket/112164/19 "2025-11-14T18:58:56Z")

</div>

I ended up setting Chrome to allow insecure content for my site and added this to the ignition.conf file: wrapper.java.additional.14=-Dignition.http.header.x\_frame\_options.enabled=false. The embedded html with the live stream works now.
