- Initialize at app startup, not on demand
The SDK should be ready before your first screen renders. Initialize in AppDelegate → application(_:didFinishLaunchingWithOptions:), SceneDelegate → scene(_:willConnectTo:), or your SwiftUI App initializer. Waiting until a user reaches a specific screen risks inconsistent experiment behaviour on the screens before it.
- One instance, reused everywhere
The PageSenseClient is designed to be initialized once and shared across the app. Multiple instances create duplicate polling loops, unnecessary memory overhead, and extra network calls. Store it as a singleton or shared reference and reuse it across view controllers, view models, and services.
- User identifiers must be stable
MurmurHash bucketing is deterministic — the same user ID always maps to the same variation for a given experiment. That only holds if the ID you pass doesn't change between calls.
Good choices: user account ID, customer ID, hashed email, persistent device identifier.
Avoid: session IDs, randomly generated IDs, request-scoped values.
- Anonymous vs logged-in users need different identifiers
For anonymous users, use a consistent device-level identifier (IDFV or an app-generated persistent ID). For authenticated users, switch to a user-specific identifier. When a user logs in or out, handle the identity transition cleanly:
Mixing identifiers within the same session leads to inconsistent variation assignments and unreliable data.
- Keep the polling interval sensible
The default of 5 minutes works well for most apps. Going shorter isn't allowed (SDK enforces a 5-minute floor). Going much longer means experiment changes take a while to reach users. 5–10 minutes is the sweet spot for most production setups.
- Never block the main thread
The SDK runs network and computation tasks asynchronously. Use completion handlers for SDK callbacks and only push UI updates onto the main thread when you have a result.
swift
DispatchQueue.main.async {
// Apply UI changes based on assigned variation
}
Debugging and Troubleshooting
Enable DEBUG logging first
When something isn't working, this is your starting point:
- swift
- let sdkOptions = PageSenseSDKOptions()
- sdkOptions.logLevel = .DEBUG
View logs in the Xcode console: View → Debug Area → Activate Console.
DEBUG mode surfaces:
SDK initialization status
Project settings fetch and sync
Experiment evaluation flow
Goal tracking events
Set it back to .info or .error before shipping to production.
Common issues and fixes:
Symptom | Likely cause | Fix |
APIs return nil, no experiment logs | SDK not initialized before API call, or invalid credentials | Initialize at app startup; validate accountId, sdkKey, projectname |
activateExperiment / getVariationName returns nil | User doesn't meet targeting conditions, or falls outside traffic allocation | Check user attributes match experiment targeting; confirm experiment is active |
PageSense changes not showing in app | Polling delay, app stayed in background, or network issue | Bring app to foreground to trigger sync; check network and polling config |
No conversion data in reports | User not qualified, wrong goal name, or goal not configured | Define goal in experiment settings; verify goal name passed to API |
Debugging variation assignment step by step:
Set log level to .debug and watch the Xcode console for evaluation logs.
Check your inputs — experimentName, userId, and userAttributes must all be correct. A single wrong value causes silent failures.
Validate targeting — confirm that the userAttributes you're passing actually satisfy the targeting rules configured in PageSense.
Use a stable user ID — test with the same user ID across sessions to confirm consistent bucketing.
Test across scenarios — try different user IDs and attribute combinations to verify variation distribution is behaving as expected.
We’ve
designed this documentation to guide you every step of the way. If you
need further assistance or have any questions, don’t hesitate to contact
us at
support@zohopagesense.com - we’re always here to help!