The Ad Placement API is designed to support AdSense and AdMob developers using interstitial and rewarded ads in HTML5 games on the web or within apps. This example demonstrates how to integrate the Ad Placement API into a game and use it to place an interstitial ad.
Prerequisites
Before you begin, you will need the following:
- Create two empty files in the same directory:
- index.html
- game.js
- Install Python locally, or use a web server to test your implementation
App sample code
AdMob publishers can download sample app code to better understand how the API can be integrated into an app game.
1. Start a development server
Because the Ads Placement API loads dependencies via the same protocol as the page which it is loaded on, you need to use a web server to test your app. You can use Python's built-in server to create a local development environment.
Open the terminal.
Go to the directory that contains your index.html file, then run:
python -m http.server 8000
In a web browser, go to
localhost:8000
You can also use any other web server, such as the Apache HTTP Server.
2. Create an HTML5 game
Modify index.html
to create an HTML5 canvas element and a button to trigger
gameplay. Then add the necessary script tag to load the game.js
file.
index.html
<!doctype html>
<html lang="en">
<head>
<title>Ad Placement API HTML5 demo</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<canvas id="gameContainer" height="300px" width="300px"></canvas>
<button id="playButton">Play</button>
<button style="display:none" id="headsButton">Heads</button>
<button style="display:none" id="tailsButton">Tails</button>
<script src="game.js"></script>
</body>
</html>
Modify game.js to play a coin flip game when the "Play" button is clicked.
game.js
// Create a coin flip game
class Game {
constructor() {
// Define variables
this.score = 0;
this.choice = '';
this.canvas = document.getElementById('gameContainer').getContext('2d');
this.canvas.font = '24px Arial';
this.playButton = document.getElementById('playButton');
this.headsButton = document.getElementById('headsButton');
this.tailsButton = document.getElementById('tailsButton');
// On click listeners for the game's buttons.
this.playButton.addEventListener('click', () => {
this.erase();
this.play();
});
this.headsButton.addEventListener('click', () => {
this.choice = 'Heads';
this.flipCoin();
});
this.tailsButton.addEventListener('click', () => {
this.choice = 'Tails';
this.flipCoin();
});
this.erase();
}
// Start the game
play() {
this.score = 0;
this.canvas.fillText('Score: ' + this.score, 8, 26);
this.canvas.fillText('Heads or Tails?', 66, 150);
this.playButton.style.display = 'none';
this.headsButton.style.display = 'inline-block';
this.tailsButton.style.display = 'inline-block';
}
// Flip the coin
flipCoin() {
this.headsButton.disabled = true;
this.tailsButton.disabled = true;
this.erase();
this.canvas.fillText('Score: ' + this.score, 8, 26);
this.canvas.fillText('Flipping coin . . .', 60, 150);
setTimeout(() => { this.coinLanded() }, 2000);
}
// Logic for when the coin lands
coinLanded() {
this.headsButton.disabled = false;
this.tailsButton.disabled = false;
let sideUp;
if(Math.random() < 0.5) {
sideUp = 'Heads';
} else {
sideUp = 'Tails';
}
if (sideUp === this.choice ) {
this.win(sideUp);
} else {
this.lose(sideUp);
}
}
// Guess the flip correctly
win(sideUp) {
this.erase();
this.score += 1;
this.canvas.fillText('Score: ' + this.score, 8, 26);
this.canvas.fillText('It was ' + sideUp + '!', 66, 150);
this.canvas.fillText('Guess again', 70, 200);
}
// Guess the flip incorrectly
lose(sideUp) {
this.erase();
this.canvas.fillText('Sorry, it was ' + sideUp, 50, 100);
this.canvas.fillText('Your score was ' + this.score, 50, 150);
this.canvas.fillText('Want to play again?', 45, 200);
this.playButton.style.display = 'inline-block';
this.headsButton.style.display = 'none';
this.tailsButton.style.display = 'none';
}
// Erase the canvas
erase() {
this.canvas.fillStyle = '#ADD8E6';
this.canvas.fillRect(0, 0, 300, 300);
this.canvas.fillStyle = '#000000';
}
}
const game = new Game();
After completing this step, when you open index.html
in your browser (via your
development server) you should be able to see the game canvas and "Play" button.
If you click Play, the coin flip game should start.
3. Import the Ad Placement API
Next, add the Ad Placement API to your game by inserting a script tag in
index.html
, before the tag for game.js
.
The script tag can take a number of parameters. We will use the following parameters to specify the AdSense property code and to enable testing mode:
data-ad-client=<AdSense property code>
Your AdSense property code. This is always required even for games that will run within apps.data-adbreak-test="on"
Enables testing mode. Remove this for games once they are being served to players.
Setup the AdSense Code and turn on testing mode
The Ad Placement API functionality is included in the AdSense code. To turn it
on, you must first add the AdSense code and include a small script snippet that
initializes its two key functions: adBreak()
and adConfig()
.
index.html (web)
[...]
<canvas id="gameContainer" height="300px" width="300px"></canvas>
<button id="playButton">Play</button>
<button style="display:none" id="headsButton">Heads</button>
<button style="display:none" id="tailsButton">Tails</button>
<script async
data-adbreak-test="on"
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-123456789"
crossorigin="anonymous">
</script>
<script>
window.adsbygoogle = window.adsbygoogle || [];
const adBreak = adConfig = function(o) {adsbygoogle.push(o);}
</script>
<script src="game.js"></script>
</body>
</html>
Embedding your game (optional)
If you wish to embed a game in other pages inside an iFrame, and the adsbygoogle
tag is in the game's HTML page, make sure to add allow='autoplay'
to the iframe element. This is a best practice, and is necessary for certain ads to be eligible for your game.
<head>
<!-- The adsbygoogle tag is not here -->
</head>
<body>
<iframe src="https://www.my-game.com" title="My game" allow="autoplay">
<!-- The game is loaded here and contains the adsbygoogle tag -->
</iframe>
</body>
Support mobile apps
An H5 game can run in a regular web browser, or in a WebView or Chrome Custom Tab within an app. The Ad Placement API can detect which environment your game is running in and direct the ad requests appropriately. If your game is running within a regular web browser the ad requests are treated like normal AdSense requests. If the Ad Placement API detects an in-app environment then it communicates with the GMA SDK, if it's present, to request and show AdMob ads.
Currently, this capability is supported on Android apps that have been linked with the AdMob GMA SDK. In order to enable it you need to register the WebView that will show your game with the GMA SDK and then configure AdMob ad units and pass them as additional parameters to the AdSense tag. When your game is run within a suitable app, the Ad Placement API will use these ad units to show ads.
To enable mobile support, you must specify the following additional tag parameters:
data-admob-interstitial-slot=<AdMob slot ID>
An AdMob interstitial ad unit ID that you’ve configured previously.data-admob-rewarded-slot=<AdMob slot ID>
An AdMob rewarded ad unit ID.
Your AdSense property code should always be passed with the
data-ad-client
parameter and at least one of data-admob-interstitial-slot
or
data-admob-rewarded-slot
must be specified. Both parameters should be
specified if your game uses both formats.
Optionally, you can also specify data-admob-ads-only=on
tag parameter to
indicate that your game should show ads only from AdMob and not fallback to
AdSense in the cases where the game is being played in an environment which
doesn't support AdMob requests (e.g. non-app environments or apps without
AdMob GMA SDK configured).
Important: When you design your game to be embedded within an app and you own the app, or are entering into a revenue share agreement with the owner of the app, then the only way to do this in a high performing and policy compliant way is to use this AdMob support.
First, register the WebView that will show your game with the GMA SDK:
MainActivity.java (app)
...
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = findViewById(R.id.webview_minigame);
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
h5AdsWebViewClient = new H5AdsWebViewClient(this, webView);
webView.setWebViewClient(h5AdsWebViewClient);
h5AdsWebViewClient.setDelegateWebViewClient(pubWebViewClient);
Next, pass AdMob ad units (one for interstitials and one for rewarded ads) as follows:
index.html (app)
[...]
<canvas id="gameContainer" height="300px" width="300px"></canvas>
<button id="playButton">Play</button>
<button style="display:none" id="headsButton">Heads</button>
<button style="display:none" id="tailsButton">Tails</button>
<script async
data-admob-interstitial-slot="ca-app-pub-0987654321/1234567890"
data-admob-rewarded-slot="ca-app-pub-0987654321/0987654321"
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-123456789"
crossorigin="anonymous">
</script>
<script>
window.adsbygoogle = window.adsbygoogle || [];
const adBreak = adConfig = function(o) {adsbygoogle.push(o);}
</script>
<script src="game.js"></script>
</body>
</html>
4. Make a call to adConfig()
The adConfig()
call communicates the game's current configuration to the Ad
Placement API. The API then can use this information to filter the types of ads
it requests so they are suitable for the game (such as video ads that require
sound, if sound is enabled).
A call should be made to adConfig()
any time this configuration changes, like
when a user mutes or unmutes the game. Make a call to adConfig()
in the game's
constructor, then add a button to mute and unmute the game that makes an
additional adConfig()
call.
game.js
class Game {
constructor() {
// Define variables
this.score = 0;
this.choice = '';
this.muted = false;
this.canvas = document.getElementById('gameContainer').getContext('2d');
this.canvas.font = '24px Arial';
this.playButton = document.getElementById('playButton');
this.headsButton = document.getElementById('headsButton');
this.tailsButton = document.getElementById('tailsButton');
this.muteButton = document.getElementById('muteButton');
adConfig({
sound: 'on',
});
// On click listeners for the game's buttons.
this.playButton.addEventListener('click', () => {
this.erase();
this.play();
});
this.headsButton.addEventListener('click', () => {
this.choice = 'Heads';
this.flipCoin();
});
this.tailsButton.addEventListener('click', () => {
this.choice = 'Tails';
this.flipCoin();
});
this.muteButton.addEventListener('click', () => {
var soundString = this.muted ? 'on' : 'off';
this.muteButton.innerHTML = this.muted ? 'Mute sound' : 'Un-mute sound';
this.muted = !this.muted;
adConfig({
sound: soundString,
});
});
this.erase();
[...]
Now, add the mute button to your HTML file.
index.html
[...]
<canvas id="gameContainer" height="300px" width="300px"></canvas>
<button id="playButton">Play</button>
<button style="display:none" id="headsButton">Heads</button>
<button style="display:none" id="tailsButton">Tails</button>
<button id="muteButton">Mute sound</button>
<script async
data-adbreak-test="on"
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-123456789"
crossorigin="anonymous">
</script>
[...]
5. Make a call to adBreak()
when the game ends
The adBreak()
call defines an ad placement and takes the object called
placement config that specifies everything required to show an ad at this point
in your game. Supporting different types of ads will require you to initialize
different subsets of the placement config.
The adBreak()
call defines a placement where an ad could show, or in other
words, an opportunity to show an ad. Whether an ad actually shows will depend on
a number of things:
- The type of ad placement that you declared.
- If there have been suitable user interactions prior to this ad placement.
- Whether a suitable ad exists for the current player, that:
- Is relevant to them.
- Is consistent with their data privacy and consent settings.
- The number of ads the user has seen recently.
- The control settings you have configured for this game as either:
- Hints in the tag.
- On AdSense (Note: the controls available in AdSense will evolve over time)
Add code for an interstitial ad to be shown when the game restarts: make a call
to adBreak()
inside the play()
function, which runs only after the game has
been played through once.
adBreak()
must be called as part of a user action, such as clicking the "Play"
button, otherwise the API will not be able to request and display ads.
Create functions to be called before and after the ad break, which you will then
use in the adBreak()
placement config. It is important to note that the
beforeAd
and afterAd
functions will only be called if a suitable ad is
found.
game.js
class Game {
constructor() {
// Define variables
this.score = 0;
this.choice = '';
this.muted = false;
this.shouldShowAdOnPlay = false;
[...]
// Start the game
play() {
if (this.shouldShowAdOnPlay) {
this.shouldShowAdOnPlay = false;
adBreak({
type: 'next', // ad shows at start of next level
name: 'restart-game',
beforeAd: () => { this.disableButtons(); }, // You may also want to mute the game's sound.
afterAd: () => { this.enableButtons(); }, // resume the game flow.
});
}
this.score = 0;
this.canvas.fillText('Score: ' + this.score, 8, 26);
this.canvas.fillText('Heads or Tails?', 66, 150);
this.playButton.style.display = 'none'
this.headsButton.style.display = 'inline-block'
this.tailsButton.style.display = 'inline-block'
}
[...]
// Guess the flip incorrectly
lose(sideUp) {
this.erase()
this.canvas.fillText('Sorry, it was ' + sideUp, 50, 100);
this.canvas.fillText('Your score was ' + this.score, 50, 150);
this.canvas.fillText('Want to play again?', 45, 200);
this.playButton.style.display = 'inline-block'
this.headsButton.style.display = 'none'
this.tailsButton.style.display = 'none'
this.shouldShowAdOnPlay = true;
}
[...]
// Erase the canvas
erase() {
this.canvas.fillStyle = '#ADD8E6';
this.canvas.fillRect(0, 0, 300, 300);
this.canvas.fillStyle = '#000000';
}
enableButtons() {
this.playButton.disabled = false;
this.headsButton.disabled = false;
this.tailsButton.disabled = false;
}
disableButtons() {
this.playButton.disabled = true;
this.headsButton.disabled = true;
this.tailsButton.disabled = true;
}
}
const game = new Game();
The coin flip app is now creating ad placements for ads to be displayed.
Your own app may have additional, appropriate places for ads other than when the
game ends. Calling adBreak()
in those places should be similar to this
example.
Turn off testing for production apps
Before releasing your app, it is important to remove or comment out the line
data-adbreak-test="on"
in index.html
, as this code turns on test settings in
production.