Preview links
This page lets testers open a campaign variant on their own device before it goes live. A preview link carries a one-time pairing code. The SDK exchanges it for a signed pin bound to that install, so the tester sees the variant and nobody else’s experience changes. Your app routes the link to Grona.handleLink.
Link format
Section titled “Link format”Preview links use your app’s own URL scheme with the host grona-preview:
| Link | Effect |
|---|---|
acmemarket://grona-preview?code=<pairing code> |
Pairs this install with one campaign variant. |
acmemarket://grona-preview?clear=1 |
Removes every preview pin on this device. |
A code is 8 to 64 characters of letters, digits and hyphens. The SDK rejects a link with any other host, a port, user info, a path other than empty or /, a fragment, an extra or repeated parameter, or a query longer than 256 characters.
Handle the link
Section titled “Handle the link”-
Add an intent filter for your scheme and the
grona-previewhost to the activity that handles deep links:app/src/main/AndroidManifest.xml <activityandroid:name=".MainActivity"android:exported="true"android:launchMode="singleTask"><intent-filter><action android:name="android.intent.action.VIEW" /><category android:name="android.intent.category.DEFAULT" /><category android:name="android.intent.category.BROWSABLE" /><data android:scheme="acmemarket" android:host="grona-preview" /></intent-filter></activity> -
Pass the link to
Grona.handleLinkfromonCreateandonNewIntent:MainActivity.kt import ai.grona.sdk.Gronaimport android.content.Intentimport android.os.Bundleclass MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)// A launch from recents carries the old link; do not replay itval fromHistory = intent.flags and Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY != 0if (savedInstanceState == null && !fromHistory) handleDeepLink(intent)}override fun onNewIntent(intent: Intent) {super.onNewIntent(intent)setIntent(intent)handleDeepLink(intent)}private fun handleDeepLink(intent: Intent?) {val uri = intent?.data ?: returnif (Grona.handleLink(uri)) return // a Grona preview link, accepted or notopenAppLink(uri) // your own deep-link routing}} -
Set a
previewUrlin your options. Grona provides it for your workspace. Without it the SDK ignores codes and can only clear pins.
handleLink returns true for any link whose host is grona-preview, whether or not the SDK accepted it, and false for every other link. A rejected link is logged through your GronaLogger.
Pairing
Section titled “Pairing”When a code arrives, the SDK posts the code, the install id and the workspace key over https to previewUrl, and stores the signed pin it gets back.
- Pairing is refused while consent is
DENIED, because the request carries the install id. UnderUNKNOWNandGRANTEDit runs: pairing is a tester action, not analytics. - One exchange runs at a time. A link that arrives while one is in flight is ignored.
- Any response other than a valid pin leaves existing pins unchanged.
How a pin behaves
Section titled “How a pin behaves”- Lifetime. A pin lasts until it expires (at most 24 hours), until a
clear=1link, untilGrona.reset(), or until consent becomesDENIED. It survives app restarts and is verified again on every load. - One per campaign. The newest pin for a campaign wins.
- What it bypasses. The pinned campaign goes first in its placement and skips audience rules, holdouts, the traffic split and activation.
- What it never bypasses. A campaign disabled in the configuration (
enabled: false), an expired configuration, or validation. A customer-unit campaign, such as every offer, still shows only to an identified shopper. - Control variants. A pinned control variant renders nothing, as any control arm does.
- Marking. SDK components draw a “Preview” chip, decisions carry
isPreview = true, and every event carries a preview flag so analysis excludes it. - No grants. A pinned offer renders without a grant, but it never appears in
Grona.activeTreatments(). Pins never produce a grant, so a preview can never change what an order costs.
Debuggable builds can also pin a variant locally from the debug view, without a link. Local pins are unsigned, last at most 24 hours, and are ignored in apps that are not debuggable.
Next steps
Section titled “Next steps”- Test and debug your integration.