AtatusSessionReplay, and runs on top of RUM.
Session Replay is available on iOS and iPadOS only. The module is empty on tvOS, so
SessionReplay.enable does not exist there.How it records
The SDK does not record the screen as video. It walks the view hierarchy and captures the shape of each view: its frame, background, border, corner radius, opacity, and the type-specific details such as label text, switch position, or image content. Those become wireframes that the player reassembles into a replay. Two consequences follow from that design:- Masking happens on the device, before anything is written to disk. Text you mask never leaves the device at all.
- Snapshots are taken when the screen changes, at most ten times a second, and not at all while the screen is static.
Prerequisites
- RUM is set up and tracking views. See iOS Monitoring Setup.
- iOS 15.0 or later.
- The
AtatusSessionReplayproduct is added to your target.
Setup
1. Add the product
With Swift Package Manager, add theAtatusSessionReplay product to your target. With CocoaPods, declare the pod:
2. Enable Session Replay
Enable it after RUM, in the same place you initialize the SDK:SessionReplay.enable never throws. When something is wrong, such as the SDK not being initialized yet or the product being enabled twice, it prints the reason to the Xcode console and carries on. Check the console first when no replay appears.Configuration
Sampling
The replay rate applies to sessions RUM has already sampled, and the two multiply. With a RUMsessionSampleRate of 80 and a replaySampleRate of 20, one in five recorded sessions has a replay, which is 16 percent of all sessions:
replaySampleRate: 0 does not register the product at all, so SessionReplay.startRecording() has nothing to start. To keep recording off until the user asks for it, use startRecordingImmediately: false with a rate above 0.Start and stop recording yourself
To hold recording back until a point you choose, for example until the user opts in, enable the product without starting it:.notGranted or call Atatus.clearAllData().
Mask sensitive content
Text and input
textAndInputPrivacyLevel divides text into four kinds and treats each differently:
Static text is masked character by character, so
"Jane Doe" becomes "xxxx xxx". Word lengths and spacing survive, which keeps the layout faithful, so treat the length of a string as something that does leave the device.
Sensitive fields are always ***, at every level and with no way to reveal them. A field counts as sensitive when it is a secure text entry field, or when its textContentType is a password, one-time code, email address, telephone number, credit card number, postal address, or postal code.
At .maskAll and .maskAllInputs, the state of a control is masked too: a switch loses its on and off position, a slider loses its value, a stepper and a date picker lose their selection, and a segmented control loses the selected segment.
Images
imagePrivacyLevel decides which images are recorded:
.maskNonBundledOnly is the useful middle ground: your interface keeps its icons while user content, such as a profile photo or a document preview, stays masked.
In SwiftUI the SDK cannot tell whether an image came from your bundle, so
.maskNonBundledOnly falls back to a size test: a raster image is recorded only when it is 100 points or smaller on both sides, and vector images are always recorded. Mask SwiftUI images you care about explicitly rather than relying on that heuristic.Touches
touchPrivacyLevel is .hide by default, which records no touch coordinates at all. Set .show to draw touch indicators in the replay:
Override privacy for one view
Global levels are the floor, not the ceiling. Any UIKit view can carry its own levels, which its subviews inherit:hide, which cannot be undone by a child. A hidden view is recorded as a solid placeholder, so the replay keeps the space it occupied without any of its content.
An override changes the text of a switch, slider, stepper, segmented control, or date picker, but not its state. Those controls read the global
textAndInputPrivacyLevel for their value, so set the global level or hide the view if the value itself is sensitive.SwiftUI
SwiftUI recording is experimental and off by default. With the flag off, a SwiftUI screen is recorded as a single placeholder, which makes replays of a SwiftUI application close to useless. Turn it on to record the view tree:SessionReplayPrivacyView, which needs iOS 16 or later:
Web views and system screens
AWKWebView is recorded as a reserved area that the web content fills in from the page side. Install the browser agent in the page and enable WebView tracking natively:
Safari, and the share sheet as one labelled Activity. Alerts are recorded normally.
Offline behavior
Records are compressed and written to disk, then uploaded when the network is reachable and the device is not low on battery or in Low Power Mode. Replay data is held for up to five hours, which is shorter than the retention for other events, so a device offline for longer than that loses the oldest part of the recording. Everything else uploads when connectivity returns.Objective-C
Session Replay is available to Objective-C withAT-prefixed types:
startRecordingImmediately and customEndpoint are properties rather than initializer parameters in Objective-C, and SessionReplayPrivacyView has no Objective-C equivalent because it is SwiftUI only.
Next steps
- Review what RUM collects in Configuration Options.
- Link web content to the native session with WebView Tracking.
- Jump from an error to its replay with Error Tracking.