For AI agents: a documentation index is available at /docs/llms.txt. Append .md to any page URL for markdown, or send Accept: text/markdown.
Session Replay iOS Standalone SDK
This article covers how to install Session Replay for iOS using the standalone SDK. Choose this option if you use a provider other than Amplitude for in-product analytics.
If your app already uses an Amplitude iOS SDK, use the Session Replay iOS SDK Plugin instead.
If you use Segment through the Analytics-Swift SDK and Amplitude (Actions) destination, choose the Segment Plugin.
Session Replay and performance
Amplitude built Session Replay to minimize impact on the performance of the iOS apps in which it's installed by:
- Asynchronously processing replay data, to avoid blocking the main user interface thread. The main thread must be used to interact with the view hierarchy, but all processing is performed on a background queue.
- Using batching and lightweight compression to reduce the number of network connections and bandwidth.
- Optimizing view hierarchy processing. Contact Amplitude if you experience issues with hierarchy processing.
Report issues
To report issues with Session Replay for iOS, go to the AmplitudeSessionReplay-ios GitHub repository.
Before you begin
The Session Replay Standalone SDK requires that:
- Your application runs on iOS or iPadOS.
- You track sessions with a timestamp or a custom string session ID that you can pass to the SDK. You inform the SDK whenever the session identifier changes.
- You can provide a device ID to the SDK.
- The
Session IDandDevice IDyou pass to the Standalone SDK match those sent as event properties to Amplitude.
The Standalone SDK doesn't provide session management. Your application or a third-party integration must update the SDK with changes to Session ID and Device ID.
Supported iOS versions
Session Replay supports a minimum target version of iOS 13.
Quickstart
Add the latest version of Session Replay to your project dependencies.
Add Session Replay as a dependency in your Package.swift file, or the Package list in Xcode.
dependencies: [
.package(url: "https://github.com/amplitude/AmplitudeSessionReplay-iOS", from: "0.12.8")
]
To integrate with third-party analytics, use the AmplitudeSessionReplay target.
.product(name: "AmplitudeSessionReplay", package: "AmplitudeSessionReplay")
Configure your application code.
- Create a
SessionReplayinstance. Pass the API key, and a session identifier and device identifier if available. - Call
sessionReplay.start()to begin capturing replays. The standalone SDK doesn't start capture automatically, so you must callstart()once you set the device and session identifiers. - When the session identifier or device identifier changes, pass the new value to Amplitude with
sessionReplay.sessionIdorsessionReplay.deviceId, respectively. For string session IDs, usesessionReplay.customSessionIdinstead. Refer to Custom session IDs. - Collect Session Replay properties to send with other event properties using
sessionReplay.additionalEventProperties.
import AmplitudeSessionReplay
import ThirdPartyAnalytics
// Initialize the standalone session replay SDK
let sessionReplay = SessionReplay(apiKey: amplitude.apiKey,
deviceId: DEVICE_ID,
sessionId: SESSION_ID,
sampleRate: 0.1)
// Start capturing replays. The standalone SDK doesn't start automatically.
sessionReplay.start()
// Track an event
// Get session replay properties for this session
var eventProperties = event.eventProperties ?? [:]
eventProperties.merge(sessionReplay.additionalEventProperties) { (current, _) in current }
event.eventProperties = eventProperties
ThirdPartyAnalytics.track(event)
// Handle session ID changes
// Whenever the session ID changes
ThirdPartyAnalytics.setSessionId(sessionId)
// Update the session ID in session replay
sessionReplay.sessionId = ThirdPartyAnalytics.getSessionId()
// Handle device ID changes
// Whenever the device ID changes
ThirdPartyAnalytics.setDeviceId(deviceId)
// Update the device ID in session replay
sessionReplay.deviceId = ThirdPartyAnalytics.getDeviceId()
Configuration
Pass the following configuration options when you initialize the Session Replay SDK.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
apiKey | String | Yes | n/a | Sets the Amplitude API key. |
deviceId | String | No | nil | Sets an identifier for the device running your application. Set it before start() to associate replay data with the device. |
sessionId | Int64 | No | -1 | Sets an identifier for the user's current session. Set it before start() to associate replay data with the session. The value must use milliseconds since epoch (Unix timestamp). To use a string session ID instead, set the customSessionId property after initialization. Refer to Custom session IDs. |
sampleRate | Float | No | 0 | Controls how many sessions to select for replay collection. Use a decimal between 0 and 1, for example 0.4, to set the fraction of sessions Amplitude randomly selects. Over a large number of sessions, 0.4 selects 40% of those sessions. |
optOut | Bool | No | false | Sets permission to collect replays for sessions. A value of true prevents Amplitude from collecting session replays. |
logger | CoreLogger? | No | nil | Sets a custom logger to emit log messages to a destination you choose. When nil, Session Replay logs errors through an OS logger. |
serverZone | ServerZone | No | .US | EU or US. Sets the Amplitude server zone. Set this to EU for Amplitude projects created in the EU data center. |
enableRemoteConfig | Bool | No | true | Enables or disables remote configuration for this instance of Session Replay. |
maskLevel | MaskLevel | No | .medium | Sets how much on-screen content Session Replay masks. Use .light, .medium, or .conservative. For more detail, refer to Mask level. |
captureWebViews | Bool | No | false | Enables capture of web view content. By default, Session Replay blocks web views. |
webviewMappings | [String: String] | No | [:] | Maps substrings in captured web view content to replacement values. When you enable captureWebViews, Session Replay applies each entry as a case-insensitive find-and-replace on the web view recording data before upload. This is an advanced option; most apps leave it empty. |
recordLogOptions.logCountThreshold | Int | No | 1000 | Configures the maximum number of logs per session. |
recordLogOptions.maxMessageLength | Int | No | 2000 | Configures the maximum length of a log message. |
quality | QualityProfile | No | .high | Controls capture and encoding quality (for example, frame rate and image resolution). Use .low, .medium, or .high to balance replay fidelity with performance and storage. Use QualityProfile.automatic to let the SDK choose a profile based on the device. |
uploadConfig | UploadConfig | No | UploadConfig() | Controls when Session Replay uploads data. Use UploadConfig(disableMeteredUploads: true) to pause uploads on metered networks (for example, cellular). |
Custom session IDs
Session Replay for iOS version 0.11.2 and later supports string session IDs, for example UUIDs, through the customSessionId property. Use a custom session ID if your project defines sessions with a custom event property instead of a timestamp-based session_id.
The initializer accepts only a numeric sessionId. To use a string value, set customSessionId on the instance after you create it, and update it whenever your custom session changes:
let sessionReplay = SessionReplay(apiKey: API_KEY,
deviceId: DEVICE_ID,
sampleRate: 0.1)
// Set a string session ID instead of the numeric sessionId
sessionReplay.customSessionId = "ef197fc7-a46f-4e6c-a77f-8d90c17065c0"
sessionReplay.start()
// Whenever your custom session changes
sessionReplay.customSessionId = ThirdPartyAnalytics.getCustomSessionId()
sessionId and customSessionId are two views of the same underlying value, which the SDK stores as a string:
- Setting
sessionIdreplaces the current custom session ID with the numeric value. When you use custom session IDs, updatecustomSessionIdinstead ofsessionIdwhenever the session changes. - When the stored value isn't numeric, the
sessionIdproperty returns-1. ReadcustomSessionIdto get the current value. - Setting a different value ends the current replay and starts a new one.
For Session Replay to match custom sessions reliably, custom session IDs must follow these constraints:
- The value can't contain
/. Session Replay uses/as a delimiter in the session replay ID, which has the format<deviceId>/<sessionId>. - The value can only contain the characters
a-z A-Z 0-9 _ - . | @ : =. - The value must match the session-defining property you send on events to Amplitude. For more information, refer to Session matching.
Change masking at runtime
Set privacyConfig to change the automatic masking level while the app runs.
sessionReplay.privacyConfig = PrivacyConfig(maskLevel: .conservative)
If Remote Config supplies a masking level, it takes precedence. The SDK retains the local privacyConfig value and applies it when Remote Config doesn't supply a masking level or when you disable Remote Config.
Remote configuration
Enable remote configuration to set Sample Rate and Masking Level in Amplitude.
Remote configuration and testing
With enableRemoteConfig set to true, settings you define in Amplitude take precedence over settings you define locally in the SDK. For this reason, while testing your application, you should disable remote configuration to ensure you can set sampleRate to 1, and ensure you capture test sessions.
Block on-screen data
Session Replay supports three ways to block sensitive on-screen data. Masking setting for WebViews is in the Web view support section.
Mask level
Session Replay for iOS supports three levels of masking, configurable with the maskLevel option.
Use this option in the Session Replay configuration.
| Mask level | Description |
|---|---|
light | Masks all passwords, email addresses, credit card numbers, and phone numbers. |
medium | Masks all editable text views. |
conservative | Masks all text views. |
Privacy methods for UIKit
Session Replay provides an extension on UIView to manage privacy. Import the Session Replay library to access it.
import AmplitudeSessionReplay
| Variable | Description |
|---|---|
amp_isBlocked | Set view.amp_isBlocked to selectively replace a view and its subviews with a placeholder in session replays. UITextViews and UITextFields are automatically blocked. To unblock a view that is masked by default, set the this value to false |
Privacy Modifiers for SwiftUI
Session Replay provides an extension on View to manage privacy. Import the Session Replay Library to access it.
import AmplitudeSessionReplay
| Modifier | Description |
|---|---|
amp_setBlocked(_ blocked: Bool) | Add the amp_setBlocked() modifier to a View to selectively replace a view and its subviews with a placeholder in session replays. To unblock a view that is masked by default, set the this value to false |
User opt-out
Session Replay provides an opt-out configuration option. Passing optOut: true during initialization prevents Amplitude from collecting session replays. For example:
// Pass a boolean value to indicate a user's opt-out status
let sessionReplay = SessionReplay(apiKey: API_KEY,
optOut: true,
/* other session replay options */)
EU data residency
Session Replay is available to Amplitude Customers who use the EU data center. Set the serverZone configuration option to EU during initialization. For example:
// Set serverZone to EU
let sessionReplay = SessionReplay(apiKey: API_KEY,
serverZone: .EU,
/* other session replay options */)
Sampling rate
By default, Session Replay captures 0% of sessions for replay. Use your SDK's sampleRate configuration option to set the proportion of sessions to capture.
For manual and dynamic sampling, quota planning, and quota accounting, go to Configure Session Replay sampling.
// This configuration samples 1% of all sessions
let sessionReplay = SessionReplay(apiKey: API_KEY,
sampleRate: 0.01,
/* other session replay options */)
Recording quality
Choose a quality profile to balance replay fidelity with performance and storage. Lower profiles use a lower capture frame rate and image resolution. Higher profiles use a higher frame rate and resolution. Use QualityProfile.automatic to let the SDK select a profile based on the device (for example, high on newer devices, lower on older ones).
// Use automatic profile selection based on device
let sessionReplay = SessionReplay(apiKey: API_KEY,
deviceId: DEVICE_ID,
sessionId: SESSION_ID,
quality: .automatic,
/* other session replay options */)
// Or set a fixed profile (low, medium, or high)
let sessionReplay = SessionReplay(apiKey: API_KEY,
deviceId: DEVICE_ID,
sessionId: SESSION_ID,
quality: .medium,
/* other session replay options */)
You can also change the profile for an existing standalone instance:
sessionReplay.quality = .medium
Disable uploads on metered networks
Avoid using the user's cellular data by pausing Session Replay uploads while the device uses a metered network. Session Replay still records data locally. Uploads resume when the device reconnects to Wi‑Fi or another non-metered connection.
let sessionReplay = SessionReplay(apiKey: API_KEY,
deviceId: DEVICE_ID,
sessionId: SESSION_ID,
uploadConfig: UploadConfig(disableMeteredUploads: true),
/* other session replay options */)
Disable replay collection
After you enable Session Replay, it runs on your app until either:
- The user leaves your app.
- You call
sessionReplay.stop().
Call sessionReplay.stop() before a user navigates to a restricted area of your app to disable replay collection while the user is in that area.
Call sessionReplay.start() to re-enable replay collection when the user returns to an unrestricted area of your app. Because start() and stop() resume and pause capture on the same instance, you can call them on screen transitions to record only the screens you choose.
Flush recorded data
Call flush() to ask the standalone SDK to flush recorded replay data. This is useful when your host analytics client flushes and you want to flush Session Replay at the same point.
sessionReplay.flush()
You can also use a feature flag product like Amplitude Experiment to create logic that enables or disables replay collection based on criteria like location. For example, create a feature flag that targets a specific user group, and add it to your initialization logic:
import AmplitudeSessionReplay
import ThirdPartyAnalytics
let sessionReplay = SessionReplay(apiKey: amplitude.apiKey,
deviceId: DEVICE_ID,
sessionId: SESSION_ID,
sampleRate: 1.0)
if (nonEUCountryFlagEnabled) {
sessionReplay.start()
}
Web view support (Beta)
By default, Session Replay blocks web views in a capture. To enable capture of all WebView components, set captureWebViews to true in the Session Replay configuration.
To mask specific WebView components, use the privacy methods described in Block on-screen data.
// UIKit
webView.amp_isBlocked = false
Map View Support (Alpha)
Session Replay supports capturing map views in iOS applications. To enable map view capture, unmask the map view in your implementation.
// UIKit
mapView.amp_isBlocked = false
// SwiftUI
Map().amp_setBlocked(false)
Log Recording
Availability
AmplitudeSessionReplay 0.8.0 and later support log recording.
Session Replay supports recording logs in iOS applications. Configure the limits with recordLogOptions when you initialize the integration, then send log messages through recordLog(level:message:date:).
import AmplitudeSessionReplay
let sessionReplay = SessionReplay(
apiKey: API_KEY,
recordLogOptions: .init(logCountThreshold: 2000, maxMessageLength: 4000)
)
sessionReplay.recordLog(level: .error, message: "This is an error log")
If you have implemented a log system, you can make single-point modifications to integrate log recording functionality. See the following examples for more information.
CocoaLumberjack
If you use CocoaLumberjack, you can integrate it with a custom logger provider.
class AmplitudeLogRecordLogger: DDAbstractLogger {
private weak var plugin: SessionReplayPlugin?
init(_ plugin: SessionReplayPlugin) {
self.plugin = plugin
}
override func log(message logMessage: DDLogMessage) {
let recordLevel: RecordLogLevel
switch logMessage.flag {
case .error:
recordLevel = .error
case .warning:
recordLevel = .warn
case .info:
recordLevel = .log
default:
return
}
plugin?.recordLog(level: recordLevel,
message: logMessage.message,
date: logMessage.timestamp)
}
}
let sessionReplayPlugin = AmplitudeSwiftSessionReplayPlugin()
amplitude.add(plugin: sessionReplayPlugin)
DDLog.add(AmplitudeLogRecordLogger(sessionReplayPlugin))
React Native
If you use console log or react-native-logs with consoleTransport, you can integrate it with RCTAddLogFunction.
RCTAddLogFunction { level, source, fileName, lineNumber, message in
let recordLevel: RecordLogLevel
switch level {
case .error:
recordLevel = .error
case .warning:
recordLevel = .warn
case .info:
recordLevel = .log
case .fatal:
recordLevel = .error
case .trace:
recordLevel = .init("trace")
default:
return
}
self.sessionReplayPlugin.recordLog(level: recordLevel, message: message)
}
Data retention, deletion, and privacy
Review consent guidance when you implement capture.
Retention period
For native and Flutter SDK retention guidance and the effective date of changes, go to the Session Replay data lifecycle reference.
DSAR API
For replay metadata returned by the DSAR API, go to Session Replay DSAR metadata.
Data deletion
For user and project deletion behavior, go to Session Replay data deletion.
Bot filter
For bot filtering and property-filter restrictions, go to Session Replay bot filtering.
Session Replay storage
If a user opts out tracking in your app, use the optOut configuration option to disable replay collection for that user.
Session Replay temporarily stores replay data data on the file system before it is uploaded. At every initialization, the least recent replays are trimmed to bring the total disk usage down to a maximum size.
Known limitations
Keep the following limitations in mind as you implement Session Replay:
Session Replay doesn't stitch together replays from a single user across multiple projects. For example:
- You instrument multiple apps as separate Amplitude projects with Session Replay enabled in each.
- A known user begins on one app, and then switch to another.
- Amplitude captures both sessions.
- The replay for each session is available for view in the corresponding host project.
The User Sessions chart doesn't show session replays if your organization uses a custom session definition.
Session Replay cannot capture the following iOS views:
- Out-of-process iOS views, such as SFSafariViewController
- AVPlayerLayer backed views
Troubleshooting
For more information about individual statuses and errors, see the Session Replay Ingestion Monitor.
Multiple Amplitude instances
Session Replay supports attaching to a single instance of the Amplitude SDK. If you have more than one instance instrumented in your application, make sure to start Session Replay on the instance that most relates to your project.
Replay length and session length don't match
In some scenarios, the length of a replay may exceed the time between the [Amplitude] Start Session and [Amplitude] End Session events. This happens when a user closes the [Amplitude] End Session occurs, but before the iOS SDK and Session Replay middleware can process it. When the user uses the app again, the SDK and middleware process the event and send it to Amplitude, along with the replay. You can verify this scenario occurs if you see a discrepancy between the End Session Client Event Time and the Client Upload Time.
Session replays don't appear in Amplitude
Session replays may not appear in Amplitude due to:
- Lack of connectivity
- No events triggered through the iOS SDK in the current session
- Sampling
Lack of connectivity
Ensure your app has access to the internet then try again.
No events triggered through the iOS SDK in the current session
Session Replay requires that at least one event in the user's session has the [Amplitude] Session Replay ID property. If you instrument your events with an analytics provider other than Amplitude, the iOS SDK may send only the default Session Start and Session End events, which don't include this property.
For local testing, you can force a Session Start event to ensure that Session Replay functions.
- In Amplitude, in the User Lookup Event Stream, you should see a Session Start event that includes the
[Amplitude] Session Replay IDproperty. After processing, the Play Session button should appear for that session.
Sampling
As mentioned above, the default sampleRate for Session Replay is 0. Update the rate to a higher number. For more information see, Sampling rate.
Some sessions don't include the Session Replay ID property
Session replay doesn't require that all events in a session have the [Amplitude] Session Replay ID property, only that one event in the session has it. Reasons why [Amplitude] Session Replay ID may not be present in an event include:
- The user may have opted out or the session may not be part of the sample set given the current
sampleRate. Increasing thesampleRatecaptures more sessions. - Amplitude events may still send through your provider, but
additionalEventPropertiesdoesn't return the[Amplitude] Session Replay IDproperty. This can result fromoptOutandsampleRateconfiguration settings. Check thatoptOutandsampleRateare set to include the session.
Session Replay processing errors
In general, replays should be available within minutes of ingestion. Delays or errors may be the result of one or more of the following:
- Mismatching API keys or Device IDs. This can happen if Session Replay and standard event instrumentation use different API keys or Device IDs.
- Session Replay references the wrong project.
- Short sessions. If a users bounces within a few seconds of initialization, the SDK may not have time to upload replay data.
- Replays older than the set retention period (defaults to 90 days).
Report an Issue
If you encounter any issues with Session Replay that aren't covered in the troubleshooting guide above, please report them on our GitHub repository.
When creating an issue, please include:
- A clear description of the problem
- Steps to reproduce the issue
- Expected vs actual behavior
- SDK version you're using
- Any relevant error messages or logs
Was this helpful?