API reference
Every public type, property and method in the Grovs iOS SDK 3.1.
All members are static on Grovs, except the extension types. Completions and delegate callbacks run on the main thread.
At a glance
| Area | Member | Kind | What it does |
|---|---|---|---|
| Setup | configure | method | Configures and authenticates the SDK |
delegate | property | Receives deep links and SDK errors | |
setSDK | method | Turns collection on or off | |
setDebug | method | Sets the minimum log level | |
| Deep links | handleSceneDelegate(openURLContexts:) | method | Forwards scene URL opens |
handleSceneDelegate(continue:) | method | Forwards scene universal links | |
handleSceneDelegate(options:) | method | Forwards the cold-start link | |
handleAppDelegate(continue:restorationHandler:) | method | Forwards app delegate universal links | |
handleAppDelegate(open:options:) | method | Forwards app delegate URL opens | |
lastReceivedPayload | method | Most recent deep link payload | |
allReceivedPayloadsSinceStartup | method | Every payload since launch | |
| Users | userIdentifier | property | Your ID for the current user |
userAttributes | property | Attributes of the current user | |
| Links | generateLink | method | Creates a smart link |
linkDetails | method | Details of a link by path | |
| Events | track | method | Tracks a custom event |
trackScreenView | method | Tracks a screen view | |
setGlobalTags | method | Tags added to every event | |
setScreenAliases | method | Renames screens for the dashboard | |
screenNameProvider | property | Custom resolver for screen names | |
| Revenue | logInAppPurchase | method | Logs an App Store purchase |
logCustomPurchase | method | Logs a purchase outside the App Store | |
| Push notifications | pushToken | property | APNs token as a hex string |
setPushToken | method | Sets the token from APNs Data | |
handleNotificationResponse | method | Handles a notification tap | |
handleNotificationOpen | method | Handles a tap from its payload | |
isGrovsNotification | method | Checks if Grovs sent a push | |
| In-app messages | inAppDelegate | property | Receives in-app message events |
pauseInAppMessages | method | Holds messages back | |
resumeInAppMessages | method | Lets messages show again | |
discardInAppMessages | method | Drops the waiting message | |
setInAppExcludedScreens | method | Screens where no message shows | |
setInAppDebugLogging | method | Logs why campaigns were skipped | |
| Types | GrovsDelegate | protocol | Deep link and error callbacks |
GrovsError | enum | SDK error categories | |
GrovsInAppDelegate | protocol | In-app message callbacks | |
GrovsScreenTracking | protocol | Names a view controller | |
GrovsScreenName | enum | Result of screenNameProvider | |
LogLevel | enum | Log verbosity | |
TransactionType | enum | Buy, cancel or refund | |
CustomRedirects | type | Per-platform link redirects | |
CustomLinkRedirect | type | One platform redirect | |
| Closure types | callback | Completion signatures | |
| Extensions | GrovsNotificationServiceExtension | class | Adds campaign images to pushes |
GrovsNotificationContent | enum | Image helper for existing extensions | |
grovsScreen | method | SwiftUI screen view modifier | |
trackScreenView (modifier) | method | Alias of grovsScreen | |
| Deprecated | displayMessagesViewController | method | Shows nothing |
numberOfUnreadMessages | method | Always 0 |
Setup
configure
static func configure(
APIKey: String,
useTestEnvironment: Bool,
baseURL: String? = nil,
autoTrackScreenViews: Bool = true,
clipboardDomains: [String]? = nil,
enabled: Bool = true,
delegate: GrovsDelegate?,
completion: GrovsBoolCompletion? = nil
)Configures and authenticates the SDK. Call once per launch, in application(_:didFinishLaunchingWithOptions:).
| Name | Type | Description |
|---|---|---|
APIKey | String | Project API key from the Grovs dashboard. |
useTestEnvironment | Bool | true targets the test environment, false production. |
baseURL | String? | Domain of a self-hosted backend, for example "https://sdk.example.com". The SDK appends the API path. Defaults to the Grovs cloud. |
autoTrackScreenViews | Bool | Track screen views automatically by hooking viewDidAppear. Defaults to true. |
clipboardDomains | [String]? | Extra link hosts accepted by clipboard-assisted deferred deep linking, for example ["links.example.com"]. Grovs-owned hosts are always accepted. |
enabled | Bool | Whether the SDK may collect and send anything this launch. Defaults to true. |
delegate | GrovsDelegate? | Receives deep link payloads and SDK errors. Held weakly. |
completion | GrovsBoolCompletion? | Called on the main thread with whether authentication succeeded. |
- Calling it again replaces the previous configuration.
enabledisn't persisted. Pass your stored consent value every launch. Withenabled: falsethe completion reportsfalsewithout attempting authentication.- An invalid
baseURL, or one without a host, refuses configuration: the completion reportsfalseand the SDK stays unconfigured. - On a background launch before the device's first unlock since reboot, configuration waits until the device is unlocked or the app becomes active. Consent,
userIdentifier,userAttributes, global tags and screen aliases set meanwhile are applied then.
Calls made before configure:
| Calls | Effect |
|---|---|
Deep link handlers, notification taps, pushToken | Held until configure runs |
setDebug, screenNameProvider, in-app methods | Applied immediately |
userIdentifier, userAttributes, track, trackScreenView | Ignored, logs an error |
setGlobalTags, setScreenAliases | Ignored silently |
| Methods with a completion | Completion gets nil or false |
delegate
static var delegate: GrovsDelegate?Receives deep link payloads and SDK errors. See GrovsDelegate.
- Held weakly. Keep a strong reference elsewhere.
- Setting it before
configurehas no effect. Pass it toconfigureor set it afterwards. - Read it on the main thread.
setSDK
static func setSDK(enabled: Bool)Turns collection on or off at runtime, for example when consent changes. See Privacy & Consent.
- While disabled, the SDK doesn't authenticate, resolve the device, or send events, screen views or purchases.
- It holds
userIdentifier,userAttributes,pushTokenand screen alias updates. Events and purchases on disk stay there. - Enabling authenticates if needed and sends everything held.
setDebug
static func setDebug(level: LogLevel)Sets the minimum log level. Default .error.
- Works before
configure. - Logs go through
os_log. In release builds, message content is private and shows as<private>in Console.app.
Deep links
Forward each system entry point to Grovs. Links received before configure are held until it runs. See Deep Linking.
handleSceneDelegate (openURLContexts)
static func handleSceneDelegate(openURLContexts URLContexts: Set<UIOpenURLContext>)Forward from scene(_:openURLContexts:).
handleSceneDelegate (continue)
static func handleSceneDelegate(continue userActivity: NSUserActivity)Forward from scene(_:continue:).
handleSceneDelegate (options)
static func handleSceneDelegate(options connectionOptions: UIScene.ConnectionOptions)Forward from scene(_:willConnectTo:options:). Handles a link that cold-started the app.
handleAppDelegate (continue)
static func handleAppDelegate(
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
) -> BoolForward from application(_:continue:restorationHandler:) and return its result.
- Main thread only. UIKit already calls your app delegate there.
handleAppDelegate (open)
static func handleAppDelegate(
open url: URL,
options: [UIApplication.OpenURLOptionsKey: Any] = [:]
) -> BoolForward from application(_:open:options:) and return its result.
- Main thread only.
- Returns
falsefor a custom scheme other than your project's Grovs URL scheme, such as a sign-in callback, so another handler after Grovs in an||chain still gets it. Grovs still looks it up, without its query and fragment.
lastReceivedPayload
static func lastReceivedPayload(completion: @escaping GrovsPayloadClosure)Gets the most recent deep link payload, or nil.
allReceivedPayloadsSinceStartup
static func allReceivedPayloadsSinceStartup(completion: @escaping GrovsPayloadsClosure)Gets every payload received since the app launched, or nil.
Users
userIdentifier
static var userIdentifier: String?Your identifier for the current user, typically your user_id. Shown in the dashboard and reports.
- Set it after
configure. - While the SDK is disabled, changes are held until it's enabled.
userAttributes
static var userAttributes: [String: Any]?Attributes of the current user, shown in the dashboard.
- Values must be JSON-representable: strings, numbers, booleans,
NSNull, or arrays and dictionaries of those. An assignment with any other value is rejected and logged. - Held while the SDK is disabled.
Links
generateLink
static func generateLink(
title: String? = nil,
subtitle: String? = nil,
imageURL: String? = nil,
data: [String: Any]? = nil,
tags: [String]? = nil,
customRedirects: CustomRedirects? = nil,
showPreviewiOS: Bool? = nil,
showPreviewAndroid: Bool? = nil,
copyToClipboardiOS: Bool? = nil,
copyToClipboardAndroid: Bool? = nil,
trackingCampaign: String? = nil,
trackingSource: String? = nil,
trackingMedium: String? = nil,
completion: @escaping GrovsURLClosure
)Creates a smart link. See Link Creation.
| Name | Type | Description |
|---|---|---|
title | String? | Link preview title. |
subtitle | String? | Link preview subtitle. |
imageURL | String? | Link preview image URL. |
data | [String: Any]? | Custom payload delivered on deep link open. |
tags | [String]? | Tags for filtering and analytics. |
customRedirects | CustomRedirects? | Per-platform redirect overrides. |
showPreviewiOS | Bool? | Show the preview page on iOS. nil uses the project default. |
showPreviewAndroid | Bool? | Show the preview page on Android. nil uses the project default. |
copyToClipboardiOS | Bool? | Copy the link on the iOS preview page, for clipboard-assisted deferred deep linking. nil uses the project default. |
copyToClipboardAndroid | Bool? | Same, for the Android preview page. |
trackingCampaign | String? | UTM campaign. |
trackingSource | String? | UTM source. |
trackingMedium | String? | UTM medium. |
completion | GrovsURLClosure | Gets the URL, or nil on failure. |
linkDetails
static func linkDetails(path: String, completion: @escaping GrovsLinkClosure)Gets details for a link generated in the current environment, by path.
Returns through completion: the details, or nil if the request fails.
Events
track
static func track(_ name: String, properties: [String: Any]? = nil, tags: [String]? = nil)Tracks a custom event.
- The name must be non-empty and not reserved.
- Events can trigger in-app messages.
- Property rules and limits: Tracking custom events.
trackScreenView
static func trackScreenView(_ screenName: String, properties: [String: Any]? = nil)Tracks a screen view.
screen_nameis added to the properties.- A repeat of the same name within one second is dropped.
setGlobalTags
static func setGlobalTags(_ tags: [String]?)Sets tags attached to every later event. Pass nil to clear them.
setScreenAliases
static func setScreenAliases(_ aliases: [String: String])Maps view controller class names to dashboard names, for example ["CheckoutViewController": "Checkout Page"].
screenNameProvider
static var screenNameProvider: ((UIViewController) -> GrovsScreenName)?Optional resolver for automatically tracked screen names. Returns a GrovsScreenName.
- Consulted before the SDK's own rules.
- Called on the main thread. Works before
configure. - See Custom resolver.
Revenue
See Revenue.
logInAppPurchase
static func logInAppPurchase(transactionID: UInt64, completion: @escaping GrovsBoolCompletion)Logs an App Store purchase by its StoreKit 2 transaction ID.
- Only the ID is sent. The backend resolves product, price and currency through the App Store Server API.
- An ID already logged on this device is skipped.
- The completion gets
trueonce sent. Once configured and enabled,falsemeans the purchase is kept and retried, so don't log it again. - Getting the ID needs StoreKit 2 (iOS 15) in your code.
logCustomPurchase
static func logCustomPurchase(
type: TransactionType,
priceInCents: Int,
currency: String,
productID: String,
startDate: Date? = nil,
completion: @escaping GrovsBoolCompletion
)Logs a purchase, cancellation or refund made outside Apple In-App Purchase.
| Name | Type | Description |
|---|---|---|
type | TransactionType | buy, cancel or refund. |
priceInCents | Int | Price in minor units. |
currency | String | ISO 4217 code. |
productID | String | Your product identifier. |
startDate | Date? | Defaults to now. |
completion | GrovsBoolCompletion | true once sent. Once configured and enabled, false means the purchase is kept and retried, so don't log it again: a second call is a second purchase. |
Push notifications
Setup: Push Notifications.
pushToken
static var pushToken: String?The APNs device token as a hex string, for push campaigns.
- Set it with
setPushToken(deviceToken:)from the APNsData. - Held before
configureand while the SDK is disabled.
setPushToken
static func setPushToken(deviceToken: Data)Sets pushToken from the token passed to application(_:didRegisterForRemoteNotificationsWithDeviceToken:).
handleNotificationResponse
@discardableResult
static func handleNotificationResponse(_ response: UNNotificationResponse) -> BoolHandles a tapped Grovs push. Call from userNotificationCenter(_:didReceive:withCompletionHandler:).
Returns true when Grovs sent the notification, whatever the action.
- Reports a campaign open (
push_open, once per device) and delivers the push togrovsReceivedPayloadFromDeeplink. - The payload is
userInfowithoutaps, merged over the link's payload if there is one. The push's keys win. - Dismissals and custom actions aren't opens.
- Taps before
configureare held until it runs.
handleNotificationOpen
@discardableResult
static func handleNotificationOpen(userInfo: [AnyHashable: Any]) -> BoolSame as handleNotificationResponse, when you only have the payload. Always treated as a tap.
- Never call it from
application(_:didReceiveRemoteNotification:fetchCompletionHandler:)oruserNotificationCenter(_:willPresent:withCompletionHandler:). Every delivery would count as an open.
isGrovsNotification
static func isGrovsNotification(userInfo: [AnyHashable: Any]) -> BoolChecks whether Grovs sent the push as part of a campaign, without handling it.
Returns true when grovs_campaign_id is non-empty.
- Since 3.1, a push with only
grovs_notification_idreturnsfalse.
In-app messages
See In-app messages. Every method here works before configure and keeps its effect across later configure calls.
inAppDelegate
static var inAppDelegate: GrovsInAppDelegate?Receives in-app message events (shown, tapped, dismissed, answered) and can stop a message. See GrovsInAppDelegate.
- Held weakly. Read it on the main thread.
- Messages show without it. See React to messages.
pauseInAppMessages
static func pauseInAppMessages()Holds in-app messages back, during a checkout or video, say. The newest highest priority one waits.
resumeInAppMessages
static func resumeInAppMessages()Lets messages show again, starting with the one that waited, if it still qualifies.
discardInAppMessages
static func discardInAppMessages(dismissCurrent: Bool = false)Drops the waiting message and stays paused. With dismissCurrent: true, also closes the message on screen.
setInAppExcludedScreens
static func setInAppExcludedScreens(_ screens: [String])Sets screens where no message shows. Messages wait until the user leaves.
- Use tracked screen names, from
trackScreenViewor automatic tracking. - Case is ignored.
setInAppDebugLogging
static func setInAppDebugLogging(_ enabled: Bool)Logs, at info level, each campaign considered for an event and why it was skipped.
Types
GrovsDelegate
@objc public protocol GrovsDelegate: AnyObject {
func grovsReceivedPayloadFromDeeplink(link: String?, payload: [String: Any]?, tracking: [String: Any]?)
@objc optional func grovsDidEncounterError(_ error: GrovsError, message: String)
}Receives deep link payloads and SDK errors. Set it with configure or delegate.
| Name | Type | Description |
|---|---|---|
link | String? | The link that opened the app, or nil if unavailable. |
payload | [String: Any]? | The custom data attached to the link. |
tracking | [String: Any]? | Attribution and campaign metadata for the link. |
- Both methods run on the main thread.
- Since 3.1 the protocol is
@objc, so Objective-C apps can adopt it. grovsDidEncounterErroris an@objc optionalmethod, not a Swift default implementation. A signature that doesn't match exactly compiles with only a "nearly matches" warning and is never called.
GrovsError
@objc public enum GrovsError: Int, CustomStringConvertible {
case authenticationFailed = 1
case networkRequestFailed = 2
case eventDispatchFailed = 3
case linkGenerationFailed = 4
case inAppDisplayFailed = 5
}Failure categories reported through grovsDidEncounterError. See Handling SDK errors.
inAppDisplayFailed(new in 3.1): an in-app message couldn't be drawn. It gains no view and retries at its next trigger.- An exhaustive
switchneeds a case forinAppDisplayFailed. descriptionis the snake-case name, for example"authentication_failed".
GrovsInAppDelegate
@objc public protocol GrovsInAppDelegate: AnyObject {
@objc optional func grovsShouldShowInAppMessage(campaignID: String) -> Bool
@objc optional func grovsDidShowInAppMessage(campaignID: String)
@objc optional func grovsDidTapInAppMessage(campaignID: String, buttonID: String?, payload: [String: Any]?)
@objc optional func grovsDidDismissInAppMessage(campaignID: String, reason: String)
@objc optional func grovsDidAnswerInAppMessage(campaignID: String, value: Any, comment: String?)
}Receives in-app message events. Every method is optional and runs on the main thread.
| Method | Called when |
|---|---|
grovsShouldShowInAppMessage | A message is about to show. Return false to stop it. It isn't counted as seen, and nothing else is shown for that event. |
grovsDidShowInAppMessage | A message is on screen. |
grovsDidTapInAppMessage | The user taps. buttonID is nil for a tap on the message itself. payload is set for a key-value action. |
grovsDidDismissInAppMessage | A message closes. See the reasons below. |
grovsDidAnswerInAppMessage | An answered message has closed, in place of the dismissal. value is an Int for stars, the option's ID for a choice. comment is nil unless one was sent. |
Dismiss reason | Meaning |
|---|---|
close_button | The user tapped the close button. |
backdrop | The user tapped outside the message. |
swipe | The user swiped it away. |
app | Your app closed it, for example with discardInAppMessages(dismissCurrent: true). |
orientation | The device turned to an orientation the campaign doesn't allow. Not counted as a dismissal in the dashboard. |
GrovsScreenTracking
public protocol GrovsScreenTracking {
var grovsScreenName: String? { get }
}Adopt on a UIViewController to name it for automatic screen tracking. Return nil to skip it.
GrovsScreenName
public enum GrovsScreenName {
case automatic
case suppress
case name(String)
}Returned from screenNameProvider.
| Value | Effect |
|---|---|
.automatic | Falls through to the SDK's resolution. |
.suppress | Skips the controller. |
.name(_:) | Overrides the name. |
LogLevel
public enum LogLevel: Int, Comparable {
case info = 0
case warn = 1
case error = 2
}Passed to setDebug.
| Value | Logs |
|---|---|
.info | Everything, including informational messages. |
.warn | Warnings and errors. |
.error | Errors only (default). |
TransactionType
public enum TransactionType: String, Codable {
case buy
case cancel
case refund
}Used with logCustomPurchase.
CustomRedirects
public struct CustomRedirects: Codable {
public var ios: CustomLinkRedirect?
public var android: CustomLinkRedirect?
public var desktop: CustomLinkRedirect?
public init(ios: CustomLinkRedirect? = nil, android: CustomLinkRedirect? = nil, desktop: CustomLinkRedirect? = nil)
}Per-platform redirect overrides for generateLink.
CustomLinkRedirect
public struct CustomLinkRedirect: Codable {
public let link: String
public var openAppIfInstalled: Bool
public init(link: String, openAppIfInstalled: Bool = true)
}One platform redirect. When openAppIfInstalled is true, the app opens if installed. Otherwise link is always used.
Closure types
| Type | Signature |
|---|---|
GrovsBoolCompletion | (Bool) -> Void |
GrovsURLClosure | (URL?) -> Void |
GrovsPayloadClosure | ([String: Any]?) -> Void |
GrovsPayloadsClosure | ([[String: Any]]?) -> Void |
GrovsLinkClosure | ([String: Any]?) -> Void |
GrovsIntClosure | (Int?) -> Void |
GrovsEmptyClosure | () -> Void |
GrovsDeviceDataClosureClosure | (Bool, [String: Any]?, String?, [String: Any]?) -> Void. Not used by any public method. |
Extensions
GrovsNotificationServiceExtension
open class GrovsNotificationServiceExtension: UNNotificationServiceExtension {
public var session: URLSession // defaults to .shared
}Shows campaign images in pushes. Make it the superclass of your Notification Service Extension's principal class.
- In the
GrovsNotificationServicemodule (SPM product or pod). Safe to use from app extensions. - Downloads the image and attaches it if it's JPEG, PNG or GIF.
- The push is delivered once, without the image if the download fails or time runs out.
GrovsNotificationContent
public enum GrovsNotificationContent {
public static let imageKey: String // "grovs_image"
@discardableResult
public static func attachImage(to content: UNNotificationContent, session: URLSession = .shared,
completion: @escaping (UNNotificationContent) -> Void) -> URLSessionTask?
@discardableResult
public static func attachImage(to request: UNNotificationRequest, session: URLSession = .shared,
completion: @escaping (UNNotificationContent) -> Void) -> URLSessionTask?
}Adds the campaign image to an existing extension's content, keeping your changes. In the GrovsNotificationService module.
Returns the download task, or nil when there's nothing to download.
completionruns once on a background queue, or right away when there's no image.- It gets the content unchanged when there's no image or it can't be shown.
- Cancel the returned task in
serviceExtensionTimeWillExpire(). The completion then runs without the image.
grovsScreen
func grovsScreen(_ screenName: String, properties: [String: Any]? = nil) -> some View
func grovsScreen(properties: [String: Any]? = nil, fileID: String = #fileID) -> some ViewSwiftUI modifier. Tracks a screen view when the view appears.
- Suppresses automatic tracking for its hosting controller, so the screen is never counted twice.
- The unnamed form uses the file name:
CheckoutView.swiftbecomes"Checkout".
trackScreenView (modifier)
func trackScreenView(_ screenName: String, properties: [String: Any]? = nil) -> some ViewSwiftUI modifier. Same as grovsScreen(_:properties:).
Deprecated
The messages inbox was removed in 3.1. These methods remain so existing code compiles, and show nothing. Use in-app messages.
displayMessagesViewController
static func displayMessagesViewController(completion: GrovsEmptyClosure?)
static func displayMessagesViewController(completion: GrovsEmptyClosure?, onFailure: GrovsEmptyClosure?)Shows nothing. Calls completion once on the main thread and never calls onFailure.
numberOfUnreadMessages
static func numberOfUnreadMessages(completion: @escaping GrovsIntClosure)Always yields 0, on the main thread.