
Dungeon Division is a mobile dungeon management game where you side with the dungeon and stop the adventurers who raid it. It's on the App Store now, and the thing I chewed on longest before launch was how it would make money. When you make a game alone, monetization keeps getting pushed back. I spent all of September building the game and only got to the shop and ads in October.
This post follows Oct 1 to Oct 16, about 60 commits that deal with the shop, ads and payments. I added nine rewarded ads, built a shop and then rebuilt it, hooked up Unity IAP and a payment server, and went as far as a first test purchase and a first refund. As usual, the images are only screens I committed at the time.
Rewarded ads came first
Ads came before the shop. The top of my monetization doc says that since I can't spend much on marketing, someone who buys once needs a reason to keep playing and buy again. For players who never pay, I wanted ads to be a way to get a bit more. The rules I wrote down: the player always chooses to watch. No forced popups, no red notification dots just for ads, no daily quests that require watching.
On the afternoon of Oct 1 I added six placements, and that night I took it to nine.
| Where | What one ad gives you | Limit |
|---|---|---|
| Business report approval | +50% Gold on that report | 3 a day |
| Repel win settlement | Extra Gold equal to the base Gold (capped) | 2 a day |
| After using all Repel Tickets | 3 tickets | 1 a day |
| Hire screen | 1 Full-Time hire | 1 a day |
| Hatchery | Egg timer cut by 2 hours | 2 a day |
| Growth support | One bundle of Soulstones or Upgrade Stones | 2 a day |
| Deep Dig | 1 entry | 1 a day |
| Guild Showdown | 1 full entry | 1 a day |
| Royal Raid | 1 record attempt | 2 a week |
With everything unlocked that's up to 13 a day, or 15 if you also use the raid ones that day. That looks like a lot on paper, but each ad only appears once its feature unlocks.
That same night I rebuilt every ad button. The first version just said something like "Fire Soulstone +5". The new one shows how many you have now and how many you'll have after (Owned 0 → 5). If you arrive from a screen where you're short on a material, that material is already selected. In places with daily entries, like the dig or the Guildmaster fights, I hid the ad offer entirely while you still have free entries left. Showing an ad when you can still play for free would be weird.

The next morning I added an entitlement for collecting rewards without ads. Anyone who buys it gets the same rewards and limits on all nine placements with no ad. They still tap the button themselves.
Dev notesWhen does a rewarded ad count as watched?
The ad SDK fires several callbacks, but the only one I accept as a completed reward is the "reward earned" callback. Closing or failing the ad doesn't pay out. The amount also comes from the game's placement rules, not from the number the SDK passes along.
Callbacks can arrive late or twice, so each request is tagged and late callbacks from earlier requests are thrown away. Ads are requested only when you tap the button, never preloaded in a loop. Where there's a base reward, like Business approval, the base reward is saved before you tap the ad button. If the app dies mid-ad, you still keep what you were owed.
On Oct 13 I connected the real AdMob SDK and the consent screen (UMP). At that point every ad unit was a Google test ID. I only switched to live ads when I built the release review build. If the consent screen doesn't allow ad requests, the app never quietly flips that to allowed.
The first shop, and doing the math on solo dev revenue
At 9:46 am on Oct 2 I committed the first shop screen. Twelve products laid out as cards, with a detail sheet when you tap one. The buy button was locked with "Payments coming soon", because there was no payment SDK yet.
There was one thing I fixed 30 minutes later. Awakening unlocks when you clear stage 1-7, and the 1-8 staff Hot Deal was also tied to clearing 1-7. So the moment you cleared 1-7, three paid products (the 1-8 staff, awakening support and the settling-in pack) popped into the shop at once. I pushed awakening support back until after the awakening tutorial.
On the night of Oct 9 I drew product art with PixelLab and added it. Soulstone and Upgrade Stone icons, product pictures, tag ribbons, a "Purchased" stamp, that kind of thing.

Then on the 12th I took the shop apart again. If you bought every one-time product on sale, the most one account could ever spend was ₩72,100. The only repeatable product was a single once-every-7-days item, and there was nothing to buy at all in Hard mode or the Guildmaster stretch after chapter 6. The late-game content from the endgame post had nothing to offer the people who stick around longest.
The first paid product, the settling-in pack (₩2,900), was a problem too. Converted to Gold per won, it was the worst value in the shop. The first thing a new player buys was the worst deal.
I worked through this diagnosis with AI tools. I researched the shop setups of eight similar games from web sources, and sorted a separate list of improvement suggestions into adopted, partly adopted and not adopted. Ideas like "make every product once per account" got dropped, because they left the revenue ceiling problem as it was.
The shop redesign: what changed and what didn't
At 3:45 pm on the 12th I committed the redesign. I kept the principles from the original monetization doc. You can grow all the way to the end for free, there are no stats you can only get by paying, and no lines like "guaranteed clear" or discount percentages with nothing behind them. On top of that, here's what changed.
- The settling-in pack kept its price and got bigger: 6,000 Gold, 60 Soulstones, 20 Upgrade Stones. On the 14th I added 450 Mana Gems as well, enough for three hires.
- The ad-free rewards entitlement was renamed Manager Perks and moved to the top of the shop. Battle ×3 speed was originally something you unlocked for an hour by watching one ad a day, and on the 7th I changed it so owners of this product get it with no limit. Finishing the story means replaying the same stages hundreds of times, so ×3 speed matters far more than the nine ad rewards. The product name didn't say any of that.
- I added repeatable products: 30-day Supplies (₩6,900, five days' worth right away and a daily mail for 30 days), a weekly pick-your-own Supplies pack (₩4,900), and a Hard Pass.
- I decided to sell Mana Gem packs. Until then I hadn't decided either way.

I changed the Mana Gem amounts once within a day. At first it was 300 for ₩4,900, but at that rate getting a guaranteed Legendary by hiring all the way to pity cost ₩110,000 to ₩180,000. And the same shop had a ₩9,900 product that gets you a Legendary staff member. So I raised every pack 1.5x at the same prices: 450 for ₩4,900, 1,500 (+150) for ₩14,900, 5,000 (+750) for ₩44,000, 10,500 (+2,250) for ₩89,000, with the base amount doubled on the first purchase of each pack.
I also wrote down what I chose not to do. No "×5 value" multipliers, because there's no real sale price to convert Gold or materials against. Instead the shop shows what you own, what you get and what you'll have afterwards. I also held off on a ₩1,500 starter product. At 4:39 pm on the 14th I finished the remaining decisions and took the "draft prices" label off the shop. In Google Play I entered all 20 products in won by hand, and left Apple pricing for when I prepared the iOS release.
How I chose the payment server: Unity IAP plus Firebase
At 5:15 pm on the 12th I decided how payments would work. There were two options.
- No server. Check the store receipt only and keep records on the device.
- A lightweight server that handles receipt validation, purchase records and server time.
With a 72-hour Hot Deal or 30-day Supplies, trusting the device clock means anyone can get around it by changing the clock. I also needed a way to get purchases back after switching phones. So I went with option 2. Payments use Unity IAP, and the server is Firebase (auth, database and server functions).
I decided one more thing that day. I wouldn't build a fake purchase record for development first. If I built it before knowing where records would live, I'd only have to rebuild it, so I'd build it once, when I hooked up the payment SDK.
Dev notesWhy Firebase, and how I kept costs in check
I decided not to also use Unity's cloud save or server code services for purchase records. Purchase records live in one place, Firebase. Unity IAP shows the payment sheet, but it doesn't validate receipts on a server for you. So the decision to deliver something is only ever made by a server function after it checks directly with the store. There's no path where the client delivers on its own.
Purchase records pile up like a ledger. Every delivery adds one numbered entry, and if the same transaction comes in twice it's only delivered once. The client can read the ledger but can't write to it.
Here's how I kept costs down.
- Server functions have a minimum of zero instances. Set it to one and you pay even when nobody is playing.
- No phone number auth. Every text message costs money.
- Call the server only when needed, and never read the full purchase history over and over.
- Save backups at most once an hour, 10 a day. That cap is enforced by the server security rules, not the app.
- A monthly budget alert at ₩10,000. It's only an alert, not a cap, so going over doesn't shut payments off.
The to-do list from that day also includes enrolling in the 15% store fee programs. You have to apply on both Google Play and Apple, otherwise the cut is 30%.
On the morning of the 13th I committed the purchase ledger, delivery and the Unity IAP hookup together. That one commit is over 5,600 lines. Right after it I added buy buttons, a purchase box where bought items wait, and per-tier pass claims. How I kept backups and purchases separate so saves wouldn't get tangled is in the save data post.
First test purchase, first refund
Around midday on the 14th I turned on payments in the Google Play internal test track. At 6:27 pm I uploaded the build with Mana Gem packs and bought the 450 pack twice on a real phone. The first came in with the first-purchase double, the second at the base amount. The ledger recorded them as two separate entries.
At 7:05 pm I refunded the second order myself from Play Console. A refund means the 450 Mana Gems have to be taken back. It took two days to see that actually happen. The scheduled check the next day didn't pick up the refund, and only on the evening of the 16th did I find that one permission setting was missing on the server side. Once I granted it, the 450 gems were taken back once, inside the app.
I decided the refund policy that day too. Staff, Gold, Soulstones and Upgrade Stones you've already received are not taken back after a refund. What gets cut off is rewards you haven't claimed yet, remaining entitlements, and Mana Gems. Taking back a staff member would tangle up every upgrade material spent on them, and turning Gold into a debt would block your progress. Accounts that refund repeatedly get a manual look, with no automatic penalty.
At 8:52 pm I made the 72-hour Hot Deal run on server time. The moment it was first shown is recorded on the server, and once the window closes, the purchase itself is blocked. The app also corrects its own clock using the last time it synced with the server. Moving the device clock forward or back doesn't change the time remaining.
About an hour later I added New Staff Growth Support. When you add an Epic or Legendary staff member to your roster for the first time, the shop offers materials to raise them for ₩4,900, for 72 hours. Bought staff, starter staff and bosses don't count, and offers are at least 7 days apart. There are only two Hot Deal slots, so story-progress products and unlock support come first, and this one only fills an empty slot. It never pushes out a Hot Deal you've already seen. That afternoon I also drew a pixel art badge on the lobby shop entrance that shows the number of new products.
I built iOS purchase validation on the night of the 15th and left it off, then turned it on the morning of the 16th while registering the app in App Store Connect.
Loot box odds disclosure
On the afternoon of the 14th I brought the hire odds display in line with the law. Since March 2024, Korea requires games with randomized paid items to show the odds in the game, on the website and in ads. Hiring can also be done with Gold, not only Mana Gems, and since shop products include Gold, hiring counts.
First I fixed how numbers were shown. I'd been displaying only three decimal places, which squashed the odds of one particular Legendary staff member to 0.011%. I changed it to keep at least four significant digits. That night I compared the decree's appendix against the in-game popup item by item. I hadn't written down that the first tutorial hire is fixed at Rare, and I'd left out how the guaranteed 10th hire (Rare 92% / Epic 7.5% / Legendary 0.5%) and the pity hire change the odds. The in-game popup and the website document are generated from the same code, so they can't drift apart. That document is now the site's odds page (in Korean).
Key commits, Oct 1 to 16, 2026
- Six rewarded ads connected
- All nine ads done, clearer reward display
- Rewards without ads entitlement
- First shop screen (12 products)
- PixelLab product art, icons and stamps
- Shop redesign (settling-in pack, Manager Perks, Supplies, Hard Pass)
- Firebase chosen for the payment server, cost guard rules
- Purchase ledger, delivery, Unity IAP hookup
- AdMob test ads and consent screen
- Payments on the Google Play internal test track
- Four Mana Gem packs
- Loot box odds disclosure
- Refund policy decided
- 72-hour Hot Deal on server time
- App Store purchase validation turned on
Looking back on the two weeks
Making the game and making the thing that sells it turned out to be pretty different jobs. The shop showed more problems when I went back through the numbers than when I first built it, and payments took more time to decide on policy than to write code for. What gets taken back after a refund, who keeps the clock, how much the server is allowed to cost in a month.
Next is putting a build with these payments onto Google Play closed testing and TestFlight and getting it through review. If you want to see the game first, the game page (in Korean) has more.

NOW AVAILABLE
Dungeon Division
Heroes are intruders, monsters are staff. Save Dungeon No. 7 from being shut down.
Available on the Korean App Store (iPhone/iPad), with English in Settings. Android is not out yet.