Skip to content
The mobile SDKs are available on request. Email support@grona.ai to get access.

Grona components

Grona components are the native views the SDK draws inside a slot view: a banner, a progress bar, an offer and a message. This page lists what each component shows and which fields a campaign can set, so you know what Grona can put in your app without a release. Your app only places the slot view; the content comes from the signed configuration.

Each SDK-rendered campaign carries a render object with a component field and that component’s fields. The SDK validates every field when it loads the configuration. A campaign with an unknown field, a missing required field or a malformed colour is inactive, and the rest of the configuration still applies.

Every text field is a map from locale to string, for example {"en": "Weekend breakfast", "fr": "Petit-déjeuner du week-end"}. The SDK picks the shopper’s locale from the context your app sets, and falls back to the workspace’s fallback locale (en unless the configuration says otherwise).

  • Text is plain text, at most 2,000 characters. No HTML, no links, no markdown.
  • The SDK strips control characters other than newline and tab, and the bidirectional embedding and override characters that could reorder digits in right-to-left scripts.
  • The SDK fills these templates: {total}, {gap}, {reward}, {min}, {name}, {price} and {count} (the number of products). Unknown tokens stay as written.
  • A known token with no value hides that text. If the text is required (a title or a call-to-action label), the whole component is hidden.
  • Money renders from minor units: whole amounts without decimals (60), otherwise with two (12.99).
  • Product names and prices always come from your app’s product data, never from the configuration.

A campaign can set style with background, text and accent, each as #RRGGBB. Any colour the campaign leaves out falls back to your app’s theme tokens. The SDK also corrects text colours that would not be readable on the background. See Theming and accessibility.

A banner image is one of:

  • An image bundled in your app, as asset://img/<path>. The path must sit under img/ in your app’s assets.
  • An https URL on a host listed in the workspace’s image host allowlist.

Anything else is dropped. A dropped or failed image means no image; the component still renders.

A card with an optional eyebrow, a title, optional body text, an optional image and an optional call-to-action button. Use it for promotions and nudges such as a weekend breakfast banner.

Field Required Meaning
eyebrow No Short label above the title
title Yes Main line
body No Supporting text
image No Bundled asset or allowlisted https image, shown beside the text
cta No {label, action}: the button label and what a tap does
style No background, text, accent
fold_on_action No When true, the banner collapses after its action succeeds. Default false

The call to action runs only from the shopper’s tap. It does one of three things:

Action Shape
Add several products {"type": "add_all", "products": [{"id": "sku_20877"}, {"id": "sku_31005", "qty": 2}]}
Add one product {"type": "add", "product": {"id": "sku_10432"}}
Navigate {"type": "navigate", "route": {"type": "category", "id": "dairy"}}

Route types are home, product, category, cart, checkout and deals; your app resolves them with its own router. Adds are capped at 5 per line and 5 lines by default (your app can change both caps), and every product must resolve through your product lookup and be in stock. In a call-to-action label, {total} is the sum of the action’s products.

{
"component": "banner",
"eyebrow": {"en": "This weekend"},
"title": {"en": "Restock the basics"},
"body": {"en": "Your usual items in one tap."},
"image": "asset://img/basics.png",
"cta": {
"label": {"en": "Add all for {total}"},
"action": {"type": "add_all", "products": [{"id": "sku_10432"}, {"id": "sku_20877"}, {"id": "sku_31005"}]}
},
"fold_on_action": true
}

A card with a progress bar towards a basket threshold, such as free delivery. It is bound live to the basket total your app pushes, so it updates as the shopper adds and removes items.

Field Required Meaning
title No Heading above the bar
tiers Yes [{min_minor, reward_minor}], in ascending order of min_minor
text Yes Line shown while below the threshold, usually with {gap}
met_text Yes Line shown once the threshold is reached
footnote No Small print below the bar
after_met Yes hold keeps showing the met state; next_tier moves on to the next tier
style No background, text, accent

{gap} is the amount still needed for the current tier and never goes below 0. {min} is the tier’s threshold and {reward} its reward.

{
"component": "progress",
"title": {"en": "Free delivery"},
"tiers": [{"min_minor": 4000, "reward_minor": 599}],
"text": {"en": "Add {gap} more for free delivery"},
"met_text": {"en": "Free delivery is on us"},
"after_met": "hold"
}

A card with an optional badge, a title and optional body text, tied to a money-bearing treatment such as 10% off the order.

Field Required Meaning
badge No Short label in a pill above the title
title Yes Main line
body No Supporting text
treatment Yes {type, value_milli}: the treatment type and its value in thousandths (10000 is 10, so 10% for a percent_off treatment)
style No background, text, accent
{
"component": "offer",
"badge": {"en": "This weekend"},
"title": {"en": "10% off this order"},
"body": {"en": "Discount applied to your order."},
"treatment": {"type": "percent_off", "value_milli": 10000}
}

A compact line of text with an optional icon, for confirmations and short notes such as “Discount applied to your order”.

Field Required Meaning
text Yes The message
icon No star, check or info. Any other value draws no icon

A message takes its colours from your theme; it has no style field.

{
"component": "message",
"text": {"en": "Discount applied to your order"},
"icon": "check"
}

When a component is shown because of a preview pin, the SDK draws a small “Preview” chip over its corner, so a tester can tell pinned content from live content. See the preview links page for Android or iOS.