Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Binaries for programs and plugins
/webview_app
*.exe
*.exe~
*.dll
Expand Down
66 changes: 66 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,69 @@ Calling `Eval()` or `Dispatch()` before `Run()` does not work because the webvie

[go-docs]: https://pkg.go.dev/github.com/webview/webview_go
[webview]: https://github.com/webview/webview


### WebView UserAgent Example

This project demonstrates how to set a custom User-Agent string in webview_go.

It builds a simple Go application that shows the current User-Agent in the UI and verifies that it matches the value defined in the source code.

Requirements
Go 1.18+
C compiler (clang/gcc)
Linux:
libgtk-3-dev
libwebkit2gtk-4.0-dev
macOS: no additional dependencies

### Build

chmod +x build.sh
./build.sh

This will:
1. Install necessary dependencies (on Linux).
2. Compile main.go into an executable webview_app.

### Run

./webview_app

Expected behavior

When the application runs:
• A window will open with:
• A UserAgent section showing the custom value (e.g. MyCustomUserAgent/1.0).
• A button and counter to demonstrate bindings.

If you see your custom User-Agent displayed in the window, the implementation is correct

Troubleshooting

Linux:
1. Error: webkit2/webkit2.h: No such file or directory
-> Install missing GTK/WebKit dependencies:
sudo apt-get update
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev

2. Error: pkg-config not found
-> Install pkg-config:
sudo apt-get install -y pkg-config

3. Blank window / crash on startup
-> Ensure you are running inside a desktop environment with GTK/WebKit support.
-> On minimal VMs, install ubuntu-desktop or run inside an X11 session.

MacOS:
1. Error: ld: framework not found WebKit
-> Ensure you use clang (not gcc) when compiling.
-> Go automatically links against Cocoa/WebKit frameworks, so usually no manual fix is required.

2. Window opens but is empty
-> Sometimes macOS blocks WebKit initialization in sandboxed terminals. Try:
open ./webview_test

3. Custom UserAgent not applied
-> Make sure you call w.SetUserAgent("MyCustomUserAgent/1.0") before w.Navigate(...) or w.SetHtml(...)

21 changes: 21 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env bash
set -e

echo "[INFO] Installing dependencies..."

# Проверка платформы
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
sudo apt-get update
sudo apt-get install -y build-essential pkg-config libgtk-3-dev libwebkit2gtk-4.0-dev
echo "[INFO] Dependencies installed (Linux)"
elif [[ "$OSTYPE" == "darwin"* ]]; then
echo "[INFO] No dependencies required on macOS"
else
echo "[ERROR] Unsupported OS: $OSTYPE"
exit 1
fi

echo "[INFO] Building Go binary..."
go build -o webview_app ./examples/bind

echo "[INFO] Build complete. Run with ./webview_test"
10 changes: 8 additions & 2 deletions examples/bind/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@ package main

import webview "github.com/webview/webview_go"

const html = `<button id="increment">Tap me</button>
const html = `<h2>UserAgent:</h2>
<div id="ua"></div>
<button id="increment">Tap me</button>
<div>You tapped <span id="count">0</span> time(s).</div>
<script>
const [incrementElement, countElement] =
document.querySelectorAll("#increment, #count");

document.addEventListener("DOMContentLoaded", () => {
document.getElementById("ua").textContent = navigator.userAgent;

incrementElement.addEventListener("click", () => {
window.increment().then(result => {
countElement.textContent = result.count;
Expand All @@ -24,8 +29,9 @@ func main() {
var count uint = 0
w := webview.New(false)
defer w.Destroy()
w.SetTitle("Bind Example")
w.SetTitle("Bind and UserAgent Example")
w.SetSize(480, 320, webview.HintNone)
w.SetUserAgent("MyCustomUserAgent/1.0")

// A binding that increments a value and immediately returns the new value.
w.Bind("increment", func() IncrementResult {
Expand Down
42 changes: 42 additions & 0 deletions libs/webview/include/webview.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,13 @@ WEBVIEW_API void webview_set_title(webview_t w, const char *title);
WEBVIEW_API void webview_set_size(webview_t w, int width, int height,
webview_hint_t hints);

/**
* @param w The webview instance.
* @param user_agent The new user agent.
*/

WEBVIEW_API void webview_set_user_agent(webview_t w, const char *user_agent);

/**
* Navigates webview to the given URL. URL may be a properly encoded data URI.
*
Expand Down Expand Up @@ -1010,6 +1017,8 @@ if (status === 0) {\
void init(const std::string &js) { init_impl(js); }
void eval(const std::string &js) { eval_impl(js); }

void set_user_agent(const std::string &ua) { set_user_agent_impl(ua); }

protected:
virtual void navigate_impl(const std::string &url) = 0;
virtual void *window_impl() = 0;
Expand All @@ -1023,6 +1032,7 @@ if (status === 0) {\
virtual void set_html_impl(const std::string &html) = 0;
virtual void init_impl(const std::string &js) = 0;
virtual void eval_impl(const std::string &js) = 0;
virtual void set_user_agent_impl(const std::string &ua) = 0;

virtual void on_message(const std::string &msg) {
auto seq = json_parse(msg, "id", 0);
Expand Down Expand Up @@ -1352,6 +1362,16 @@ class gtk_webkit_engine : public engine_base {
}
}

void set_user_agent_impl(const std::string &ua) override {
if (!m_webview) return;

WebKitSettings *settings = webkit_web_view_get_settings(WEBKIT_WEB_VIEW(m_webview));
if (!settings) return;

webkit_settings_set_user_agent(settings, ua.c_str());
webkit_web_view_set_settings(WEBKIT_WEB_VIEW(m_webview), settings);
}

void navigate_impl(const std::string &url) override {
webkit_web_view_load_uri(WEBKIT_WEB_VIEW(m_webview), url.c_str());
}
Expand Down Expand Up @@ -1718,6 +1738,23 @@ class cocoa_wkwebview_engine : public engine_base {
nullptr);
}

void set_user_agent_impl(const std::string &ua) override {
objc::autoreleasepool pool;

if (!m_webview) return;

id configuration = objc::msg_send<id>(m_webview, "configuration"_sel);
if (!configuration) return;

id uaString = objc::msg_send<id>("NSString"_cls,
"stringWithUTF8String:"_sel,
ua.c_str());

objc::msg_send<void>(configuration,
"setApplicationNameForUserAgent:"_sel,
uaString);
}

private:
id create_app_delegate() {
objc::autoreleasepool arp;
Expand Down Expand Up @@ -3552,6 +3589,11 @@ WEBVIEW_API void webview_set_size(webview_t w, int width, int height,
static_cast<webview::webview *>(w)->set_size(width, height, hints);
}

WEBVIEW_API void webview_set_user_agent(webview_t w, const char *user_agent) {
if (!w || !user_agent) return;
static_cast<webview::webview *>(w)->set_user_agent(user_agent);
}

WEBVIEW_API void webview_navigate(webview_t w, const char *url) {
static_cast<webview::webview *>(w)->navigate(url);
}
Expand Down
19 changes: 15 additions & 4 deletions webview.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,17 @@ void CgoWebViewUnbind(webview_t w, const char *name);
*/
import "C"
import (
_ "github.com/webview/webview_go/libs/mswebview2"
_ "github.com/webview/webview_go/libs/mswebview2/include"
_ "github.com/webview/webview_go/libs/webview"
_ "github.com/webview/webview_go/libs/webview/include"
"encoding/json"
"errors"
"reflect"
"runtime"
"sync"
"unsafe"

_ "github.com/webview/webview_go/libs/mswebview2"
_ "github.com/webview/webview_go/libs/mswebview2/include"
_ "github.com/webview/webview_go/libs/webview"
_ "github.com/webview/webview_go/libs/webview/include"
)

func init() {
Expand Down Expand Up @@ -122,6 +123,9 @@ type WebView interface {

// Removes a callback that was previously set by Bind.
Unbind(name string) error

// Sets a user agent based on OS
SetUserAgent(ua string) error
}

type webview struct {
Expand Down Expand Up @@ -329,3 +333,10 @@ func (w *webview) Unbind(name string) error {
C.CgoWebViewUnbind(w.w, cname)
return nil
}

func (w *webview) SetUserAgent(ua string) error {
cua := C.CString(ua)
defer C.free(unsafe.Pointer(cua))
C.webview_set_user_agent(w.w, cua)
return nil
}