<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Python GUIs - qtwebengine</title><link href="https://www.pythonguis.com/" rel="alternate"/><link href="https://www.pythonguis.com/feeds/qtwebengine.tag.atom.xml" rel="self"/><id>https://www.pythonguis.com/</id><updated>2020-09-15T09:00:00+00:00</updated><subtitle>Create GUI applications with Python and Qt</subtitle><entry><title>PyQt5 runJavaScript with QtWebEngine — Execute JavaScript in web pages embedded in your PyQt5 applications</title><link href="https://www.pythonguis.com/faq/pyqt5-runjavascript-with-qtwebengine/" rel="alternate"/><published>2020-09-15T09:00:00+00:00</published><updated>2020-09-15T09:00:00+00:00</updated><author><name>Martin Fitzpatrick</name></author><id>tag:www.pythonguis.com,2020-09-15:/faq/pyqt5-runjavascript-with-qtwebengine/</id><summary type="html">PyQt5's &lt;code&gt;QtWebEngineWidgets&lt;/code&gt; module lets you embed full web pages inside your desktop applications using &lt;code&gt;QWebEngineView&lt;/code&gt;. That alone is useful, but the real power comes when you start &lt;em&gt;interacting&lt;/em&gt; with those web pages from Python &amp;mdash; clicking buttons, filling in forms, or sending commands to JavaScript-based interfaces.</summary><content type="html">
            &lt;p&gt;PyQt5's &lt;code&gt;QtWebEngineWidgets&lt;/code&gt; module lets you embed full web pages inside your desktop applications using &lt;code&gt;QWebEngineView&lt;/code&gt;. That alone is useful, but the real power comes when you start &lt;em&gt;interacting&lt;/em&gt; with those web pages from Python &amp;mdash; clicking buttons, filling in forms, or sending commands to JavaScript-based interfaces.&lt;/p&gt;
&lt;p&gt;The way you do this is with the &lt;code&gt;runJavaScript()&lt;/code&gt; method on &lt;code&gt;QWebEnginePage&lt;/code&gt;. This method lets you inject and execute arbitrary JavaScript code inside the loaded web page, giving your Python application direct control over the web content.&lt;/p&gt;
&lt;p&gt;In this tutorial, we'll walk through how &lt;code&gt;runJavaScript()&lt;/code&gt; works, starting from a simple example and building up to more practical use cases.&lt;/p&gt;
&lt;h2 id="setting-up-a-basic-qwebengineview"&gt;Setting up a basic QWebEngineView&lt;/h2&gt;
&lt;p&gt;Before we can run any JavaScript, we need a web view with a loaded page. Let's start with the basics: creating a &lt;code&gt;QWebEngineView&lt;/code&gt; that loads a simple HTML page.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtCore import QUrl


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("QtWebEngine Example")
        self.resize(800, 600)

        self.browser = QWebEngineView()
        self.browser.setHtml("""
            &amp;lt;html&amp;gt;
            &amp;lt;body&amp;gt;
                &amp;lt;h1 id="title"&amp;gt;Hello from QtWebEngine!&amp;lt;/h1&amp;gt;
                &amp;lt;p id="content"&amp;gt;This is a web page embedded in PyQt5.&amp;lt;/p&amp;gt;
            &amp;lt;/body&amp;gt;
            &amp;lt;/html&amp;gt;
        """)

        central_widget = QWidget()
        layout = QVBoxLayout()
        layout.addWidget(self.browser)
        central_widget.setLayout(layout)
        self.setCentralWidget(central_widget)


app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This creates a window with an embedded web page. The page is defined inline using &lt;code&gt;setHtml()&lt;/code&gt;, but you could also load a URL with &lt;code&gt;setUrl(QUrl("https://example.com"))&lt;/code&gt;. If you're new to building windows with PyQt5, see our tutorial on &lt;a href="https://www.pythonguis.com/tutorials/creating-your-first-pyqt-window/"&gt;creating your first PyQt window&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="running-javascript-on-the-page"&gt;Running JavaScript on the page&lt;/h2&gt;
&lt;p&gt;Now let's modify the page after it's loaded. The &lt;code&gt;runJavaScript()&lt;/code&gt; method is available on the &lt;em&gt;page&lt;/em&gt; object (accessed via &lt;code&gt;self.browser.page()&lt;/code&gt;), and you call it with a string of JavaScript code.&lt;/p&gt;
&lt;p&gt;Here's how you'd change the heading text from Python:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;self.browser.page().runJavaScript(
    'document.getElementById("title").innerText = "Modified by Python!";'
)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;There's one thing to watch out for: you need to make sure the page has finished loading before you try to run JavaScript on it. If you call &lt;code&gt;runJavaScript()&lt;/code&gt; before the page is ready, your JavaScript will have nothing to work with.&lt;/p&gt;
&lt;p&gt;Connect to the &lt;code&gt;loadFinished&lt;/code&gt; signal to know when it's safe:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;self.browser.loadFinished.connect(self.on_load_finished)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Then define your slot. If you're not familiar with how signals and slots work in PyQt5, take a look at our &lt;a href="https://www.pythonguis.com/tutorials/pyqt-signals-slots-events/"&gt;signals, slots and events tutorial&lt;/a&gt;:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;def on_load_finished(self, ok):
    if ok:
        self.browser.page().runJavaScript(
            'document.getElementById("title").innerText = "Modified by Python!";'
        )
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Let's put that together into a complete example:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget
from PyQt5.QtWebEngineWidgets import QWebEngineView


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("runJavaScript Example")
        self.resize(800, 600)

        self.browser = QWebEngineView()
        self.browser.setHtml("""
            &amp;lt;html&amp;gt;
            &amp;lt;body&amp;gt;
                &amp;lt;h1 id="title"&amp;gt;Hello from QtWebEngine!&amp;lt;/h1&amp;gt;
                &amp;lt;p id="content"&amp;gt;This is a web page embedded in PyQt5.&amp;lt;/p&amp;gt;
            &amp;lt;/body&amp;gt;
            &amp;lt;/html&amp;gt;
        """)
        self.browser.loadFinished.connect(self.on_load_finished)

        central_widget = QWidget()
        layout = QVBoxLayout()
        layout.addWidget(self.browser)
        central_widget.setLayout(layout)
        self.setCentralWidget(central_widget)

    def on_load_finished(self, ok):
        if ok:
            self.browser.page().runJavaScript(
                'document.getElementById("title").innerText = "Modified by Python!";'
            )


app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;When you run this, you'll see the heading briefly show "Hello from QtWebEngine!" and then change to "Modified by Python!" once the page finishes loading.&lt;/p&gt;
&lt;h2 id="getting-values-back-from-javascript"&gt;Getting values back from JavaScript&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;runJavaScript()&lt;/code&gt; can also return values from the JavaScript back to Python. You do this by passing a callback function as the second argument. The callback receives whatever value the JavaScript expression evaluates to.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;def on_load_finished(self, ok):
    if ok:
        self.browser.page().runJavaScript(
            'document.getElementById("title").innerText;',
            self.handle_result
        )

def handle_result(self, result):
    print(f"The title text is: {result}")
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The JavaScript expression needs to &lt;em&gt;evaluate&lt;/em&gt; to something &amp;mdash; think of it like the return value of the last expression in your script. Simple values like strings, numbers, booleans, and even JSON-serializable objects can be passed back this way.&lt;/p&gt;
&lt;p&gt;Here's a complete example that reads a value from the page:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;import sys
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QVBoxLayout, QWidget, QPushButton, QLabel,
)
from PyQt5.QtWebEngineWidgets import QWebEngineView


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("runJavaScript Return Values")
        self.resize(800, 600)

        self.browser = QWebEngineView()
        self.browser.setHtml("""
            &amp;lt;html&amp;gt;
            &amp;lt;body&amp;gt;
                &amp;lt;h1 id="title"&amp;gt;Hello from QtWebEngine!&amp;lt;/h1&amp;gt;
                &amp;lt;p id="counter"&amp;gt;0&amp;lt;/p&amp;gt;
                &amp;lt;script&amp;gt;
                    var count = 0;
                    function increment() {
                        count += 1;
                        document.getElementById("counter").innerText = count;
                        return count;
                    }
                &amp;lt;/script&amp;gt;
            &amp;lt;/body&amp;gt;
            &amp;lt;/html&amp;gt;
        """)

        self.result_label = QLabel("Click the button to increment the counter")
        self.button = QPushButton("Increment Counter")
        self.button.clicked.connect(self.increment_counter)

        central_widget = QWidget()
        layout = QVBoxLayout()
        layout.addWidget(self.browser)
        layout.addWidget(self.result_label)
        layout.addWidget(self.button)
        central_widget.setLayout(layout)
        self.setCentralWidget(central_widget)

    def increment_counter(self):
        self.browser.page().runJavaScript("increment();", self.handle_result)

    def handle_result(self, result):
        self.result_label.setText(f"Counter value from JavaScript: {result}")


app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Each time you click the button, Python calls the &lt;code&gt;increment()&lt;/code&gt; JavaScript function, the counter on the page updates, and the return value is sent back to Python and displayed in the label.&lt;/p&gt;
&lt;h2 id="triggering-javascript-from-buttons"&gt;Triggering JavaScript from buttons&lt;/h2&gt;
&lt;p&gt;A common pattern is to have buttons in your PyQt5 interface that trigger actions in the embedded web page. This is straightforward &amp;mdash; connect your button's &lt;code&gt;clicked&lt;/code&gt; signal to a method that calls &lt;code&gt;runJavaScript()&lt;/code&gt;.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;self.button.clicked.connect(self.run_my_script)

def run_my_script(self):
    script = """
        document.body.style.backgroundColor = '#2c3e50';
        document.body.style.color = '#ecf0f1';
    """
    self.browser.page().runJavaScript(script)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;You can make the JavaScript as simple or complex as you need. Multi-line scripts work well when formatted as Python triple-quoted strings.&lt;/p&gt;
&lt;h2 id="passing-python-variables-into-javascript"&gt;Passing Python variables into JavaScript&lt;/h2&gt;
&lt;p&gt;Often you'll want to include Python data in your JavaScript code. Since &lt;code&gt;runJavaScript()&lt;/code&gt; takes a string, you can use Python string formatting to inject values:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;username = "admin"
message = "Welcome back!"

script = """
    document.getElementById("title").innerText = "%s";
    document.getElementById("content").innerText = "User: %s";
""" % (message, username)

self.browser.page().runJavaScript(script)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Be careful with special characters in your variables. If a string might contain quotes or newlines, you'll want to properly escape them. For simple, controlled values this approach works well. For more complex data, consider using &lt;code&gt;json.dumps()&lt;/code&gt; to safely serialize your Python values:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;import json

data = {"username": "admin", "message": "Welcome back!"}

script = """
    var data = %s;
    document.getElementById("title").innerText = data.message;
""" % json.dumps(data)

self.browser.page().runJavaScript(script)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Using &lt;code&gt;json.dumps()&lt;/code&gt; handles escaping automatically and is much safer when your data might contain unexpected characters.&lt;/p&gt;
&lt;h2 id="interacting-with-javascript-libraries-on-the-page"&gt;Interacting with JavaScript libraries on the page&lt;/h2&gt;
&lt;p&gt;When you load a web page that includes its own JavaScript libraries or APIs, you can call those functions directly from &lt;code&gt;runJavaScript()&lt;/code&gt;. This is where things get really powerful &amp;mdash; your Python application can drive any web-based interface.&lt;/p&gt;
&lt;p&gt;For example, if a loaded page has a JavaScript object called &lt;code&gt;app&lt;/code&gt; with a &lt;code&gt;sendMessage()&lt;/code&gt; method, you could call it like this:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;def send_message(self, text):
    script = """
        app.sendMessage(`%s`);
    """ % text
    self.browser.page().runJavaScript(script)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="things-to-keep-in-mind"&gt;Things to keep in mind&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Asynchronous execution.&lt;/strong&gt; &lt;code&gt;runJavaScript()&lt;/code&gt; is asynchronous. The JavaScript executes in the web engine's process, and your Python code continues running immediately. If you need the result, always use the callback form.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Page must be loaded.&lt;/strong&gt; Always wait for &lt;code&gt;loadFinished&lt;/code&gt; before running JavaScript. Any scripts executed before the page is ready will silently fail.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;String escaping.&lt;/strong&gt; When injecting Python strings into JavaScript, use &lt;code&gt;json.dumps()&lt;/code&gt; to handle escaping. This prevents bugs from quotes, backslashes, or newlines in your data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Security.&lt;/strong&gt; If you're loading external web pages (not ones you control), be cautious about what JavaScript you inject. Running arbitrary code on untrusted pages could have unintended consequences.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;runJavaScript()&lt;/code&gt;, your PyQt5 application can fully control any web-based interface embedded within it. Whether you're automating a web-based terminal, scraping data from a loaded page, or building a hybrid desktop-web application, this method gives you the bridge between Python and the browser engine. Once your application is ready, you can &lt;a href="https://www.pythonguis.com/tutorials/packaging-pyqt5-pyside2-applications-windows-pyinstaller/"&gt;package it for distribution with PyInstaller&lt;/a&gt;.&lt;/p&gt;
            &lt;p&gt;For an in-depth guide to building Python GUIs with PyQt5 see my book, &lt;a href="https://www.pythonguis.com/pyqt5-book/"&gt;Create GUI Applications with Python &amp; Qt5.&lt;/a&gt;&lt;/p&gt;
            </content><category term="pyqt5"/><category term="qtwebengine"/><category term="javascript"/><category term="qwebengineview"/><category term="python"/><category term="qt"/><category term="qt5"/></entry></feed>