SessionReplaySDK

main

πŸ“Ή Lightweight iOS SDK for recording user sessions with video, touch events, console logs & network requests. Privacy-first with automatic PII masking. Pure Swift, zero dependencies.
AlmoutasemNabil/SessionReplaySDK

SessionReplaySDK

Version 0.2.0 Platform iOS 15+ Swift 5.9+ MIT License SPM Compatible

A powerful, privacy-focused session replay SDK for iOS applications.

Capture user sessions with video recording, touch visualization, console logs, and network requestsβ€”all synchronized for powerful debugging and UX analysis.

A complete demo application SessionReplayDemo


Features

Feature Description
Video Recording H.264 encoded screen capture with configurable quality and frame rate
Touch Visualization Record and overlay touch events with visual indicators
Console Log Capture Automatically intercept print(), NSLog(), and stderr
Network Tracking Monitor all HTTP/HTTPS requests (works with Alamofire SSL pinning)
User Identification Attach user info (userId, email, custom data) to sessions
Auto Start/Stop Configurable automatic session lifecycle management
Crash Recovery Periodic checkpoints to recover sessions after crashes
App Groups Share session data between app and extensions
Screen Transitions Track navigation flow between screens
Synchronized Timeline All events timestamped for video sync playback
Local Storage Save sessions locally with JSON metadata
Cloud Upload Multipart form data upload to your backend
Privacy Controls Redact headers, exclude URLs, sanitize logs
SwiftUI & UIKit Full support with view modifiers and components

Installation

Swift Package Manager

Xcode:

  1. Go to File > Add Package Dependencies
  2. Enter: https://github.com/AlmoutasemNabil/SessionReplaySDK
  3. Select version and add to your target

Package.swift:

dependencies: [
    .package(url: "https://github.com/AlmoutasemNabil/SessionReplaySDK", from: "0.2.0")
]

Quick Start

1. Configure on App Launch

import SessionReplaySDK

@main
struct MyApp: App {
    init() {
        var config = SessionReplayConfig()
        config.captureFrameRate = 10
        config.jpegCompressionQuality = 0.7
        config.autoStartOnLaunch = false    // Manual control
        config.enableCrashRecovery = true   // Save on crash
        config.debugLogging = false         // Disable in production

        SessionReplaySDK.configure(
            videoConfig: config,
            logConfig: SessionLoggerConfig()
        )
    }

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

2. Logs-Only Mode (No Video)

For lightweight logging without video recording:

var config = SessionReplayConfig()
config.enableVideoRecording = false  // Disable video, capture logs only

SessionReplaySDK.configure(
    videoConfig: config,
    logConfig: SessionLoggerConfig()
)

// Start/stop works the same way
SessionReplaySDK.start()
// ... session captures console logs and network requests only
SessionReplaySDK.stop()

3. Identify Users

// After user logs in
SessionReplaySDK.identifyUser(
    userId: "user_123",
    email: "user@example.com",
    name: "John Doe",
    additionalInfo: ["plan": "premium", "branchId": "branch_456"]
)

// Or set custom info directly
SessionReplaySDK.setUserInfo([
    "userId": "123",
    "email": "user@example.com",
    "customField": "value"
])

3. Start/Stop Recording

// Start recording
SessionReplaySDK.startSession()

// Stop recording
SessionReplaySDK.stopSession()

// Check status
if SessionReplaySDK.isRecording {
    print("Recording in progress...")
}

4. Track Screens (SwiftUI)

struct HomeView: View {
    var body: some View {
        NavigationView {
            // Your content
        }
        .trackScreen("HomeScreen")
    }
}

5. Custom Logging

SessionReplaySDK.debug("Debug: User opened settings")
SessionReplaySDK.info("Info: Purchase completed")
SessionReplaySDK.warning("Warning: Low storage")
SessionReplaySDK.error("Error: Network timeout")

6. Upload Sessions

// Configure endpoint
SessionReplaySDK.configureUpload(
    baseURL: URL(string: "https://api.yourserver.com/sessions")!,
    apiKey: "your-api-key"
)

// Upload specific session
SessionReplaySDK.uploadSession(sessionId: "abc-123") { result in
    switch result {
    case .success(let response):
        print("Uploaded: \(response.sessionId)")
    case .failure(let error):
        print("Failed: \(error)")
    }
}

// Upload all sessions
SessionReplaySDK.uploadAllSessions { results in
    let successful = results.filter { $0.1.isSuccess }.count
    print("Uploaded \(successful)/\(results.count) sessions")
}

Configuration

Video (SessionReplayConfig)

Option Default Description
enableVideoRecording true Enable video recording (false for logs-only mode)
captureFrameRate 1 Frames per second (1-30)
jpegCompressionQuality 0.3 JPEG quality (0.0-1.0)
captureScale 1.0 Resolution scale (0.25-1.0)
videoBitrate 75,000 H.264 bitrate in bps
captureTouches true Record touch events
showTouchIndicators true Draw touch dots on video
maskSensitiveViews true Mask marked sensitive views
sensitiveViewMaskColor .gray Color for masked areas
autoMaskTextFields true Auto-mask text inputs
autoMaskSecureTextFields true Auto-mask password fields
autoMaskViewClasses [] Custom classes to auto-mask
maxStorageSize 50MB Max local storage
storageDirectory Documents Custom storage location

Auto Start/Stop (SessionReplayConfig)

Option Default Description
autoStartOnLaunch false Start recording on app launch
autoStopOnBackground true Stop when app enters background
autoStopOnTerminate true Emergency save on terminate
enableCrashRecovery true Save checkpoints periodically
crashRecoveryInterval 5.0 Seconds between checkpoints
debugLogging true Print debug logs to console

Logging (SessionLoggerConfig)

Option Default Description
captureConsoleLogs true Capture stdout/stderr
captureNetworkRequests true Intercept URLSession
minimumLogLevel .debug Minimum capture level
maxLogMessageLength 2000 Truncate long messages
maxBodySize 100KB Max request/response body
redactedHeaders [auth, cookie...] Headers to redact
excludedURLPatterns [] URL regex patterns to skip
logSanitizer nil Custom sanitization closure
excludeSDKLogs true Exclude SDK internal logs from session data

Upload (SessionUploadConfig)

Option Default Description
baseURL Required Your upload endpoint
apiKey nil Bearer token auth
additionalHeaders [:] Custom headers
maxRetries 3 Retry on failure
timeoutInterval 120s Request timeout
deleteAfterUpload false Remove local files

App Group Support

Share session data between your main app and extensions:

// Configure with App Group
SessionReplaySDK.configureWithAppGroup(
    "group.com.yourcompany.yourapp",
    videoConfig: config,
    logConfig: logConfig
)

// Or manually set storage directory
var config = SessionReplayConfig()
if let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.yourapp") {
    config.storageDirectory = containerURL.appendingPathComponent("SessionReplays", isDirectory: true)
}
SessionReplaySDK.configure(videoConfig: config)

User Identification

Attach user info to sessions for easier debugging:

// Simple identification
SessionReplaySDK.identifyUser(
    userId: "user_123",
    email: "user@example.com",
    name: "John Doe"
)

// With additional custom data
SessionReplaySDK.identifyUser(
    userId: "cashier_456",
    email: "cashier@foodics.com",
    additionalInfo: [
        "branchId": "branch_123",
        "role": "cashier",
        "shiftId": "shift_789"
    ]
)

// Set individual values
SessionReplaySDK.setUserInfo(key: "subscriptionTier", value: "premium")

// Clear on logout
SessionReplaySDK.clearUserInfo()

// Access current info
let currentUser = SessionReplaySDK.userInfo

User info is saved in both metadata.userInfo and root userInfo in the session JSON.

Crash Recovery

The SDK automatically saves session checkpoints:

var config = SessionReplayConfig()
config.enableCrashRecovery = true      // Enable checkpoints
config.crashRecoveryInterval = 3.0     // Save every 3 seconds

SessionReplaySDK.configure(videoConfig: config)

// Check for incomplete sessions after app restart
let incompleteSessions = SessionReplaySDK.recoverIncompleteSessions()
for sessionId in incompleteSessions {
    print("Found incomplete session: \(sessionId)")
    // Video segments may be available even if session didn't complete
}

Session Data Format

{
  "sessionId": "550e8400-e29b-41d4-a716-446655440000",
  "startTime": "2025-01-27T10:30:00Z",
  "endTime": "2025-01-27T10:35:00Z",
  "durationMs": 300000,
  "frameCount": 3000,
  "videoSegments": ["session_segment0.mp4"],
  "userInfo": {
    "userId": "user_123",
    "email": "user@example.com",
    "branchId": "branch_456"
  },
  "touches": [
    {"timestamp": 1500, "location": {"x": 200, "y": 400}, "phase": 0}
  ],
  "logs": [
    {"timestamp": 2000, "level": "info", "message": "Button tapped", "source": "stdout"}
  ],
  "networkRequests": [
    {"timestamp": 3000, "method": "GET", "url": "https://api.example.com/data", "statusCode": 200, "duration": 150}
  ],
  "screenTransitions": [
    {"timestamp": 0, "screenName": "HomeScreen"}
  ],
  "metadata": {
    "appVersion": "1.0.0",
    "osVersion": "17.0",
    "deviceModel": "iPhone15,2",
    "locale": "en_US",
    "userInfo": {
      "userId": "user_123",
      "email": "user@example.com"
    }
  }
}

Built-in Components

SwiftUI

// Recording controls
RecordingControlView()

// Sessions list with upload
SessionsListView()

// Activity timeline (live during recording)
LiveActivityView()

// Activity timeline (for completed sessions)
ActivityTimelineView(session: selectedSession)

// Session player
SessionReplayViewer(session: selectedSession)

// Screen tracking modifier
.trackScreen("ScreenName")

// Touch indicators overlay
.withTouchIndicators()

// Mark sensitive content
.sensitiveContent()

UIKit

// Base view controller with tracking
class MyVC: SessionReplayViewController {
    override var screenName: String { "MyScreen" }
}

// Debug view controller
let debugVC = SessionReplayDebugViewController()
present(debugVC, animated: true)

// Mark sensitive views
passwordField.markAsSensitive()

Network Capture

The SDK captures all URLSession-based network requests, including:

  • Direct URLSession usage
  • Alamofire (including custom sessions with SSL pinning)
  • FNetwork and other URLSession-based libraries

No additional configuration neededβ€”network capture works automatically.

Upload API

The SDK sends multipart form data:

Field Type Description
sessionId String Session identifier
video File MP4 video file
metadata File JSON metadata file

Expected Response:

{
  "sessionId": "...",
  "videoURL": "https://...",
  "metadataURL": "https://...",
  "message": "Success"
}

Testing Upload:

Privacy & Security

Sensitive Data Masking

The SDK automatically masks sensitive content in screen recordings:

Automatic Masking (enabled by default):

  • Secure text fields (password inputs)
  • Regular text fields and text views
  • Views marked with markAsSensitive() or .sensitiveContent()

Configuration Options:

var config = SessionReplayConfig()
config.maskSensitiveViews = true          // Enable/disable masking
config.sensitiveViewMaskColor = .gray     // Mask color
config.autoMaskTextFields = true          // Auto-mask UITextField/UITextView
config.autoMaskSecureTextFields = true    // Auto-mask password fields
config.autoMaskViewClasses = ["CreditCardView"]  // Custom classes to mask

Manual Masking - UIKit:

// Mark any UIView as sensitive
passwordField.markAsSensitive()
creditCardView.markAsSensitive()

// Check if view is marked
if myView.isSensitive { ... }

Manual Masking - SwiftUI:

// Mark any SwiftUI view as sensitive
SecretDataView()
    .sensitiveContent()

// With custom mask color
PaymentForm()
    .sensitiveContent(maskColor: .black)

Additional Privacy Features

  • Header Redaction: Authorization, Cookie, API keys auto-redacted from network logs
  • URL Exclusion: Regex patterns to exclude specific endpoints
  • Log Sanitization: Custom closure for PII removal
  • Local-First: All data stored locally, upload is opt-in
  • No Dependencies: Pure Swift, no third-party tracking code

Architecture

SessionReplaySDK/
β”œβ”€β”€ Core/
β”‚   β”œβ”€β”€ Models.swift              # Data structures
β”‚   β”œβ”€β”€ SessionReplayManager.swift # Main controller
β”‚   └── VideoWriter.swift         # H.264 encoding
β”œβ”€β”€ Logging/
β”‚   β”œβ”€β”€ SessionLogger.swift       # Console capture
β”‚   └── NetworkInterceptor.swift  # URL monitoring
β”œβ”€β”€ Upload/
β”‚   └── SessionUploader.swift     # Cloud upload
β”œβ”€β”€ Integration/
β”‚   β”œβ”€β”€ SwiftUIIntegration.swift  # SwiftUI support
β”‚   └── UIKitIntegration.swift    # UIKit support
└── SessionReplaySDK.swift        # Public facade

Changelog

Version 0.2.0

  • User Identification: New identifyUser() and setUserInfo() APIs to attach user data to sessions
  • App Group Support: Configure custom storage directory for sharing data between app and extensions
  • Auto Start/Stop: New config options for automatic session lifecycle management
  • Crash Recovery: Periodic checkpoints to recover sessions after crashes
  • Network Capture Improvements: Works with all URLSession-based networking including Alamofire with SSL pinning
  • Activity Timeline Views: New LiveActivityView and ActivityTimelineView SwiftUI components
  • Debug Logging Control: New debugLogging config to reduce console noise in production
  • Removed Verbose Touch Logging: Touch began/ended events no longer spam the console

Version 0.1.0

  • Initial release
  • Video recording with H.264 encoding
  • Touch event capture and visualization
  • Console log interception
  • Network request monitoring
  • SwiftUI and UIKit integration
  • Cloud upload support

Contributing

We welcome contributions!

  1. Fork the repository
  2. Create feature branch: git checkout -b feature/amazing
  3. Commit changes: git commit -m 'Add amazing feature'
  4. Push: git push origin feature/amazing
  5. Open Pull Request

Please include tests and update documentation.

Requirements

  • iOS 15.0+
  • Swift 5.9+
  • Xcode 15.0+

Support


πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.


Made with ❀️ by AlmoutasemNabil

Β© 2026 AlmoutasemNabil. All rights reserved.

⭐ Star this repo if you find it helpful!

Description

  • Swift Tools 5.9.0
View More Packages from this Author

Dependencies

  • None
Last updated: Sun Feb 22 2026 17:34:19 GMT-1000 (Hawaii-Aleutian Standard Time)