Complete API reference for the LinkForty iOS SDK.
- LinkForty - Main SDK class
- LinkFortyConfig - Configuration
- DeepLinkData - Deep link data model
- CreateLinkOptions - Link creation options
- CreateLinkResult - Link creation result
- InstallResponse - Attribution response
- LinkFortyError - Error types
- Type Aliases - Callback types
- SwiftUI - View modifiers
Main singleton class providing the SDK interface.
LinkForty.sharedInitializes the SDK with configuration and reports the install.
func initialize(
config: LinkFortyConfig,
attributionWindowHours: Int = 168,
deviceId: String? = nil
) async throws -> InstallResponseParameters:
config: SDK configuration (required)attributionWindowHours: Attribution window in hours (default: 168 = 7 days)deviceId: Optional device identifier for attribution
Returns: InstallResponse with attribution data
Throws: LinkFortyError if initialization fails
Example:
let config = LinkFortyConfig(
baseURL: URL(string: "https://go.yourdomain.com")!,
apiKey: "your-api-key",
appToken: "at_a1b2c3d4..." // recommended for Cloud — enables organic-install attribution
)
let response = try await LinkForty.shared.initialize(config: config)
print("Install ID: \(response.installId)")
print("Attributed: \(response.attributed)")Handles a deep link URL (Universal Link or custom scheme).
func handleDeepLink(url: URL)Parameters:
url: The deep link URL to handle
Example:
// In SwiftUI
.onOpenURL { url in
LinkForty.shared.handleDeepLink(url: url)
}
// In AppDelegate
func application(_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
if let url = userActivity.webpageURL {
LinkForty.shared.handleDeepLink(url: url)
}
return true
}Registers a callback for deferred deep links (install attribution).
func onDeferredDeepLink(_ callback: @escaping DeferredDeepLinkCallback)Parameters:
callback: Closure invoked with deep link data (or nil for organic installs)
Callback Type:
typealias DeferredDeepLinkCallback = (DeepLinkData?) -> VoidExample:
LinkForty.shared.onDeferredDeepLink { deepLinkData in
if let data = deepLinkData {
print("Attributed install: \(data.shortCode)")
// Navigate to content
} else {
print("Organic install")
}
}Registers a callback for direct deep links (when app opens from a link).
func onDeepLink(_ callback: @escaping DeepLinkCallback)Parameters:
callback: Closure invoked with URL and parsed deep link data
Callback Type:
typealias DeepLinkCallback = (URL, DeepLinkData?) -> VoidExample:
LinkForty.shared.onDeepLink { url, deepLinkData in
print("Opened from: \(url)")
if let data = deepLinkData {
// Navigate based on deep link data
}
}Creates a short link programmatically.
func createLink(options: CreateLinkOptions) async throws -> CreateLinkResultParameters:
options: Link creation options (see CreateLinkOptions)
Returns: CreateLinkResult with the shareable URL, short code, and link ID
Throws:
LinkFortyError.notInitializedif SDK not initializedLinkFortyError.missingApiKeyif no API key configured
Note: Requires an API key in LinkFortyConfig. If templateId is provided, uses the dashboard endpoint (POST /api/links). Otherwise, uses the simplified SDK endpoint (POST /api/sdk/v1/links) which auto-selects the organization's most recent template.
Example:
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)")
print("Short code: \(result.shortCode)")
print("Link ID: \(result.linkId)")Tracks a custom event.
func trackEvent(
name: String,
properties: [String: Any]? = nil
) async throwsParameters:
name: Event name (e.g., "purchase", "signup")properties: Optional event properties (must be JSON-serializable)
Throws: LinkFortyError if tracking fails
Example:
// Simple event
try await LinkForty.shared.trackEvent(name: "button_clicked")
// Event with properties
try await LinkForty.shared.trackEvent(
name: "purchase",
properties: [
"product_id": "123",
"amount": 29.99,
"category": "electronics"
]
)Tracks a revenue event.
func trackRevenue(
amount: Decimal,
currency: String,
properties: [String: Any]? = nil
) async throwsParameters:
amount: Revenue amount (must be non-negative)currency: Currency code (e.g., "USD", "EUR")properties: Optional additional properties
Throws: LinkFortyError if tracking fails
Example:
try await LinkForty.shared.trackRevenue(
amount: 29.99,
currency: "USD",
properties: [
"product_id": "123",
"payment_method": "credit_card"
]
)Reports a screen view. Emits a screen_view event carrying the screen name and the previously tracked screen, stamped with the active last-click attribution context, so the dashboard can build a per-link screen-flow funnel.
func trackScreenView(
name: String,
properties: [String: Any]? = nil
) async throwsParameters:
name: Screen name (e.g., "ProductDetail"). Must not be empty.properties: Optional additional properties
Throws: LinkFortyError if tracking fails (including an empty screen name)
Example:
// UIKit — from viewDidAppear
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
Task { try? await LinkForty.shared.trackScreenView(name: "ProductDetail") }
}For SwiftUI, prefer the .linkfortyScreen(_:) view modifier.
Flushes the event queue, attempting to send all queued events.
func flushEvents() asyncExample:
await LinkForty.shared.flushEvents()Clears the event queue without sending events.
func clearEventQueue()Example:
LinkForty.shared.clearEventQueue()Returns the number of events currently queued.
var queuedEventCount: Int { get }Example:
let count = LinkForty.shared.queuedEventCount
print("Queued events: \(count)")Returns the install ID if available.
func getInstallId() -> String?Returns: Install ID or nil if not initialized
Example:
if let installId = LinkForty.shared.getInstallId() {
print("Install ID: \(installId)")
}Returns the install attribution data if available.
func getInstallData() -> DeepLinkData?Returns: Deep link data or nil if organic install
Example:
if let data = LinkForty.shared.getInstallData() {
print("Short code: \(data.shortCode)")
print("UTM source: \(data.utmParameters?.source ?? "none")")
}Returns whether this is the first launch.
func isFirstLaunch() -> BoolReturns: true if first launch, false otherwise
Example:
if LinkForty.shared.isFirstLaunch() {
print("First launch - show onboarding")
}Clears all stored SDK data.
func clearData()Example:
LinkForty.shared.clearData()Resets the SDK to uninitialized state.
Note: This does NOT clear stored data. Call clearData() first if needed.
func reset()Example:
LinkForty.shared.clearData()
LinkForty.shared.reset()Configuration for the LinkForty SDK.
init(
baseURL: URL,
apiKey: String? = nil,
appToken: String? = nil,
debug: Bool = false,
attributionWindowHours: Int = 168
)Parameters:
baseURL: Backend URL (must be HTTPS except localhost)apiKey: API key (optional for self-hosted)appToken: Public workspace token (LinkForty Cloud only). Recommended — required for organic installs (App Store discovery, social mentions, etc.) to be attributed to your workspace. Find it in the dashboard under Workspace Settings → App Token. Format:at_<32 hex chars>. Safe to ship in your app bundle.debug: Enable debug logging (default: false)attributionWindowHours: Attribution window in hours (default: 168 = 7 days, max: 2160 = 90 days)
Example:
let config = LinkFortyConfig(
baseURL: URL(string: "https://go.yourdomain.com")!,
apiKey: "your-api-key",
appToken: "at_a1b2c3d4...",
debug: true,
attributionWindowHours: 24
)baseURL: URL- Backend URLapiKey: String?- API key (optional)appToken: String?- Public workspace token (optional, recommended for Cloud)debug: Bool- Debug mode flagattributionWindowHours: Int- Attribution window
Validates the configuration.
func validate() throwsThrows: LinkFortyError.invalidConfiguration if validation fails
Deep link data model containing parsed link information.
public let shortCode: String // LinkForty short code (required)
public let iosURL: String? // iOS deep link URL
public let androidURL: String? // Android deep link URL
public let webURL: String? // Fallback web URL
public let utmParameters: UTMParameters? // UTM tracking parameters
public let customParameters: [String: String]? // Custom query parameters
public let deepLinkPath: String? // Deep link path for in-app routing (e.g., "/product/123")
public let appScheme: String? // App URI scheme (e.g., "myapp")
public let clickedAt: Date? // When the link was clicked (ISO 8601)
public let linkId: String? // Link UUID from the backendif let data = deepLinkData {
print("Short code: \(data.shortCode)")
// Use deep link path for in-app routing
if let path = data.deepLinkPath {
navigateToPath(path)
}
if let utm = data.utmParameters {
print("Source: \(utm.source ?? "unknown")")
print("Campaign: \(utm.campaign ?? "unknown")")
}
if let productId = data.customParameters?["product_id"] {
navigateToProduct(id: productId)
}
}Response from install attribution API.
public let installId: String // Unique install ID
public let attributed: Bool // Whether install was attributed
public let confidenceScore: Double // Confidence score (0-100)
public let matchedFactors: [String] // Matched fingerprint factors
public let deepLinkData: DeepLinkData? // Deep link data if attributedlet response = try await LinkForty.shared.initialize(config: config)
print("Install ID: \(response.installId)")
print("Attributed: \(response.attributed)")
if response.attributed {
print("Confidence: \(response.confidenceScore)%")
print("Matched factors: \(response.matchedFactors)")
if let data = response.deepLinkData {
print("Short code: \(data.shortCode)")
}
}Options for creating a short link programmatically.
init(
templateId: String? = nil,
templateSlug: String? = nil,
deepLinkParameters: [String: String]? = nil,
title: String? = nil,
description: String? = nil,
customCode: String? = nil,
utmParameters: UTMParameters? = nil
)Parameters:
templateId: Template UUID (auto-selected if omitted)templateSlug: Template slug (only needed withtemplateId)deepLinkParameters: Deep link parameters for in-app routing (e.g.,["route": "VIDEO_VIEWER", "id": "..."])title: Link titledescription: Link descriptioncustomCode: Custom short code (auto-generated if omitted)utmParameters: UTM parameters for campaign tracking
Result of creating a short link.
public let url: String // Full shareable URL (e.g., "https://go.yourdomain.com/tmpl/abc123")
public let shortCode: String // The generated short code
public let linkId: String // Link UUIDError types thrown by the SDK.
case notInitialized
// SDK not initialized - call initialize() first
case alreadyInitialized
// SDK already initialized
case invalidConfiguration(String)
// Invalid configuration
case networkError(Error)
// Network request failed
case invalidResponse(statusCode: Int?, message: String?)
// Invalid or unexpected server response
case decodingError(Error)
// Failed to decode response
case encodingError(Error)
// Failed to encode request
case invalidEventData(String)
// Invalid event data
case invalidDeepLinkURL(String)
// Invalid deep link URL
case missingApiKey
// API key is required for this operation (e.g., createLink)do {
try await LinkForty.shared.trackEvent(name: "test")
} catch let error as LinkFortyError {
switch error {
case .notInitialized:
print("SDK not initialized")
case .networkError(let underlyingError):
print("Network error: \(underlyingError)")
case .invalidEventData(let message):
print("Invalid event: \(message)")
default:
print("Error: \(error)")
}
}Callback for deferred deep links (install attribution).
typealias DeferredDeepLinkCallback = (DeepLinkData?) -> VoidParameter: Deep link data if attributed, nil for organic installs
Callback for direct deep links (when app opens from a link).
typealias DeepLinkCallback = (URL, DeepLinkData?) -> VoidParameters:
URL: The URL that opened the appDeepLinkData?: Parsed deep link data, nil if parsing failed
A View modifier that reports a screen_view event when the view appears. Equivalent to calling trackScreenView(name:properties:) from onAppear, including the active last-click attribution stamp.
func linkfortyScreen(
_ name: String,
properties: [String: Any]? = nil
) -> some ViewParameters:
name: Screen name (e.g., "ProductDetail")properties: Optional additional properties
Example:
struct ProductView: View {
var body: some View {
VStack { /* ... */ }
.linkfortyScreen("ProductDetail")
}
}All SDK methods are thread-safe and can be called from any thread. Callbacks are executed on the main thread.
The SDK uses modern Swift concurrency (async/await) for asynchronous operations:
// All async methods can be called with await
try await LinkForty.shared.initialize(config: config)
try await LinkForty.shared.trackEvent(name: "test")
await LinkForty.shared.flushEvents()Events are automatically queued when offline and sent when connectivity is restored. The queue has a maximum size of 100 events.
For more information, see the full documentation or LinkForty Docs.