Native iOS SDK for deep linking, mobile attribution, and conversion tracking.
- Deferred Deep Linking: Match app installs to link clicks using privacy-compliant fingerprinting
- Universal Links: Full support for iOS Universal Links (HTTPS deep links)
- Custom URL Schemes: Handle custom app URL schemes
- Event Tracking: Track in-app events and conversions
- Offline Support: Queue events when offline with automatic retry
- Privacy-First: No IDFA collection, complies with Apple's privacy requirements
- Zero Dependencies: Lightweight, no third-party dependencies
- Swift-Native: 100% Swift, modern async/await APIs
- iOS 13.0+
- Xcode 14.0+
- Swift 5.9+
Add the following to your Package.swift file:
dependencies: [
.package(url: "https://github.com/LinkForty/mobile-sdk-ios.git", from: "1.0.0")
]Or in Xcode:
- File > Add Package Dependencies
- Enter:
https://github.com/LinkForty/mobile-sdk-ios.git - Select version and add to your target
pod 'LinkFortySDK', '~> 1.0'github "LinkForty/mobile-sdk-ios" ~> 1.0
In your AppDelegate.swift or @main App struct:
import LinkFortySDK
// In AppDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
Task {
do {
let config = LinkFortyConfig(
baseURL: URL(string: "https://go.yourdomain.com")!,
apiKey: "your-api-key", // Optional for self-hosted
debug: true,
attributionWindowHours: 168 // 7 days
)
try await LinkForty.shared.initialize(config: config)
} catch {
print("LinkForty initialization failed: \(error)")
}
}
return true
}LinkForty.shared.onDeferredDeepLink { deepLinkData in
if let data = deepLinkData {
// User installed from a link - navigate to content
print("Install attributed to: \(data.shortCode)")
print("UTM Source: \(data.utmParameters?.source ?? "none")")
// Navigate to the right content
if let productId = data.customParameters?["productId"] {
navigateToProduct(id: productId)
}
} else {
// Organic install - no attribution
print("Organic install")
}
}First, enable Associated Domains in your Xcode project:
- Select your target > Signing & Capabilities
- Add "Associated Domains"
- Add domain:
applinks:go.yourdomain.com
Then handle Universal Links:
// In AppDelegate or SceneDelegate
func application(_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let url = userActivity.webpageURL else {
return false
}
LinkForty.shared.handleDeepLink(url: url)
return true
}
// Or in SwiftUI
.onOpenURL { url in
LinkForty.shared.handleDeepLink(url: url)
}
// Register callback
LinkForty.shared.onDeepLink { url, deepLinkData in
print("Deep link opened: \(url)")
if let data = deepLinkData {
print("Link data: \(data)")
// Navigate to content
}
}// Track a simple event
try await LinkForty.shared.trackEvent(name: "button_clicked")
// Track event with properties
try await LinkForty.shared.trackEvent(
name: "purchase",
properties: [
"product_id": "123",
"amount": 29.99,
"currency": "USD"
]
)
// Track revenue
try await LinkForty.shared.trackRevenue(
amount: 29.99,
currency: "USD",
properties: ["product_id": "123"]
)If you're running your own LinkForty Core instance:
let config = LinkFortyConfig(
baseURL: URL(string: "https://links.yourcompany.com")!,
apiKey: nil, // No API key needed for self-hosted
debug: false
)
try await LinkForty.shared.initialize(config: config)let config = LinkFortyConfig(
baseURL: URL(string: "https://go.yourdomain.com")!,
attributionWindowHours: 24 // 1 day instead of default 7 days
)if let installData = LinkForty.shared.getInstallData() {
print("Short code: \(installData.shortCode)")
print("UTM source: \(installData.utmParameters?.source ?? "none")")
}
if let installId = LinkForty.shared.getInstallId() {
print("Install ID: \(installId)")
}// Check queued events count
let count = LinkForty.shared.queuedEventCount
// Manually flush event queue
await LinkForty.shared.flushEvents()
// Clear event queue
LinkForty.shared.clearEventQueue()LinkForty.shared.clearData()
// Reset SDK to uninitialized state
LinkForty.shared.reset()Your backend must serve an Apple App Site Association file at:
https://go.yourdomain.com/.well-known/apple-app-site-association
Example:
{
"applinks": {
"apps": [],
"details": [{
"appID": "TEAM_ID.com.yourcompany.yourapp",
"paths": ["*"]
}]
}
}- Enable "Associated Domains" capability
- Add domain:
applinks:go.yourdomain.com - Handle Universal Links in AppDelegate (see Quick Start)
Use Apple's validation tool:
Or test manually:
- Create a link in LinkForty
- Open link in Safari on device
- Long press the link
- Verify "Open in YourApp" appears
- No IDFA: Does not collect Identifier for Advertisers
- No Persistent IDs: Uses probabilistic fingerprinting only
- Data Minimization: Collects only necessary attribution data
- User Control: Provides
clearData()for user data deletion - Privacy Manifest: Includes
PrivacyInfo.xcprivacyfile
- Device timezone
- Device language
- Screen resolution
- iOS version
- App version
- User-Agent string
The SDK enforces HTTPS for all API endpoints (except localhost for testing).
swift testOr in Xcode:
Cmd+U to run all tests
See Tests/LinkFortySDKIntegrationTests/README.md for setup instructions.
- Basic Example - Simple SwiftUI app demonstrating all SDK features
This SDK requires a running LinkForty backend:
- LinkForty Core (open source): Self-host for free
- LinkForty Cloud (SaaS): Managed service with advanced features
See: https://github.com/linkforty/core
- Documentation: https://docs.linkforty.com
- Issues: https://github.com/LinkForty/mobile-sdk-ios/issues
- Discussions: https://github.com/LinkForty/mobile-sdk-ios/discussions
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
See CHANGELOG.md for version history.
LinkForty iOS SDK is available under the MIT license. See LICENSE for more info.
- LinkForty Core - Open source deep linking backend
- LinkForty React Native SDK - React Native integration
- LinkForty Android SDK - Android SDK (coming soon)
Made with ❤️ by the LinkForty team