Set-up anonymous messages for your hashnode blog

Create a new messages widget, code the server, setup telegram bot, and deploy the app to vercel

Let's see how to create a messaging widget for your hashnode blog. We will set-up the widget to send the message to a server, which sends the message to the user via telegram.

Final Product

This is our final result. A messaging widget that sends messages straight to the authors via telegram. Please feel free to send feedback.

Creating a new Hashnode widget

A hashnode widget is a small HTML application(HTML + CSS + JS), that can be embedded into any hashnode blog using a shortcut like %%[widget-name].

Hashnode dashboard -> Widgets -> Add a new Widget

We can skip about the UI as you can design better than mine. The important thing here is the endpoint.{chat_id_here}

Send a POST request to the endpoint with payload,

    "message": "<your-message-here>"

In a later section, we'll see how to deploy your own instance of the app to vercel.

Setting up the server

We will build our application using FastAPI.

Create a new virtualenv and install fastapi.

virtualenv .venv

pip install fastapi==0.63.0 uvicorn==0.13.3

We will use uvicorn for the development purpose. The deployment doesn't require uvicorn as vercel runs serverless python.

The API will have just one endpoint to receive a POST request from our widget.

# app/ 

from fastapi import APIRouter, Query
from fastapi.background import BackgroundTasks

from app.telegram import send_message
from app.schemas import Payload

api = APIRouter(prefix="/api")"/message")
async def post_anonymous_message(
    data: Payload, background: BackgroundTasks, chat_id: str = Query(...)
    background.add_task(send_message, data.message, chat_id)
    return {"message": "success"}

Let's see what we did here. We imported all the required stuff on top. The send_message and Payload imports will be explained below. The router(/api) will have a single POST endpoint at /message. It takes in the payload, chat_id, and an instance of FastAPI's BackgroundTasks.

BackgroundTasks let you run tasks in the background. This comes in very handy when you want to instantly return the response instead of making the user wait for a long-running job. In our case, we don't know the network delay in sending a telegram message.

For example, let's consider an application that allows people to upload and share images(like Instagram). Once an image is uploaded, you want to resize the image to 5 different sizes(for thumbnails and other purposes). We can use background tasks to resize the images and send the response as soon as the upload is complete.

Here's how it works,


  1. User uploads image
  2. Send response as soon as the upload is finished
  3. Resize the image in the background

What's in the Payload?

Payload is a pydantic model for validating the JSON input.

# app/

from pydantic import BaseModel, Field

class Payload(BaseModel):
    message: str = Field(..., max_length=100)

Here the json data contains a single field, message, with a max length of 100.

Define the send_message function

To define the send_message function, we need to set up a new telegram bot.

Go to your telegram app and search for @BotFather


Now type /newbot in the chatbox to start creating the app. Follow all the instructions, and finally, you'll get the bot token. Save the bot token to a .env file.

# .env

# dummy token for illustration purposes

Install python-dotenv to load the env variables.

pip install python-dotenv==0.15.0

And we'll use pydantic to load the environment variables.

# app/

from pydantic import BaseSettings

class Config(BaseSettings):
    token: str

    class Config:
        env_file = ".env"
        env_file_encoding = "utf-8"

Before defining our send_message function, we need to install one more requirement. We'll use aiohttp to make requests to telegram API

pip install aiohttp==3.7.3

Once everything is set-up, we define the send_message function.

import aiohttp
from app.config import Config

settings = Config()

async def send_message(message: str, chat_id: str):
    url = f"{settings.token}/sendMessage?chat_id={chat_id}&text={message}"
    async with aiohttp.ClientSession() as session:
        await session.get(url)

A GET request to the telegram API endpoint sends our message to the provided chat_id. In case you don't know your chat_id, send /start to the bot @getmyid_bot. It'll return your chat_id.

Finally, we create a FastAPI app.


from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

from app.api import api

app = FastAPI(include_in_schema=False)

origins = [



Since the widget is served from, we add it to CORS.

How to deploy one for yourself?

  • Deploy the backend to vercel Deploy with Vercel

  • Create a new telegram bot

  • Add the token to env variables while deploying
  • Change the API endpoint at your widget to the newly deployed one.

If you want to use the feature without deploying one, add a new widget with the endpoint as{chat_id_here}. You can use the widget here or create one for your own.

If you liked this, please give your feedback. In case you didn't like what I created and want to write something that goes against the hashnode policies, please feel free to write an anonymous message



Comments (2)

Rutik Wankhade's photo

This is really cool! I remember hashnode had a DM feature earlier. It's not just limited to hashnode right? Can we use it elsewhere like on a portfolio site or something?

Amal Shaji's photo

Yeah, it can be deployed on any website. Just change the CORS in your deployment to your website.