Set useragent in WKWebview

IosUser AgentWkwebview

Ios Problem Overview


How do I set a custom useragent string in a WKWebView? I'm trying to embed the version of my app so that my server-side can see what features are available. I found the following method:

let userAgent = "MyApp/1.33.7"
request.setValue(userAgent, forHTTPHeaderField: "User-Agent")

NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {(response, data, error) in
    let content = NSString(data: data, encoding: NSUTF8StringEncoding)
    self.web!.loadHTMLString(content!, baseURL: url)
}
self.web!.loadRequest(request);

But this means the useragent is only set for that single request. The first other request (e.g. a forward), will mean the useragent is reset to default again. How can I more permanently configure the wkwebview to use my custom useragent string?

Ios Solutions


Solution 1 - Ios

You'll be happy to hear that WKWebView just gained a customUserAgent property in iOS 9 and OSX 10.11

Example:

wkWebView.customUserAgent = "your agent" 

Solution 2 - Ios

Update:

As of iOS 9.0 it is possible to set the user agent directly (as stated in other answers). But it is important to note that setting it will completely override the default user agent. If for some reason you need to just append a custom user agent use one of the following approaches.

webView.evaluateJavaScript("navigator.userAgent") { [weak webView] (result, error) in
    if let webView = webView, let userAgent = result as? String {
        webView.customUserAgent = userAgent + "/Custom Agent"
    }
}

or by using a sacrificial UIWebView

webView.customUserAgent = (UIWebView().stringByEvaluatingJavaScript(from: "navigator.userAgent") ?? "") + "/Custom agent"


Old answer:

As noted in my comment you can use the same approach as described here: https://stackoverflow.com/questions/478387/change-user-agent-in-uiwebview-iphone-sdk

Now if you want to get the user agent you need to have an instance of a WKWebView and evaluate this javascript on it:

navigator.userAgent

The problem is that if you set a custom user agent after a WKWebView has been instantiated you will always get the same user agent. To solve this problem you have to reinstantiate the web view. Here is a sample how this might look:

self.wkWebView = [[WKWebView alloc] initWithFrame:self.view.bounds];
__weak typeof(self) weakSelf = self;

[self.wkWebView evaluateJavaScript:@"navigator.userAgent" completionHandler:^(id result, NSError *error) {
    __strong typeof(weakSelf) strongSelf = weakSelf;
        
    NSString *userAgent = result;
    NSString *newUserAgent = [userAgent stringByAppendingString:@" Appended Custom User Agent"];
        
    NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:newUserAgent, @"UserAgent", nil];
    [[NSUserDefaults standardUserDefaults] registerDefaults:dictionary];

    strongSelf.wkWebView = [[WKWebView alloc] initWithFrame:strongSelf.view.bounds];
        
    // After this point the web view will use a custom appended user agent
    [strongSelf.wkWebView evaluateJavaScript:@"navigator.userAgent" completionHandler:^(id result, NSError *error) {
        NSLog(@"%@", result);
    }];
}];

The code above will log:

Mozilla/5.0 (iPhone; CPU iPhone OS 8_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Mobile/12B411 Appended Custom User Agent
Alternative

This could be made even simpler by using a "sacrificial" UIWebView since it evaluates javascript synchronously.

UIWebView *webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
NSString *userAgent = [webView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];
NSString *newUserAgent = [userAgent stringByAppendingString:@" Appended Custom User Agent"];
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:newUserAgent, @"UserAgent", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:dictionary];

self.wkWebView = [[WKWebView alloc] initWithFrame:self.view.bounds];
[self.wkWebView evaluateJavaScript:@"navigator.userAgent" completionHandler:^(id result, NSError *error) {
    NSLog(@"%@", result);
}];

Which logs the same thing:

Mozilla/5.0 (iPhone; CPU iPhone OS 8_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Mobile/12B411 Appended Custom User Agent

Right now UIWebView and WKWebView use the same user agent but this approach might cause problems if that changes in the future.

Solution 3 - Ios

Custom User Agent

To set a custom User Agent you can use customUserAgent property:

let webConfiguration = WKWebViewConfiguration()
let webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.customUserAgent = "ExampleApp/1.0 (iPhone)"

Available: iOS 9+

Append to the default User Agent

To append a custom string at the and of the default user agent you can use applicationNameForUserAgent property:

let webConfiguration = WKWebViewConfiguration()
webConfiguration.applicationNameForUserAgent = "ExampleApp/1.0 (iPhone)"
let webView = WKWebView(frame: .zero, configuration: webConfiguration)

Then it will look for example like:

Mozilla/5.0 (iPhone; CPU iPhone OS 11_2 like Mac OS X) AppleWebKit/604.4.7
(KHTML, like Gecko) ExampleApp/1.0 (iPhone)
                    ^^^^^^^^^^^^^^^^^^^^^^^

Available: iOS 9+

Solution 4 - Ios

WKWebView Swift 3 example:

let userAgentValue = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/603.2.4 (KHTML, like Gecko) Version/10.1.1 Safari/603.2.4"
webView.customUserAgent = userAgentValue


Note to those who try to do this using Storyboard or Interface Builder: Unfortunately, Xcode doesn't currently support using WKWebView in Storyboards (Xcode version 8.3.2), so you have to add the web view manually in your code.

UIWebView Swift 3 example:

UserDefaults.standard.register(defaults: ["UserAgent": userAgentValue])

Solution 5 - Ios

the default User-Agent in WKWebView is as

Mozilla/5.0 (iPhone; CPU iPhone OS 13_3 like Mac OS X)

You can customize the WKWebView User-Agent

webView.customUserAgent = "zgpeace User-Agent"

I write a demo for WKWebView:

func requestWebViewAgent() {
        print("requestWebViewAgent")
        
        let webView = WKWebView()
        webView.evaluateJavaScript("navigator.userAgent") { (userAgent, error) in
            if let ua = userAgent {
                print("default WebView User-Agent > \(ua)")
            }
            
            // customize User-Agent
            webView.customUserAgent = "zgpeace User-Agent"
        }
    }

Warning: "User-Agent" is nil from webView, when webView is released. You can set webView object as property to keep the webView.

NSURLSession send User-Agent by default.
default User-Agent style like.

"User-Agent" = "UserAgentDemo/1 CFNetwork/1121.2.1 Darwin/19.2.0";

We can customize the User-Agent.

let config = URLSessionConfiguration.default
config.httpAdditionalHeaders = ["User-Agent": "zgpeace User-Agent"]

I write a demo for URLSession in the below.

     func requestUrlSessionAgent() {
        print("requestUrlSessionAgent")
        
        let config = URLSessionConfiguration.default
        // default User-Agent: "User-Agent" = "UserAgentDemo/1 CFNetwork/1121.2.1 Darwin/19.2.0";
        // custom User-Agent
        config.httpAdditionalHeaders = ["User-Agent": "zgpeace User-Agent"]
        let session = URLSession(configuration: config)

        let url = URL(string: "https://httpbin.org/anything")!
        var request = URLRequest(url: url)
        request.httpMethod = "GET"
        
        let task = session.dataTask(with: url) { data, response, error in

            // ensure there is no error for this HTTP response
            guard error == nil else {
                print ("error: \(error!)")
                return
            }
            
            // ensure there is data returned from this HTTP response
            guard let content = data else {
                print("No data")
                return
            }
            
            // serialise the data / NSData object into Dictionary [String : Any]
            guard let json = (try? JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers)) as? [String: Any] else {
                print("Not containing JSON")
                return
            }
            
            print("gotten json response dictionary is \n \(json)")
            // update UI using the response here
        }

        // execute the HTTP request
        task.resume()
        
    }

NSURLConnection send User-Agent by default.
default User-Agent style like.

"User-Agent" = "UserAgentDemo/1 CFNetwork/1121.2.1 Darwin/19.2.0";

We can customize the User-Agent.

urlRequest.setValue("URLConnection zgpeace User-Agent", forHTTPHeaderField: "User-Agent")

I write a demo for URLConnection in the below.

func requestUrlConnectionUserAgent() {
    print("requestUrlConnectionUserAgent")
    
    let url = URL(string: "https://httpbin.org/anything")!
    var urlRequest = URLRequest(url: url)
    urlRequest.httpMethod = "GET"
    // default User-Agent: "User-Agent" = "UserAgentDemo/1 CFNetwork/1121.2.1 Darwin/19.2.0";
    urlRequest.setValue("URLConnection zgpeace User-Agent", forHTTPHeaderField: "User-Agent")
    
    NSURLConnection.sendAsynchronousRequest(urlRequest, queue: OperationQueue.main) { (response, data, error) in
        // ensure there is no error for this HTTP response
        guard error == nil else {
            print ("error: \(error!)")
            return
        }
        
        // ensure there is data returned from this HTTP response
        guard let content = data else {
            print("No data")
            return
        }
        
        // serialise the data / NSData object into Dictionary [String : Any]
        guard let json = (try? JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers)) as? [String: Any] else {
            print("Not containing JSON")
            return
        }
        
        print("gotten json response dictionary is \n \(json)")
        // update UI using the response here
    }
    
  }

Demo in github:
https://github.com/zgpeace/UserAgentDemo.git

Solution 6 - Ios

In my swift 3 case, I need entire app using a custom userAgent, here is my solution in AppDelegate. Here using UIWebview is because I don't need to set up the WKWebViewConfiguration, because I just only need the userAgent string

 fileprivate func setupGlobalWebviewUserAgent() {
    
    let webview = UIWebView()
    var newUserAgent = webview.stringByEvaluatingJavaScript(from: "navigator.userAgent")
    newUserAgent = newUserAgent?.appending("custom user agent")
    let dictionary = Dictionary(dictionaryLiteral: ("UserAgent", newUserAgent))
    UserDefaults.standard.register(defaults: dictionary)
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPvelView Question on Stackoverflow
Solution 1 - IosEraView Answer on Stackoverflow
Solution 2 - IosNikola LajicView Answer on Stackoverflow
Solution 3 - IosMarián ČernýView Answer on Stackoverflow
Solution 4 - IosAlexView Answer on Stackoverflow
Solution 5 - IosZgpeaceView Answer on Stackoverflow
Solution 6 - IosStephen ChenView Answer on Stackoverflow