Dynamic Offers in Mobile Games: How to Match a Proposal to a Specific Player

The same pack after a defeat, on energy dry-up, and at a new stage is not an offer. It is a shop window. The studio sees ARPU move after a discount and calls it personalization. The player sees that the game waits until they feel bad and then sells an exit. The gap is not the model. The gap is whether you assemble the proposal from this player’s signals or show a shared catalog at a “lucky” moment.
Get sandboxThis is a TOFU/MOFU piece on MONE’s core theme: how to pick mix, price, and show time for a specific player. For Founder, CEO, Producer, and Monetization Lead. You leave with a map of four signals and three outputs you can sign before an SDK. Timelines and floors below are site claims from mone.tools, not a promise for your title. Do not treat unnamed genre cards as proven results.
What a dynamic offer actually is
A dynamic offer is not “a discount that moves.” It is a three-part decision assembled from four signals. MONE describes a closed loop: collect data → read behavior on Player Journey Maps (PJM) → issue an offer and a spot inside designer rules → calibrate in an isolated A/B test. “Offer and spot” here is product: SKU mix, a price inside Hard Limits, and a moment Smart Triggers are allowed to use.

If any of the three outputs is frozen forever, you have a static shop with a nicer name. If any of the four signals never reaches the decision, the model guesses from one slice — usually payment or panic.
The site’s public pipeline (site claim): SandBox in 1–2 hours at the audit step, telemetry in 1–2 days, personalization launch in 2–3 days once Hard Limits and cohorts exist. Full personalization connection is less than a week (site claim). Those hours do not replace the meeting where the producer signs which signals may be used at all.
Minimum for an ML personalization pilot on the site: 5,000 unique players per month. Below that floor, still write the signal map on paper. An offer without traffic beats a shop window you cannot explain.
Four signals without which a “personal” pack is a lottery
A signal is not “one more Amplitude event.” It is a field that changes at least one output: mix, price, or moment. If the field does not change an output, that is logging, not personalization.
| Signal | What you read | What breaks without it |
|---|---|---|
| Progress | Stage, gate, Battle Pass, unfinished upgrade | An offer for content the player has not unlocked or has already outgrown |
| Balance | Soft / hard / energy / tickets at decision time | A pack of a resource they already have, or a discount when the vault is full |
| Purchase history | First pay, repeat, recency, refuse, refund | One SKU for Engaged Free and Whale; a dead second purchase |
| Session | Fail streaks, idle, session length, UI spot | A show during panic, or when the offer surface is closed |
Progress is not a level in the profile
Progress says which content is even eligible. A player on gate 12 must not see a gate 3 pack “because it is cheap.” A player who finished a branch must not get an accelerator for that branch. On the site, offer spots live inside PJM: defeat, resource dry-up, upgrade complete, new stage. Progress decides which whitelist SKU is a candidate. Price is the next step, not the first.
Demand before the pilot:
- A dictionary of stages and gates the Event List can emit without touching combat.
- A ban on SKUs for locked or already-cleared content (a progress black list).
- A separate Battle Pass rule: season pace is not a discount on the whole track.
- An explicit “too early”: an offer that waits for the gate instead of breaking it.
If progress is not in the decision, personalization optimizes payment against design. That is not MONE’s core theme. That is a conflict.
Balance is vault context, not a fire-sale trigger
Balance answers “is this resource needed now.” A player with full energy must not get an energy pack, even if the model is “confident.” A player with zero soft and a live gate is a candidate for a pointed pack, not −70% on the whole shop.
Lock:
- Which currencies enter the decision. The rest stay out of the offer.
- Thresholds for low / enough / excess per segment, not one number for everyone.
- A ban on discounts when the vault is above “enough.”
- A balance × progress join: the resource only matters on an open gate.
Balance without progress yields a potion in the lobby. Progress without balance yields a chest with nowhere to spend it.
Purchase history exists so you do not treat everyone with one price
History separates first purchase from second, Whale from Engaged Free, a refuse from “has not seen it yet.” Without it, the dynamic offer collapses into a shop window with a personal headline. Retention-First on the site should block a show that teaches players to wait for a sale. The rule is empty until you know whether this player bought the same SKU on discount yesterday.
Lock:
- Windows: never paid / paid long ago / paid this season / paid this session.
- A different discount cap for first purchase and for Whale. One price list is not personalization.
- A ban on repeating the same pack right after a refuse or a refund.
- A dedicated cell for “dead second purchase”: the first converted, the repeat shop is identical.
Do not replace in-game purchase history with UA meta. Channel meta helps marketing. An in-session offer reads what the player already did in the game.
Session is the moment, not “now, while the app is open”
Session decides whether an offer may appear in this frame. A fail streak is not an automatic fire sale. Idle after a win is not the same spot as idle on a gate. Impression Caps per player and per session are part of the offer, not a separate “anti-spam” note in the LiveOps chat.
Demand:
- A list of live UI surfaces the pilot may use. No new popups.
- A panic rule: N fails in a row do not open a discount above the signed cap.
- A cap per session and per day. Smart Triggers without a cap are scored spam.
- Fallback: if the session is short or telemetry is silent, the player sees the default shop.
Three outputs: mix, price, moment
Four signals are useless if you only move one output. The common anti-pattern: price dances, mix is always the starter pack, moment is always “after defeat.” That is a dynamic discount, not a dynamic offer.

| Output | What the studio signs | Typical failure |
|---|---|---|
| Mix | SKU whitelist × segment × progress | Cosmetics on dry-up, a booster on a fair gate |
| Price | Range and discount cap inside Hard Limits | −70% as the only “personalization” lever |
| Moment | Spot, cap, panic ban, Fallback | A show because the model is “sure” while the UI is closed |
Mix is which pack, not which banner
Mix answers which SKUs, in which bundle. A player dry on energy needs the gate resource, not a new skin. A Whale who already bought the combat pack must not see the same pack with a different number. White / black lists on the site live in the Management Console for this: the model proposes from what is allowed, not from the whole catalog.
Put on one page:
- SKU candidates by PJM cell, not the full catalog.
- Banned joins (cosmetics + panic, booster + fair gate).
- A max number of items in one offer. Three SKUs “just in case” is a shop window.
- A rule of “one offer, one job”: clear a gate, restore a resource, speed a season.
Price is a corridor, not the model’s personality
Dynamic Pricing on the site is a mechanism inside Hard Limits, not a right to rewrite the price list. Price may move with willingness to pay, progress, and session context. It may not leave the floor and ceiling economy signed as balance. A discount without a cap teaches players to wait. A price without a mix is a coupon for a random SKU.
Moment is a spot that already exists in the client
Moment is not a cron job. It is a spot the designer already placed: defeat, resource, upgrade, new stage. A pilot that needs new UI is a different project. Smart Triggers may pick a spot from the signed list and stay silent if an Impression Cap or Retention-First said no. Silence is a valid offer. An empty show is not.
When this is still not personalization
Name the anti-pattern before a player names it in the store.
- One SKU, three prices, zero signals except paid / not paid.
- A discount after a fail streak as the only Smart Trigger.
- A “for you” banner on a shared catalog.
- An offer you cannot turn off without a client build.
- First-purchase conversion up while D7/D30 fall. On the site, retention is a guardrail, not a vanity chart.
If any line describes your current shop, you are still in audit, not in a pilot. Historical SandBox exists for this: six months of events can show where the window does not match the segment, while analytics on the site is $0.
Who owns the decision, not “the model will figure it out”
The cycle dies when “the vendor tunes the offer.” Use a RACI-style split. R = does the work, A = owns the call, C = consulted, I = informed.

| Role | Signals | Mix / price / moment | Stop |
|---|---|---|---|
| Producer | A: which signals are in scope | A: Hard Limits, lists, caps | A: kill the offer in minutes |
| Analyst | R: quality, windows, segments | C: which metric must move | R: D7/D30 next to ARPU |
| LiveOps / economy | C: gate and currency dictionary | R: SKU whitelist, price floors | C: do not break the season |
| Developer | R: Event List, session, Fallback | I: no new UI for the pilot | R: rollback without a resubmit |
| Vendor | C: comparable PJM cuts | R: issuance inside the console | I until the studio expands |
Checklist (print this)
- Four signals are named: progress, balance, purchase history, session. Each one changes at least one output.
- Three outputs are signed separately: mix, price, moment. You may not “only move the discount” and call it a pilot.
- SKU white / black lists and Hard Limits live in one place a producer can read.
- Impression Caps and the panic ban are written down. Smart Triggers may stay silent.
- Fallback is tested: when the model is silent, the player sees the live default shop.
- The Event List emits the four signals without touching combat. No new popups in the pilot.
- If you will test, a baseline pack exists: ARPU/LTV, 1st Pay Conv., D7/D30, window, denominator.
- Traffic is at or above the site floor of 5,000 unique players per month for an ML pilot, or the cycle is explicitly “offer map and audit only.”
- The week-5 decision meeting is on the calendar before week 1 starts, if you connect.
The point
- A dynamic offer is mix, price, and moment assembled from progress, balance, purchase history, and session. A shop window with a personal headline is not an offer.
- A signal that does not change an output need not be logged for the pilot. An output that does not read a signal is a random discount.
- Hard Limits, lists, and caps are part of the offer. The model proposes. The studio decides what this player may see now.
- Smart Trigger silence is a valid result. A show “because the score is high” on a closed surface is not.
- The offer map is an entry to one experimental cycle, not a replacement for it. SandBox can show where the window misses the player; scale still needs an A/B memo with D7/D30.
Ask for SandBox, not a license
If you have about six months of events and a producer who can lock signals and a corridor, the next step is a historical audit: segments, PJM, offer spots, and a report you can hold next to the current stack. Start from the MONE audit / SandBox path or from the pipeline. Studio console: dash.mone.tools. Analytics is the free layer; personalization payment, on the site, starts only after an A/B test confirms ARPU uplift.
Read also
- From Audit to Scale: monetization personalization in one cycle
- Player Journey Map for mobile games: how to turn the player path into a monetization tool
- How to keep control of the game economy when you use AI
- How to grow mobile-game revenue without raising base prices or aggressive discounts
