Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
a4e6572
✨ Implement preview experience using qr code
motasem-userpilot Jun 30, 2026
dd0520d
πŸ› avoid preview dismissal side effects and seen content.
motasem-userpilot Jul 7, 2026
7b617a1
✨ Added offline event persistence and restore support, including auto…
motasem-userpilot Jul 8, 2026
26af41a
Merge branch 'main' into 1.3.0
motasem-userpilot Jul 8, 2026
a331680
Merge branch '1.3.0' into 1.4.0
motasem-userpilot Jul 8, 2026
0b85598
πŸ”€ merge BRs
motasem-userpilot Jul 8, 2026
10516d9
Merge branch 'main' into 1.3.0
motasem-userpilot Jul 13, 2026
31de0b2
πŸ› Fix sending events in preview mode for thankyou screen
motasem-userpilot Jul 13, 2026
f2dc033
πŸ› Preserve preview sessions across lifecycle changes
motasem-userpilot Jul 14, 2026
092066f
πŸ› Improve experience deduplication with seen-status checks
motasem-userpilot Jul 20, 2026
8526bb8
🚸 Add full featured ConfigActivity
motasem-userpilot Jul 21, 2026
dd32929
✨ Send identify once per screen when user data is unchanged and re-sy…
motasem-userpilot Aug 12, 2026
3092b43
πŸ”€ Merge branch 'main' into 1.3.0
motasem-userpilot Aug 26, 2026
506e10a
πŸ”€ Merge branch 'feat/identify-refresh' into 1.4.0
motasem-userpilot Aug 26, 2026
b7fc0c1
πŸ™ˆ Update gitignore file
motasem-userpilot Aug 26, 2026
c57af98
πŸš‘οΈ fix(socket): Serialize socket lifecycle and guard shared state
motasem-userpilot Aug 26, 2026
5efad37
πŸ› fix(extensions): Reuse a single background dispatch queue
motasem-userpilot Aug 26, 2026
f9b8ce2
πŸ› fix(socket): Capture the receive task before detaching it
motasem-userpilot Aug 26, 2026
746e32c
πŸ™ˆ Update gitignore file
motasem-userpilot Aug 26, 2026
9aa4842
πŸ”€ Merge branch 'hot-fix/socket-connection' into 1.3.0
motasem-userpilot Aug 26, 2026
61d4aab
πŸ› fix(autocapture): Restore text and accessibility policy helpers
motasem-userpilot Aug 27, 2026
22ccc07
πŸš‘οΈ fix(socket): Serialize socket lifecycle and guard shared state
motasem-userpilot Aug 27, 2026
1834195
πŸ”§ chore(utilities): Name the remaining dispatch queue labels
motasem-userpilot Aug 27, 2026
616ecae
🚚 refactor(utilities): Drop the AutoCaptureConstants typealias
motasem-userpilot Aug 27, 2026
7fba6a6
πŸ”’οΈ fix(autocapture): Enforce capture policy on text and label payloads
motasem-userpilot Aug 27, 2026
c6123e3
πŸ› fix(experiences): Bring forward seen-status dedup and preview sessions
motasem-userpilot Aug 27, 2026
c5e794e
πŸ› fix(experiences): Stop preview thank-you screens from sending events
motasem-userpilot Aug 27, 2026
aa50580
⚰️ refactor(remote): Remove the empty SDKSettingsDetector stub
motasem-userpilot Aug 27, 2026
04d609d
βœ… test(analytics): Cover the identify refresh state machine
motasem-userpilot Aug 27, 2026
64b1011
βœ… test(analytics): Repair the publish helper and extend coverage
motasem-userpilot Aug 27, 2026
371746b
βœ… test(utilities): Remove the timing race from the flush test
motasem-userpilot Aug 27, 2026
0a6d2ff
✨ feat(api): Enable interaction value capture by default
motasem-userpilot Aug 27, 2026
45ba228
πŸ”§ chore(gitignore): Stop tracking locally generated agent specs
motasem-userpilot Aug 27, 2026
a93a994
πŸ”§ ci: Add green-gate scripts and harden Actions workflows
motasem-userpilot Aug 31, 2026
95acb6e
πŸ“ docs: Add wrapper-impact checks to the PR template
motasem-userpilot Aug 31, 2026
27a9564
πŸ”§ chore: Ignore locally generated agent specs
motasem-userpilot Aug 31, 2026
9aac2ed
πŸ”€ Merge branch 'feat/enhance-demo-app-integration' into 1.4.0
motasem-userpilot Aug 31, 2026
e23acbc
πŸ”’οΈ fix(Remote): Stop logging remote request URLs
motasem-userpilot Aug 31, 2026
87df35e
♻️ refactor(Environment): Route preview content API by environment
motasem-userpilot Sep 2, 2026
2766e12
πŸ› fix(socket): Release the connect gate and preserve shutdown during …
motasem-userpilot Sep 2, 2026
5426307
πŸ”€ Merge branch '1.3.0' into 1.4.0
motasem-userpilot Sep 3, 2026
2259c96
πŸ”€ Merge branch 'main' into 1.4.0
motasem-userpilot Sep 3, 2026
87d13c9
πŸ”– chore(release): Bump version to 1.4.0
motasem-userpilot Sep 3, 2026
357e254
πŸ› fix(analytics): Keep queued events through a user switch
motasem-userpilot Sep 8, 2026
5fc5be3
πŸ”§ chore(sample): List configurations first on the home screen
motasem-userpilot Sep 8, 2026
b65ed4c
πŸ› fix(Experiences): Marshal idle overlay hiding onto the main thread
motasem-userpilot Sep 10, 2026
c7f1768
πŸ› fix(Experiences): Tear the overlay window down with its owner
motasem-userpilot Sep 10, 2026
cfbe87a
πŸ› fix(PushNotification): Hold a push opened before the SDK is configured
motasem-userpilot Sep 10, 2026
cc4f179
πŸ“ docs(docc): Note that the url scheme drops the STG- prefix
motasem-userpilot Sep 10, 2026
643d505
πŸ› fix(DeepLink): Match the scheme against the token as it was given
motasem-userpilot Sep 11, 2026
88fa652
✨ feat(Analytics): Re-state the user before a screen reload
motasem-userpilot Sep 13, 2026
7f98e8c
✨ feat(Analytics): Add requestIdentifyBeforeScreen config flag
motasem-userpilot Sep 13, 2026
c04ea99
✨ feat(sample): Add Debug and Auto Capture hubs with QA screens
motasem-userpilot Sep 13, 2026
93dc5cf
πŸ”₯ chore(sample): Remove Socket Race crash repro harness
motasem-userpilot Sep 13, 2026
d496625
πŸ› fix(AutoCapture): Resolve target_text at row level, not leaf level
motasem-userpilot Sep 14, 2026
d0537ac
✨ feat(sample): Rebuild the demo app UI in code and add QA harnesses
motasem-userpilot Sep 14, 2026
80944f8
πŸ› fix(Analytics): Send internal SDK events after offline sync finishes
motasem-userpilot Sep 14, 2026
76ae189
πŸ› fix(Analytics): Guard the SDK event cache with a lock
motasem-userpilot Sep 15, 2026
5bd6d3b
πŸ› fix(Analytics): Drain SDK events cached after the queue empties
motasem-userpilot Sep 15, 2026
6a43c6c
βœ… test(Analytics): Cover the cached SDK event drain
motasem-userpilot Sep 15, 2026
6fb24c0
♻️ refactor: Hold cached SDK events in a generic EventQueue
motasem-userpilot Sep 15, 2026
399d478
πŸ› fix(Utilities): Guard the multicast delegate list with a lock
motasem-userpilot Sep 15, 2026
9ed4cc5
♻️ refactor(AutoCapture): Use the SDK's own locking primitives
motasem-userpilot Sep 15, 2026
02d9e8a
πŸ› fix(Utilities): Always cancel a pending delay through its queue
motasem-userpilot Sep 15, 2026
6c99863
♻️ refactor(Utilities): Keep the multicast lock out of invoke's scope
motasem-userpilot Sep 15, 2026
6e7350e
chore: ignore local plan/ folder
motasem-userpilot Sep 16, 2026
75470b9
πŸ› fix(Experiences): Keep suppressed NPS from blocking track content
motasem-userpilot Sep 17, 2026
36ffe42
πŸ’‘ docs(Experiences): Simplify overlay window comments
motasem-userpilot Sep 17, 2026
a2bdb38
πŸ› fix(Analytics): Clear seen content when the user navigates offline
motasem-userpilot Sep 20, 2026
eeb620d
πŸ”§ chore: Ignore local GitHub Actions cleanup files
motasem-userpilot Sep 20, 2026
623fd82
πŸ› fix(Experiences): Keep the NPS close button clear of the progress bar
motasem-userpilot Sep 20, 2026
6742ba2
πŸ› fix(Analytics): Drop the post-dismissal screen event while offline
motasem-userpilot Sep 21, 2026
1f4561f
πŸ› fix(Analytics): Flush cached SDK events before the screen message
motasem-userpilot Sep 21, 2026
fc07fd3
βœ… test(Analytics): Pin cached SDK event retention across socket close
motasem-userpilot Sep 21, 2026
939f606
πŸ”§ ci: Rename the CI workflow to Quality Gate
motasem-userpilot Sep 21, 2026
b2d8f8d
πŸ”§ ci: Rename the CI workflow file to quality-gate.yml
motasem-userpilot Sep 21, 2026
97fcec6
✨ feat: Persist and replay internal SDK events while offline
motasem-userpilot Sep 21, 2026
72264a0
πŸ› fix(PushNotification): Do not gate notification taps on the socket
motasem-userpilot Sep 21, 2026
b8f306a
♻️ refactor(Database): Mirror the Android package layout
motasem-userpilot Sep 21, 2026
64ea7d0
πŸ› fix: Hold deep links until the host can route them
motasem-userpilot Sep 21, 2026
61a524f
docs: sync mobile integration guidance
motasem-userpilot Sep 22, 2026
4e29619
πŸ› fix(monitor): Resume on didBecomeActive, not willEnterForeground
motasem-userpilot Sep 22, 2026
d35079b
πŸ› fix(monitor): Guard the app-active flag across threads
motasem-userpilot Sep 22, 2026
9826fe0
πŸ› fix(monitor): Guard the session-start flag across threads
motasem-userpilot Sep 23, 2026
65363dc
♻️ refactor: Restore APP_TOKEN placeholders
motasem-userpilot Sep 23, 2026
65da305
πŸ› fix(Monitor): Recheck reachability when offline events arrive
motasem-userpilot Sep 25, 2026
f38f221
πŸ› fix(AutoCapture): Honor redaction on table title labels
motasem-userpilot Sep 25, 2026
55e8ad7
πŸ› fix(Analytics): Reject autocapture events without a screen
motasem-userpilot Sep 25, 2026
37bc71f
πŸ› fix(Analytics): Keep offline replay within the current user
motasem-userpilot Sep 25, 2026
8731504
πŸ› fix(Socket): Keep message references unique across threads
motasem-userpilot Sep 25, 2026
0466155
πŸ› fix(Analytics): Serialize identify before screen through the queue
motasem-userpilot Sep 25, 2026
d08cfe6
βœ… test: Strengthen SDK assertions and remove placeholder cases
motasem-userpilot Sep 25, 2026
537cc1d
πŸ’₯ refactor(api)!: Remove identify-before-screen configuration
motasem-userpilot Sep 25, 2026
8715e94
πŸ› fix(Analytics): Queue generated screens until acknowledged
motasem-userpilot Sep 26, 2026
64d574a
πŸ› fix(Analytics): Preserve identity across background transitions
motasem-userpilot Sep 26, 2026
c797da6
πŸ› fix(Experiences): Settle preview sessions after dismissal
motasem-userpilot Sep 27, 2026
10b3181
πŸ› fix(Experiences): Skip preview reloads for deep links
motasem-userpilot Sep 27, 2026
ab4d038
πŸ› fix(Analytics): Clear stale SDK requests on user changes
motasem-userpilot Sep 27, 2026
22d6a74
πŸ› fix(Analytics): Preserve metadata when replaying offline screens
motasem-userpilot Sep 27, 2026
e9dd0a1
πŸ› fix(Experiences): Keep NPS suppression across preview sessions
motasem-userpilot Sep 27, 2026
c947f93
πŸ› fix(Experiences): Preserve pending triggers and cached requests
motasem-userpilot Sep 27, 2026
bec2a78
βœ… test(Utilities): Reject preview links from other environments
motasem-userpilot Sep 27, 2026
c532340
βœ… test(Experiences): Stabilize pending experience gate tests
motasem-userpilot Sep 27, 2026
1324076
πŸ› fix(AutoCapture): Disable interaction value capture by default
motasem-userpilot Sep 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#
# Only the SDK is built here β€” the Sample/ apps are covered by publish-sample.yml.

name: CI
name: Quality Gate

on:
pull_request:
Expand All @@ -25,7 +25,7 @@ on:

# πŸ›‘ A new push to the same PR/branch supersedes the previous run
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
Expand Down
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ fastlane/test_output
# Mac OS X
*.DS_Store

# AI agent tooling (Cursor / Claude / local agent memory)
# AI agent tooling (local while evaluating β€” not tracked)
# Keeps files on disk across branch switches; use git rm --cached if they were previously tracked.
.agents/
.claude/
.cursor/
Expand All @@ -72,3 +73,8 @@ CLAUDE.md

# Locally generated agent specs/plans β€” not project documentation
docs/superpowers/
plan/

# Local GitHub Actions cleanup helper and audit records
/scripts/cleanup-github-actions.py
/.local/github-actions-cleanup/
41 changes: 35 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Userpilot iOS SDK

![version](https://img.shields.io/github/v/tag/Userpilot/ios-sdk?label=version)
[![Documentation](https://img.shields.io/badge/Documentation-blue.svg)](https://docs.userpilot.com/article/313-install-userpilot-on-your-ios-app)
[![Documentation](https://img.shields.io/badge/Documentation-blue.svg)](https://docs.userpilot.com/developer/installation/mobile/ios/installation)
[![Swift Package Manager compatible](https://img.shields.io/badge/Swift%20Package%20Manager-compatible-brightgreen.svg)](https://github.com/apple/swift-package-manager)
[![CocoaPods compatible](https://img.shields.io/badge/CocoaPods-compatible-red.svg)](https://cocoapods.org/pods/Userpilot)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/Userpilot/ios-sdk/blob/main/LICENSE)
Expand All @@ -25,6 +25,8 @@ This document provides a step-by-step walkthrough of the installation and initia
- [Initializing](#initializing)
- [Using the SDK](#using-the-SDK)
- [Configurations](#configurations-optional)
- [Scan QR Code for Review](#scan-qr-code-for-review)
- [Offline Mode](#offline-mode)
- [Auto Capture](#auto-capture)
- [Push Notification](#push-notification)
- [Multi-Instance Support](#multi-instance-support)
Expand Down Expand Up @@ -66,6 +68,8 @@ Before you begin, ensure your iOS project meets the following requirements:

Once integrated, the Userpilot SDK is available throughout your application.

See the official [iOS SDK release notes](https://docs.userpilot.com/developer/installation/mobile/ios/mobile-ios-release-notes) for version history and upgrade details.

### Initializing

To use Userpilot, initialize it once in your App Delegate or Scene Delegate during app launch. This ensures the SDK is ready as soon as your app starts. Replace `<APP_TOKEN>` with your Application Token, which can be fetched from your [Environments Page](https://run.userpilot.io/environment).
Expand Down Expand Up @@ -187,11 +191,13 @@ userpilot.triggerExperience("<EXPERIENCE_ID>")

If you have additional configuration needs, you can pass a custom configuration when initializing Userpilot. You can enable logging, provide navigation and experience delegates, and set up analytics listeners.

Interaction value capture is disabled by default. Call `.enableInteractionValueCapture(true)` on the configuration to capture control values when interaction autocapture is enabled.

```swift
userpilot = Userpilot(
config: Userpilot.Config(token: "APP_TOKEN")
.logging(true) // Enable or disable logging.
.enableUseInAppBrowser(enabled: true) // Enable Open external link In-app browser using SFSafariViewController.
.logging(enabled: true) // Enable or disable logging.
.enableUseInAppBrowser(true) // Enable Open external link In-app browser using SFSafariViewController.
.disableRequestPushNotificationsPermission() // Disable SDK push permission request flow (default false).
)
userpilot.navigationDelegate = self
Expand All @@ -210,7 +216,18 @@ public protocol UserpilotNavigationDelegate: AnyObject {
}
```

The Userpilot SDK automatically handles navigation if you haven't implemented the `UserpilotNavigationHandler`. When a deep link is external, the SDK will handle it appropriately. For complete control over link handling, you can override the `UserpilotNavigationHandler` protocol. This allows you to customize the behavior for all types of links as per your requirements.
Implement `UserpilotNavigationDelegate` to control link handling. Without a delegate, the SDK opens custom schemes through the system and web links through the system browser or the configured in-app browser.

Assign `userpilot.navigationDelegate` immediately after initializing the SDK,
and keep a strong reference to the delegate because the SDK holds it weakly.
Navigation callbacks run on the main thread. In SDK 1.4.0 and later, the latest
link received during initialization is held until a delegate is assigned or the
next main-queue turn after initialization. If no delegate is assigned, the SDK
uses its normal URL-opening behavior. This startup delay does not wait for a
router that your app initializes asynchronously; buffer the URL in your delegate
if your navigation UI is not ready.

See the [SDK Callbacks guide](https://docs.userpilot.com/developer/installation/mobile/ios/callbacks#navigation-handler).

#### Analytics Delegate

Expand Down Expand Up @@ -289,17 +306,29 @@ public protocol UserpilotExperienceDelegate: AnyObject {
}
```

### Scan QR Code for Review

To review a draft Flow or Survey on a real device, configure the Userpilot custom URL scheme and scan the experience QR code from the Mobile Builder. The QR code opens a Userpilot preview link in your app, and the SDK loads the draft experience for review.

See the official [Custom URL Scheme guide](https://docs.userpilot.com/developer/installation/mobile/ios/custom_scheme) for setup and troubleshooting.

### Offline Mode

SDK **1.4.0 and later** automatically stores offline analytics, flow/survey/NPS interactions, and push-notification opens for the current user. Stored events survive app restarts and are sent together when the connection returns. All event types share a **3 MB / 5,000-event** limit; events removed for sending are not retried if that send fails.

See the official [Offline Mode guide](https://docs.userpilot.com/developer/installation/mobile/ios/features#offline-mode) for supported events, exclusions, and delivery limits.

### Auto Capture

The Userpilot SDK supports automatic capture of screen views and user interaction events. please refer to the [Userpilot Documentation](https://docs.userpilot.com/developer/installation/mobile/ios/installation).

### Push Notification

Userpilot SDK supports handling push notifications to help you deliver targeted messages and enhance user engagement. For setup instructions, and integration details, please refer to the [Push Notifications Guide](https://docs.userpilot.com/developer/installation/mobile/ios/push-notifications).
Userpilot SDK supports handling push notifications to help you deliver targeted messages and enhance user engagement. For setup instructions and integration details, see the official [Push Notifications Guide](https://docs.userpilot.com/developer/installation/mobile/ios/push-notifications).

### Multi-Instance Support

Userpilot iOS SDK supports running multiple independent instances in the same process. Each instance keeps its own analytics, autocapture scope, storage, and experience overlay window isolated from other instances. For setup instructions and routing details, please refer to the [Multi-Instance Guide](Sources/Userpilot/Userpilot.docc/MultiInstance.md).
Userpilot iOS SDK supports running multiple independent instances in the same process. Each instance keeps its own analytics, autocapture scope, storage, and experience overlay window isolated from other instances. For setup instructions and routing details, see the official [Multi-Instance Guide](https://docs.userpilot.com/developer/installation/mobile/ios/multi-instance).

## πŸ“ Documentation

Expand Down
Loading
Loading