Show full-screen image modals over gameplay, configured by ZBD without an app store release.
Creatives are full-screen image modals your game can show over gameplay. ZBD sets up the creative and hosts the artwork; your game shows it with one line of code. Changing artwork, copy, or behavior later is a ZBD-side change — no SDK update and no app store release.Typical uses:
An onboarding carousel explaining how rewards work
That’s the whole integration. The SDK fetches your app’s creatives during Init() and preloads their images, so the modal appears instantly.To react to what the player did:
ZBDController.Instance.ShowCreative("cr_onboarding_tour", result =>{ if (!result.shown) { Debug.Log($"Nothing shown: {result.error}"); return; } if (result.dismissReason == "cta") Debug.Log("Player tapped through to rewards"); else Debug.Log($"Closed on page {result.lastPage + 1} of {result.pageCount}");});
Creatives can’t be configured self-serve yet. To set one up, reach out to your Customer Success Manager — they’ll configure it with you and host your artwork.
Tell your Customer Success Manager the following, and send them your images:
What to provide
Notes
Creative key
The ID your game will pass to ShowCreative(). Choose it carefully — it can’t be changed later, because analytics reference it.
Number of pages
One page = a simple modal. Several = a swipeable carousel with page dots.
Locale
Only if you need it. Leave it out for a creative that should show to everyone (see Localization).
Transition
How the modal appears: popup, fade, or slide. Defaults to fade.
Tap opens rewards
Whether tapping the last page opens the ZBD rewards interface. Off = the creative is purely informational.
Two further properties are set on the ZBD side and worth knowing about:
Property
What it does
Backdrop dismisses
Whether tapping the dimmed area outside the image closes the modal. The close button always works regardless.
Active
Inactive creatives are not served to the SDK at all. This is how a creative is retired — preferred over deleting, so historical analytics keep resolving.
Each page needs at least one image — portrait, landscape, or both. The SDK picks whichever matches the device’s current orientation, and swaps automatically when the player rotates. If you supply only one, it’s used in both orientations.
Portrait art is not required. If your game is landscape-only, send landscape art alone — there’s no need to supply portrait images that would never be shown. The same applies in reverse for portrait-only games.
On a multi-page creative the player can:
Tap the image to advance to the next page
Swipe left or right to move between pages
Use the next arrow (hidden on the last page)
See their position via page dots
On the final page, tapping either opens the rewards interface or does nothing, depending on the Tap opens rewards setting.
HTTPS only — plain HTTP is blocked by iOS App Transport Security and Android’s cleartext policy.
PNG or JPEG only — WebP, SVG, GIF, and AVIF cannot be decoded on device, even though they preview fine in a browser.
Serve images with a Content-Type of image/png or image/jpeg and no Content-Encoding header. An image that displays correctly in a browser can still fail to decode on device if it’s served with an encoding header.
Maximum 5 pages per creative. Every page is downloaded before the modal appears, so keep image dimensions reasonable — target the device resolution you actually need, not the largest possible.
Not set — served to everyone. This is what you want for most creatives.
Set (e.g. en, en-GB, pt-BR) — served only to players whose locale matches.
If a creative key has only localized versions and none without a locale, players whose locale doesn’t match will see nothing. When you localize, always keep one version with no locale as the fallback.
Shows the creative with the given key. The callback fires when the modal closes — or immediately, with shown == false, if it couldn’t be shown.Your game decides when a creative appears. The SDK does no scheduling or frequency capping, so you’re free to build your own rules (once per session, after level 3, only when a balance is unclaimed, and so on). See Best practices.
The player tapped the creative. If Tap opens rewards is on, the rewards interface is opening.
"close"
The player used the close button.
"backdrop"
The player tapped outside the image.
"programmatic"
Your game called CloseCreative().
"safety-timeout"
An internal safeguard closed the modal. Rare.
"none"
Placeholder value; not seen on a normal close.
Together, lastPage and pageCount give you a drop-off funnel: you can tell whether a player read all three pages and tapped through, or bailed on page one.
No active creative with that key for this app. Check spelling with your Customer Success Manager, and that your build is pointed at the right environment.
A creative is already showing or pending
One creative at a time. Wait for the previous callback.
Creative images could not be loaded
An image failed to download or decode — usually the format or Content-Type rules above.
Creative has no usable image
The creative has no valid page images configured.
A creative ID is required
Empty key passed.
Cancelled before display
CloseCreative() was called while it was still loading.
Every one of these is a clean no-op from the player’s perspective: nothing renders and your callback runs, so it’s safe to call ShowCreative optimistically.
A one- to three-page reveal explaining how rewards work is the highest-value creative you can ship. Show it once — after the player’s first reward has landed, not at cold launch. A pitch before the player has earned anything is a cold offer and triggers suspicion; a reveal of a balance they already have converts. Fire the first reward early in normal play, let the toast land, then show the creative.Three pages is usually enough to answer the only three questions a new player has:
The reveal — this game pays real rewards, and you’ve already started earning. Lead with the balance the player already has — “you’ve already earned 240 coins” converts better than an announcement.
The reason — here’s why, so it doesn’t feel like a scam. This page carries the most important sentence in your rewards copy — “game studios share their ad revenue with players” — which the modal’s built-in first-time screen doesn’t show. The creative is how you ship it. See the Player Communication Guide.
The portal — here’s where your progress lives and how you claim.
What page 3 says depends on how your players actually get paid, so the flow differs. Each example below is a six-step journey spanning several creatives — the three reveal pages above, then separate creatives for the first-earn, stacking and payout-confirmation moments (a single creative is capped at five pages, and you wouldn’t want all six at once anyway):
Gift cards
Cash App
Mixed options
Gift cards have a minimum to reach, so the flow is about saving up toward a named card — the goal is what motivates.
A three-page reveal: what just happened, the reason it's real, and where rewards live.
Page
What it says
1 · Reveal
This game pays real rewards — and you’ve already started earning
2 · Reason why
No catch — we share a slice of this game’s revenue with players
3 · The portal
Where your progress lives, and how you claim
4 · First earn
You’ve earned your first [Currency]
5 · Stacking
You’re X% of the way to a $5 gift card
6 · Claimed
Your gift card is ready
With Cash App there’s no minimum, so lead on immediacy instead of a savings goal: a few cents can leave straight away. Page 3 explains the mechanic — paid in bitcoin, landing in their Cash App.
Cash App set: no threshold, so a balance and a live cash-out replace the progress bar.
Page
What it says
1 · Reveal
This game pays you real money — straight to Cash App. No $5 minimum. Cash out a few cents if you want.
2 · Reason why
No catch — we share a slice of this game’s revenue with players
3 · How you’re paid
You’re paid in bitcoin, straight to your Cash App. Free to receive. Keep it, or turn it into dollars.
4 · First cents
You’ve earned 6c. There’s no minimum — cash out whenever you like.
5 · Stacking
You’re at $1. Cash out now, or keep stacking.
6 · Sent
Sent — $1 landed in your Cash App. That took about four seconds.
The “no minimum” line is doing the work here: it removes the objection a player brings from other rewards apps, where earnings are stuck behind a threshold they’ll never reach.
Claim “free” only for the receive. Cash App charges nothing to receive bitcoin, but selling it for dollars carries their standard fee (around 2% under $500, plus a spread). Page 3 above says “free to receive” and then “turn it into dollars” without pricing it — deliberately. Don’t write copy implying the conversion is free.
Removing the threshold also removes your motivational engine — there’s no goal to climb toward when the whole pitch is that you don’t have to climb. That’s the trade: instant liquidity rewards checking in, where a goal pushes players on. If retention is the aim, consider the mixed set instead.
Offering several payout options? Make choice the pitch — small amounts out instantly, or save toward something bigger. Page 3 shows the options rather than one mechanic.
Mixed set: the only one carrying both motivations — take it now, or climb to a named card.
Page
What it says
1 · Reveal
This game pays you real money — however you want it. Amazon cards, Cash App, your ZBD wallet and more.
2 · Reason why
No catch — we share a slice of this game’s revenue with players
3 · Your options
Cash out your way. A few cents to Cash App or ZBD, or save up for a gift card.
4 · First cents
You’ve earned 6c. Take it now, or keep going for something bigger.
5 · Stacking
You’re at $1. Take it now, or reach $5 for an Amazon card.
6 · Sent
Sent — your $1 is on its way. Switch payout any time.
Naming the brands (“Amazon cards, Cash App”) converts better than “multiple payout options” — concrete beats abstract.
“No minimum” is not a blanket claim once gift cards are in the mix. It’s true of Cash App and the ZBD wallet, and false of gift cards, which only come in fixed denominations. Split it the way page 3 does — “a few cents to Cash App or ZBD, or save up for a gift card” — rather than promising no minimum across the board.
This is the only set that gets both motivational engines at once: instant rails let a player take six cents now, and gift-card denominations still leave something ahead worth reaching. Page 5 carries both — a live balance above a meter that ends at a named card.
The Amazon and Cash App marks in these examples are stylised stand-ins. Swap them for licensed assets before shipping anything player-facing — Amazon in particular has specific rules about the smile and its clear space, which usually arrive with your gift-card agreement.
Don’t ship all six steps as one creative. The first three belong together as the reveal; steps 4–6 are separate creatives triggered at those moments — a player who has just earned 6c doesn’t need to be told what happens at $5 yet.
Trigger it from your first-reward moment, with PlayerPrefs so it only ever shows once:
private const string RevealShownKey = "zbd_reveal_shown";// Call this from the gameplay moment where the player's first reward landsvoid OnFirstRewardLanded(){ // Already seen it — don't show it again if (PlayerPrefs.GetInt(RevealShownKey, 0) == 1) return; ZBDController.Instance.ShowCreative("cr_onboarding_tour", result => { // Only record it if it actually displayed, so a failed // image load doesn't suppress the reveal forever if (!result.shown) return; PlayerPrefs.SetInt(RevealShownKey, 1); PlayerPrefs.Save(); });}
Set your “already shown” flag inside the callback and only when result.shown is true. If you set it before calling ShowCreative, a network or image failure would permanently prevent the player from ever seeing the reveal.
A creative that reflects the player’s actual progress converts far better than a generic announcement. Once a player is earning, show reminder creatives at milestones on the way to their first reward.
Reminder creatives at three milestones: first reward earned, halfway to a gift card, and ready to claim.
Three milestones map naturally onto the player’s journey:
Started earning — their first reward has landed. Reinforce that it’s real.
Halfway — they’re about halfway to a specific gift card. Name the card to make it concrete.
Ready to claim — they can redeem now. This is the one that should open the rewards interface.
GetGiftCards tells you exactly where the player is: unlockedPercent is a 0–100 progress value toward each card, so you can pick the right creative without doing any conversion yourself.Ask your Customer Success Manager to enable Tap opens rewards on the “ready to claim” creative, so tapping it opens the rewards interface directly.
private const string MilestoneKey = "zbd_reward_milestone";void MaybeShowProgressReminder(){ ZBDController.Instance.GetGiftCards(response => { if (!response.success) return; if (response.giftCards == null || response.giftCards.Length == 0) return; // The cheapest card is the one the player will reach first ZBDGiftCard target = response.giftCards[0]; foreach (ZBDGiftCard card in response.giftCards) { if (card.priceInSats < target.priceInSats) target = card; } // -1 means progress couldn't be calculated — skip rather than guess if (target.unlockedPercent < 0) return; string creativeId = null; int milestone = 0; if (target.unlockedPercent >= 100) { creativeId = "cr_ready_to_claim"; milestone = 3; } else if (target.unlockedPercent >= 50) { creativeId = "cr_halfway"; milestone = 2; } else if (response.availableBalanceInSats > 0) { creativeId = "cr_started_earning"; milestone = 1; } if (creativeId == null) return; // Show each milestone at most once, and never step backwards if (PlayerPrefs.GetInt(MilestoneKey, 0) >= milestone) return; ZBDController.Instance.ShowCreative(creativeId, result => { if (!result.shown) return; PlayerPrefs.SetInt(MilestoneKey, milestone); PlayerPrefs.Save(); }); });}
Storing a single monotonic milestone number rather than a flag per creative means a player who jumps straight past 50% only sees the milestone they actually reached, and never sees an earlier one afterwards.If you’d rather remind periodically than only once per milestone, store a timestamp alongside the milestone and re-show after a cooldown you’re comfortable with.
Creatives only reach a player who is already in your game. To win back a player who left with an uncashed balance, pair them with local notifications — OS-scheduled reminders that need no push infrastructure, and can be driven from the same GetGiftCards progress value.
The SDK draws its own close button, next arrow, and page dots. Any of them can be replaced with your own art or hidden entirely, so the modal fits your game.You don’t need to call SetCreativeStyle at all — the SDK’s built-in defaults apply automatically. Only call it if you want to change something:
SetCreativeStyle(ZBDCreativeStyle style)
Call it once after Init(), before your first ShowCreative.
ZBDController.Instance.SetCreativeStyle(new ZBDCreativeStyle{ closeButtonSprite = myCloseSprite, nextButtonSprite = myArrowSprite, pageDotActiveSprite = myDotOn, pageDotInactiveSprite = myDotOff, backdropColor = new Color(0.05f, 0f, 0.15f, 0.8f), showNextButton = false, // the artwork already draws its own NEXT button});
Every field is optional — omit one and the SDK’s built-in control is used. If you’ve set a custom style and want to go back, pass null to reset to defaults.
Sizes and offsets are in the overlay’s reference space (1080×1920, scaled to fit), not raw pixels, so they stay consistent across devices.
If you set showCloseButton = false on a creative that also has Backdrop dismisses turned off, the SDK re-enables the close button anyway — otherwise the player would have no way to close the modal.
Optional. Refreshes the cached creative list. The SDK already fetches during Init(), and ShowCreative fetches lazily if needed, so most games never call this.
Preloading. Creatives and their images are fetched during Init() so the first ShowCreative is instant. If the fetch fails (no network, for example), Init() still completes normally — creatives simply retry on the next attempt.One at a time. Calling ShowCreative while another creative is showing or loading returns shown = false rather than stacking modals.Rotation. The modal handles rotation while visible, swapping to the other orientation’s artwork where one is provided.Input. While a creative is visible, its backdrop absorbs taps so the game underneath doesn’t receive them.A/B testing. Ask for two creatives with different keys, assign players to a variant in your own code, and call ShowCreative with the matching key. Your game keeps full control of the split.
“Creative not found” but it was just set up. Confirm the creative key spelling with your Customer Success Manager, check that it’s been made active, and make sure your build is pointed at the same environment it was configured in. The App ID must match your game’s token exactly — it’s case-sensitive.The modal doesn’t appear and I get “Creative images could not be loaded”. Almost always the image: confirm it’s HTTPS, PNG or JPEG, and served with an image Content-Type and no Content-Encoding header. A browser preview succeeding does not guarantee the device can decode it.Nothing shows for some players only. Check the locale — a creative with a locale set is only served to matching players. Ask for a version with no locale as a fallback.A newly updated creative isn’t picked up. The creative list is cached for the session. Restart the app, or call FetchCreatives() to refresh.