Making money
AdMob Integration
Monetization Setup
1Create AdMob Account#
Sign up for a Google AdMob account. You'll need a Google account to get started. AdMob is Google's mobile advertising platform.
2Add Your App#
In AdMob dashboard:
- Click 'Apps' in the sidebar
- Click 'Add App'
- Select 'No' for 'Is your app listed on a supported app store?'
- Enter your app name
- Select 'Android' as platform
- Click 'Add'
3Get App ID#
After creating your app:
- Copy the App ID shown (format: ca-app-pub-XXXXXXXXXXXXXXXX~XXXXXXXXXX)
- This is different from your Ad Unit ID
- You'll use this in AndroidManifest.xml
App ID format:
ca-app-pub-1234567890123456~12345678904Create Ad Unit (Banner)#
In your AdMob app:
- Click 'Ad units' tab
- Click 'Add ad unit'
- Select 'Banner'
- Enter ad unit name (e.g., 'Main Banner')
- Click 'Create ad unit'
- Copy the Ad Unit ID
Banner Ad Unit ID format:
ca-app-pub-1234567890123456/12345678905Setup in Web2APK Generator#
In the generator app:
- Enable 'Ads' toggle in Step 3
- Select ad placement (Top or Bottom)
- Paste your AdMob Banner Ad Unit ID
- Continue with other settings and generate your APK
Ad Unit ID (not App ID):
ca-app-pub-XXXXXXXXXXXXXXXX/YYYYYYYYYY6Test Ads in Your App#
During development, use Google's official test IDs to avoid policy violations. Copy-paste these into the generator:
๐ AdMob App ID:
ca-app-pub-3940256099942544~3347511713
๐ Banner Ad Unit ID:
ca-app-pub-3940256099942544/6300978111
๐ Interstitial Ad Unit ID:
ca-app-pub-3940256099942544/1033173712
๐ Rewarded Ad Unit ID:
ca-app-pub-3940256099942544/5224354917
๐ Publisher ID:
pub-3940256099942544
๐ Developer Website:
https://example.com
These test IDs show real-looking ads without generating revenue or violating policies. Replace with your real IDs for production.
Test IDs for Generator:
AdMob App ID: ca-app-pub-3940256099942544~3347511713
Banner Ad ID: ca-app-pub-3940256099942544/6300978111
Interstitial ID: ca-app-pub-3940256099942544/1033173712
Rewarded Ad ID: ca-app-pub-3940256099942544/5224354917
Publisher ID: pub-3940256099942544
Developer URL: https://example.com7Interstitial Ads#
Interstitial ads are full-screen ads that cover the entire app interface. Users can close them to return to the app.
๐บ How to Enable:
- Toggle ON 'Enable Interstitial Ad' in Step 3
- Enter your Interstitial Ad Unit ID (or leave empty for test ads)
- Choose a trigger mode:
๐ After Navigations (default):
The ad shows after every N page navigations. For example, if set to 4, the ad appears after the 4th, 8th, 12th page load, and so on.
๐ฑ App Open:
The ad shows once immediately after the splash screen, when the app first opens.
โ ๏ธ You can enable either Interstitial OR Rewarded - not both at the same time.
Example: Action Count = 4
Page 1 โ No ad
Page 2 โ No ad
Page 3 โ No ad
Page 4 โ ๐บ Interstitial Ad shown!
Page 5 โ No ad
Page 6 โ No ad
Page 7 โ No ad
Page 8 โ ๐บ Interstitial Ad shown!
...8Rewarded Ads#
Rewarded ads are full-screen video ads that users watch in exchange for a reward. They provide higher revenue than banner or interstitial ads.
๐ How to Enable:
- Toggle ON 'Enable Rewarded Ad' in Step 3
- Enter your Rewarded Ad Unit ID (or leave empty for test ads)
- Choose a trigger mode:
๐ After Navigations (default):
Similar to interstitial - the ad shows after every N page loads. Set the 'Action Count' to control frequency. Default is 4.
๐ฑ App Open:
The reward video shows once when the app first opens after splash.
๐ก What is Action Count?
The number of page navigations between each ad. Lower = more ads (more revenue but worse UX). Higher = fewer ads (better UX but less revenue). Recommended: 3-5.
โ ๏ธ Google policy: rewarded ads need the user's OK. In After Navigations and App Open modes your app first shows a 'Watch an ad?' prompt with a 'No thanks' button; the ad plays only if they accept. For a 'watch ad to earn' button with no automatic ads, use On Demand.
Revenue comparison (approximate):
Banner Ads: $0.10 - $0.50 per 1000 views
Interstitial Ads: $1 - $5 per 1000 views
Rewarded Ads: $5 - $15 per 1000 views
Recommended Action Count:
Aggressive: 2-3 (more ads, more revenue)
Balanced: 4-5 (recommended)
Conservative: 6-10 (fewer ads, better UX)9Consent & Privacy Policy (Required)#
โ ๏ธ AdMob requires a consent mechanism for users in the EEA, UK, Switzerland, and US states.
This is handled automatically by the generated app using Google's User Messaging Platform (UMP). The app will:
- Show a consent dialog to EEA/UK/Switzerland users before displaying ads
- Show an opt-out dialog to users in applicable US states
- Only request ads after consent is obtained
What YOU must do:
- In AdMob console โ Privacy & messaging โ Create a European regulations message
- In AdMob console โ Privacy & messaging โ Create a US state regulations message
- Set your Privacy Policy URL in the generator (Step 3 or Step 4)
- Make sure your privacy policy mentions AdMob advertising
โ ๏ธ Without this setup, AdMob may show a policy warning: 'Consent requirement: No CMP'
10Ad Review Process#
After publishing your app:
- AdMob will review your app (usually takes 24-48 hours)
- Initially, you'll see test ads
- Once approved, real ads will start showing
- Keep your app content policy-compliant
11Enable Payments#
To receive ad revenue:
- Go to 'Payments' in AdMob dashboard
- Add payment method (bank account or other options)
- Verify your address
- Set up tax information
- Payments are made monthly after reaching $100 threshold
12Best Practices#
โ Banner Placement: Bottom banner is less intrusive and has better user experience
โ Interstitial/Rewarded: Choose one, not both. Rewarded ads earn more but require user engagement
โ Action Count: Start with 4-5 navigations between ads. Too frequent = bad reviews
โ Test First: Always test with test ad units during development
โ Monitor Performance: Check AdMob dashboard regularly for earnings and metrics
โ ๏ธ Don't Click: Never click your own ads - this violates AdMob policy
โ ๏ธ Quality Content: Ensure your app provides value and follows AdMob policies
๐ก Pro Tip: Combine Banner (always visible) + Interstitial or Rewarded (periodic) for maximum revenue
13Troubleshooting#
Common issues and solutions:
- No ads showing: Check if you're using correct Ad Unit ID (not App ID)
- Test ads work but real ads don't: Wait for AdMob review to complete
- Ad request failed: Verify internet connection and AdMob account status
- Account suspended: Review AdMob policies and appeal if needed
14Developer-controlled ads: place every ad yourself#
Download the complete demo page below (Coin Runner): a banner inside the layout, an interstitial between levels, a 'Watch ad to earn 50 coins' button, a 300ร250 rectangle, the app-open switch and a live log of every result. Zip it, upload it as an Offline ZIP, choose Developer-controlled with the prefilled test IDs, build - every button explains itself.
The options above are the Automatic mode: the app shows the banner and the full-page or rewarded ad for you. If you want every AdMob format and the freedom to put each one exactly where your page needs it, choose 'Ad Control โ Developer-controlled' in Step 3 instead.
In this mode NOTHING is automatic. Enter one ad unit ID for each format you use - banner, medium rectangle (300ร250), interstitial, rewarded, rewarded interstitial, app-open - and leave the rest empty. Your page then drives everything through window.AppMintAds:
- AppMintAds.banner.attach('#slot', {size:'banner'|'medium_rectangle'}) - a banner placed over the element you name, in a card, between list items, anywhere. It follows the element on scroll; detach() removes it. Up to two at once.
- await AppMintAds.load('interstitial') โ {ok:true} or {ok:false, code:'no_fill'|'network'|'invalid_unit'|'consent'|'ad_free'|'disabled'}
- await AppMintAds.show('rewarded') โ {shown:true, earned:true, reward:{type,amount}} or {shown:false, reason}
- AppMintAds.isReady('interstitial') - enable your button off this
- AppMintAds.appOpen.setEnabled(false) - pause the app-open ad while the user is mid-task
AppMintAds exists only inside the installed app - always feature-detect (if (window.AppMintAds) โฆ) so the page still works in a browser. Google's rules still apply and the app enforces them: a rewarded ad only plays from the user's own tap (your 'Watch ad' button IS the opt-in), interstitials keep a 60-second gap, and never put an ad on top of a core action.
// Feature-detect: AppMintAds exists only in the installed app
const ads = window.AppMintAds;
// 1. A banner INSIDE your layout โ <div id="ad-slot"></div> reserves the space
if (ads) {
const r = await ads.banner.attach('#ad-slot', { size: 'banner' });
console.log(r.ok ? 'banner ' + r.width + 'x' + r.height : 'no banner: ' + r.code);
}
// 2. A full-page ad at a natural break (between levels), never on every tap
async function levelFinished() {
if (ads && ads.isReady('interstitial')) await ads.show('interstitial');
showNextLevel(); // continues whether or not an ad was shown
}
// 3. A 'Watch ad to earn 50 coins' button โ the tap is the user's opt-in
watchBtn.onclick = async () => {
if (!ads) return; // browser: no native ads
// From a tap the ad plays. Without one (a timer, a route change) the app shows
// AdMob's "Watch an ad? / No thanks" intro first and answers code 'declined'.
const r = await ads.show('rewarded');
if (r.earned) addCoins(r.reward.amount || 50); // grant ONLY when earned
else if (r.reason === 'ad_free') addCoins(50); // premium user: grant without an ad
else toast('No ad available right now'); // no popup, no Skip button
};
// 4. Preload and keep the button honest
ads?.load('rewarded').then(r => { watchBtn.disabled = !r.ok; });
In the app, this step's button saves these to your phone. Here they are direct downloads.
admob-developer-demo.html15Ad status events: know what happened to every request#
Every developer-controlled ad reports its full life cycle on ONE event, appmint:ad, so you can log fills, react to failures and drive your own UI:
{ type, phase, slot?, code?, adCode?, message?, width?, height?, reward?, earned? }
- type: banner | mrec | interstitial | rewarded | rewarded_interstitial | app_open
- phase: loading โ loaded | failed โ opened โ impression โ clicked โ closed, plus rewarded (a reward was earned) and show_failed
- code (on failed): no_fill | network | invalid_unit | internal - adCode is AdMob's own number, message its text
- slot: which banner slot, for banner/mrec
The promises give you the same answer per call; the event gives you everything, including ads you did not call show() for (an app-open ad, a banner refresh). In the Automatic mode AppMintAds still exists but answers code 'automatic_mode' - use the WebToApk.showInterstitialAd()/showRewardedAd() calls and the appmint:reward / appmint:ad-closed / appmint:ad-unavailable events there.
window.addEventListener('appmint:ad', e => {
const a = e.detail;
console.log(a.type, a.phase, a.code || '', a.message || '');
if (a.phase === 'failed' && a.code === 'no_fill') analytics.track('ad_no_fill', a);
if (a.type === 'rewarded' && a.phase === 'rewarded') console.log('earned', a.reward);
if (a.type === 'banner' && a.phase === 'loaded') console.log('banner ' + a.width + 'x' + a.height + ' in ' + a.slot);
});
// What can this build serve? (guard it โ in a browser AppMintAds is undefined)
if (window.AppMintAds) console.log(AppMintAds.config());
// โ { control: 'developer', formats: { banner: true, mrec: false, interstitial: true, ... } }