WKNavigationDelegate is useful for tracking when user navigates to a different URL with functions such as webView(_:,decidePolicyFor:,decisionHandler:). But if the site uses HTML History API to the location (common with React and friends), it doesn’t pick it up. Here’s how to support it:

1. This JavaScript to dispatch a message to the WKWebView instance’s message handler:

 // So we can detect when sites use History API to generate the page location. Especially common with React and similar frameworks
 ;(function() {
   var pushState = history.pushState;
   var replaceState = history.replaceState;

   history.pushState = function() {
     pushState.apply(history, arguments);
     window.dispatchEvent(new Event('locationchange'));
   };

   history.replaceState = function() {
     replaceState.apply(history, arguments);
     window.dispatchEvent(new Event('locationchange'));
   };

   window.addEventListener('popstate', function() {
     window.dispatchEvent(new Event('locationchange'))
   });
 })();

 window.addEventListener('locationchange', function(){
   webkit.messageHandlers.locationChanged.postMessage(window.location.href)
 })

2. Inject the JavaScript above is to install a user script:

let webViewConfig = WKWebViewConfiguration()
let userScript = WKUserScript(source: js, injectionTime: .atDocumentStart, forMainFrameOnly: false)
webViewConfig.userContentController.addUserScript(userScript)
//Install handler (below)
let webView = WKWebView(frame: .zero, configuration: config)  

3. Specify the message handler:

webViewConfig.userContentController.add(messageHandler, name: "locationChanged")

4. Handle the message, getting the URL:

 extension SomeClass: WKScriptMessageHandler {
     func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
         //get the URL from `message` or just from `webView.url`
     }
 }

Thanks to the suggestion from @hishnash.