A WKWebView runs its own JavaScript context, so the browser agent inside the page and the iOS SDK around it each open their own RUM session. A journey that crosses into embedded web content is otherwise recorded as two unrelated sessions with no shared identifier.

WebView tracking installs a bridge between the two. Events emitted by the page are re-attributed to the native session, producing a single timeline that spans the native screens, the web content, and the return path.

Before you start

The integration has three requirements:

  • The Atatus iOS SDK initialized with RUM enabled. See iOS Monitoring Setup.
  • The Atatus Browser Agent loaded on the pages rendered in the web view. Without it the page emits no events to correlate.
  • The AtatusWebViewTracking product added to your target.
Note:

WebView tracking is available on iOS and iPadOS. The module is empty on tvOS, which has no WebKit.

Setup

1. Add the product

With Swift Package Manager, add the AtatusWebViewTracking product to your target. With CocoaPods, declare the pod:

copy
icon/buttons/copy
pod 'AtatusWebViewTracking', '~> 1.0'

2. Enable tracking on the web view

Call WebViewTracking.enable before you load a URL, passing the hosts whose events should be correlated:

copy
icon/buttons/copy
import UIKit
import WebKit
import AtatusCore
import AtatusWebViewTracking

final class StoreViewController: UIViewController {
    private var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()

        webView = WKWebView(frame: view.bounds)
        view.addSubview(webView)

        WebViewTracking.enable(
            webView: webView,
            hosts: ["shop.example.com", "checkout.example.com"]
        )

        webView.load(URLRequest(url: URL(string: "https://shop.example.com/cart")!))
    }

    deinit {
        WebViewTracking.disable(webView: webView)
    }
}
Warning:

Enable before the first load. The bridge is injected as a user script that runs at document start, so a page that has already loaded never receives it. Calling enable a second time for the same web view is ignored with a console warning.

3. Disable it when the web view goes away

copy
icon/buttons/copy
WebViewTracking.disable(webView: webView)

This removes the bridge and the injected script. Call it when the web view is about to be released, in deinit or in viewWillDisappear, and pair it with an enable call if the screen can appear again.

4. Verify the correlation

Open the web view in your application, then locate the session in your Atatus dashboard. A correlated session interleaves native views and web page views on one timeline. Two separate sessions mean the bridge did not attach, which has three common causes:

  • The browser agent is not loaded on the page, so no web events are produced.
  • The document's host does not match an entry in hosts.
  • enable ran after the page had already loaded.

The Xcode console reports the rest. Enabling before Atatus.initialize(), enabling twice, or passing an invalid host each print a message that names the problem.

Match multiple hosts

List every origin the web view loads. A host is matched as given, and one wildcard is allowed per entry:

copy
icon/buttons/copy
WebViewTracking.enable(
    webView: webView,
    hosts: [
        "shop.example.com",
        "checkout.example.com",
        "*.preview.example.com"
    ]
)

A pattern must contain a dot and exactly one *, and the part after the * must start with a dot. *.example.com matches shop.example.com but not example.com itself, so list the bare host as well when you need both. Invalid entries are dropped with a console warning, and the rest still work.

Warning:

Restrict hosts to origins you control. The bridge is reachable from any page served by a listed host, so such a page can write events into your native RUM session.

What is bridged

Three kinds of event cross the bridge, each requiring the matching product on the native side:

Web event Native product required Result
Browser RUM events: views, actions, resources, errors, long tasks RUM.enable() Re-attributed to the native session and application
Browser logs Logs.enable() Carry the native session, view, and action
Browser session replay records SessionReplay.enable() Merged into the native replay, in place of the web view area

When a product is missing, the matching events are dropped and the console says which ones. Web activity also keeps the native session alive, so time spent in a web view does not let the session time out.

To sample the logs that come out of the page, pass logsSampleRate. It is a percentage, defaults to 100, and applies to web logs only:

copy
icon/buttons/copy
WebViewTracking.enable(
    webView: webView,
    hosts: ["shop.example.com"],
    logsSampleRate: 25
)

Session Replay in web views

A web view is recorded as a reserved area in the native replay, which the page fills in from its own side. For that to work, Session Replay must be enabled natively, the browser agent must be recording, and WebView tracking must be enabled for the page's host. See Session Replay.

Privacy settings are passed through to the page, so masking you configure natively also applies to the recorded web content.

Billing

Correlated web events are attributed to the existing native session rather than opening a second one, so WebView tracking does not increase your session count. Your browser RUM application continues to record its own sessions for users who reach the same pages in a desktop or mobile browser.

Objective-C

copy
icon/buttons/copy
@import AtatusWebViewTracking;

[ATWebViewTracking enableWithWebView:self.webView
                               hosts:[NSSet setWithObjects:@"shop.example.com", nil]
                      logsSampleRate:100];

// When the web view goes away
[ATWebViewTracking disableWithWebView:self.webView];

Objective-C has no default arguments, so pass every parameter. There is also an overload that takes an instanceName, for applications running more than one SDK instance.

Next steps