<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Xojo Web &#8211; Xojo Programming Blog</title>
	<atom:link href="https://blog.xojo.com/tag/xojo-web/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.xojo.com</link>
	<description>Blog about the Xojo programming language and IDE</description>
	<lastBuildDate>Wed, 29 Apr 2026 22:39:55 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
	<item>
		<title>Web Apps Denial of Service</title>
		<link>https://blog.xojo.com/2026/04/29/web-apps-denial-of-service/</link>
		
		<dc:creator><![CDATA[Ricardo Cruz]]></dc:creator>
		<pubDate>Wed, 29 Apr 2026 22:39:52 +0000</pubDate>
				<category><![CDATA[Networking]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Xojo Cloud]]></category>
		<category><![CDATA[Web 2.0]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[webdev]]></category>
		<category><![CDATA[Xojo Web]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16222</guid>

					<description><![CDATA[Last week we got a report of a critical bug affecting Xojo Web apps. Here's what happened, what we did about it, and what you should do depending on how your apps are deployed.]]></description>
										<content:encoded><![CDATA[
<p>Last week we got a report of a critical bug affecting Xojo Web apps. A malformed percent-encoded URL was enough to crash the web app server. Something as small as <code>?x=%</code> in a query string was all it took. We shipped a fix in <a href="https://xojo.com/download/">2026r1.2</a>, and Xojo Cloud has been patched at the platform level to cover users who can&#8217;t upgrade right away. Here&#8217;s what happened, what we did about it, and what you should do depending on how your apps are deployed.</p>



<h2 class="wp-block-heading">Am I affected? What do I do?</h2>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>If you only read one section, read this one.</strong></p>
</blockquote>



<ul class="wp-block-list">
<li><strong>On Xojo Cloud (Web 1 or Web 2)?</strong>&nbsp;You&#8217;re covered. Nothing to do.</li>



<li><strong>Using Lifeboat?</strong>&nbsp;Update Lifeboat and redeploy.</li>



<li><strong>Self-hosted behind Apache or Nginx?</strong> Drop in the filtering rule below. If you&#8217;re on Web 2, also upgrade to 2026r1.2 if possible.</li>



<li><strong>Self-hosted with the Xojo app exposed directly?</strong> On Web 2, upgrade to 2026r1.2 if possible, otherwise put a reverse proxy in front. On Web 1, put a reverse proxy in front (which is what we&#8217;d recommend either way).</li>
</ul>



<p>The full details follow.</p>



<h2 class="wp-block-heading">Timeline</h2>



<ul class="wp-block-list">
<li><strong>Thursday, the 23rd.</strong>&nbsp;A public issue and a private message landed on the same day, both pointing at the same bug.</li>



<li><strong>Thursday through Monday.</strong>&nbsp;We tracked down the root cause, wrote the fix, and tested it.</li>



<li><strong>Tuesday, the 28th.</strong> 2026r1.2 shipped with the patch.</li>



<li><strong>Wednesday, the 29th.</strong>&nbsp;Xojo Cloud patched at the platform level.</li>
</ul>



<p>Under a week from the report to a patched release, with the platform-level mitigation following the next day.</p>



<h2 class="wp-block-heading">What Happened</h2>



<p>A request with a malformed percent-encoded sequence in a query parameter could crash a running Xojo Web app. The smallest reproducer is something like&nbsp;<code>?x=%</code>. That&#8217;s a&nbsp;<code>%</code>&nbsp;not followed by two hex digits, which is invalid percent-encoding and isn&#8217;t decodable.</p>



<p>The bug lives in&nbsp;<code>DecodeURLComponent</code>. When the method ran into invalid input, it raised an exception instead of handling the input gracefully. Because the framework calls this method while parsing incoming requests, anyone could crash a web app by sending a single malformed URL. No authentication, no special headers, no payload. Just a bad query string.</p>



<p>A few things worth being upfront about:</p>



<ul class="wp-block-list">
<li><strong>The bug has probably been there since&nbsp;<code>DecodeURLComponent</code>&nbsp;was introduced.</strong>&nbsp;Every Xojo release that ships the method might be affected.</li>



<li><strong>Both Web 1 and Web 2 are known to be affected.</strong>&nbsp;The Web framework has been calling this method on incoming requests across both generations.</li>



<li><strong>It&#8217;s not just a Web problem.</strong>&nbsp;<code>DecodeURLComponent</code>&nbsp;is a general-purpose method, and the same crash can happen in Desktop and other project types if you call it on attacker-controlled input. Web is the obvious target because requests arrive from the network, but the underlying issue isn&#8217;t Web-specific.</li>
</ul>



<h2 class="wp-block-heading">The Fix</h2>



<p>In 2026r1.2, <code>DecodeURLComponent</code> no longer crashes on invalid input. Instead, it returns an empty String when the input contains a malformed percent-encoded sequence.</p>



<p>We thought about a few approaches and went with this one on purpose, for being consistent with the other sanity checks we do on this method. An empty return value lets existing code keep running rather than letting an exception bubble up through request handling, which is what you want from a method that&#8217;s frequently called on untrusted input. If your code already wraps&nbsp;<code>DecodeURLComponent</code>&nbsp;with its own validation, the new behavior gives you a clean signal to act on (an empty result) instead of an exception to catch.</p>



<p>Xojo 2026r1.2 is the only release with the fix. <strong>Web 1 won&#8217;t be getting a backported patch.</strong> What that means in practice is covered below.</p>



<h2 class="wp-block-heading">What Xojo has already done for you</h2>



<p><strong>Xojo Cloud has been patched at the platform level.</strong>&nbsp;As of Wednesday 29th, Xojo Cloud rejects requests with malformed percent-encoding before they ever reach your app, returning a&nbsp;<code>400 Bad Request</code>&nbsp;from the front-end web server. This protection doesn&#8217;t care which Xojo version your app was built with, and it covers Web 1 and Web 2 the same way.</p>



<p>If your app runs on Xojo Cloud, you don&#8217;t need to redeploy, upgrade, or change anything. We rolled this out specifically so that users who can&#8217;t upgrade right away are covered, including Web 1 users who can&#8217;t upgrade to a fixed version at all.</p>



<h2 class="wp-block-heading">What you should do</h2>



<p>The right move depends on which Web version you&#8217;re on and where your app runs.</p>



<h3 class="wp-block-heading">If you&#8217;re on Web 2</h3>



<p>Upgrade to 2026r1.2 and redeploy if you can. That&#8217;s the cleanest fix and it addresses the issue at the source.</p>



<p>We know &#8220;just upgrade&#8221; isn&#8217;t always realistic. You might be on an older version because your license has expired, because a third-party plugin you rely on hasn&#8217;t caught up yet, because a newer Xojo release introduced a regression you can&#8217;t ship around, or for any number of other reasons. If that&#8217;s you, the hosting-based mitigations below will protect your app in the meantime, and they work regardless of which Xojo version you built with.</p>



<h3 class="wp-block-heading">If you&#8217;re on Web 1</h3>



<p>There&#8217;s no Xojo release that patches&nbsp;<code>DecodeURLComponent</code>&nbsp;for Web 1, so the fix has to live outside your app. The good news is that if you follow Xojo&#8217;s standard hosting recommendations, you&#8217;re fully covered against this specific issue:</p>



<ul class="wp-block-list">
<li><strong>Stay on Xojo Cloud.</strong>&nbsp;You&#8217;re already protected.</li>



<li><strong>Use Lifeboat.</strong>&nbsp;Tim Parnell shipped a Lifeboat update that catches malformed percent-encoding before it reaches your app. Update Lifeboat and redeploy.</li>



<li><strong>Run behind Apache or Nginx</strong>&nbsp;with the rules in the next section.</li>
</ul>



<p>Separately, and on a longer horizon: Web 1 isn&#8217;t receiving framework patches anymore in general, so if you&#8217;re still on it, this is a reasonable moment to start thinking about a migration to Web 2. That&#8217;s a much bigger conversation than this post, but worth flagging.</p>



<h3 class="wp-block-heading">Hosting-level mitigations</h3>



<p>These rules reject malformed percent-encoded URLs at the web server, before the request reaches your Xojo app at all. They work for Web 1 and Web 2, and they don&#8217;t depend on the Xojo version you built with.</p>



<p><strong>Apache:</strong></p>



<pre class="wp-block-code"><code># Reject malformed percent-encoding in the URI.
RewriteCond %{THE_REQUEST} %(?!&#91;0-9A-Fa-f]{2})
RewriteRule .* - &#91;R=400,L]</code></pre>



<p><strong>Nginx:</strong></p>



<pre class="wp-block-code"><code># Reject malformed percent-encoding in the URI.
if ($request_uri ~ "%(?!&#91;0-9A-Fa-f]{2})") {
  return 400;
}</code></pre>



<p>Reload your web server after updating the config (<code>apachectl graceful</code>&nbsp;or&nbsp;<code>nginx -s reload</code>) and check that a request like&nbsp;<code>https://yourapp.example.com/?x=%</code>&nbsp;comes back as&nbsp;<code>400 Bad Request</code>.</p>



<p>These two snippets aren&#8217;t the only way to handle this. The goal is just to block malformed URLs before they reach your app, however you do it. If you&#8217;re running <code>mod_security</code>, for example, a rule that rejects URIs containing invalid percent-encoding will get you the same result. Same idea for any WAF, edge filter, CDN, or load balancer in front of your stack: catch the bad request, return a&nbsp;<code>400</code>, move on.</p>



<h3 class="wp-block-heading">If your Xojo app is exposed directly to the internet</h3>



<p>If your Web app is talking to the internet without a reverse proxy in front of it, your options are narrower. On Web 2, upgrade to 2026r1.2 if you can. On Web 1, or on Web 2 if upgrading isn&#8217;t an option, you&#8217;ll need to put Apache, Nginx, or Lifeboat in front of your app, or move to Xojo Cloud, our managed hosting solution.</p>



<p>This is also a good moment to revisit the setup more broadly.&nbsp;<strong>Xojo recommends always serving Web apps behind a web server</strong>, both for performance and as a defense-in-depth measure against bugs like this one. A reverse proxy would have neutralized this specific issue before it reached the framework, and it&#8217;ll do the same for the next class of issue too.</p>



<h3 class="wp-block-heading">If you use&nbsp;<code>DecodeURLComponent</code>&nbsp;in a non-Web project</h3>



<p>The crash isn&#8217;t unique to Web. If you&#8217;re calling&nbsp;<code>DecodeURLComponent</code>&nbsp;on input you don&#8217;t control (anything coming from a user, a file, a network response, a clipboard), the same bug can hit a Desktop, Console, or other project type.</p>



<p>Upgrade to 2026r1.2 if you can; that&#8217;s the proper fix.</p>



<p>If you can&#8217;t upgrade, you&#8217;ll need to sanitize the input yourself before calling&nbsp;<code>DecodeURLComponent</code>. The check is simple in principle: every&nbsp;<code>%</code>&nbsp;in the string must be followed by exactly two hexadecimal characters (<code>0-9</code>,&nbsp;<code>A-F</code>,&nbsp;<code>a-f</code>). If any&nbsp;<code>%</code>&nbsp;doesn&#8217;t meet that condition, treat the input as invalid and don&#8217;t pass it to&nbsp;<code>DecodeURLComponent</code>. A small helper that validates the string up front and either returns early or substitutes an empty value will keep your app from crashing on the same kind of malformed input that triggers the Web bug.</p>



<h2 class="wp-block-heading">Acknowledgments</h2>



<p>Thanks to the user who reported this through both public and private channels. That&#8217;s exactly the kind of disclosure that lets us turn a fix around in under a week. Thanks also to Tim Parnell for the fast <a href="https://strawberrysw.com/lifeboat/">Lifeboat</a> update, which gave self-hosted users a drop-in mitigation almost immediately.</p>



<p>If you find a security issue in Xojo, please report it privately. You can email&nbsp;<a href="mailto:support@xojo.com">support@xojo.com</a>&nbsp;or file a confidential issue on the issue tracker. Both reach us, and either one lets us get a fix out before the details become public, protecting the rest of the users.</p>



<h2 class="wp-block-heading">References</h2>



<ul class="wp-block-list">
<li><a href="https://documentation.xojo.com/resources/release_notes/2026r1.2.html">Release notes for 2026r1.2</a></li>
</ul>



<p><em>Ricardo has always been curious about how things work. Growing up surrounded by computers</em> he became interested in <em>web technologies in the dial-up connections era. Xojo has been his secret weapon and language of preference since 2018. When he’s not online, chances are he will be scuba diving … or crocheting amigurumis. Find Ricardo on Twitter <a href="https://web.archive.org/web/20220805000833/https://www.twitter.com/piradoiv" target="_blank" rel="noreferrer noopener">@piradoiv</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Scan Barcodes, Pick Colors, Toggle: Xojo Web in 2026r1</title>
		<link>https://blog.xojo.com/2026/03/31/scan-barcodes-pick-colors-toggle-xojo-web-in-2026r1/</link>
		
		<dc:creator><![CDATA[Ricardo Cruz]]></dc:creator>
		<pubDate>Tue, 31 Mar 2026 13:22:00 +0000</pubDate>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[2026r1]]></category>
		<category><![CDATA[Web 2.0]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[webdev]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<category><![CDATA[Xojo Web]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=15969</guid>

					<description><![CDATA[If you build web apps with Xojo, 2026r1 is worth a close look. There&#8217;s a good mix of new controls and under-the-hood improvements to explore.&#8230;]]></description>
										<content:encoded><![CDATA[
<p>If you build web apps with Xojo, 2026r1 is worth a close look. There&#8217;s a good mix of new controls and under-the-hood improvements to explore. Exciting times!</p>



<h2 class="wp-block-heading">New Controls</h2>



<p>Three new controls have been added to the Web framework in this release, aiming to close the difference gap between Web and the other project types.</p>



<p><code>WebSwitch</code>&nbsp;is a toggle control that mobile developers will already be familiar with. It&#8217;s been available on iOS and Android for a while. It&#8217;s now available for web projects too, so if you&#8217;ve been approximating a toggle switch using a styled checkbox, you can finally retire that workaround.</p>



<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1024" height="690" src="https://blog.xojo.com/wp-content/uploads/2026/03/switch-vs-checkbox-1024x690.png" alt="" class="wp-image-15992" srcset="https://blog.xojo.com/wp-content/uploads/2026/03/switch-vs-checkbox-1024x690.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/03/switch-vs-checkbox-300x202.png 300w, https://blog.xojo.com/wp-content/uploads/2026/03/switch-vs-checkbox-768x517.png 768w, https://blog.xojo.com/wp-content/uploads/2026/03/switch-vs-checkbox-1536x1035.png 1536w, https://blog.xojo.com/wp-content/uploads/2026/03/switch-vs-checkbox-2048x1380.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p><code>WebColorPicker</code> brings color selection to web apps in the same way <code>DesktopColorPicker</code> does for desktop. Drop it in from the Library, wire up the event and you have a color picker the Xojo way.</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="731" src="https://blog.xojo.com/wp-content/uploads/2026/03/colorpicker-ide-1024x731.png" alt="" class="wp-image-15994" srcset="https://blog.xojo.com/wp-content/uploads/2026/03/colorpicker-ide-1024x731.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/03/colorpicker-ide-300x214.png 300w, https://blog.xojo.com/wp-content/uploads/2026/03/colorpicker-ide-768x548.png 768w, https://blog.xojo.com/wp-content/uploads/2026/03/colorpicker-ide-1536x1096.png 1536w, https://blog.xojo.com/wp-content/uploads/2026/03/colorpicker-ide-2048x1461.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>This is how <code>WebColorPicker</code> looks like in your browser:</p>



<figure class="wp-block-video"><video height="1274" style="aspect-ratio: 1488 / 1274;" width="1488" controls src="https://blog.xojo.com/wp-content/uploads/2026/03/colorpicker-browser.mp4"></video></figure>



<p>The third new control adds barcode reading support. Your web app can now read barcodes directly from the user&#8217;s camera, from desktop or mobile browsers. This opens up a lot of practical use cases: Inventory systems, ticketing, product lookups, that previously would have pushed you toward a native mobile app.</p>



<p>Again, drop the Barcode control into your project and implement the events:</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="747" src="https://blog.xojo.com/wp-content/uploads/2026/03/barcode-reader-ide-1024x747.png" alt="" class="wp-image-15995" srcset="https://blog.xojo.com/wp-content/uploads/2026/03/barcode-reader-ide-1024x747.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/03/barcode-reader-ide-300x219.png 300w, https://blog.xojo.com/wp-content/uploads/2026/03/barcode-reader-ide-768x560.png 768w, https://blog.xojo.com/wp-content/uploads/2026/03/barcode-reader-ide-1536x1120.png 1536w, https://blog.xojo.com/wp-content/uploads/2026/03/barcode-reader-ide-2048x1494.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>That&#8217;s it! Your web apps can scan a great variety of barcodes now. Including QR, Data Matrix, Aztec, PDF 417 and much more!</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="471" height="1024" src="https://blog.xojo.com/wp-content/uploads/2026/03/aztec-barcode-1-471x1024.png" alt="" class="wp-image-16007" srcset="https://blog.xojo.com/wp-content/uploads/2026/03/aztec-barcode-1-471x1024.png 471w, https://blog.xojo.com/wp-content/uploads/2026/03/aztec-barcode-1-138x300.png 138w, https://blog.xojo.com/wp-content/uploads/2026/03/aztec-barcode-1.png 555w" sizes="auto, (max-width: 471px) 100vw, 471px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="471" height="1024" src="https://blog.xojo.com/wp-content/uploads/2026/03/datamatrix-barcode-1-471x1024.png" alt="" class="wp-image-16008" srcset="https://blog.xojo.com/wp-content/uploads/2026/03/datamatrix-barcode-1-471x1024.png 471w, https://blog.xojo.com/wp-content/uploads/2026/03/datamatrix-barcode-1-138x300.png 138w, https://blog.xojo.com/wp-content/uploads/2026/03/datamatrix-barcode-1.png 555w" sizes="auto, (max-width: 471px) 100vw, 471px" /></figure>
</div>
</div>



<h2 class="wp-block-heading">Icons on WebButtons</h2>



<p><code>WebButton</code>&nbsp;now has an&nbsp;<code>Icon</code>&nbsp;property. You can assign any&nbsp;<code>WebPicture</code>&nbsp;to it, or use one of the Bootstrap icons that are already bundled with the framework. It&#8217;s a small addition, but it makes a noticeable difference when building action-heavy interfaces where a label alone doesn&#8217;t communicate enough at a glance.</p>



<p>Add a button into your project:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="690" src="https://blog.xojo.com/wp-content/uploads/2026/03/button-icon-ide-2-1024x690.png" alt="" class="wp-image-16001" srcset="https://blog.xojo.com/wp-content/uploads/2026/03/button-icon-ide-2-1024x690.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/03/button-icon-ide-2-300x202.png 300w, https://blog.xojo.com/wp-content/uploads/2026/03/button-icon-ide-2-768x517.png 768w, https://blog.xojo.com/wp-content/uploads/2026/03/button-icon-ide-2-1536x1035.png 1536w, https://blog.xojo.com/wp-content/uploads/2026/03/button-icon-ide-2-2048x1380.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Configure its Icon property in the <code>Opening</code> event:</p>



<pre class="wp-block-code"><code>Me.Icon = WebPicture.BootstrapIcon("key-fill")</code></pre>



<p>If you don&#8217;t specify a color in BootstrapIcon, it will inherit the button caption color in this case. This is the easiest way to support Dark Mode with the new <code>WebButton.Icon</code> property, without doing any special tricks.</p>



<p>Here is how it looks like at runtime:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="889" src="https://blog.xojo.com/wp-content/uploads/2026/03/button-browser-light-1024x889.png" alt="" class="wp-image-15999" srcset="https://blog.xojo.com/wp-content/uploads/2026/03/button-browser-light-1024x889.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/03/button-browser-light-300x261.png 300w, https://blog.xojo.com/wp-content/uploads/2026/03/button-browser-light-768x667.png 768w, https://blog.xojo.com/wp-content/uploads/2026/03/button-browser-light-1536x1334.png 1536w, https://blog.xojo.com/wp-content/uploads/2026/03/button-browser-light.png 1612w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Dark Mode:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="889" src="https://blog.xojo.com/wp-content/uploads/2026/03/button-browser-dark-1024x889.png" alt="" class="wp-image-16000" srcset="https://blog.xojo.com/wp-content/uploads/2026/03/button-browser-dark-1024x889.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/03/button-browser-dark-300x261.png 300w, https://blog.xojo.com/wp-content/uploads/2026/03/button-browser-dark-768x667.png 768w, https://blog.xojo.com/wp-content/uploads/2026/03/button-browser-dark-1536x1334.png 1536w, https://blog.xojo.com/wp-content/uploads/2026/03/button-browser-dark.png 1612w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h2 class="wp-block-heading">WebLabel: Semantic HTML and Proper Element Types</h2>



<p>Two related changes landed for&nbsp;<code>WebLabel</code>&nbsp;in this release. The first is a correctness fix: the control was previously rendered using the HTML&nbsp;<code>&lt;label&gt;</code>&nbsp;element, which is semantically meant to label form inputs, not to display general text. That has been corrected.</p>



<p>The more interesting addition is that you can now choose which HTML element&nbsp;<code>WebLabel</code>&nbsp;renders as. If you want a label to be an&nbsp;<code>&lt;h1&gt;</code>&nbsp;or an&nbsp;<code>&lt;h2&gt;</code>, you can set that directly in the Inspector. This is useful not just for visual styling, but for accessibility tools and search engines that rely on page structure to understand content hierarchy.</p>



<p>Improving both, accessibility and making search engines happier, are some of our goals for 2026. You will continue seeing improvements in this sense.</p>



<h2 class="wp-block-heading">WebTextArea Gets AddText</h2>



<p><code>WebTextArea</code>&nbsp;now has an&nbsp;<code>AddText</code>&nbsp;method, consistent with how the control works on Desktop and Mobile. If you&#8217;re writing code that targets multiple platforms, this kind of parity saves you from having to check which target you&#8217;re on, before appending text.</p>



<h2 class="wp-block-heading">Scale Indicator on WebMapViewer</h2>



<p><code>WebMapViewer</code>&nbsp;now has a&nbsp;<code>HasScaleIndicator</code>&nbsp;property. When enabled, a small visual scale appears on the map showing real-world distance. It makes a difference in apps where users need spatial context. Field work, logistics or anything where &#8220;how far is that?&#8221; is a question users might actually ask.</p>



<h2 class="wp-block-heading">Performance and Modernization Under the Hood</h2>



<p>A few changes in this release won&#8217;t be immediately visible, but they improve things for everyone.</p>



<p>Bootstrap has been updated to v5.3.8 which fixes some issues introduced in v5.3.7 impacting Xojo. The TypeScript compiler has been updated to v5.9.3, and the compilation target has been bumped from ES6 to ES2020. Unused code in the Web Framework has been cleaned up to reduce the compiled bundle size.</p>



<p>Xojo has also removed its own internal usage of Modernizr. The library is still present for now so existing apps that rely on it won&#8217;t break, but it&#8217;s no longer used by the framework itself and will be removed in a future release.</p>



<p>If you&#8217;ve been meaning to audit your web app for performance, this is a good moment to look at&nbsp;<code>SendEventsInBatches</code>&nbsp;and&nbsp;<code>LazyLoadDependencies</code>&nbsp;on&nbsp;<code>WebSession</code>&nbsp;as well. Both now default to&nbsp;<code>True</code>&nbsp;on new projects, so if your existing app has them disabled, it&#8217;s worth trying them out. These properties have been around for a while already but were turned off by default.</p>



<h2 class="wp-block-heading">API Consistency Cleanups</h2>



<p>A few methods have been deprecated in favour of names that are consistent with the rest of the framework:</p>



<ul class="wp-block-list">
<li><code>WebApplication.AutoQuit</code>&nbsp;→&nbsp;<code>AllowAutoQuit</code></li>



<li><code>WebListBox.ReloadData</code>&nbsp;→&nbsp;<code>ReloadFromDataSource</code></li>



<li><code>WebRadioGroup.RemoveAllRows</code>&nbsp;→&nbsp;<code>RemoveAll</code>, and&nbsp;<code>RemoveRowAt</code>&nbsp;→&nbsp;<code>RemoveAt</code></li>
</ul>



<p>Your existing code will still compile, but it&#8217;s worth updating these when you get a chance.</p>



<h2 class="wp-block-heading">Wrapping Up</h2>



<p>Between new controls, better HTML semantics, and a leaner runtime, 2026r1 is a worthwhile update for anyone building web apps with Xojo. Check out the&nbsp;<a href="https://documentation.xojo.com/resources/release_notes/2026r1.html">full release notes</a>&nbsp;for the complete list of changes.</p>



<p><em>Ricardo has always been curious about how things work. Growing up surrounded by computers</em> he became interested in <em>web technologies in the dial-up connections era. Xojo has been his secret weapon and language of preference since 2018. When he’s not online, chances are he will be scuba diving … or crocheting amigurumis. Find Ricardo on Twitter <a href="https://web.archive.org/web/20220805000833/https://www.twitter.com/piradoiv" target="_blank" rel="noreferrer noopener">@piradoiv</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		<enclosure url="https://blog.xojo.com/wp-content/uploads/2026/03/colorpicker-browser.mp4" length="707463" type="video/mp4" />

			</item>
		<item>
		<title>How To Share Your Local Xojo Web App to the Internet Using ngrok</title>
		<link>https://blog.xojo.com/2025/08/07/how-to-share-your-local-xojo-web-app-to-the-internet-using-ngrok/</link>
		
		<dc:creator><![CDATA[Gabriel Ludosanu]]></dc:creator>
		<pubDate>Thu, 07 Aug 2025 14:52:22 +0000</pubDate>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Networking]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Developer Tools]]></category>
		<category><![CDATA[Remote Testing]]></category>
		<category><![CDATA[Web App Testing]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[Webhook Development]]></category>
		<category><![CDATA[Xojo Web]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=15075</guid>

					<description><![CDATA[Have you ever built an amazing Xojo web application locally on your machine and wished you could instantly share it with a client, test it&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Have you ever built an amazing Xojo web application locally on your machine and wished you could instantly share it with a client, test it on a real mobile device outside your local network, or integrate it with a webhook service like Stripe or Twilio? If so, you know the pain of needing a publicly accessible URL for your locally running app.</p>



<p>This is where&nbsp;ngrok&nbsp;comes in: a fantastic tool that creates secure tunnels to your localhost, making your locally running Xojo web app accessible from anywhere in the world. It&#8217;s a game-changer for testing, demonstrations, and rapid development.</p>



<h2 class="wp-block-heading">What is ngrok and Why Xojo Developers Need It?</h2>



<p>At its core, ngrok is a command-line tool that creates a secure, public URL for a service running on your local machine. Think of it as a temporary bridge from the internet directly to your computer, bypassing firewalls and NAT configurations.</p>



<p>For Xojo Web developers, this offers a wealth of benefits:</p>



<ul class="wp-block-list">
<li><strong>Real-device Testing:</strong>&nbsp;Test your Xojo web app&#8217;s responsiveness and functionality on actual mobile phones, tablets, or other computers, even if they&#8217;re not on your local Wi-Fi network.</li>



<li><strong>Instant Demonstrations:</strong>&nbsp;Share your work-in-progress with clients, colleagues, or friends without the need of deploying to a remote server. They just need the ngrok-provided URL!</li>



<li><strong>Webhook Development:</strong>&nbsp;Many third-party services (payment gateways, messaging platforms, etc.) use webhooks to notify your application of events. These webhooks require a public URL to send data to. ngrok provides this, making local webhook development a breeze.</li>



<li><strong>Debugging Public-Facing Issues:</strong>&nbsp;Sometimes, an issue only appears when your app is publicly accessible. ngrok allows you to debug such scenarios without a full deployment cycle.</li>
</ul>



<p>It&#8217;s truly a must-have tool in your Xojo Web development toolkit!</p>



<h2 class="wp-block-heading">Getting Started with ngrok</h2>



<p>Before we connect our Xojo app, we need to get ngrok set up.</p>



<h3 class="wp-block-heading">Step 1: Download ngrok</h3>



<p>Head over to the official ngrok website:&nbsp;<a href="https://ngrok.com/download" target="_blank" rel="noreferrer noopener">https://ngrok.com/download</a>.</p>



<p>Download the version appropriate for your operating system (Windows, macOS, Linux).</p>



<h3 class="wp-block-heading">Step 2: Unzip and Place</h3>



<p>Once downloaded, you&#8217;ll get a single executable file (e.g.,&nbsp;<code>ngrok.exe</code>&nbsp;on Windows,&nbsp;<code>ngrok</code>&nbsp;on macOS/Linux). Unzip it and place it in a convenient location. I recommend creating a dedicated folder for it, or placing it somewhere easily accessible from your terminal or command prompt.</p>



<h2 class="wp-block-heading">Preparing Your Xojo Web App</h2>



<p>Xojo Web applications are self-contained web servers. When you run a Xojo Web app in debug mode or build it for deployment, it listens for incoming connections on a specific port. By default, Xojo Web apps usually listen on&nbsp;port 8080.</p>



<p>Let&#8217;s quickly ensure your Xojo Web app is ready:</p>



<ol class="wp-block-list">
<li><strong>Open your Xojo Web Project:</strong>&nbsp;Open any existing Xojo Web project, or create a new one for testing.</li>



<li><strong>Run in Debug Mode:</strong>&nbsp;Click the &#8220;Run&#8221; button in the Xojo IDE. Your web app will launch in your default browser, at&nbsp;<code>http://localhost:8080</code>.</li>
</ol>



<h2 class="wp-block-heading">Tunneling Your Xojo App with ngrok</h2>



<p>Now for the magic! With your Xojo Web app running locally, we&#8217;ll open a tunnel to it using ngrok.</p>



<h3 class="wp-block-heading">Step 1: Open Terminal/Command Prompt</h3>



<p>Open your system&#8217;s terminal (macOS/Linux) or Command Prompt/PowerShell (Windows).</p>



<h3 class="wp-block-heading">Step 2: Navigate to ngrok Directory (if needed)</h3>



<p>If you didn&#8217;t place the&nbsp;<code>ngrok</code>&nbsp;executable in a system PATH location, navigate to the directory where you unzipped&nbsp;<code>ngrok</code>&nbsp;using the&nbsp;<code>cd</code>&nbsp;command. For example:</p>



<pre class="wp-block-code"><code>cd /path/to/your/ngrok/folder</code></pre>



<h3 class="wp-block-heading">Step 3: Run the ngrok Command</h3>



<p>Now, execute the&nbsp;<code>ngrok</code>&nbsp;command to create the tunnel. Since Xojo Web apps typically run on port 8080, the command will be:</p>



<pre class="wp-block-code"><code>ngrok http 8080</code></pre>



<ul class="wp-block-list">
<li><code>http</code>: Specifies that we&#8217;re tunneling an HTTP service.</li>



<li><code>8080</code>: This is the port your Xojo Web app is listening on. If you&#8217;ve configured your Xojo app to use a different port (e.g., in the Build Settings), make sure to use that port number instead.</li>
</ul>



<p>After running the command, ngrok will output information about the tunnel it has created. You&#8217;ll see output similar to this:</p>



<pre class="wp-block-code"><code>ngrok                                                                            (Ctrl+C to quit)

Session Status                online
Account                       Account Name (Free)
Version                       3.x.x
Region                        United States (us)
Forwarding                    https://a52b-20-40-100-120.ngrok-free.app -&gt; http://localhost:8080

Connections                   ttl     opn     rt1     rt5     p50     p90
                              0       0       0.00    0.00    0.00    0.00
</code></pre>



<p>The most important lines here are the&nbsp;<code>Forwarding</code>&nbsp;lines. These provide you with the public URLs that point to your Xojo web app.</p>



<h2 class="wp-block-heading">Testing Your Public Xojo App</h2>



<p>With the ngrok tunnel active, your Xojo web app is now live to the world!</p>



<ol class="wp-block-list">
<li><strong>Copy the HTTPS URL:</strong>&nbsp;Copy the&nbsp;<code>https://</code>&nbsp;URL provided by ngrok.</li>



<li><strong>Test It:</strong>
<ul class="wp-block-list">
<li>Paste this URL into any web browser, on any device, anywhere with an internet connection.</li>



<li>Send the URL to a friend or client to get their feedback.</li>



<li>Test it on your mobile phone&#8217;s browser using its cellular data connection (not your local Wi-Fi) to simulate a truly external connection.</li>
</ul>
</li>
</ol>



<p>You&#8217;ll see your Xojo web app load as if it were hosted on a remote server!</p>



<p>To stop the ngrok tunnel, press Ctrl+C in the console.</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p>ngrok can be an indispensable tool for any Xojo Web developer. It transforms the challenging task of exposing a local web app into a simple, one-line command. Whether you&#8217;re testing on diverse devices, showcasing your progress to clients, or integrating with external webhook services, ngrok streamlines your workflow and lets you focus on what you do best: building amazing applications with Xojo.</p>



<p>Give ngrok a try on your next Xojo Web project, and prepare to be amazed by the convenience it offers!</p>



<p>What if we create a Build Step script to automatically run ngrok when needed? Share your experiences and tips in the <a href="https://forum.xojo.com/" target="_blank" rel="noreferrer noopener">Xojo forums</a>!</p>



<p><em>Gabriel is a digital marketing enthusiast who loves coding with Xojo to create cool software tools for any platform. He is always eager to learn and share new ideas!</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Deploy Xojo Web Apps with Caddy Reverse Proxy</title>
		<link>https://blog.xojo.com/2025/08/04/deploy-xojo-web-apps-with-caddy-reverse-proxy/</link>
		
		<dc:creator><![CDATA[Gabriel Ludosanu]]></dc:creator>
		<pubDate>Mon, 04 Aug 2025 18:45:28 +0000</pubDate>
				<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Deployment]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[Xojo Web]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=15201</guid>

					<description><![CDATA[Deploying Xojo web applications offers developers flexible pathways to production. For devs prioritizing minimal infrastructure management,&#160;Xojo Cloud&#160;provides a fully-managed solution with automatic scaling, SSL, and&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Deploying Xojo web applications offers developers flexible pathways to production. For devs prioritizing minimal infrastructure management,&nbsp;<a href="https://www.xojo.com/cloud/" target="_blank" rel="noreferrer noopener">Xojo Cloud</a>&nbsp;provides a fully-managed solution with automatic scaling, SSL, and zero-server-maintenance. However, for developers requiring granular control over their deployment environment, implementing a reverse proxy like <a href="https://caddyserver.com/" data-type="link" data-id="https://caddyserver.com/" target="_blank" rel="noreferrer noopener">Caddy</a> delivers enterprise-grade performance while simplifying critical operations.</p>



<p>This guide focuses on production-ready Caddy configurations that streamline deployments for self-managed Xojo applications, delivering:</p>



<ul class="wp-block-list">
<li>Automated TLS certificate management</li>



<li>Native load balancing between instances</li>



<li>Simplified configuration compared to traditional proxies</li>



<li>Header optimizations specifically tuned for Xojo’s framework</li>
</ul>



<p>You’ll learn configuration strategies that <em>in some benchmarks, can have resource savings as high as 40%</em> over conventional proxies while maintaining Xojo’s signature performance characteristics.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Core Configuration Strategies</h3>



<p><strong>Basic Reverse Proxy Setup</strong></p>



<pre class="wp-block-code"><code>yourdomain.com {
    # Connect to Xojo application
    reverse_proxy localhost:8080 {
        # Preserve client information
        header_up X-Forwarded-For {http.request.remote.host}
        header_up Host {http.request.host}
    }
    
    # Automate HTTPS
    tls admin@yourdomain.com
}</code></pre>



<p><em>Note: The&nbsp;<code>header_up</code>&nbsp;directives ensure Xojo correctly logs client IPs in web events</em></p>



<p><strong>Load Balancing Across Instances</strong></p>



<pre class="wp-block-code"><code>app.yourdomain.com {
    reverse_proxy localhost:8080 localhost:8081 localhost:8082 {
        load_balancer {
            policy round_robin
            health_interval 10s
            health_uri /health
        }
        # Timeouts for heavy processing
        lb_try_duration 30s
    }
}</code></pre>



<p><strong>Security Hardening Measures</strong></p>



<pre class="wp-block-code"><code>yourdomain.com { 
	# Critical protection headers 
	header { 
		X-Content-Type-Options "nosniff" 
		X-Frame-Options "DENY" 
		Content-Security-Policy "default-src 'self'" 
	} 

	# Rate limiting for API endpoints 
	route /api/* { 
		rate_limit { 
			zone api 
			burst 100 
			period 10s 
		} 
	} 
}</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Production-Ready Deployment Scripts</h3>



<p><strong>Linux Systemd Service</strong><br><code>/etc/systemd/system/xojo-caddy.service</code>:</p>



<pre class="wp-block-code"><code>&#91;Unit]
Description=Xojo Caddy Reverse Proxy
After=network.target

&#91;Service]
Type=simple
User=caddy
ExecStart=/usr/bin/caddy run --config /etc/caddy/Caddyfile
Restart=on-failure
RestartSec=5

&#91;Install]
WantedBy=multi-user.target</code></pre>



<p>For a broader, step-by-step guide on preparing your server, please see our foundational tutorial:&nbsp;<a href="https://blog.xojo.com/2021/05/28/tutorial-deploying-web-apps-on-linux/" target="_blank" rel="noreferrer noopener">Tutorial: Deploying Web Apps on Linux</a>. The&nbsp;<code>systemd</code>&nbsp;service above integrates perfectly into that workflow.</p>



<p><strong>Windows Deployment Package</strong><br><code>Xojo-Caddy.bat</code>:</p>



<pre class="wp-block-code"><code>@echo off
REM Start Xojo application instances
start "Xojo Instance 1" /MIN XojoWebApp.exe --port=8080
start "Xojo Instance 2" /MIN XojoWebApp.exe --port=8081

REM Launch Caddy reverse proxy
start "Caddy Proxy" /MIN caddy.exe run --config C:\caddy\Caddyfile</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p><strong>Optimized Xojo-Caddy Template</strong><br>Save as&nbsp;<code>Caddyfile</code>&nbsp;in your deployment root:</p>



<pre class="wp-block-code"><code># Production-Grade Xojo Proxy Template
yourdomain.com, www.yourdomain.com {
    # Automated HTTPS
    tls contact@yourdomain.com
    
    # Primary app routing
    reverse_proxy localhost:8080 localhost:8081 {
        header_up X-Forwarded-Proto https
        header_up X-Real-IP {http.request.remote}
    }
    
    # Static content handling
    handle /static/* {
        root * /var/www/static
        file_server
    }
    
    # Security headers
    header {
        Strict-Transport-Security "max-age=31536000"
        Referrer-Policy "strict-origin-when-cross-origin"
    }
}</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Conclusion</h3>



<p>Caddy eliminates proxy complexity while delivering enterprise capabilities:</p>



<ol class="wp-block-list">
<li><strong>Simplified Operations</strong>: Single configuration file replaces complex proxy setups</li>



<li><strong>Automatic Security</strong>: Continuous HTTPS protection without maintenance</li>



<li><strong>Effortless Scaling</strong>: Built-in load balancing grows with your user base</li>



<li><strong>Reduced Overhead</strong>: 40% fewer resources than traditional proxies in benchmarks</li>
</ol>



<p>Implement the provided Xojo-Caddy template to achieve production-grade deployment in under 15 minutes. Monitor performance via Caddy’s built-in&nbsp;<code>/metrics</code>&nbsp;endpoint and scale horizontally as traffic increases.</p>



<p><em>Gabriel is a digital marketing enthusiast who loves coding with Xojo to create cool software tools for any platform. He is always eager to learn and share new ideas!</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
