<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>webmonetization &amp;mdash; Innkeeper Games</title>
    <link>https://innkeepergames.com/tag:webmonetization</link>
    <description>Indie studio making Cowork, a gamified accountability tool</description>
    <pubDate>Sat, 18 Apr 2026 00:44:28 +0000</pubDate>
    <item>
      <title>How to Monetize a Godot Game with Web Monetization</title>
      <link>https://innkeepergames.com/how-to-monetize-a-godot-game-with-web-monetization?pk_campaign=rss-feed</link>
      <description>&lt;![CDATA[Web Monetization is a new way to monetize web games (and any other web content). Users can sign up through a Web Monetization provider (like Coil) to gain access all Web Monetized content, and creators of that content get paid based on the amount of time users spend on their sites. It uses Interledger, a protocol that allows for quick transfers of money, to enable very fast short-term payments.&#xA;&#xA;We can use Web Monetization to earn money from web exported games made with Godot. We can even check if the user is paying and offer them exclusive content if they are! This tutorial offers example approaches to monetizing your web game using Godot and Web Monetization (WM). Check out the demo and source code below.&#xA;&#xA;#godot #webmonetization&#xA;!--more--&#xA;&#xA;You can find the demo here (click and hold to move to your cursor&#39;s location--you can only walk through the gate if you have Web Monetization enabled) and the (MIT licensed) source code here.&#xA;&#xA;div class=&#34;iframe-container&#34;iframe src=&#34;https://muse.ai/embed/CoEgCUq?links=0&amp;logo=0&amp;title=0&amp;autoplay=1&amp;loop=1&amp;style=no-controls&#34; frameborder=&#34;0&#34; allowfullscreen/iframe/div&#xA;&#xA;Just Monetize the Game&#xA;The simplest step is to alert the WM provider that the game is monetized and give it a pointer to send money to. In general, we do this by adding a meta tag to the head section of our HTML document. Here&#39;s the one included in the demo:&#xA;&#xA;meta name=&#34;monetization&#34; content=&#34;$ilp.uphold.com/ghyDriDrafqi&#34; /&#xA;&#xA;The meta tags include the name &#34;monetization&#34; and the content of your payment pointer. Without a payment pointer, the WM provider won&#39;t know where to send money, so you&#39;ll need to get your hands on one of these to monetize your game. Check out this page to learn how to grab one.&#xA;&#xA;Once you have your payment pointer, open your Godot project and navigate to Project -  Export.... This will open the window to export your game. If you haven&#39;t already added HTML5 to your list of exports, add it by pressing Add... -  HTML5.&#xA;&#xA;Then, in the Options tab, add your meta tag (including your payment pointer) under Head Include to include the tag in the exported game&#39;s head section. After you&#39;ve done that, you&#39;ll already be ready to start earning money! WM-enabled users of your web exported Godot game will cause money to be streamed to your payment pointer while they play. The rest of this tutorial covers how to detect Web Monetization and offer exclusive content to those with Web Monetization enabled in Godot.&#xA;&#xA;Image indicating visually where to find the section described in the previous paragraph.&#xA;&#xA;Check if a User has Web Monetization Enabled in Godot&#xA;Web Monetization has a helpful JavaScript API that lets us check whether the user&#39;s browser knows about Web Monetization, and, if it does, lets us check the state of monetization (namely, whether the user&#39;s payment is stopped, pending, or started). In this case, if it&#39;s started, we&#39;ll offer exclusive content.&#xA;&#xA;For this tutorial, we&#39;ll be focused on whether the user has a WM provider and whether they&#39;re actively streaming money. Thankfully, Godot offers its JavaScript singleton that allows us to interact with the browser by accessing its JavaScript context. We can directly use its eval method to evaluate JavaScript and get a return value. Through this singleton, we can use the Web Monetization JavaScript API.&#xA;&#xA;First, create a new script called WebMonetization.gd that extends Node. We&#39;ll AutoLoad this script so it&#39;s accessible as a singleton from anywhere in our game. Go to Project -  Project Settings... and then navigate to the AutoLoad tab. Add the path of your script and press Add. The name appearing in the Name column is how you&#39;ll call functions from anywhere in the project (i.e. using WebMonetization.function).&#xA;&#xA;Let&#39;s add some code to our singleton that checks whether the user&#39;s browser supports Web Monetization, and then, if it does, starts keeping track of whether the user is paying.&#xA;&#xA;As soon as our game loads, we want to know whether the user&#39;s browser supports WM, so We&#39;ll start by adding some code to our WebMonetization singleton&#39;s ready function that performs the check.&#xA;&#xA;First, add a poll timer node and a paying boolean to our singleton&#39;s member fields.&#xA;&#xA;var paying: bool&#xA;var poll: Timer&#xA;&#xA;Then, using the JavaScript class&#39;s eval method, we can check if the document.monetization property exists, i.e. if the user&#39;s browser supports WM. If it does, we can create timer and connect it to another method we write, so each time the timer runs out, our method is executed (we&#39;ll cover signals more in-depth when we talk about exclusive content). This allows us to repeatedly check whether monetization is started. (If you only care about the first time monetization starts and don&#39;t care to check repeatedly, you can add the commented line to free the timer node at that point.)&#xA;&#xA;func ready() -  void:&#xA;&#x9;if JavaScript.eval(&#34;(document.monetization !== null);&#34;):&#xA;&#x9;&#x9;poll = Timer.new()&#xA;&#x9;&#x9;addchild(poll)&#xA;&#x9;&#x9;poll.connect(&#34;timeout&#34;, self, &#34;onpolltimeout&#34;)&#xA;&#x9;&#x9;poll.oneshot = false&#xA;&#x9;&#x9;poll.start(1)&#xA;&#xA;func onpolltimeout() -  void:&#xA;&#x9;if JavaScript.eval(&#34;(document.monetization.state === &#39;started&#39;);&#34;):&#xA;&#x9;&#x9;if not paying:&#xA;&#x9;&#x9;&#x9;paying = true&#xA;&#x9;&#x9;&#x9;#poll.queuefree()&#xA;&#x9;elif paying:&#xA;&#x9;&#x9;paying = false&#xA;&#xA;Now, we can write a method, accessible from anywhere in the project, called ispaying that returns our whether the user is currently paying.&#xA;&#xA;func ispaying() -  bool:&#xA;&#x9;return paying&#xA;&#xA;Offering Exclusive Content to Web Monetized Users&#xA;Here are two useful ways to act on whether a user has WM enabled and offer them exclusive content if they do.&#xA;&#xA;Using Our ispaying Method&#xA;This is how the gate works in the demo. When the player KinematicBody2D enters the gate&#39;s Area2D, the gate checks whether the user is paying using WebMonetization.ispaying(). If the method returns True, we open the gate and disable the gate&#39;s collision so the user can pass through.&#xA;&#xA;(Left and Right are the AnimatedSprites corresponding to the left and right sides of the gate, respectively.)&#xA;&#xA;func onArea2Dbodyentered(body: CollisionObject2D):&#xA;&#x9;if body is KinematicBody2D and WebMonetization.ispaying():&#xA;&#x9;&#x9;$Opening/CollisionShape2D.setdeferred(&#34;disabled&#34;, true)&#xA;&#x9;&#x9;$Left.play(&#34;open&#34;)&#xA;&#x9;&#x9;$Right.play(&#34;open&#34;)&#xA;&#xA;func onArea2Dbodyexited(body: CollisionObject2D):&#xA;&#x9;if body is KinematicBody2D and WebMonetization.ispaying():&#xA;&#x9;&#x9;$Opening/CollisionShape2D.setdeferred(&#34;disabled&#34;, false)&#xA;&#x9;&#x9;$Left.play(&#34;close&#34;)&#xA;&#x9;&#x9;$Right.play(&#34;close&#34;)&#xA;&#xA;We use setdeferred() here to ensure that the collision shape is disabled when it&#39;s safe to (after the current frame&#39;s physics step has finished).&#xA;&#xA;Using Godot&#39;s Signals&#xA;For content that needs to change as soon as payment starts, we can use Godot&#39;s Signals, analogous to the observer pattern in software design. Essentially, objects in Godot can emit signals, like a signal for when monetization starts, and other objects can connect those signals to their own methods, so that whenever those signals are emitted, their own methods are called. It&#39;s like a subscription. This is how the sign&#39;s popup works in the demo.&#xA;&#xA;First, we need to declare the signals for when monetization starts and stops. We&#39;ll do this near the member fields we&#39;ve already declared in the WebMonetization singleton.&#xA;&#xA;signal onmonetizationstarted&#xA;signal onmonetizationstopped&#xA;Now, we need to actually emit this signals when their corresponding events occur. Since we already have a method, onpolltimeout, called regularly that checks if the user is paying, we can do this from that method.&#xA;&#xA;func onpolltimeout() -  void:&#xA;&#x9;if JavaScript.eval(&#34;(document.monetization.state === &#39;started&#39;);&#34;):&#xA;&#x9;&#x9;if not paying:&#xA;&#x9;&#x9;&#x9;emitsignal(&#34;onmonetizationstarted&#34;)&#xA;&#x9;&#x9;&#x9;paying = true&#xA;&#x9;&#x9;&#x9;#poll.queuefree()&#xA;&#x9;elif paying:&#xA;&#x9;&#x9;paying = false&#xA;&#x9;&#x9;emitsignal(&#34;onmonetizationstopped&#34;)&#xA;&#xA;Now, when the gate is ready, we connect the WebMonetization singleton&#39;s onmonetizationstarted signal to a method belonging to self which we&#39;ll then write, onmonetizationstarted().&#xA;&#xA;func ready() -  void:&#xA;&#x9;WebMonetization.connect(&#34;onmonetizationstarted&#34;, self, &#34;onmonetizationstarted&#34;)&#xA;&#xA;Our onmonetizationstarted() method should enable our exclusive content, since it&#39;s connected to the signal emitted when the user starts paying. In this case, we&#39;re changing the text on the sign&#39;s popup to thank the user.&#xA;&#xA;func onmonetizationstarted() -  void:&#xA;&#x9;$PanelContainer/Label.text = &#34;&#34;&#34;Thanks for supporting our&#xA;&#x9;work with Web Monetization!&#34;&#34;&#34;&#xA;&#xA;If you&#39;d like, you can follow a similar approach to change the content back when monetization stops.&#xA;&#xA;That&#39;s it! In this tutorial, we&#39;ve covered how to detect if a user&#39;s browser supports Web Monetization in the Godot Game Engine, and, if it does, two ways to act on that and offer exclusive content.&#xA;&#xA;I&#39;d love any feedback and/or corrections you might have! Feel free to email contact@innkeepergames.com or create an issue or PR on the GitHub repo. Thanks!&#xA;&#xA;Innkeeper Games is a one-person indie game studio making warm games about community while creating educational resources for game developers. If you&#39;re interested in more tutorials and game development content from Innkeeper Games, follow me on Twitter and subscribe to get new posts directly in your inbox.&#xA;&#xA;!--emailsub--]]&gt;</description>
      <content:encoded><![CDATA[<p><a href="https://webmonetization.org/" rel="nofollow">Web Monetization</a> is a new way to monetize web games (and any other web content). Users can sign up through a Web Monetization provider (like <a href="https://coil.com" rel="nofollow">Coil</a>) to gain access all Web Monetized content, and creators of that content get paid based on the amount of time users spend on their sites. It uses <a href="https://interledger.org/" rel="nofollow">Interledger</a>, a protocol that allows for quick transfers of money, to enable very fast short-term payments.</p>

<p>We can use Web Monetization to earn money from web exported games made with <a href="https://godotengine.org/" rel="nofollow">Godot</a>. We can even check if the user is paying and offer them exclusive content if they are! This tutorial offers example approaches to monetizing your web game using Godot and Web Monetization (WM). Check out the demo and source code below.</p>

<p><a href="https://innkeepergames.com/tag:godot" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">godot</span></a> <a href="https://innkeepergames.com/tag:webmonetization" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">webmonetization</span></a>
</p>

<p>You can find the demo <a href="https://innkeeper-games.github.io/web-monetization-godot/" rel="nofollow">here</a> (click and hold to move to your cursor&#39;s location—you can only walk through the gate if you have Web Monetization enabled) and the (MIT licensed) source code <a href="https://github.com/innkeeper-games/web-monetization-godot" rel="nofollow">here</a>.</p>

<div class="iframe-container"><iframe src="https://muse.ai/embed/CoEgCUq?links=0&amp;logo=0&amp;title=0&amp;autoplay=1&amp;loop=1&amp;style=no-controls" frameborder="0" allowfullscreen=""></iframe></div>

<h3 id="just-monetize-the-game" id="just-monetize-the-game">Just Monetize the Game</h3>

<p>The simplest step is to alert the WM provider that the game is monetized and give it a pointer to send money to. In general, we do this by adding a <code>meta</code> tag to the <code>&lt;head&gt;</code> section of our HTML document. Here&#39;s the one included in the demo:</p>

<p><code>&lt;meta name=&#34;monetization&#34; content=&#34;$ilp.uphold.com/ghyDriDrafqi&#34; /&gt;</code></p>

<p>The meta tags include the name “monetization” and the content of your payment pointer. Without a payment pointer, the WM provider won&#39;t know where to send money, so you&#39;ll need to get your hands on one of these to monetize your game. Check out <a href="https://help.coil.com/accounts/digital-wallets-payment-pointers" rel="nofollow">this page</a> to learn how to grab one.</p>

<p>Once you have your payment pointer, open your Godot project and navigate to <code>Project -&gt; Export...</code>. This will open the window to export your game. If you haven&#39;t already added HTML5 to your list of exports, add it by pressing <code>Add... -&gt; HTML5</code>.</p>

<p>Then, in the <code>Options</code> tab, add your meta tag (including your payment pointer) under <code>Head Include</code> to include the tag in the exported game&#39;s <code>&lt;head&gt;</code> section. After you&#39;ve done that, you&#39;ll already be ready to start earning money! WM-enabled users of your web exported Godot game will cause money to be streamed to your payment pointer while they play. The rest of this tutorial covers how to detect Web Monetization and offer exclusive content to those with Web Monetization enabled in Godot.</p>

<p><img src="https://i.snap.as/t9syR5k.png" alt="Image indicating visually where to find the section described in the previous paragraph."/></p>

<h3 id="check-if-a-user-has-web-monetization-enabled-in-godot" id="check-if-a-user-has-web-monetization-enabled-in-godot">Check if a User has Web Monetization Enabled in Godot</h3>

<p>Web Monetization has a helpful <a href="https://webmonetization.org/docs/api" rel="nofollow">JavaScript API</a> that lets us check whether the user&#39;s browser knows about Web Monetization, and, if it does, lets us check the <code>state</code> of monetization (namely, whether the user&#39;s payment is <code>stopped</code>, <code>pending</code>, or <code>started</code>). In this case, if it&#39;s <code>started</code>, we&#39;ll offer exclusive content.</p>

<p>For this tutorial, we&#39;ll be focused on whether the user has a WM provider and whether they&#39;re actively streaming money. Thankfully, Godot offers its <a href="https://docs.godotengine.org/en/3.2/classes/class_javascript.html" rel="nofollow"><code>JavaScript</code></a> singleton that allows us to interact with the browser by accessing its JavaScript context. We can directly use its <code>eval</code> method to evaluate JavaScript and get a return value. Through this singleton, we can use the Web Monetization JavaScript API.</p>

<p>First, create a new script called <code>WebMonetization.gd</code> that extends <code>Node</code>. We&#39;ll <code>AutoLoad</code> this script so it&#39;s accessible as a singleton from anywhere in our game. Go to <code>Project -&gt; Project Settings...</code> and then navigate to the <code>AutoLoad</code> tab. Add the path of your script and press <code>Add</code>. The name appearing in the <code>Name</code> column is how you&#39;ll call functions from anywhere in the project (i.e. using <code>WebMonetization.&lt;function&gt;</code>).</p>

<p>Let&#39;s add some code to our singleton that checks whether the user&#39;s browser supports Web Monetization, and then, if it does, starts keeping track of whether the user is paying.</p>

<p>As soon as our game loads, we want to know whether the user&#39;s browser supports WM, so We&#39;ll start by adding some code to our <code>WebMonetization</code> singleton&#39;s <code>_ready</code> function that performs the check.</p>

<p>First, add a <code>poll</code> timer node and a <code>paying</code> boolean to our singleton&#39;s member fields.</p>

<pre><code>var _paying: bool
var _poll: Timer
</code></pre>

<p>Then, using the <code>JavaScript</code> class&#39;s <code>eval</code> method, we can check if the <code>document.monetization</code> property exists, i.e. if the user&#39;s browser supports WM. If it does, we can create timer and <code>connect</code> it to another method we write, so each time the timer runs out, our method is executed (we&#39;ll cover signals more in-depth when we talk about exclusive content). This allows us to repeatedly check whether monetization is started. (If you only care about the first time monetization starts and don&#39;t care to check repeatedly, you can add the commented line to free the timer node at that point.)</p>

<pre><code>func _ready() -&gt; void:
	if JavaScript.eval(&#34;(document.monetization !== null);&#34;):
		_poll = Timer.new()
		add_child(_poll)
		_poll.connect(&#34;timeout&#34;, self, &#34;_on_poll_timeout&#34;)
		_poll.one_shot = false
		_poll.start(1)
</code></pre>

<pre><code>func _on_poll_timeout() -&gt; void:
	if JavaScript.eval(&#34;(document.monetization.state === &#39;started&#39;);&#34;):
		if not _paying:
			_paying = true
			#_poll.queue_free()
	elif _paying:
		_paying = false
</code></pre>

<p>Now, we can write a method, accessible from anywhere in the project, called <code>is_paying</code> that returns our whether the user is currently paying.</p>

<pre><code>func is_paying() -&gt; bool:
	return _paying
</code></pre>

<h3 id="offering-exclusive-content-to-web-monetized-users" id="offering-exclusive-content-to-web-monetized-users">Offering Exclusive Content to Web Monetized Users</h3>

<p>Here are two useful ways to act on whether a user has WM enabled and offer them exclusive content if they do.</p>

<h4 id="using-our-is-paying-method" id="using-our-is-paying-method">Using Our <code>is_paying</code> Method</h4>

<p>This is how the gate works in the demo. When the player <code>KinematicBody2D</code> enters the gate&#39;s <code>Area2D</code>, the gate checks whether the user is paying using <code>WebMonetization.is_paying()</code>. If the method returns <code>True</code>, we open the gate and disable the gate&#39;s collision so the user can pass through.</p>

<p>(<code>Left</code> and <code>Right</code> are the <code>AnimatedSprite</code>s corresponding to the left and right sides of the gate, respectively.)</p>

<pre><code>func _on_Area2D_body_entered(body: CollisionObject2D):
	if body is KinematicBody2D and WebMonetization.is_paying():
		$Opening/CollisionShape2D.set_deferred(&#34;disabled&#34;, true)
		$Left.play(&#34;open&#34;)
		$Right.play(&#34;open&#34;)


func _on_Area2D_body_exited(body: CollisionObject2D):
	if body is KinematicBody2D and WebMonetization.is_paying():
		$Opening/CollisionShape2D.set_deferred(&#34;disabled&#34;, false)
		$Left.play(&#34;close&#34;)
		$Right.play(&#34;close&#34;)
</code></pre>

<p>We use <code>set_deferred()</code> here to ensure that the collision shape is disabled when it&#39;s safe to (after the current frame&#39;s physics step has finished).</p>

<h4 id="using-godot-s-signals" id="using-godot-s-signals">Using Godot&#39;s Signals</h4>

<p>For content that needs to change as soon as payment starts, we can use Godot&#39;s Signals, analogous to the <a href="https://en.wikipedia.org/wiki/Observer_pattern" rel="nofollow">observer pattern</a> in software design. Essentially, objects in Godot can <code>emit</code> signals, like a signal for when monetization starts, and other objects can <code>connect</code> those signals to their own methods, so that whenever those signals are emitted, their own methods are called. It&#39;s like a subscription. This is how the sign&#39;s popup works in the demo.</p>

<p>First, we need to declare the signals for when monetization starts and stops. We&#39;ll do this near the member fields we&#39;ve already declared in the <code>WebMonetization</code> singleton.</p>

<pre><code>signal on_monetization_started
signal on_monetization_stopped
</code></pre>

<p>Now, we need to actually <code>emit</code> this signals when their corresponding events occur. Since we already have a method, <code>_on_poll_timeout</code>, called regularly that checks if the user is paying, we can do this from that method.</p>

<pre><code>func _on_poll_timeout() -&gt; void:
	if JavaScript.eval(&#34;(document.monetization.state === &#39;started&#39;);&#34;):
		if not _paying:
			emit_signal(&#34;on_monetization_started&#34;)
			_paying = true
			#_poll.queue_free()
	elif _paying:
		_paying = false
		emit_signal(&#34;on_monetization_stopped&#34;)
</code></pre>

<p>Now, when the gate is ready, we <code>connect</code> the <code>WebMonetization</code> singleton&#39;s <code>on_monetization_started</code> signal to a method belonging to <code>self</code> which we&#39;ll then write, <code>_on_monetization_started()</code>.</p>

<pre><code>func _ready() -&gt; void:
	WebMonetization.connect(&#34;on_monetization_started&#34;, self, &#34;_on_monetization_started&#34;)
</code></pre>

<p>Our <code>_on_monetization_started()</code> method should enable our exclusive content, since it&#39;s connected to the signal emitted when the user starts paying. In this case, we&#39;re changing the text on the sign&#39;s popup to thank the user.</p>

<pre><code>func _on_monetization_started() -&gt; void:
	$PanelContainer/Label.text = &#34;&#34;&#34;Thanks for supporting our
	work with Web Monetization!&#34;&#34;&#34;
</code></pre>

<p>If you&#39;d like, you can follow a similar approach to change the content back when monetization stops.</p>

<p>That&#39;s it! In this tutorial, we&#39;ve covered how to detect if a user&#39;s browser supports Web Monetization in the Godot Game Engine, and, if it does, two ways to act on that and offer exclusive content.</p>

<p>I&#39;d love any feedback and/or corrections you might have! Feel free to email <code>contact@innkeepergames.com</code> or create an issue or PR on the <a href="https://github.com/innkeeper-games/web-monetization-godot" rel="nofollow">GitHub repo</a>. Thanks!</p>

<p>Innkeeper Games is a one-person indie game studio making warm games about community while creating educational resources for game developers. If you&#39;re interested in more tutorials and game development content from Innkeeper Games, <a href="https://twitter.com/innkeeper_games" rel="nofollow">follow me on Twitter</a> and subscribe to get new posts directly in your inbox.</p>


]]></content:encoded>
      <guid>https://innkeepergames.com/how-to-monetize-a-godot-game-with-web-monetization</guid>
      <pubDate>Mon, 14 Sep 2020 17:21:20 +0000</pubDate>
    </item>
  </channel>
</rss>