The mobile SDKs are available on request. Email support@grona.ai to get access.
iOS API reference
This page lists the public API of the Grona iOS SDK 0.1.0. The Grona product is the module Grona; the GronaDebug product is the module GronaDebug. Every type is public, and the value types are Sendable.
The SDK never throws into your app, with one exception: the GronaOptions initialiser throws GronaOptionsError on invalid input.
The SDK entry point. Call start once at launch. Every other call does nothing until then.
Member
Description
static let version: String
The SDK version, "0.1.0". Compared against the minimum SDK version in configurations.
@MainActor static func start(options: GronaOptions, host: any GronaHost)
Starts the SDK. Constant time: work is queued off the main thread. Ignored on repeat calls and in app extensions. Keeps a strong reference to host for the life of the process.
static func setConsent(_ consent: GronaConsent)
Sets the consent state. The SDK starts in .unknown on every launch: events stay in memory and none are sent.
static func identify(_ customerID: String?)
An opaque internal customer id matching [A-Za-z0-9._:-]{1,128}, never a phone number, email or national id; nil on logout. A new id clears the profile and grants.
static func setProfile(_ profile: GronaProfile?)
Profile from your own authenticated session. Ignored unless it matches the identified customer. nil clears it.
static func setContext(_ context: GronaContext)
Sets the shopper context that rules read.
static func setBasket(_ basket: GronaBasket)
Push a fresh snapshot whenever the basket changes. Live components and decisions re-evaluate.
Decision for a host-rendered placement, bound to anchor. key is the line’s product id for keyed placements such as cart_line. onDecision runs on the main actor, never synchronously, and again only when the result changes. Binding the same anchor again replaces the previous subscription.
Handles a preview link: <scheme>://grona-preview?... or https://<host>/grona-preview?.... Returns true when the link was Grona’s, whether or not it was accepted.
static func reset()
Logout or erasure: new install id, and the queue, customer, profile, grants, basket snapshot, preview pins and session cleared.
Options for Grona.start. Each parameter is also readable as a let property of the same name.
Parameter
Description
workspaceKey
The workspace key, a public identifier, not a secret. Must match [A-Za-z0-9._:-]{1,128}.
configURL
Signed remote configuration (https). Without it the SDK runs on the bundled copy.
bundledConfig
File URL of the signed bundled configuration, applied at launch and offline.
configKeys
Trusted configuration signing keys, key id to base64 DER SubjectPublicKeyInfo of a P-256 key. Add current and next. At least one is required.
grantKeys
Trusted grant signing keys, in the same format.
eventsURL
Events endpoint (https). Without it the SDK sends no events and keeps no event queue. Debug builds keep the last 200 events in memory for the debug view.
previewURL
Preview pairing endpoint (https). Without it preview links only clear pins.
activationSource
Source of on and off answers from an external campaign system.
grantSource
Fetches treatment grants from your backend.
theme
Visual tokens for SDK components.
logger
Receives SDK diagnostics. Silent when nil.
maxAddQuantity
Highest quantity one action may add, 1 to 20. Default 5.
maxAddLines
Most lines one action may add, 1 to 20. Default 5.
sendPreConsentEvents
Send events buffered before consent once it is granted. Default false.
demoMode
Demo only, never in production. Takes effect only when the signed configuration also enables demo mode. Default false.
A place in your UIKit layout where Grona renders native components: banner, progress, offer and message. With nothing to show it stays laid out at zero height. Never hide it.
Member
Description
init(placement: String)
Creates a slot for placement.
override init(frame: CGRect)
Creates a slot with an empty placement. Set placement before screen.
required init?(coder: NSCoder)
For storyboards and nibs. Set placement in the Attributes inspector.
@IBInspectable var placement: String
The placement. Set it before screen.
var screen: GronaScreen?
Starts the slot; rules read it. An equal value continues the visit; nil ends it and empties the slot.
The slot changes its height through Auto Layout when content arrives or leaves. In table and collection views, set selfSizingInvalidation to .enabledIncludingConstraints.
A GronaSlotView for SwiftUI. Reports its height to SwiftUI layout. A nil screen ends the visit and empties the slot.
gronaDecision(placement:screen:key:onDecision:)
Requests a decision with the modified view as the anchor, measured through a UIKit view placed behind it. Calls the latest onDecision you pass. A nil screen ends the subscription and its visit; a new placement, screen or key resubscribes.
Commerce events your app forwards from its analytics layer. Money is in minor units; no search text, no full baskets. Exception: on keyed placements such as cart_line, campaign events carry the line’s product id as their key, in every arm. So while a cart_line campaign is live, the product ids of the cart lines bound to it leave the device.
A product decision your app renders with its own views. Treat unknown types as no decision. Two values are equal only when they come from the same delivery. A decision delivered again, for example after a rebind, is a new value even when its content is the same, so SwiftUI redraws with its new action handle. Do not compare decisions field by field to skip updates.
Member
Description
let placement: String
The placement.
let campaignID: String
The campaign.
let variantID: String
The variant.
let type: GronaDecisionType
.rail, .bundle, .productCard, .substitute, or a type from a newer configuration.
let title: String?, let subtitle: String?, let badge: String?, let ctaLabel: String?
Copy from the configuration. Render as plain text.
let products: [GronaDecisionProduct]
The products to show. Never empty.
let key: String?
For keyed placements such as cart_line: the line this decision belongs to.
let extras: [String: String]
Layout hints from the configuration, such as position for feed rows. Untrusted.
A money-bearing treatment. Display state only: your order backend applies it only after verifying token.
Member
Description
let campaignID: String
The campaign.
let variantID: String
The variant.
let placement: String
Where it was shown.
let type: String
The treatment type.
let valueMilli: Int
Value in thousandths, so 10000 is 10 (10% off with percent_off).
let token: String?
Grona-signed grant (compact JWS); nil in demo mode. A real backend ignores a treatment without a token: no treatment, and the order still goes through.
let isDemo: Bool
true for a demo-mode treatment.
var description: String, var debugDescription: String, var customMirror: Mirror
A summary that leaves the token out, so printing or dumping a treatment never writes the grant to your logs.
Visual tokens so SDK components match your app. Each value is readable as a property. Colours are resolved once, the first time Grona draws a component.
Receives SDK diagnostics, called off the main actor. Never given customer ids, baskets, tokens or keys.
enum GronaLogLevel: Int, Comparable, Sendable
debug, info, warning, error
The level of a log message.
protocol GronaActivationSource: Sendable
func activeExternalIDs() async -> Set<String>?
On and off answers from an external campaign system, called off the main actor. nil when unknown. After 10 seconds the SDK stops waiting and cancels the task. Activation can only switch campaigns off.
Fetches grants from your backend, which asks Grona’s server for them. Called off the main actor. Returns compact JWS grants, or throws on failure. After 10 seconds the SDK stops waiting and cancels the task.