There is no universal cooldown that makes advertising safe for every game. A puzzle game with long rounds, a fast arcade game, and a session-based roguelike create very different interruption costs. Treating one interval as an industry standard hides the real design problem: deciding whether a specific ad opportunity is appropriate for a specific player at a specific moment.
A production-ready system combines placement rules, local session guards, account-level limits, provider-side frequency caps, and reliable lifecycle callbacks. It also separates mobile app products such as Google AdMob from web products governed by Google AdSense policies.
This guide focuses on the control system around interstitial and rewarded ads. It does not prescribe universal caps, revenue forecasts, retention lifts, or premium prices.
Start With Product Boundaries
Before choosing any interval, identify the actual delivery product.
Mobile apps with AdMob
AdMob interstitials are full-screen ads intended for natural transition points, such as the end of a level. The Android implementation guide also requires test ads during development and provides lifecycle callbacks for presentation, dismissal, and failure.
For rewarded ads, the reward event is separate from the request to show an ad. Server-side verification can add protection against forged client callbacks, which matters when rewards affect a persistent economy.
Web games with AdSense
A browser game should not copy a mobile SDK integration and label it an AdSense implementation. Confirm that the format is supported for the site and account, then follow the policy for that specific format.
For AdSense ad units that offer rewards, the action and reward must be disclosed clearly. Rewards must be non-transferable and usable only within the publisher's platform. Users must not lose normal access merely because they decline or skip a rewarded experience.
Do not draw a custom close button or simulated ad layer around an unrelated ad format. Presentation controls and reward behavior must match the supported product.
Design the Gate as Layers
A single timer cannot handle restarts, multiple devices, storage deletion, concurrent callbacks, or delayed provider settings. Use independent layers that answer different questions.
- Placement guard: Is this a natural break in play?
- First-experience guard: Has the player completed the critical tutorial or first loop?
- Session guard: Has this session stayed within its interval and exposure limits?
- Rolling-window guard: How many verified impressions occurred in the recent window?
- Account guard: Has this signed-in account reached a cross-device limit?
- Provider cap: Does the ad network allow another impression?
- Readiness guard: Is a fresh ad object ready to show?
The provider cap is a final safety layer, not a substitute for game-aware UX. A client guard is also insufficient by itself because local state can be reset and does not automatically cover multiple devices.
AdMob allows caps at both app and ad-unit level. When both exist, the first limit reached applies. Google also notes that setting changes can take up to 24 hours to take effect and that server delay may occasionally allow a slight overage. Operations dashboards should account for those properties instead of treating every small mismatch as a client bug.
Google's help page uses two impressions per 30 minutes as an example of how configuration works. It is an illustration, not a recommendation for every game.
Implementation Strategy
Use injected policy, not hidden constants
The gate should require an explicit policy object. This makes values reviewable, remotely configurable, and reversible.
type AdKind = 'interstitial' | 'rewarded';
type FrequencyPolicy = {
minimumIntervalMs: number;
sessionLimit: number;
rollingWindowMs: number;
rollingWindowLimit: number;
};
type Exposure = {
kind: AdKind;
occurredAtMs: number;
providerImpressionId?: string;
};
type GateContext = {
nowMs: number;
kind: AdKind;
atNaturalBreak: boolean;
onboardingComplete: boolean;
userOptedIn: boolean;
adReady: boolean;
history: Exposure[];
policy: FrequencyPolicy;
};
type GateResult =
| { allowed: true }
| { allowed: false; reason: string; retryAtMs?: number };Evaluate the least expensive and most product-specific conditions first.
function evaluateAdGate(context: GateContext): GateResult {
const { nowMs, kind, history, policy } = context;
if (!context.onboardingComplete) {
return { allowed: false, reason: 'onboarding-incomplete' };
}
if (kind === 'interstitial' && !context.atNaturalBreak) {
return { allowed: false, reason: 'not-a-natural-break' };
}
if (kind === 'rewarded' && !context.userOptedIn) {
return { allowed: false, reason: 'reward-not-requested' };
}
const sameKind = history
.filter(item => item.kind === kind)
.sort((a, b) => b.occurredAtMs - a.occurredAtMs);
if (sameKind.length >= policy.sessionLimit) {
return { allowed: false, reason: 'session-limit' };
}
const last = sameKind[0];
if (last && nowMs - last.occurredAtMs < policy.minimumIntervalMs) {
return {
allowed: false,
reason: 'minimum-interval',
retryAtMs: last.occurredAtMs + policy.minimumIntervalMs,
};
}
const windowStart = nowMs - policy.rollingWindowMs;
const recent = sameKind.filter(item => item.occurredAtMs >= windowStart);
if (recent.length >= policy.rollingWindowLimit) {
const oldest = recent.at(-1);
return {
allowed: false,
reason: 'rolling-window-limit',
retryAtMs: oldest
? oldest.occurredAtMs + policy.rollingWindowMs
: undefined,
};
}
if (!context.adReady) {
return { allowed: false, reason: 'ad-not-ready' };
}
return { allowed: true };
}Validate configuration before it reaches the gate. Intervals and windows must be positive, limits must be positive integers, and the rolling window should not be shorter than the minimum interval unless the behavior is deliberate.
Record impressions, not requests
Do not start the cooldown when an ad is requested. A load or presentation failure would consume an opportunity even though the player saw nothing.
Record exposure only after the SDK reports an actual impression or successful full-screen presentation, using the strongest lifecycle signal available for the product. Deduplicate records with the provider impression ID when one is available.
For intervals inside a running session, prefer a monotonic clock so changing the device clock does not bypass or extend the delay. For persistent account limits, use server time and server storage.
Interstitial lifecycle
The reliable flow is:
natural transition occurs
-> evaluate every guard
-> confirm a fresh ad is ready
-> present the ad
-> record a confirmed impression
-> restore play after dismissal or failure
-> load the next ad objectAn ad load failure must not become a game progression failure. After dismissal, restore input focus, audio, pause state, and the intended scene. Do not attempt to present the same one-time ad object repeatedly.
Rewarded lifecycle
The player should see the action, reward, and relevant conditions before opting in.
show the reward offer
-> receive explicit player choice
-> evaluate guards and readiness
-> present the ad
-> receive the reward event
-> deduplicate the transaction
-> grant immediately or await server verification
-> display the final resultNever grant the reward merely because the call to present the ad succeeded. Tie the grant to the reward event and the chosen verification policy.
Every grant needs a transaction ID and an idempotent state transition. A client callback, retry, and server verification message may all refer to the same transaction. Only one of them may create value.
Two verification strategies are common:
- Fast feedback: Grant on the client reward callback, then reconcile with server-side verification.
- Stronger economy protection: Keep the transaction pending until the server verifies it.
The second approach is safer for scarce or trade-sensitive rewards but introduces visible delay. The first feels faster but requires reconciliation and abuse monitoring.
Tradeoffs
Local guard versus account guard
A local guard works offline and responds immediately, but players can reset local storage and can receive independent allowances on different devices. An account guard provides a unified limit but requires identity, network access, storage, and conflict handling.
Many games need both: a local session guard for responsiveness and a server account guard for persistent limits.
Conservative frequency versus monetization opportunity
Lower frequency reduces interruption opportunities but may leave revenue unrealized. Higher frequency increases inventory while risking shorter sessions and worse return behavior. The direction and magnitude depend on the game, audience, region, and demand; they should be measured rather than asserted.
Immediate reward versus verified reward
Immediate rewards minimize friction. Verified rewards protect the economy. Select the mode per reward class instead of forcing one global behavior. A temporary revive may favor speed, while premium currency may justify verification.
Fixed configuration versus remote configuration
Hard-coded values are simple but require a release to change. Remote configuration supports experiments and emergency rollback, but it introduces versioning, validation, caching, and safe-default requirements.
Failure Modes
Counting a failed request as exposure
Symptom: players are denied ads even though no ad appeared.
Prevention: write history only from a confirmed presentation or impression callback.
Duplicate reward delivery
Symptom: the same client callback or server message creates value more than once.
Prevention: use a unique transaction ID, a durable state machine, and an atomic grant operation.
Clock manipulation
Symptom: changing device time resets a delay or extends it unexpectedly.
Prevention: use monotonic elapsed time for session rules and server time for persistent rules.
Stale remote policy
Symptom: a bad value or incompatible schema reaches clients.
Prevention: validate ranges and versions before activation, retain the last known good policy, and provide a kill switch.
Provider and client counts disagree
Symptom: dashboards differ by a small number of impressions.
Prevention: account for provider processing delay, configuration propagation time, and different counting boundaries. Compare identifiers and timestamps before changing policy.
Play does not resume
Symptom: the ad closes, but input, audio, pause state, or scene navigation remains broken.
Prevention: centralize restoration in dismissal and failure paths and test operating-system interruptions.
First experience is interrupted
Symptom: a new player sees a full-screen ad before understanding the core loop.
Prevention: use a semantic onboarding-complete event. Do not approximate learning with an unverified universal number of minutes or runs.
Testing Plan
Deterministic unit tests
Cover the gate without loading an SDK:
- Interstitials are denied during active play.
- Interstitials can proceed at an eligible transition.
- Rewarded ads are denied without explicit opt-in.
- The minimum interval produces the expected retry time.
- Session and rolling-window limits are independent.
- An unready ad is denied after policy checks pass.
- History for one ad kind does not accidentally affect another unless policy says it should.
- Invalid policy values are rejected before evaluation.
Use a fake clock and explicit exposure fixtures. Tests should never depend on wall-clock waiting.
Lifecycle integration tests
Use test ad units and simulate:
- load success and failure;
- presentation success and failure;
- dismissal during scene changes;
- application backgrounding and restoration;
- repeated impression callbacks;
- reward callback followed by repeated server verification;
- network loss while a reward transaction is pending.
Assert both ad state and game state. A technically successful callback is not enough if the player returns to a frozen game.
Experiment design
Instrument potential opportunities before enabling ads. Then compare a control group with carefully bounded variants. Track:
- eligible opportunities and confirmed impressions;
- denial reasons by policy version;
- immediate session exits after interstitials;
- rewarded offer, opt-in, completion, and grant rates;
- missing and duplicate grants;
- session quality and D1/D7 return behavior by exposure cohort;
- observed revenue and SDK error rates.
Define safety thresholds and rollback behavior before launching the experiment. Record sample size, observation period, audience, geography, placement, and policy version with every conclusion.
Production Checklist
AdMob app checklist
- Use test ad units in development and QA.
- Restrict interstitials to reviewed natural transitions.
- Document the interaction between app-level and ad-unit caps.
- Include provider setting propagation time in rollout plans.
- Handle presentation, failure, dismissal, and reward callbacks.
- Decide which reward classes require server-side verification.
- Deduplicate impression and reward identifiers.
- Ensure ad failure never prevents game progression.
- Restore input, audio, pause state, and scenes after full-screen content.
- Keep a remote kill switch and a validated last-known-good policy.
AdSense web checklist
- Confirm that the selected format is supported for the site and account.
- Disclose the required action and the exact reward.
- Disclose possible outcomes and probabilities for random rewards when required.
- Keep rewards non-transferable and usable only within the platform.
- Preserve normal use when a player declines or skips the rewarded experience.
- Deliver the promised reward exactly once.
- Do not imitate provider controls with a custom ad overlay.
What This Guide Intentionally Does Not Promise
This guide does not provide:
- a universal cooldown or daily cap;
- a guaranteed retention or session-length improvement;
- a standard rewarded-ad conversion rate;
- a recommended ad-removal price;
- a guaranteed eCPM or revenue increase;
- a provider-independent close or skip timer.
Those are product observations, not platform constants. Publish them only with the source, audience, experimental design, sample, and observation period that produced them.
