naughty.games
Play
Games Live CamsTagsBest of
Home / Guides

How to add in-game ads to your HTML5 game with the naughty.games SDK

Load https://naughty.games/sdk/v1.js with a script tag in the head of your index.html, then call NgSdk.commercialBreak() at natural pauses and NgSdk.rewardedBreak() when a player chooses to watch an ad for a reward. Both return promises that always settle: a commercial break can finish at once, and a rewarded break resolves true only when the player watched the ad to the end. Ads run only in builds hosted on naughty.games; on localhost the SDK shows a test ad instead, and ready-made wrappers exist for Unity, Godot 4, Construct 3 and GameMaker.

Last checked 2026-10-04

Using an AI coding agent? Copy this prompt

Paste it into Claude Code, Cursor, Copilot or any coding agent. It adds the SDK to your project and tests it.

Preview the prompt
Goal: integrate the naughty.games in-game ads SDK (lifecycle and ad breaks only) into this HTML5 (plain browser game) project.

Setup:
1. Add this tag inside <head> of index.html, before the game's own scripts. Use the plain tag exactly, not a copy of the file:
   <script src="https://naughty.games/sdk/v1.js"></script>
2. Wire the SDK into the game code (see "API" and "Rules" below). No wrapper file is needed: the global is NgSdk.

API (global NgSdk, added by the script tag; the engine wrappers call these for you):
- NgSdk.init(): Promise of { env, locale }. Call it first.
- NgSdk.gameLoadingFinished(): the game finished loading.
- NgSdk.gameplayStart() / NgSdk.gameplayStop(): active play starts or stops (menu, pause screen, game over).
- NgSdk.commercialBreak(): Promise of nothing. Shows an ad if one is due.
- NgSdk.rewardedBreak(): Promise of true or false. true only when the player watched the ad to the end.
- NgSdk.on('pause' | 'resume' | 'mute' | 'unmute', fn): fired around every ad.

Rules:
- Every call settles, and the game must carry on once it does. A commercial break may finish at once (no ad, or too soon), so never wait for an ad to appear.
- Grant a reward only when rewardedBreak() resolves true. Not on the button tap, not when the promise settles.
- On pause and mute, stop the game loop and silence audio; restore both on resume and unmute. Keep the handlers quick, they can arrive back to back.
- Place commercial breaks at natural pauses (between levels, after game over), never mid-action or mid-dialogue, and not at startup.
- Put rewarded breaks behind a button the player chooses to tap, and say what the reward is first. Never block progress behind one: on false the player keeps playing.

Verify:
- Run the game from localhost, or add ?ngsdk=test to its address. A test ad covers the game with Complete and Skip buttons. Check both paths: Complete must grant the reward, Skip must not, and the game must continue after each.
- Zip the build with index.html at the top level and upload it. The Build tab in the naughty.games developer console shows "SDK detected" when an HTML file in the build loads https://naughty.games/sdk/v1.js.

Ask me before changing any gameplay. If anything is unclear, read the full guide at https://naughty.games/guides/in-game-ads-sdk before guessing.

What you need

  • A browser build of your game that you upload to naughty.games as a zip. The SDK talks to naughty.games only from a hosted build; an embed URL build or a copy on another site gets no ads.
  • Access to your build's index.html, or to the engine setting that writes it (a Unity WebGL template, Godot's Head Include, or the exported file for Construct 3 and GameMaker).
  • Two places in your game where an ad fits: a natural pause for a commercial break, and something worth a reward for a rewarded ad.

The SDK is small (under 10 KB), has no dependencies, and adds one global object, NgSdk. It covers your game's lifecycle and ad breaks, nothing else.

Load the SDK

Add this line inside <head> of your index.html, before your game's own scripts:

<script src="https://naughty.games/sdk/v1.js"></script>

Use the plain tag exactly like this, not a copy of the file: v1 gets fixes without you re-uploading, and the developer console looks for this tag to show "SDK detected" on your build. A breaking change would ship as a new file name, so v1 keeps working.

API reference

Call Returns What it does
NgSdk.init() Promise of { env, locale } Connects to the page. env is naughty on naughty.games, local in test mode and inert anywhere else. locale is the player's language, for example en. Settles within 1.5 seconds.
NgSdk.gameLoadingFinished() nothing Your game finished loading and can be played.
NgSdk.gameplayStart() nothing Active play started (or resumed after a menu).
NgSdk.gameplayStop() nothing Active play stopped: a menu, a pause screen, a game over.
NgSdk.commercialBreak() Promise of nothing Shows an ad if one is due. Continue your game when it settles.
NgSdk.rewardedBreak() Promise of true or false Shows a rewarded ad. true only when the player watched it to the end.
NgSdk.on(event, fn) nothing Calls fn on pause, resume, mute or unmute.

You can call breaks and lifecycle calls before init() settles; they wait for it. Calling init() first is still the clearest order.

Pause and mute when asked

Before an ad, the page sends pause and mute. After it, resume and unmute. The page cannot silence your game's audio from outside, so your game has to do it:

NgSdk.on('pause', () => game.pause());
NgSdk.on('resume', () => game.resume());
NgSdk.on('mute', () => audio.mute());
NgSdk.on('unmute', () => audio.unmute());

These can arrive back to back when no ad was available, so keep the handlers quick.

Where to place breaks

  • Commercial breaks go at natural pauses: between levels, after a game over, before the next chapter. Never in the middle of action or dialogue, and not at startup: naughty.games may already show an ad before your game starts.
  • Rewarded ads are always the player's choice: a button such as "Watch an ad for 50 coins" or "Watch an ad to continue". Say what the reward is before they tap.
  • Never block progress behind a rewarded ad. If it resolves false, the player keeps playing without the bonus.

A plain HTML5 example

<!doctype html>
<html>
	<head>
		<script src="https://naughty.games/sdk/v1.js"></script>
	</head>
	<body>
		<button id="bonus">Watch an ad for 50 coins</button>
		<script>
			NgSdk.on('pause', () => game.pause());
			NgSdk.on('resume', () => game.resume());
			NgSdk.on('mute', () => audio.mute());
			NgSdk.on('unmute', () => audio.unmute());

			NgSdk.init().then(() => {
				NgSdk.gameLoadingFinished();
				NgSdk.gameplayStart();
			});

			async function onLevelComplete() {
				NgSdk.gameplayStop();
				await NgSdk.commercialBreak(); // may finish at once
				NgSdk.gameplayStart();
				startNextLevel();
			}

			document.getElementById('bonus').addEventListener('click', async () => {
				const granted = await NgSdk.rewardedBreak();
				if (granted) {
					addCoins(50);
				} else {
					showMessage('No ad right now. Try again later.');
				}
			});
		</script>
	</body>
</html>

How breaks behave

Every call settles, and your game must carry on once it does:

  • No ad available: commercialBreak() settles at once and rewardedBreak() resolves false.
  • Too soon: commercial breaks are spaced out per player session. Right now that is at least 3 minutes between breaks and none in the first 60 seconds after your game starts. A call inside those limits settles at once. The limits may change, so do not build your game around the exact numbers.
  • One at a time: while a rewarded ad plays, another rewardedBreak() call does not start a second one.
  • Something went wrong: every call has a timeout, so a lost connection never leaves your game waiting forever.

Grant a reward only when rewardedBreak() resolves true. Not on the button tap, not when the promise settles, not when pause arrives.

Test it locally

On localhost, 127.0.0.1 or a file:// page, or with ?ngsdk=test added to the address, the SDK runs in test mode (env is local):

  • A test ad covers the game with Complete and Skip buttons. Complete resolves a rewarded break true; Skip resolves it false, so you can check both paths.
  • If you click neither, the test ad closes by itself after 5 seconds and counts as completed.
  • pause, mute, resume and unmute fire around the test ad just like the real thing.
  • Lifecycle calls are logged to the browser console as [naughty.games SDK mock] gameplayStart and so on.

Unity and Godot builds need a local web server anyway (see the Unity and Godot export guides), and both serve on localhost, so test mode turns on by itself. Real ads only play once the build is hosted on naughty.games.

Engine wrappers

Each wrapper is a small, commented file you add to your project. They all need the script tag above in your page, and they all finish breaks at once if the SDK is missing, so your game never waits.

Unity (WebGL)

Download NaughtyGamesSdk.jslib into Assets/Plugins/WebGL/ and NaughtyGamesSdk.cs anywhere under Assets/. Attach the NaughtyGamesSdk component to an empty GameObject in your first scene; it stays across scene loads.

For the script tag, copy Unity's Default template from your Editor install (Editor/Data/PlaybackEngines/WebGLSupport/BuildTools/WebGLTemplates/Default) to Assets/WebGLTemplates/NaughtyGames/, add the tag inside <head> of its index.html, and pick it under Player Settings > Web > Resolution and Presentation > WebGL Template.

NaughtyGamesSdk.Instance.GameLoadingFinished();
NaughtyGamesSdk.Instance.CommercialBreak(() => LoadNextLevel());
NaughtyGamesSdk.Instance.RewardedBreak(granted => { if (granted) AddCoins(50); });

The component sets Time.timeScale to 0 and mutes AudioListener during ads (both can be turned off in the Inspector). In the Editor there is no ad: breaks finish at once, and a tick box decides whether a rewarded break grants, so you can test your reward code.

Godot 4

Download naughty_games_sdk.gd and add it as an autoload named NaughtyGamesSdk (Project > Project Settings > Globals > Autoload). In Project > Export > Web, paste the script tag into HTML > Head Include. The wrapper uses JavaScriptBridge, so it works in GDScript projects.

NaughtyGamesSdk.game_loading_finished()
await NaughtyGamesSdk.commercial_break()
if await NaughtyGamesSdk.rewarded_break():
    add_coins(50)

It pauses the scene tree and mutes the Master bus during ads, and emits paused, resumed, muted and unmuted signals if you want to do more.

Construct 3

Download naughty-games-sdk.js, add it to your project's Scripts folder and set its Purpose to Main script. Set Project Properties > Advanced > Use worker to No, and export with Minify script set to None or Simple. After each Web export, add the script tag inside <head> of the exported index.html.

From a Run script action in an event sheet, call ngCommercialBreak() or ngRewardedBreak(). The wrapper answers by calling event sheet functions: NgBreakDone after a commercial break, and NgRewardDone with 1 when the player watched the ad to the end or 0 when not. It sets the time scale to 0 during ads and calls NgMute and NgUnmute so you can silence audio.

GameMaker (HTML5)

Download naughty_games_sdk.js and scr_naughty_games_sdk.gml. Create an extension, add the JavaScript file for the HTML5 target and add the functions listed at the top of that file. Add the GML file as a script. After export, add the script tag inside <head> of index.html.

// Persistent controller object
// Create: ng_sdk_start();
// Step:   ng_sdk_step();

ng_sdk_commercial_break(function() { room_goto_next(); });
ng_sdk_rewarded_break(function(_granted) { if (_granted) global.coins += 50; });

GameMaker cannot take a JavaScript callback on HTML5, so the extension holds each result until ng_sdk_step() collects it and runs your function. During an ad, global.ng_paused is true and the master gain is 0.

Check it in the developer console

After you upload a zip, the Build tab shows SDK detected when an HTML file in your build loads https://naughty.games/sdk/v1.js with a script tag, or SDK not detected when none does. Once players play your live game, it also shows the last day their plays reached the SDK, which catches a build that loads the script some other way. The owner's preview never counts toward that.

How revenue share works

The SDK plays ads on your game page, so they follow the same deal as every other ad there:

You receive 70% of the net revenue from ads served by our ad network partners on your game page, including video and display ads. Earnings are paid in USDC on the Polygon network on the 10th of each month once your balance reaches 50 USDC.

That applies to games in the revenue share program, which covers builds hosted on naughty.games. On the free listing you keep 100% of what your own links earn, and there is no share of ad revenue, from breaks or anything else. The full rules are in section 8 of the developer terms.

Do not click ads on your own game page, ask players to click them, or send bot or bought traffic to it. Ad networks remove this traffic, and we treat it as breaking these terms.

Builds may not include ad code from other networks. The SDK is the way to show ads inside your game.

Publish it

Once your game shows the test ad on localhost and carries on after both Complete and Skip, zip the build with index.html at the top level (up to 250 MB unpacked and 2,000 files) and upload it. Review usually takes about 2 working days. Head to /submit when you are ready.

Questions

Do ads from the SDK count toward my revenue share?
Yes, if your game is in the revenue share program. You receive 70% of the net revenue from ads served by our ad network partners on your game page, including video and display ads. Breaks you call through the SDK play on your game page, so an ad our ad network partners serve in a break counts the same as any other ad there.
Why did commercialBreak() finish straight away?
That is normal. A commercial break finishes at once when no ad is available, when the last one showed less than 3 minutes ago, or in the first 60 seconds after your game starts. These limits may change, so continue your game when the promise settles, whatever happened.
Does the SDK work on itch.io or in an embed URL build?
No ads run there. The SDK connects only on builds hosted on naughty.games (uploaded as a zip). Anywhere else every break finishes at once and rewardedBreak() resolves false, so the same build still plays fine on other sites.
Can I use another ad network in my build instead?
No. Builds may not include third-party ad code; the developer console flags it and such builds are rejected. The SDK is the way to show ads inside your game on naughty.games.
How do I test ads without uploading?
Run the game from localhost or 127.0.0.1, or add ?ngsdk=test to the address. The SDK then shows a test ad with Complete and Skip buttons. It closes by itself after 5 seconds and counts as completed if you click neither.

Sources

  • naughty.games developer terms (revenue share program, section 8.2)
  • MDN: Window.postMessage()
  • Unity Manual: Interaction with browser scripting
  • Unity Manual: Web templates
  • Godot docs: JavaScriptBridge
  • Godot docs: Exporting for the Web
  • Construct 3 manual: IRuntime script interface
  • GameMaker manual: Extensions

Free hosting, real players on phone and desktop, and a stats console.

Publish your adult game for free

More guides

  • Where to publish your adult game

    itch.io, Steam, Patreon, SubscribeStar, Nutaku, DLsite and naughty.games compared for adult games: content rules, fees, browser play and the 2025 delistings.

  • How to make money from your adult game

    Patreon, SubscribeStar, Ko-fi, Steam, itch.io, DLsite and Nutaku for adult games: fees, payouts and rules as of September 2026, plus what drives pledges.

  • Payment processors and adult games: what each platform allows

    Adult content rules and payouts on Patreon, SubscribeStar, Ko-fi, itch.io, Steam and DLsite, and where the 2025 payment processor crackdown stands in 2026.

  • How to put your Ren'Py game in the browser

    How to export a Ren'Py visual novel for the web, test it on a local server, zip it correctly, and publish it so players can play in the browser.

  • How to export your Unity game to WebGL for the browser

    How to build a Unity WebGL player, set compression correctly, test it locally, zip it, and publish it so players can play in the browser.

  • How to export your Godot game for the web

    How to export a Godot 4 project to HTML5, why single-threaded export is the safe choice, test it locally, zip it, and publish it to naughty.games.

Browse

  • Play online
  • Live cams
  • All games
  • Tags
  • Platforms
  • Best of
  • Privacy
  • Terms
  • DMCA
  • 2257
  • DSA
  • Advertise
  • For developers
  • Guides
  • Data reports
  • Contact
© 2026 naughty.games Adult content. 18+.

Adult content ahead

naughty.games contains adult-oriented game listings. By entering, you confirm you are at least 18 years old and that adult content is legal in your jurisdiction.

What do you want to see?

You can change this anytime

Nothing selected = show me everything