SignalSeal Docs

iOS

Install the SignalSeal iOS SDK in your Swift or Objective-C app.

The SignalSeal iOS SDK reports installs, sends events, and powers in-app attribution.

Requirements

  • iOS 15.0 or higher
  • Swift 5.9 or higher
  • Xcode 14 or higher

Install

Swift Package Manager

Add the SDK to your Package.swift:

.package(url: "https://github.com/signalseal/ios-signalseal-sdk", from: "0.2.5")

Then add SignalSealSDK to your target:

.target(
  name: "MyApp",
  dependencies: [
    .product(name: "SignalSealSDK", package: "ios-signalseal-sdk"),
  ]
)

Or in Xcode: File → Add Package Dependencies, paste https://github.com/signalseal/ios-signalseal-sdk, and add the SignalSealSDK library to your target.

Initialize

Call configure(...) once on app launch - typically in your AppDelegate, SceneDelegate, or a SwiftUI @main initializer.

import SignalSealSDK

SignalSealSDK.shared.configure(
  apiKey: "ak_ios_..."
)

Configuration parameters

public func configure(
  apiKey: String,
  isDebug: Bool = false,
  endpointBaseUrl: String? = nil,
  logLevel: LogLevel = .info,
  customerUserId: String? = nil,
  environment: SignalSealEnvironment? = nil
)
ParameterTypeDescription
apiKeyStringRequired. Your iOS SDK key (ak_ios_…) from Settings → SDK.
isDebugBoolDefaults to false. When true, every event is tagged is_debug so it's visible in the Live Feed but not forwarded to ad networks.
endpointBaseUrlString?Override the ingestion URL. Leave unset unless SignalSeal told you to set it. Must end with /.
logLevelLogLevelDefaults to .info. One of .off, .error, .warn, .info, .debug. isDebug: true forces .debug.
customerUserIdString?Your app's stable user ID, if you have one. Helpful for cross-device identity.
environmentSignalSealEnvironment?Auto-detected (Simulator/TestFlight/debugger → .sandbox, App Store → .production). Pass .sandbox explicitly for ad-hoc or Enterprise QA builds.

configure(...) is safe to call from any thread and is idempotent - the second call is logged and ignored.

The SDK fires the INSTALL event automatically the first time configure(...) runs on a device. Don't send it manually.

Send events

SignalSealSDK.shared.sendEvent(
  event: .purchase,
  parameters: [
    "value": 9.99,
    "proceeds": 6.99,
    "currency": "USD"
  ]
)

value is the gross amount in the buyer's currency. proceeds is optional - the net you keep after store commission and tax, in the same currency; pass it if you know it (e.g. from your receipt-validation backend). currency is the ISO-4217 code; omit it and value is treated as USD.

The first argument is an EventType - see the full list below. For events that don't fit any of those, use .custom with a name:

SignalSealSDK.shared.sendEvent(
  event: .custom,
  name: "onboarding_completed",
  parameters: ["steps": 5]
)

sendEvent(...) is fire-and-forget. Events queue in memory and flush in the background.

Event types

public enum EventType: String {
  case install = "INSTALL"
  case login = "LOGIN"
  case signUp = "SIGN_UP"
  case register = "REGISTER"
  case purchase = "PURCHASE"
  case addToCart = "ADD_TO_CART"
  case addToWishlist = "ADD_TO_WISHLIST"
  case initiateCheckout = "INITIATE_CHECKOUT"
  case startTrial = "START_TRIAL"
  case subscribe = "SUBSCRIBE"
  case levelStart = "LEVEL_START"
  case levelComplete = "LEVEL_COMPLETE"
  case tutorialComplete = "TUTORIAL_COMPLETE"
  case search = "SEARCH"
  case viewItem = "VIEW_ITEM"
  case viewContent = "VIEW_CONTENT"
  case share = "SHARE"
  case custom = "CUSTOM"
}

Set user attributes

Attach known user data to all subsequent events. Pass only the fields you have - everything is optional.

SignalSealSDK.shared.setUserAttributes(
  UserAttributes(
    email: "alice@example.com",
    firstName: "Alice",
    country: "US",
    externalId: "user_42"
  )
)

Available fields:

FieldTypeNotes
emailString?
phoneString?E.164 format recommended (+14155551234).
firstName, lastNameString?
dobString?ISO-8601 (YYYY-MM-DD).
genderString?
city, state, zip, countryString?country should be ISO-3166-1 alpha-2.
externalIdString?Your app's internal user ID after login.

Apple Search Ads

To attribute installs from Apple Search Ads, enable ASA tracking after configure(...):

import SignalSealSDK

SignalSealASAAttribution.shared.enableAppleAdsAttribution()

This is a separate call so apps that don't run Apple Search Ads aren't forced to ship the integration.

Automatic purchase tracking

If you're on StoreKit 2 and you want SignalSeal to capture purchases automatically without you calling sendEvent for each one, enable purchase tracking after configure(...):

SignalSealSDK.shared.enablePurchaseTracking()

The SDK listens to StoreKit.Transaction.updates and emits a PURCHASE event for each verified transaction. Skip this if you already log purchases yourself or you process them server-side through RevenueCat or SuperWall.

Helpers

Get the SignalSeal ID

A stable per-install ID, useful for bridging to RevenueCat, SuperWall, or your own backend.

let id = SignalSealSDK.shared.getSignalSealId()

Returns nil until configure(...) has finished setting up.

Get attribution parameters

Returns the install's attribution data - the campaign that drove it, plus raw click IDs for any further server-side correlation.

Task {
  if let params = await SignalSealSDK.shared.getAttributionParams() {
    // { "signalseal_id": "...", "signalseal_adnetwork": "meta",
    //   "signalseal_campaign_id": "...", "fbclid": "...", ... }
  }
}

Organic installs return { "signalseal_id": "..." } only. Attributed installs add signalseal_* keys plus any raw click IDs the original ad carried (gclid, fbclid, ttclid, wbraid, etc.).

Flush

Force-flush the in-memory event queue. Useful in tests.

SignalSealSDK.shared.flush()

Reset

Wipe all locally-stored SDK state - installation ID, queued events, cached user data. Use this for "log out" or "forget me" flows. The SDK re-mints an installation ID and re-fires the INSTALL event on the next call.

SignalSealSDK.shared.resetData()

Debug mode

Pass isDebug: true when configuring during development:

#if DEBUG
SignalSealSDK.shared.configure(
  apiKey: "ak_ios_...",
  isDebug: true
)
#else
SignalSealSDK.shared.configure(
  apiKey: "ak_ios_..."
)
#endif

In debug mode every event is tagged is_debug - events still appear in the SignalSeal dashboard so you can verify they look right, but they won't be forwarded to your ad networks.

What's next