KUMODeck

Ads

Rewarded videos ("watch an ad for an extra life", "watch an ad for 10 free credits") and interstitials at natural breaks, in an app or a game (interstitials show only in development for now: the production ad network is rewarded video only). Off by default: no app or game gets ads unless its creator turns them on. When you do, 100% of the ad revenue is yours (0% fee).

Note In development every ad is a built-in test ad, so you can build and test the whole flow without real ads. Production uses the ad network; the code below is the same in both.

Note The production ad network for kumo.ads is rewarded video only — no interstitials (kumo.ads.interstitial resolves without showing anything in production). The ad network's SDK is loaded only the first time a user (called a player in the API) watches a rewarded ad, and the SDK creates its own container element. You add nothing to your page, and it works the same on KUMODeck hosting and on your own server. Banner ads are a separate switch that needs no code: see Banner ads.

Banner ads need no code and no rewards. Turn on Banner, Social Bar or both in the dashboard (your project's overview, Banner ads), or set "ads": { "banner": { "enabled": true } } / "ads": { "socialBar": { "enabled": true } } in kumo.config.json and push it. KUMODeck then adds the ad (from Adsterra) to your published page on KUMODeck hosting from the next visit; turning it off removes it from the next visit. ads.enabled (rewarded video) is not needed.

BannerSocial Bar
WhereA bar that stays at the bottom of the page (320×50 on phones, 728×90 on wider screens)On top of your game's screen, not in a strip of its own
LookAlways the same shape, and quietAdsterra picks the form each time: a small notification-like ad, a widget, an icon, or an ad that covers the whole screen. You can't pick the form
your-gameAd · 320×50Banner: a bar at the bottom, always the same(1) New Message!Ad×Social Bar: on top of the game, form varies

What Social Bar is like#

  • It appears on top of your game's screen, in a form Adsterra picks each time (see the table above).
  • It may change the text on the browser tab, for example to "(1) New Message!".
  • Players get nothing for seeing it: it is not a rewarded ad, and your game is not told when it shows (for rewards, use the rewarded ads below).
  • Good: because it stands out more, it tends to bring in more than the banner. There is no set amount, and it may not.
  • To consider: it can cover part of the game while people play, and the tab text can look like a message.

It's your call: use it with the banner, on its own, or not at all. You can turn it off any time.

  • Ads show only on the published version at your KUMODeck hosting address — not on the test version, a custom domain or a server-rendered app, and not when audience is kids or mixed.
  • The page is not wrapped in a frame, and nothing loads when your page is itself inside someone else's frame.
  • KUMODeck shows "Advertisement" and a privacy link with the ad. Visitors in Europe are asked before the ad loads; browsers with Global Privacy Control get no ad.
  • The banner is a bar fixed to the bottom of the screen. KUMODeck moves things your page fixes to the bottom (position: fixed or sticky, such as a menu or a sound button) up by the bar's height, and puts them back when the bar goes. When you place something at the bottom yourself, use the bar's height, which is in the CSS variable --kumo-ad-band-height (it is 0px or unset when there is no bar): bottom: calc(16px + var(--kumo-ad-band-height, 0px)). Your game's canvas is not resized, so keep buttons out of its bottom edge.
  • You get 100% of what Adsterra actually pays for the ads on your app. All apps share the same ad slots, so your part is an estimate: each day, the payment for a slot is split by how many times the ad was shown on each app (up to 5 times per visitor per day).
  • It reaches your balance after Adsterra confirms the numbers (a few days) and a 60-day review period.

Turn it on#

kumo.config.json
{
  "features": { "inventory": true },
  "currencies": [{ "key": "coins" }],
  "ads": {
    "enabled": true,
    "rewards": [
      { "key": "extra_life", "grants": [{ "currency": "coins", "count": 50 }], "dailyLimit": 5 }
    ]
  }
}

Push it with kumodeck config push. ads.enabled: false (or no ads section) turns every ad off; the SDK calls then resolve without showing anything. You can also switch ads.enabled on or off in the dashboard (your project's overview, Features); the rewards stay in your config file.

Note There is no "just ask your AI agent" step for ads yet: the kumodeck commands and KUMODeck's AI tools do not offer ads for now. Edit kumo.config.json as shown above, push it, and use the SDK calls below.

Rewarded ads#

Call it from a button the user pressed. The reward comes from ads.rewards in your config and is granted on the server after the view is verified — the client only names the placement, so a modified app cannot mint coins.

extraLifeButton.onclick = async () => {
  const r = await kumo.ads.rewarded({ placement: 'extra_life' });
  if (r.granted) showRewardToast(r.reward);
};

// The inventory once the grant has landed (the SDK re-reads it for you)
kumo.ads.on('inventory', (inv) => renderWallet(inv));

In production the ad network reports the completed view directly to KUMODeck's server, which verifies it and then grants the reward, so the reward can arrive a few seconds after the ad ends. In that case r.pending is true and r.reward is what will be granted. The SDK re-reads the inventory a few times (for up to about 30 seconds) and emits inventory when the grant shows up; to check yourself, call kumo.inventory.get() a few seconds later. If the user closes the ad early you get granted: false (reason: 'not_completed') and nothing is granted.

The coins land in the user's inventory (turn on features.inventory in your config, as in the example above, when a reward grants a currency or an item). Your app reads and spends them; it never adds them itself:

// { currencies: { coins: 150 }, items: {} }
const inv = await kumo.inventory.get();
// e.g. buy a continue
await kumo.inventory.consume({ currencies: { coins: 50 } });

Interstitials#

Show them at natural breaks (the production ad network has no interstitials, so none are shown for now; you can leave the calls in place). They never appear during gameplay, never in the first 3 minutes of a session, and at most once every 90 seconds (you can only make these stricter). The call always resolves, even when no ad is shown, so your app never waits.

kumo.ads.gameplayStop();
await kumo.ads.interstitial({ placement: 'level_end' });
kumo.ads.gameplayStart();

kumo.ads.on('adStart', () => muteAudio());
kumo.ads.on('adEnd', () => unmuteAudio());

Settings#

FieldDefaultYou can set
ads.enabledfalsetrue to use ads
ads.interstitial.enabledfalsetrue to also use interstitials
ads.interstitial.minIntervalSeconds9090–3600 (longer only)
ads.interstitial.initialDelaySeconds180180–3600
ads.rewarded.dailyLimit20 per user per 24 h1–20
ads.rewards[]none{ key, title?, grants, dailyLimit? } — in-app currency (credits, coins) or items only, never cash
audience (top level)generalkids: rewarded only, non-personalized, child-directed · mixed: users whose age is unknown are treated as children

Pass your consent banner's result with kumo.ads.setConsent({ personalized, tcString?, gppString? }); the browser's Global Privacy Control signal is sent automatically. The server decides whether an ad may be personalized from consent and your audience, and the ad adapter follows that decision.

Ad revenue#

  • 100% yours, no fee. Ad revenue goes to your balance on KUMODeck. Each project gets what the ad network's report shows for it; anything the report does not split by project is shared by that day's impressions per country.
  • A 60-day review period (90 days for a project's first month), because the ad network's deductions for invalid traffic arrive late.
  • After the ad network pays. The ad network pays KUMODeck monthly, about 30 days after the month ends, so a month's revenue can wait a little longer than the review period. Only what the ad network actually paid is added.

See the summary at GET /v1/projects/:projectId/ads/summary.