Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
166 changes: 96 additions & 70 deletions plugins/contentsquare-ios/skills/contentsquare-ios-sdk/SKILL.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ static func start(environmentID: String, options: [AnalyticsOption: Any] = [:])

Starts Product Analytics with the given environment ID, and also starts DXA if configured for the app.

| Parameter | Type | Description |
| --------------- | ------------------------ | --------------------------------------------------------------------- |
| `environmentID` | `String` | Numeric string. Invalid (non-numeric) value logs an error and aborts. |
| `options` | `[AnalyticsOption: Any]` | Optional configuration. See [AnalyticsOption](#analyticsoption). |
| Parameter | Type | Description |
|-----------|------|-------------|
| `environmentID` | `String` | Numeric string. Invalid (non-numeric) value logs an error and aborts. |
| `options` | `[AnalyticsOption: Any]` | Optional configuration. See [AnalyticsOption](#analyticsoption). |

### start (Product Analytics + DXA with data source ID)

Expand All @@ -41,10 +41,10 @@ static func start(dataSourceID: String, options: [AnalyticsOption: Any] = [:])

Starts both DXA and Product Analytics with the given data source ID. Preferred for new clients.

| Parameter | Type | Description |
| -------------- | ------------------------ | --------------------------------------------------------------------- |
| `dataSourceID` | `String` | Numeric string. Invalid (non-numeric) value logs an error and aborts. |
| `options` | `[AnalyticsOption: Any]` | Optional configuration. See [AnalyticsOption](#analyticsoption). |
| Parameter | Type | Description |
|-----------|------|-------------|
| `dataSourceID` | `String` | Numeric string. Invalid (non-numeric) value logs an error and aborts. |
| `options` | `[AnalyticsOption: Any]` | Optional configuration. See [AnalyticsOption](#analyticsoption). |

### stop

Expand Down Expand Up @@ -110,8 +110,8 @@ static func identify(_ identity: String)

Sets the user identity. If a different identity was already set, starts a new session with a new user ID.

| Parameter | Constraint |
| ---------- | ------------------ |
| Parameter | Constraint |
|-----------|------------|
| `identity` | Max 255 characters |

### resetIdentity (Product Analytics only)
Expand All @@ -130,8 +130,8 @@ static func sendUserIdentifier(_ userIdentifier: String)

Sends a user identifier to DXA. The identifier is immediately hashed -- no PII is stored.

| Parameter | Constraint |
| ---------------- | ------------------ |
| Parameter | Constraint |
|-----------|------------|
| `userIdentifier` | Max 100 characters |

---
Expand Down Expand Up @@ -166,11 +166,11 @@ public init(index: UInt32, name: String, value: String)

Additional context attached to a screen view.

| Parameter | Constraint |
| --------- | -------------------------------------------------------------------------- |
| `index` | `UInt32` identifier. Use consistent index for a given name across the app. |
| `name` | Max 512 characters. Empty string uses `"cs-empty"`. |
| `value` | Max 255 characters. Empty string uses `"cs-empty"`. |
| Parameter | Constraint |
|-----------|------------|
| `index` | `UInt32` identifier. Use consistent index for a given name across the app. |
| `name` | Max 512 characters. Empty string uses `"cs-empty"`. |
| `value` | Max 255 characters. Empty string uses `"cs-empty"`. |

---

Expand All @@ -189,10 +189,10 @@ public init(id: String?, value: Float, currency: Currency)
public init(id: String?, value: Float, currency: String)
```

| Parameter | Description |
| ---------- | --------------------------------------------------------------------------------------------------------------------------- |
| `id` | Optional purchase identifier. |
| `value` | Purchase amount as `Float`. |
| Parameter | Description |
|-----------|-------------|
| `id` | Optional purchase identifier. |
| `value` | Purchase amount as `Float`. |
| `currency` | ISO 4217 `Currency` enum (e.g. `.usd`, `.eur`, `.gbp`) or a string matching a case name. Invalid string maps to `.unknown`. |

**Example:**
Expand Down Expand Up @@ -232,10 +232,10 @@ public init(key: String, value: String) // string variant
public init(key: String, value: UInt32) // int variant
```

| Variant | Key limit | Value limit |
| -------------- | ------------- | ------------- |
| String | Max 512 chars | Max 255 chars |
| Int (`UInt32`) | Max 50 chars | 0 to 2^32-1 |
| Variant | Key limit | Value limit |
|---------|-----------|-------------|
| String | Max 512 chars | Max 255 chars |
| Int (`UInt32`) | Max 50 chars | 0 to 2^32-1 |

Empty key or string value uses `"cs-empty"`.

Expand Down Expand Up @@ -519,14 +519,14 @@ static let metadata: CSQ.Metadata

Read-only access to current session information.

| Property | Type | Description |
| ------------------ | --------- | ------------------------------- |
| `userID` | `String?` | Current user identifier |
| `sessionID` | `String?` | Current session identifier |
| `identity` | `String?` | Identity set via `identify(_:)` |
| `environmentID` | `String?` | PA environment ID |
| `projectID` | `String?` | DXA project ID |
| `sessionReplayURL` | `URL?` | URL to view the session replay |
| Property | Type | Description |
|----------|------|-------------|
| `userID` | `String?` | Current user identifier |
| `sessionID` | `String?` | Current session identifier |
| `identity` | `String?` | Identity set via `identify(_:)` |
| `environmentID` | `String?` | PA environment ID |
| `projectID` | `String?` | DXA project ID |
| `sessionReplayURL` | `URL?` | URL to view the session replay |

### metadata.onChange

Expand All @@ -550,18 +550,18 @@ CSQ.metadata.onChange { metadata in

Configuration options passed to `start(options:)`. All options are optional.

| Option | Type | Description |
| ----------------------------------------- | -------------- | --------------------------------------------------------------------------------------------- |
| `.uploadInterval` | `TimeInterval` | How often events are uploaded |
| `.baseURL` | `URL` | Custom API endpoint (e.g. EU data residency) |
| `.sessionReplayAutoStart` | `Bool` | If `false`, SR doesn't start at launch — use `startSessionReplay()` manually. Default: `true` |
| `.disablePageviewAutocapture` | `Bool` | Disable native pageview autocapture |
| `.disablePageviewTitleAutocapture` | `Bool` | Disable iOS page title autocapture |
| `.disableInteractionAutocapture` | `Bool` | Disable native iOS interaction autocapture |
| `.enableNativeAutocapture` | `Bool` | Enable native UIKit autocapture (PA) |
| `.enablePushNotificationAutocapture` | `Bool` | Capture push notification events |
| `.enablePushNotificationTitleAutocapture` | `Bool` | Capture push notification title |
| `.enablePushNotificationBodyAutocapture` | `Bool` | Capture push notification body |
| Option | Type | Description |
|--------|------|-------------|
| `.uploadInterval` | `TimeInterval` | How often events are uploaded |
| `.baseURL` | `URL` | Custom API endpoint (e.g. EU data residency) |
| `.sessionReplayAutoStart` | `Bool` | If `false`, SR doesn't start at launch — use `startSessionReplay()` manually. Default: `true` |
| `.disablePageviewAutocapture` | `Bool` | Disable native pageview autocapture |
| `.disablePageviewTitleAutocapture` | `Bool` | Disable iOS page title autocapture |
| `.disableInteractionAutocapture` | `Bool` | Disable native iOS interaction autocapture |
| `.enableNativeAutocapture` | `Bool` | Enable native UIKit autocapture (PA) |
| `.enablePushNotificationAutocapture` | `Bool` | Capture push notification events |
| `.enablePushNotificationTitleAutocapture` | `Bool` | Capture push notification title |
| `.enablePushNotificationBodyAutocapture` | `Bool` | Capture push notification body |

> `.enableUIKitAutocapture` is deprecated — use `.enableNativeAutocapture` instead.
> `ProductAnalyticsOption` is a deprecated typealias for `AnalyticsOption` — prefer `AnalyticsOption` in new code.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ To allow Contentsquare users to enable in-app features, two implementation tasks
The app must be opened via a custom URL scheme.

**Using Xcode:**

1. Open the project settings
2. Select the app target
3. Select the `Info` settings
Expand Down Expand Up @@ -111,3 +110,4 @@ struct MyApp: App {
}
}
```

Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,14 @@ Exceptions: views explicitly masked/unmasked with `mask(_:)` / `unmask(_:)` take

### What each method masks

| Method | What gets masked |
| ------------------------- | ----------------------------------------------------------------------------- |
| `maskTexts(true)` | `UILabel`, SwiftUI `Text` |
| `maskTextInputs(true)` | `UITextField`, `UITextView`, SwiftUI `TextField`, `SecureField`, `TextEditor` |
| `maskImages(true)` | `UIImageView`, SwiftUI `Image` |
| `mask(_ view:)` | The specific view and its subviews |
| `mask(viewsOfType:)` | All instances of a UIView subclass |
| `setDefaultMasking(true)` | Everything (text inputs always masked) |
| Method | What gets masked |
|--------|-----------------|
| `maskTexts(true)` | `UILabel`, SwiftUI `Text` |
| `maskTextInputs(true)` | `UITextField`, `UITextView`, SwiftUI `TextField`, `SecureField`, `TextEditor` |
| `maskImages(true)` | `UIImageView`, SwiftUI `Image` |
| `mask(_ view:)` | The specific view and its subviews |
| `mask(viewsOfType:)` | All instances of a UIView subclass |
| `setDefaultMasking(true)` | Everything (text inputs always masked) |

### Ignoring interactions

Expand Down Expand Up @@ -124,10 +124,10 @@ CSQ.startSessionReplay()
CSQ.stopSessionReplay()
```

| Method | Effect |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `startSessionReplay()` | Starts SR on-demand. Behaves like automatic start once invoked. **One-shot** -- intended to be called at most once per SDK lifetime when `sessionReplayAutoStart: false`. |
| `stopSessionReplay()` | Stops SR only. Other tracking (events, screenviews, identity, etc.) keeps running. **Terminal** -- once called, SR cannot be restarted. Use `CSQ.stop()` to stop everything. |
| Method | Effect |
|--------|--------|
| `startSessionReplay()` | Starts SR on-demand. Behaves like automatic start once invoked. **One-shot** -- intended to be called at most once per SDK lifetime when `sessionReplayAutoStart: false`. |
| `stopSessionReplay()` | Stops SR only. Other tracking (events, screenviews, identity, etc.) keeps running. **Terminal** -- once called, SR cannot be restarted. Use `CSQ.stop()` to stop everything. |

> **No restart support.** This is not a pause/resume mechanism. Plan accordingly: start SR at the beginning of the journey you want to record, and only call `stopSessionReplay()` when you are certain the recording is complete for the rest of the session.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,16 @@ compatibility: Requires Swift to be installed locally and macOS environment.
Before performing any Xcode setup or file manipulation, you **MUST** adhere to the following rules. A hefty fee will be applied if you violate them.

### 1. The Anti-Ruby Mandate

You are **strictly forbidden** from using Ruby, Rails, or any Ruby gems (including the `xcodeproj` gem). Under no circumstances may you write or execute Ruby scripts.

### 2. Modern Xcode Folder Synchronization

Modern Xcode projects support folder synchronization. When adding new source code (`.swift`) or resource files, simply write them to the correct directory on disk. They will be automatically included in the Xcode project. **Never manually modify the `.pbxproj` file to add files.**

### 3. Allowed Scripting Languages

If you absolutely must write a script to manipulate the project environment (e.g., configuring SPM packages beyond what the provided `xcode_spm_setup` script does), you **must use Swift**. Only as an absolute last resort, if Swift is completely unviable, may you use Node.js or TypeScript.

### 4. Toolchain Verification

Because this skill relies entirely on a native Swift script, you must verify the environment:

- Run `swift --version` before proceeding.
- If the Swift command is not found, you must stop and recommend the user install the Swift toolchain (e.g., via `xcode-select --install` on macOS), or ask if you can attempt to install it for them. Do not attempt to proceed without Swift.

Expand All @@ -46,15 +41,11 @@ Do not use raw text parsing, `sed`, or Ruby scripts to modify `.pbxproj` files d
Instead, execute the Swift configuration package bundled with this skill (`scripts/xcode_spm_setup`) to securely install SPM packages.

### **CRITICAL: Always Use Latest SDK Version**

To ensure access to the latest features and security fixes, always use the most recent version of the Contentsquare iOS SDK. Check for the latest release version at [https://github.com/ContentSquare/apple-sdk/releases](https://github.com/ContentSquare/apple-sdk/releases).

To ensure access to the latest features and security fixes, always use the most recent version of the Contentsquare iOS SDK. Check for the latest release version at [https://github.com/ContentSquare/apple-sdk/releases](https://github.com/ContentSquare/apple-sdk/releases).
- Use the most recent version number (e.g., `1.x.y`) in your commands instead of hardcoded placeholders.

### Understanding the Script's Actions

When adding a Swift Package to an Xcode project, two distinct steps must occur:

1. Adding the package repository dependency (e.g., `https://github.com/Alamofire/Alamofire`).
2. Selecting the target (e.g., `MyApp`), navigating to **General > Frameworks, Libraries, and Embedded Content**, and hitting the `+` button to explicitly link the specific product modules (e.g., `Alamofire`).

Expand All @@ -70,17 +61,15 @@ swift run --package-path <PATH_TO_SKILL>/scripts/xcode_spm_setup xcode_spm_setup
```

### Example 1: Generic Package (e.g., Alamofire)

Adding Alamofire to a standard Xcode project.

```bash
swift run --package-path /Users/foo/.agents/skills/xcode-project-setup/scripts/xcode_spm_setup xcode_spm_setup MyApp.xcodeproj https://github.com/Alamofire/Alamofire 5.8.1 Alamofire
```

Example 2: Contentsquare

```bash
swift run --package-path /Users/foo/.agents/skills/xcode-project-setup/scripts/xcode_spm_setup xcode_spm_setup MyApp.xcodeproj https://github.com/ContentSquare/apple-sdk 1.11.0 ContentsquareSDK
```

_Note: It will upgrade the packages that are already present in the project._
*Note: It will upgrade the packages that are already present in the project.*
Loading