---
updatedAt: 2025-06-16T21:15:15.000Z
---

Fetch the complete documentation index at: https://docs.ultralig.ht/llms.txt. Use this file to discover all available pages before exploring further.

# Calling a JS Function from C++

Let's say that we have a page with the following HTML/JS on it:

```html
<html>
  <head>
    <script>
      function ShowMessage(message)
      {
        document.getElementById('msg').innerHTML = message;
      }
    </script>
  </head>
  <body>
    <div id="msg"></div>
  </body>
</html>
```

Our goal is to call the JavaScript function `ShowMessage()` from C++.

## Calling the JS Function with EvaluateScript()

The easiest way to call `ShowMessage()` from C++ is by evaluating a string of JavaScript.

```cplusplus
///
/// Use LoadListener::OnDOMReady to wait for the DOM to load.
///
void MyApp::OnDOMReady(View* caller,
                       uint64_t frame_id,
                       bool is_main_frame,
                       const String& url) {
  if (!is_main_frame)
    return;
  
  ///
  /// Call ShowMessage() by evaluating a string of JavaScript
  ///
  caller->EvaluateScript("ShowMessage('Howdy!')");
  
}
```

## Calling the JS Function with JSObjectCallAsFunction()

For greater performance and control, you can pass arguments directly to the Function object using JavaScriptCore's [`JSObjectCallAsFunction()`](https://ultralig.ht/api/cpp/1_4_0/_j_s_object_ref_8h.html#a4cb5561ed2976191f3462f2a13e39b16).

This API function also offers exception handling, overriding the `this` object, and more.

```cplusplus
#include <JavaScriptCore/JSRetainPtr.h>

// Use LoadListener::OnDOMReady to wait for the DOM to load.
void MyApp::OnDOMReady(View* caller,
                       uint64_t frame_id,
                       bool is_main_frame,
                       const String& url) {
  if (!is_main_frame)
    return;
  
  // Acquire the JS execution context for the current page.
  auto scoped_context = caller->LockJSContext();
  
  // Typecast to the underlying JSContextRef.
  JSContextRef ctx = (*scoped_context);
  
  // Get the ShowMessage function by evaluating a script. We could have
  // also used JSContextGetGlobalObject() and JSObjectGetProperty() to 
  // retrieve this from the global window object as well.
  
  // Create our string of JavaScript, automatically managed by JSRetainPtr
  JSRetainPtr<JSStringRef> str = adopt(
    JSStringCreateWithUTF8CString("ShowMessage"));

	// Evaluate the string "ShowMessage"
  JSValueRef func = JSEvaluateScript(ctx, str.get(), 0, 0, 0, 0);

  // Check if 'func' is actually an Object and not null
  if (JSValueIsObject(ctx, func)) {
    
    // Cast 'func' to an Object, will return null if typecast failed.
    JSObjectRef funcObj = JSValueToObject(ctx, func, 0);

    // Check if 'funcObj' is a Function and not null
    if (funcObj && JSObjectIsFunction(ctx, funcObj)) {
      
      // Create a JS string from null-terminated UTF8 C-string, store it
      // in a smart pointer to release it when it goes out of scope.
      JSRetainPtr<JSStringRef> msg = 
        adopt(JSStringCreateWithUTF8CString("Howdy!"));

      // Create our list of arguments (we only have one)
      const JSValueRef args[] = { JSValueMakeString(ctx, msg.get()) };

      // Count the number of arguments in the array.
      size_t num_args = sizeof(args) / sizeof(JSValueRef*);

      // Create a place to store an exception, if any
      JSValueRef exception = 0;

      // Call the ShowMessage() function with our list of arguments.
      JSValueRef result = JSObjectCallAsFunction(ctx, funcObj, 0, 
                                                 num_args, args, 
                                                 &exception);

      if (exception) {
        // Handle any exceptions thrown from function here.
      }
      
      if (result) {
        // Handle result (if any) here.
      }
    }
  }
}
```