<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Love Otudor</title>
    <description>The latest articles on DEV Community by Love Otudor (@loveotudor).</description>
    <link>https://dev.to/loveotudor</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2892962%2F35aad0e7-7f68-4d57-aab9-314834591403.jpg</url>
      <title>DEV Community: Love Otudor</title>
      <link>https://dev.to/loveotudor</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/loveotudor"/>
    <language>en</language>
    <item>
      <title>Build with AI in the Anvil Editor</title>
      <dc:creator>Love Otudor</dc:creator>
      <pubDate>Wed, 01 Jul 2026 15:19:19 +0000</pubDate>
      <link>https://dev.to/anvil/build-with-ai-in-the-anvil-editor-im3</link>
      <guid>https://dev.to/anvil/build-with-ai-in-the-anvil-editor-im3</guid>
      <description>&lt;p&gt;Anvil's AI integration is here! You can now connect to and chat with your favourite AI agent directly from the Anvil Editor.&lt;/p&gt;

&lt;p&gt;Whether you're starting a new project or improving an existing one, AI agents in Anvil understand how Anvil apps are built. That means less time explaining your framework to an AI and more time building. You can ask it to build an entire app from a prompt, or bring it in as a coding assistant to fix bugs, implement features, or explain unfamiliar code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz3tnldaibci3t5t26cqy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz3tnldaibci3t5t26cqy.gif" alt="Building an app with the AI agent in the Anvil Editor" width="720" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Read on to find out more, or start building now.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build?utm_source=crosspost:dev.to:/blog/ai-in-anvil"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff5hbzvtv9lo0nqbpwhmu.png" alt="Start building" width="306" height="84"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Connect to your preferred Agent with no Upcharge
&lt;/h2&gt;

&lt;p&gt;Connect your existing ChatGPT or Claude account from the Anvil Editor and start chatting straight away. Anvil doesn't add any extra charges, so you only pay for your provider as normal, whether you're on a free or paid plan.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn5lu6mcqk5fhfq2qvfua.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn5lu6mcqk5fhfq2qvfua.png" alt="Connect to your model provider" width="800" height="526"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With &lt;a href="https://anvil.works/enterprise?utm_source=crosspost:dev.to:/blog/ai-in-anvil"&gt;Anvil Enterprise&lt;/a&gt;, you can connect your own enterprise model provider and private endpoints instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generate Apps from a Prompt
&lt;/h2&gt;

&lt;p&gt;Describe the app you want to build using plain text, recorded audio, or images, and the agent will build it for you. It can create Forms, layouts, server code, modules, Data Tables, and any other Anvil services your app needs, all in one go. Because the agent understands how Anvil apps are structured, it generates apps that feel familiar, using Python and tools you already know.&lt;/p&gt;

&lt;p&gt;Need a particular look and feel? Instead of describing layouts, spacing, and colours in words, you can attach images to your prompt to guide the design of your app. The agent uses those images to create interfaces that are closer to what you have in mind from the start.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8628rf9zmj33sfilca3b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8628rf9zmj33sfilca3b.png" alt="Prompt with reference images and generated design" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tweak the Results
&lt;/h2&gt;

&lt;p&gt;The agent writes real, editable code, and every change it makes can be modified or reverted in the Anvil Editor. You can still drag and drop components into the generated UI in the designer like you always have, or edit the properties of the generated UI elements in the Properties panel. The same goes for your Forms, modules, Data Tables, and everything else the agent creates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwcvfbht0wfm5sfsxo024.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwcvfbht0wfm5sfsxo024.gif" alt="Edit generated design in the drag and drop designer" width="600" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also ask the agent to make changes to the code from chat. You can even mention specific Forms, modules, layouts, or assets in the chat, so the agent knows exactly what you're referring to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use the Agent on your existing Apps
&lt;/h2&gt;

&lt;p&gt;The agent works just as well on existing apps. Ask it to implement new features, fix bugs, suggest improvements, or explain unfamiliar code. You can also use agent commands like &lt;code&gt;/review-commit&lt;/code&gt; to review code changes in a particular commit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flgztyhjkl28zjlj1n6yu.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flgztyhjkl28zjlj1n6yu.gif" alt="Review a commit in an existing app" width="720" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because the agent reads and understands your existing Anvil code, its changes and suggestions fit naturally into your app's architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get started
&lt;/h2&gt;

&lt;p&gt;Open an app in the Anvil Editor, click the  &lt;strong&gt;✧&lt;/strong&gt;  icon in the sidebar, connect your AI provider, and start chatting.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzuo6uh4kih9svijmcl5s.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzuo6uh4kih9svijmcl5s.gif" alt="Create an app and start prompting" width="800" height="526"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For tips on getting the best results, check out our &lt;a href="https://anvil.works/docs/ai?utm_source=crosspost:dev.to:/blog/ai-in-anvil"&gt;docs&lt;/a&gt; and &lt;a href="https://anvil.works/docs/how-to/prompting-best-practices?utm_source=crosspost:dev.to:/blog/ai-in-anvil"&gt;prompting best practices&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Looking forward to what you build!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build?utm_source=crosspost:dev.to:/blog/ai-in-anvil"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff5hbzvtv9lo0nqbpwhmu.png" alt="Start building" width="306" height="84"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  More about Anvil
&lt;/h2&gt;

&lt;p&gt;If you're new here, welcome! &lt;a href="https://anvil.works?utm_source=crosspost:dev.to:/blog/ai-in-anvil"&gt;Anvil&lt;/a&gt; is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks – just &lt;strong&gt;build it all in Python&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build?utm_source=crosspost:dev.to:/blog/ai-in-anvil"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftlwt9hvvr64hnd8sx5xo.png" alt="https://anvil.works/build?utm_source=crosspost:dev.to:/blog/ai-in-anvil" width="381" height="85"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>python</category>
      <category>agents</category>
    </item>
    <item>
      <title>Build a Web App with MongoDB Using Just Python</title>
      <dc:creator>Love Otudor</dc:creator>
      <pubDate>Tue, 13 Jan 2026 16:37:03 +0000</pubDate>
      <link>https://dev.to/anvil/build-a-web-app-with-mongodb-using-just-python-321a</link>
      <guid>https://dev.to/anvil/build-a-web-app-with-mongodb-using-just-python-321a</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Build and deploy a full-stack web app that interacts with your external database using only Python. No HTML, CSS, or JavaScript required.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/OX5L_8hH7xM"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In this tutorial, we guide you step-by-step on how to create a &lt;strong&gt;Customer Relationship Management (CRM) system&lt;/strong&gt; connected to a &lt;strong&gt;MongoDB Atlas cluster&lt;/strong&gt;, starting completely from scratch. You'll see how to build both the frontend and backend in Python using Anvil and deploy it to the web with &lt;strong&gt;two clicks&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build#clone:UJ3PW3CWLBQVGO6Q%3d3WYYRMWKPSTUZJV2NSW7ACBK?utm_source=crosspost:dev.to:/blog/crm-with-mongodb"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpkvbvqp0y0tdl5jyjcic.png" alt="Open in Anvil" width="461" height="140"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/?utm_source=crosspost:dev.to:/blog/crm-with-mongodb"&gt;&lt;strong&gt;Anvil&lt;/strong&gt;&lt;/a&gt; lets you build full-stack web apps with all the power of Python and the flexibility of code.&lt;/p&gt;

&lt;p&gt;In this tutorial, we will cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Installing Python packages in your Server Module&lt;/li&gt;
&lt;li&gt;Securing passwords with App Secrets&lt;/li&gt;
&lt;li&gt;Communicating between Forms with custom events&lt;/li&gt;
&lt;li&gt;Authentication with the Users Service&lt;/li&gt;
&lt;li&gt;Deploying your app on Anvil's free hosting&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  More about Anvil
&lt;/h2&gt;

&lt;p&gt;If you're new here, welcome! &lt;a href="https://anvil.works/?utm_source=crosspost:dev.to:/blog/crm-with-mongodb"&gt;Anvil&lt;/a&gt; is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks – just &lt;strong&gt;build it all in Python&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build?utm_source=crosspost:dev.to:/blog/crm-with-mongodb"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz95af95e963brxl2o9zt.png" alt="Sign up for Anvil" width="800" height="191"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>anvil</category>
      <category>webdev</category>
      <category>mongodb</category>
    </item>
    <item>
      <title>Case Study: How Chris Houston Built a BI Tool with Anvil</title>
      <dc:creator>Love Otudor</dc:creator>
      <pubDate>Fri, 11 Jul 2025 14:45:28 +0000</pubDate>
      <link>https://dev.to/anvil/case-study-how-chris-houston-built-a-bi-tool-with-anvil-4l7n</link>
      <guid>https://dev.to/anvil/case-study-how-chris-houston-built-a-bi-tool-with-anvil-4l7n</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Query Streams transforms Excel and Google Sheets into powerful BI tools by enabling real-time database queries directly within the spreadsheet—no coding required. Built as a nights-and-weekends side project by Chris using Anvil, Query Streams soft launched just four weeks ago and is already being used by data analysts across multiple companies.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Built by a solo developer&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Production-ready in under 5 months&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Google Sheets add-on is live&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Microsoft Excel add-in is live&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Challenge: When BI Tools Meet Reality
&lt;/h2&gt;

&lt;p&gt;Every data team knows the cycle: Companies invest heavily in BI tools because everyone loves beautiful dashboards. Yet somehow, the most common follow-up question is still:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"The dashboards look great… uh, how do I export this to a spreadsheet?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And then it all ends up in a spreadsheet anyway. Despite years of trying to move away from Excel and Google Sheets, spreadsheets are more popular than ever. According to a 2025 survey by &lt;a href="https://www.alteryx.com/about-us/newsroom/press-release/new-research-reveals-that-ai-brings-productivity-gains-but-reliance-on-spreadsheets-puts-data-quality-at-risk" rel="noopener noreferrer"&gt;Alteryx&lt;/a&gt;, &lt;strong&gt;76% of data analysts still use spreadsheets as their primary tool&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What If We Stopped Fighting Spreadsheets?
&lt;/h3&gt;

&lt;p&gt;Chris had been thinking about this for years. What if, instead of replacing spreadsheets, we empowered them?&lt;br&gt;
&lt;em&gt;“What if we didn’t try to replace spreadsheets with BI tools? What if we made spreadsheets the BI tool?”&lt;/em&gt;&lt;br&gt;
This idea stuck with him until just after Thanksgiving 2024, when he started building a solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: Turn Spreadsheets Into the BI Tool
&lt;/h2&gt;

&lt;p&gt;Query Streams is a real-time data integration platform that lets users run SQL queries from Google Sheets and Excel directly against remote databases, without exposing credentials, setting up VPNs, or configuring firewalls. It supports SQL Server, MySQL, PostgreSQL, SQLite, Access, and other databases. You can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Share and receive queries&lt;/li&gt;
&lt;li&gt;Build live dashboards&lt;/li&gt;
&lt;li&gt;Securely expose specific database queries&lt;/li&gt;
&lt;li&gt;Choose what data to share and with whom&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqxj7yb3ru10rddalwv9f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqxj7yb3ru10rddalwv9f.png" alt="Query Streams Image" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No hassle. No copy-pasting. No manual exports. Just real-time data, right where analysts already work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Query Streams: Smarter Tools, Built Faster with Anvil
&lt;/h2&gt;

&lt;p&gt;The most challenging part of building Query Streams was building the network agent in C# and other technologies that Chris wasn’t familiar with. Once he overcame that technical hurdle, building the web app in Anvil was straightforward.&lt;/p&gt;

&lt;p&gt;With minimal experience in HTML, CSS, and JavaScript, Chris leaned heavily on &lt;a href="https://anvil.works/docs/ui/custom-components/html-components?utm_source=crosspost:dev.to:/case-studies/querystreams"&gt;Anvil’s custom HTML support &lt;/a&gt; and Anvil components to bring his unique UI ideas to life.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I thought we were locked into the Anvil components on the designer. But as I explored custom components in Anvil, I realised that, wow, you can build anything in Anvil.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/chris_houston_7d34a375ece"&gt;&lt;strong&gt;Chris Houston&lt;/strong&gt;&lt;/a&gt; — &lt;em&gt;Founder and CEO, Query Streams&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In just four months, Query Streams was ready to use. Built entirely in Chris's spare time while working a full-time job. Since Anvil is web-based, he could work on Query Streams wherever and whenever he had time—whether at home, in early mornings, or even while travelling with just his laptop.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Results: From Idea to Impact
&lt;/h2&gt;

&lt;p&gt;Query Streams has begun gaining traction even before its official launch. In the four weeks since its soft launch with the Google Sheets add-on, teams and analysts across several organisations have started using the platform.&lt;/p&gt;

&lt;p&gt;Now, with the Excel add-in also live on the Microsoft AppSource marketplace, Query Streams has expanded its reach to both major spreadsheet platforms. With both add-ons available, Chris is preparing for the official launch and broader publicity efforts. You can follow along and get updates on &lt;a href="https://x.com/querystreams" rel="noopener noreferrer"&gt;X&lt;/a&gt; and &lt;a href="https://www.linkedin.com/company/querystreams/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Anvil is like a Swiss army knife of awesome! It allowed me to build Query Streams with a lot of ease while working alone.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/chris_houston_7d34a375ece"&gt;&lt;strong&gt;Chris Houston&lt;/strong&gt;&lt;/a&gt; — &lt;em&gt;Founder and CEO, Query Streams&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fngnel9z8255z7xkbw135.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fngnel9z8255z7xkbw135.png" alt=" " width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  More Information
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Query Streams&lt;/strong&gt; lets you run real-time database queries directly from Excel or Google Sheets — no code required.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.querystreams.com/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fle7jxf944svyjd9kxnba.png" alt=" " width="608" height="140"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you’re new to &lt;strong&gt;Anvil&lt;/strong&gt; and want to see how you can build powerful web apps using just Python, up to 7× faster than traditional development:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works?utm_source=crosspost:dev.to:/case-studies/querystreams"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flywzy5mdmou1v27k104o.png" alt=" " width="608" height="140"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Have questions or want to get in touch? Visit &lt;a href="https://anvil.works/contact?utm_source=crosspost:dev.to:/case-studies/querystreams"&gt;anvil.works/contact&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>businessintelligence</category>
      <category>webdev</category>
      <category>python</category>
      <category>startup</category>
    </item>
    <item>
      <title>Secure Team Collaboration in Anvil</title>
      <dc:creator>Love Otudor</dc:creator>
      <pubDate>Fri, 30 May 2025 14:48:49 +0000</pubDate>
      <link>https://dev.to/anvil/secure-team-collaboration-in-anvil-3680</link>
      <guid>https://dev.to/anvil/secure-team-collaboration-in-anvil-3680</guid>
      <description>&lt;p&gt;You asked and we answered! We put together a practical how-to guide on collaborating as a team in Anvil. Building amazing Anvil apps is even better with your team by your side, and we've developed foolproof methods to make this process hassle-free.&lt;/p&gt;

&lt;p&gt;This guide walks you through how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set up secure, real-world workflows for collaborating on Anvil apps while keeping your production environment isolated and safe.&lt;/li&gt;
&lt;li&gt;Separate development and production environments to ensure only well-tested and reviewed changes reach your users.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whether your team prefers working together on a shared Anvil app or on individual ones, this step-by-step guide will help you implement Git-based workflows that improve code quality and team efficiency.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/docs/how-to/collaborate-in-anvil?utm_source=crosspost:devto:/blog/secure-team-collaboration" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwrc91ohsy7sslyw2vqwz.png" alt="Check out the full guide here" width="379" height="86"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  More about&amp;nbsp;Anvil
&lt;/h2&gt;

&lt;p&gt;If you're new here, welcome! &lt;a href="https://anvil.works?utm_source=crosspost:devto:/blog/secure-team-collaboration" rel="noopener noreferrer"&gt;Anvil&lt;/a&gt; is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks - just build it all in Python.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build?utm_source=crosspost:devto:/blog/secure-team-collaboration" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsw66qxlkopgppg50i2i7.png" alt="Sign up for Anvil" width="800" height="191"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>anvil</category>
      <category>webdev</category>
      <category>git</category>
    </item>
    <item>
      <title>Building a Game App with Just Python</title>
      <dc:creator>Love Otudor</dc:creator>
      <pubDate>Wed, 16 Apr 2025 16:51:04 +0000</pubDate>
      <link>https://dev.to/anvil/building-a-game-app-with-just-python-4fbm</link>
      <guid>https://dev.to/anvil/building-a-game-app-with-just-python-4fbm</guid>
      <description>&lt;p&gt;"&lt;strong&gt;Guess the Sketch&lt;/strong&gt;" is a multiplayer game where you draw sketches and challenge friends to guess what they are. Players earn points for correct guesses, with fewer attempts leading to higher scores. Each round, one player is chosen to sketch, while the others try to guess as quickly as possible.&lt;/p&gt;

&lt;p&gt;I built this game using Python and Anvil, and it was surprisingly easy! I didn’t need to write HTML, CSS, or JavaScript. In this post, I will walk you through the key parts of building Guess the Sketch:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
Building the UI,&lt;/li&gt;
&lt;li&gt;
Saving and sending sketches,&lt;/li&gt;
&lt;li&gt;
Sending invites,&lt;/li&gt;
&lt;li&gt;
Managing players and scores, and&lt;/li&gt;
&lt;li&gt;
Publishing and sharing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's get started!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd4m8wl12p5mv20ylnzts.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd4m8wl12p5mv20ylnzts.gif" alt="Game Demo" width="1114" height="868"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build#clone:LBYMHJ3D5VHWUS3G=V2TWD2XDO3Z6MHCCXTEPXQVF" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpkvbvqp0y0tdl5jyjcic.png" alt="Open in Anvil" width="461" height="140"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Building the UI
&lt;/h2&gt;

&lt;p&gt;With Anvil’s drag-and-drop editor, building the UI was very intuitive. Instead of writing HTML and CSS, I simply dragged components from the &lt;a href="https://anvil.works/docs/editor/form-editor?utm_source=crosspost:dev.to:/blog/guess-the-sketch-game#toolbox"&gt;Toolbox&lt;/a&gt; onto the Form and arranged them as needed. Here is how easy it was to build the &lt;strong&gt;SketchScreen&lt;/strong&gt;, where players create and name their sketches.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fezl5ads6zoss1frjfeq7.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fezl5ads6zoss1frjfeq7.gif" alt="Creating the Sketch Screen in Anvil" width="640" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Anvil’s &lt;a href="https://anvil.works/docs/ui/components/canvas?utm_source=crosspost:dev.to:/blog/guess-the-sketch-game"&gt;Canvas component&lt;/a&gt; provided a seamless way to add a drawing area to the game. It is a Python wrapper around the HTML &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; element, with built-in &lt;a href="https://anvil.works/docs/api/anvil?utm_source=crosspost:dev.to:/blog/guess-the-sketch-game#Canvas_attributes"&gt;methods and event handlers&lt;/a&gt; that handle drawing effortlessly. I used the &lt;code&gt;mouse_down&lt;/code&gt;, &lt;code&gt;mouse_move&lt;/code&gt;, and &lt;code&gt;mouse_up&lt;/code&gt; events to track real-time mouse movement and draw lines on the canvas. Adding an eraser was as simple as setting the brush colour to match the background of the drawing area.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Want to learn more about the Canvas component? Check out this Canvas Tutorial:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/learn/tutorials/canvas?utm_source=crosspost:dev.to:/blog/guess-the-sketch-game"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnv7i6eqqgwpg06ac8dbz.png" alt="Canvas Tutorial" width="745" height="90"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Saving and Sending Sketches
&lt;/h2&gt;

&lt;p&gt;Once a player finishes drawing and clicks the &lt;strong&gt;Send Sketch&lt;/strong&gt; button, the image is retrieved from the Canvas using the &lt;code&gt;.get_image()&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;sketch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;canvas_1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_image&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This converts the sketch into a &lt;a href="https://anvil.works/docs/working-with-files/media?utm_source=crosspost:dev.to:/blog/guess-the-sketch-game#media-objects"&gt;Media object&lt;/a&gt;, which is then stored in a &lt;a href="https://anvil.works/docs/data-tables?utm_source=crosspost:dev.to:/blog/guess-the-sketch-game"&gt;Data Table&lt;/a&gt; for later retrieval.&lt;/p&gt;

&lt;p&gt;When a player submits a sketch, one of two things happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A new game is created, along with its first round (if the player is starting a new game).&lt;/li&gt;
&lt;li&gt;A new round is added to an existing game, which happens when a player joins an ongoing game and takes their turn.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s how I handled both scenarios:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;sketch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;canvas_1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_image&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Add a round to an existing game
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;game_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;add_game_round&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;game_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sketch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sketch_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/invite/:id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;game_id&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;# Create a new game
&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;game_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;start_game&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sketch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sketch_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/invite/:id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;game_id&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In both cases, a new game round is created and linked to the current game, whether the game is newly created or ongoing.&lt;/p&gt;

&lt;p&gt;With &lt;a href="https://anvil.works/docs/data-tables?utm_source=crosspost:dev.to:/blog/guess-the-sketch-game"&gt;Data Tables&lt;/a&gt;, creating a round is as simple as inserting a new row into the Rounds Table and adding the round ID to the corresponding game's &lt;code&gt;rounds&lt;/code&gt; column (which stores a list of round IDs for that game).&lt;/p&gt;

&lt;p&gt;Here’s how I create and link a round to an existing game:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@anvil.server.callable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;require_user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_game_round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;game_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sketch_name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="c1"&gt;# Other game logic...
&lt;/span&gt;  &lt;span class="n"&gt;game&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app_tables&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;game_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_by_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;game_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;round&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app_tables&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rounds_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;game_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;game_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sketch_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sketch_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start_time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rounds&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;round&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="c1"&gt;# Other game logic... 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Sending Invites
&lt;/h2&gt;

&lt;p&gt;Anvil has a built-in  &lt;a href="https://anvil.works/docs/email?utm_source=crosspost:dev.to:/blog/guess-the-sketch-game"&gt;Email Service&lt;/a&gt;, which makes sending invites as simple as a single function call. I used &lt;code&gt;anvil.email.send()&lt;/code&gt; to email friends a game invite with a preview of the sketch as an  &lt;a href="https://anvil.works/docs/email/attachments?utm_source=crosspost:dev.to:/blog/guess-the-sketch-game#using-inline-attachments"&gt;inline attachment&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;  &lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;bcc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;emails&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;from_address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
    &lt;span class="n"&gt;subject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; is inviting you to Guess the Sketch!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
      Hey,
      I just created this sketch:&amp;lt;br&amp;gt;
      &amp;lt;img src=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cid:sketch&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&amp;lt;br&amp;gt;
      Think you can figure out what it is? Click this link to play: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; 
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;inline_attachments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sketch&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Players receive this email with a preview of the sketch right in their inbox. Here’s how it looks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1vuarvjrg1mda7qi0r2b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1vuarvjrg1mda7qi0r2b.png" alt="Invite Email" width="800" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This makes it really easy for players to see the sketch before they click the link to play.&lt;/p&gt;




&lt;h2&gt;
  
  
  Managing Players and Scores
&lt;/h2&gt;

&lt;p&gt;To manage player authentication, I used Anvil’s &lt;a href="https://anvil.works/docs/users?utm_source=crosspost:dev.to:/blog/guess-the-sketch-game"&gt;Users Service&lt;/a&gt;, which automatically created a &lt;strong&gt;Users Table&lt;/strong&gt; that stored player details.&lt;/p&gt;

&lt;p&gt;With just one line, I could add a login Form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;login_with_form&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows players to sign up and log in with their Google accounts, making it easy to track their progress across games. Each new user is automatically added as a row in the Users Table.&lt;/p&gt;

&lt;p&gt;At any point in the app, I can access the currently logged-in player by calling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;player&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_user&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tracking Player Scores
&lt;/h3&gt;

&lt;p&gt;To track scores, I added a &lt;code&gt;points&lt;/code&gt; column to the automatically generated &lt;strong&gt;Users Table&lt;/strong&gt;, where I store the total points each player accumulates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fynl7wag7d2rcmxeyhpeb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fynl7wag7d2rcmxeyhpeb.png" alt="Users Table" width="800" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For every point a player earns in a game, I update the player’s total score:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;player&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_user&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Other game logic...
&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;points&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
      &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;points&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;points_gained&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;points&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;points_gained&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures that scores remain updated and persistent across game sessions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Publishing and Sharing
&lt;/h2&gt;

&lt;p&gt;Once everything was ready, publishing the game was just one click on the  &lt;a href="https://anvil.works/docs/deployment/environments?utm_source=crosspost:dev.to:/blog/guess-the-sketch-game"&gt;Publish button&lt;/a&gt; in the Anvil editor. I instantly got a public URL, that I could share with friends to start playing right away!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd4m8wl12p5mv20ylnzts.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd4m8wl12p5mv20ylnzts.gif" alt="Full Game Demo" width="1114" height="868"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Want to Build Your Own?
&lt;/h2&gt;

&lt;p&gt;These are just some of the highlights, but you can clone the full project and explore how it works yourself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build#clone:LBYMHJ3D5VHWUS3G=V2TWD2XDO3Z6MHCCXTEPXQVF" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo74xkd1d2ganf56ftrnp.png" alt="Image description" width="608" height="140"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  More about Anvil
&lt;/h2&gt;

&lt;p&gt;If you're new here, welcome! &lt;a href="https://anvil.works/?utm_source=crosspost:dev.to:/blog/guess-the-sketch-game"&gt;Anvil&lt;/a&gt; is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks – just &lt;strong&gt;build it all in Python&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build?utm_source=crosspost:dev.to:/blog/guess-the-sketch-game"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fow63l4svon8tal3uola3.png" alt="Sign up for Anvil" width="800" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>python</category>
      <category>anvil</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Introducing the Interactive Debugger in Anvil</title>
      <dc:creator>Love Otudor</dc:creator>
      <pubDate>Wed, 26 Feb 2025 09:47:49 +0000</pubDate>
      <link>https://dev.to/anvil/introducing-the-interactive-debugger-in-anvil-10kn</link>
      <guid>https://dev.to/anvil/introducing-the-interactive-debugger-in-anvil-10kn</guid>
      <description>&lt;h2&gt;
  
  
  Say Hello to the Interactive Debugger in Anvil
&lt;/h2&gt;

&lt;p&gt;We are very excited to announce the first release of &lt;strong&gt;the Interactive Debugger&lt;/strong&gt; in Anvil. Say goodbye to countless &lt;code&gt;print&lt;/code&gt; statements!&lt;/p&gt;

&lt;p&gt;With the Interactive Debugger, you can now pause your code as it executes, inspect variables, and gain deeper insights into what’s happening in your code—whether on the client or server side.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgjo3kcs35m3i2p9i79yq.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgjo3kcs35m3i2p9i79yq.gif" alt="Debugger Demo" width="1024" height="1024"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What is the Interactive Debugger?
&lt;/h2&gt;

&lt;p&gt;The Interactive Debugger lets you:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Add breakpoints&lt;/strong&gt; to your code to pause execution at specific lines.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Inspect variables&lt;/strong&gt; and &lt;strong&gt;values&lt;/strong&gt; at runtime.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Debug&lt;/strong&gt; both &lt;strong&gt;client-side&lt;/strong&gt; and &lt;strong&gt;server-side code&lt;/strong&gt;, including &lt;strong&gt;background tasks&lt;/strong&gt; and &lt;strong&gt;HTTP endpoints&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Getting started is simple:&lt;/strong&gt; Click in the gutter next to any executable line of code to add a breakpoint and then run your code. When this breakpoint is hit, the debugger pauses execution and opens the Debugger Window, where you can easily view and inspect all the variables in your code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Get Deeper Insights into your Code in real time
&lt;/h2&gt;

&lt;p&gt;With the debugger, you can add and remove breakpoints even while execution is paused, allowing you to adjust your debugging strategy as needed. The debugger toolbar gives you complete control to resume, restart, or stop execution, step over breakpoints, and step into or out of functions effortlessly. This makes it easy to navigate through your code seamlessly and gain a deeper understanding of its behaviour.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fho05ikm5nko21y3v1162.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fho05ikm5nko21y3v1162.gif" alt="Add and remove breakpoints" width="1512" height="819"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Easy Debugging Across Client and Server Code
&lt;/h2&gt;

&lt;p&gt;Anvil’s debugger allows you to step into server code directly from client code. For example, you can start in your client-side form code and step directly into your server code while showing the entire call stack on the browser frame.&lt;/p&gt;

&lt;p&gt;Here is a demo illustrating how you can step into server code from client code seamlessly:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F77ho3wq2ct1iuxfk7wqh.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F77ho3wq2ct1iuxfk7wqh.gif" alt="Step into server code" width="760" height="579"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Debug Background Tasks and HTTP Endpoints
&lt;/h2&gt;

&lt;p&gt;Debugging background tasks and HTTP endpoints in server modules has never been easier. By adding breakpoints to your background tasks or endpoint calls, you can pause execution, inspect variables, and diagnose issues with accuracy and confidence.&lt;/p&gt;




&lt;h2&gt;
  
  
  Availability
&lt;/h2&gt;

&lt;p&gt;The debugger is available to everyone!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Free users can use Anvil’s debugger only on the client-side (Form) code.&lt;/li&gt;
&lt;li&gt;Client-side and server-side debugging is available on a Business Plan or higher.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What’s Next?
&lt;/h2&gt;

&lt;p&gt;This is just the first version of the Anvil Debugger and we have plans for more interesting features, so stay tuned! In the meantime, we would love to hear your feedback! Try out the debugger today and let us know how it works for you.&lt;/p&gt;

&lt;p&gt;For a deep dive into debugging with the interactive debugger in Anvil, as well as additional tools to enhance your debugging process, check out our &lt;a href="https://anvil.works/docs/debugger?utm_source=crosspost:dev.to:/blog/announcing-the-debugger"&gt;Debugging Documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy debugging!&lt;/p&gt;




&lt;h2&gt;
  
  
  More about Anvil
&lt;/h2&gt;

&lt;p&gt;If you're new here, welcome! &lt;a href="https://anvil.works?utm_source=crosspost:dev.to:/blog/announcing-the-debugger"&gt;Anvil&lt;/a&gt; is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks – just &lt;strong&gt;build it all in Python&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works?utm_source=crosspost:dev.to:/blog/announcing-the-debugger"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fow63l4svon8tal3uola3.png" alt="Sign up for Anvil" width="800" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>python</category>
      <category>webapp</category>
    </item>
  </channel>
</rss>
