Docs
grovs.io Start for free

iOS SDK 3.0

What changes when you move the Grovs iOS SDK from 2.x to 3.0.

3.0.0 removes four public types that were SDK internals and changes one closure signature. Most apps bump the version, decide on automatic screen tracking, and check how they use setSDK(enabled:).

Requirements are unchanged: iOS 13.0, Swift 5.9 (Xcode 15).

Checklist

  1. Bump the dependency to 3.0.0.
  2. Decide on automatic screen tracking. It's on by default.
  3. Remove references to types that are now internal.
  4. Update GrovsDeviceDataClosureClosure if you name it.
  5. Review your consent gating: setSDK(enabled: false) now stops everything, and configure has an enabled: parameter.
  6. Check the other behavior changes: the clipboard paste prompt, links in messages, and your App Store privacy details.

1. Bump the version

Swift Package Manager: in your project's Package Dependencies, select Grovs and set the rule to Up to Next Major Version from 3.0.0. A rule pinned to 2.x won't pick up 3.0. In a Package.swift:

Swift
.package(url: "https://github.com/grovs-io/grovs-iOS.git", from: "3.0.0")

CocoaPods: in your Podfile, then run pod update Grovs:

Ruby
pod 'Grovs', '~> 3.0'

2. Decide on automatic screen tracking

This changes behavior with no code change on your side.

autoTrackScreenViews defaults to true. An app that only recompiles starts hooking UIViewController.viewDidAppear and sending a screen_view event for each screen.

Keep it for screen analytics. Events & Screen Tracking explains how names are chosen and overridden.

To opt out, pass false:

Swift
Grovs.configure(
    APIKey: "your-api-key",
    useTestEnvironment: false,
    autoTrackScreenViews: false,
    delegate: self
)

Existing configure calls compile unchanged: every new parameter has a default.

3. Remove references to types that are now internal

Four types public in 2.x are internal in 3.0. They were implementation details, but code that referenced or subclassed one won't build:

TypeWasReplacement
DataCacheopen class, plus DataCache.instanceNone. Use your own cache.
BaseServiceopen classNone. Use URLSession directly.
ImageFormatpublic enumNone.
JSONClosurepublic typealiasDefine your own closure type.

Everything else public in 2.x is still public and source-compatible.

4. Update GrovsDeviceDataClosureClosure if you use it

The typealias gained a leading success flag, so a transport failure differs from an empty result:

Swift
// 2.x
(_ dictionary: [String: Any]?, _ link: String?, _ tracking: [String: Any]?) -> Void
 
// 3.0
(_ success: Bool, _ dictionary: [String: Any]?, _ link: String?, _ tracking: [String: Any]?) -> Void

No public method uses this type. If you declared a variable or parameter with it, add the leading parameter.

setSDK(enabled: false) now stops everything. In 2.x it blocked link generation and deep link resolution but kept collecting lifecycle events. In 3.0, while disabled, the SDK doesn't authenticate, resolve the device, or send lifecycle events, custom events, screen views or purchases. Changes to userIdentifier, userAttributes, pushToken and screen aliases are held until you re-enable it. Queued events stay on disk.

Start disabled with enabled:. Calling setSDK(enabled: false) right after configure is too late: configuring starts the first round of collection. If you gate on consent, pass it to configure:

Swift
// 2.x — collection has already started when setSDK runs
Grovs.configure(APIKey: "your-api-key", useTestEnvironment: false, delegate: self)
if !hasConsent {
    Grovs.setSDK(enabled: false)
}
 
// 3.0
Grovs.configure(APIKey: "your-api-key", useTestEnvironment: false, enabled: hasConsent, delegate: self)

The value isn't persisted, so pass your stored consent on every launch. A disabled configure reports false without authenticating. If that completion feeds your error reporting, don't count it as a failure. See Privacy & Consent.

6. Check the other behavior changes

Clipboard-assisted deferred deep linking is on. On the first launch after a fresh install, the SDK can read a Grovs link from the clipboard to attribute the install, and iOS may show its paste prompt. It happens only if the backend reports recent clicks on copy-to-clipboard links for your project (currently a 48-hour window) and the clipboard holds a web URL. If you never enable copy-to-clipboard for the project or its links, the prompt never appears. See Clipboard-assisted deferred deep linking.

Links in messages are restricted. Message content now opens only http, https, mailto, tel, and sms links. Other schemes are ignored. Switch links that use a custom scheme such as yourapp:// to a universal link.

The SDK ships a privacy manifest. PrivacyInfo.xcprivacy is bundled for Swift Package Manager and CocoaPods and merged into your app's privacy report. Check your App Store privacy details against what the SDK collects.

Logging moved to os_log. setDebug(level:) works as before. In release builds, message content is marked private and appears as <private> in Console.app.

Device model is Apple's identifier. The SDK sends the hardware identifier (for example iPhone15,2) instead of a mapped name, so new devices need no SDK update.

Queued events survive the upgrade. 3.0 reads 2.x event archives, so nothing pending is lost.

What's new in 3.0

Nothing here is required.

  • Custom events and screen tracking: track, trackScreenView, global tags, screen aliases, .grovsScreen() for SwiftUI, and GrovsScreenTracking for UIKit.
  • Consent gating: the enabled: parameter on configure, and a setSDK(enabled:) that stops all collection.
  • Error callbacks: an optional grovsDidEncounterError(_:message:) on GrovsDelegate. It has a default implementation, so existing delegates need no change.
  • Clipboard-assisted deferred deep linking: deterministic install attribution on first launch, with clipboardDomains for custom link domains.
  • copyToClipboardiOS / copyToClipboardAndroid: per-link override of the project's copy-to-clipboard setting.
  • displayMessagesViewController(completion:onFailure:): tells a dismissal apart from a presentation that never happened. The messages inbox was later removed in 3.1.

Verifying the upgrade

Turn on info logging before configure and confirm the completion reports true:

Swift
Grovs.setDebug(level: .info)
Grovs.configure(APIKey: "your-api-key", useTestEnvironment: true, delegate: self) { success in
    print("Grovs configured: \(success)")
}

Then check that deep links still reach grovsReceivedPayloadFromDeeplink. If you kept automatic screen tracking, check that screen views appear in the dashboard under names you recognize. Rename any that read like class names with setScreenAliases.

See also

Last updated 2026-10-27
Was this page helpful?