diff --git a/examples/README.md b/examples/README.md
index d3d0f7d6a..74806cb78 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -52,6 +52,12 @@ A basic example on how to set up a custom error handler.
### [`chatmemberbot.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/chatmemberbot.py)
A basic example on how `(my_)chat_member` updates can be used.
+### [`webappbot.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/webappbot.py)
+A basic example of how [Telegram WebApps](https://core.telegram.org/bots/webapps) can be used.
+Use in combination with [`webappbot.html`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/webappbot.html).
+For your convenience, this file is hosted by the PTB team such that you don't need to host it yourself.
+Uses the [`iro.js`](https://iro.js.org) JavaScript library to showcase a user interface that is hard to achieve with native Telegram functionality.
+
### [`contexttypesbot.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/contexttypesbot.py)
This example showcases how `telegram.ext.ContextTypes` can be used to customize the `context` argument of handler and job callbacks.
diff --git a/examples/webappbot.html b/examples/webappbot.html
new file mode 100644
index 000000000..1565ec34b
--- /dev/null
+++ b/examples/webappbot.html
@@ -0,0 +1,39 @@
+
+
+
+
+
+ python-telegram-bot Example WebApp
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/webappbot.py b/examples/webappbot.py
new file mode 100644
index 000000000..e2d47cc38
--- /dev/null
+++ b/examples/webappbot.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+# pylint: disable=unused-argument,wrong-import-position
+# This program is dedicated to the public domain under the CC0 license.
+
+"""
+Simple example of a Telegram WebApp which displays a color picker.
+The static website for this website is hosted by the PTB team for your convenience.
+Currently only showcases starting the WebApp via a KeyboardButton, as all other methods would
+require a bot token.
+"""
+import json
+import logging
+
+from telegram import __version__ as TG_VER
+
+try:
+ from telegram import __version_info__
+except ImportError:
+ __version_info__ = (0, 0, 0, 0, 0) # type: ignore[assignment]
+
+if __version_info__ < (20, 0, 0, "alpha", 1):
+ raise RuntimeError(
+ f"This example is not compatible with your current PTB version {TG_VER}. To view the "
+ f"{TG_VER} version of this example, "
+ f"visit https://github.com/python-telegram-bot/python-telegram-bot/tree/v{TG_VER}/examples"
+ )
+from telegram import KeyboardButton, ReplyKeyboardMarkup, ReplyKeyboardRemove, Update, WebAppInfo
+from telegram.ext import Application, CommandHandler, ContextTypes, MessageHandler, filters
+
+# Enable logging
+logging.basicConfig(
+ format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO
+)
+logger = logging.getLogger(__name__)
+
+
+# Define a `/start` command handler.
+async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+ """Send a message with a button that opens a the web app."""
+ await update.message.reply_text(
+ "Please press the button below to choose a color via the WebApp.",
+ reply_markup=ReplyKeyboardMarkup.from_button(
+ KeyboardButton(
+ text="Open the color picker!",
+ web_app=WebAppInfo(url="https://python-telegram-bot.org/static/webappbot"),
+ )
+ ),
+ )
+
+
+# Handle incoming WebAppData
+async def web_app_data(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+ """Print the received data and remove the button."""
+ # Here we use `json.loads`, since the WebApp sends the data JSON serialized string
+ # (see webappbot.html)
+ data = json.loads(update.effective_message.web_app_data.data)
+ await update.message.reply_html(
+ text=f"You selected the color with the HEX value {data['hex']}
. The "
+ f"corresponding RGB value is {tuple(data['rgb'].values())}
.",
+ reply_markup=ReplyKeyboardRemove(),
+ )
+
+
+def main() -> None:
+ """Start the bot."""
+ # Create the Application and pass it your bot's token.
+ application = Application.builder().token("TOKEN").build()
+
+ application.add_handler(CommandHandler("start", start))
+ application.add_handler(MessageHandler(filters.StatusUpdate.WEB_APP_DATA, web_app_data))
+
+ # Run the bot until the user presses Ctrl-C
+ application.run_polling()
+
+
+if __name__ == "__main__":
+ main()