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
- Programmatic Link Creation: Create short links directly from your app
- Zero Dependencies: Lightweight, no third-party dependencies
- Swift-Native: 100% Swift, modern async/await APIs
- iOS 16.0+
- Xcode 15.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 using deep link path
if let path = data.deepLinkPath {
navigateToPath(path)
}
}
}Server-side resolution: When the SDK is initialized, deep links are automatically resolved via the server to provide enriched data including
deepLinkPath,appScheme, andlinkId. If the server is unreachable, the SDK falls back to local URL parsing.
// 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"]
)let result = try await LinkForty.shared.createLink(
options: CreateLinkOptions(
deepLinkParameters: ["route": "VIDEO_VIEWER", "id": "vid123"],
title: "Check this out!",
utmParameters: UTMParameters(source: "app", campaign: "share")
)
)
print("Share this link: \(result.url)")
// e.g., "https://go.yourdomain.com/tmpl/abc123"Note: Requires an API key in
LinkFortyConfig. See API Reference for all options.
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