< Back to list of posts

Building a Paste App

I kept running into the same problem: I needed to get a code snippet, URL, or quick note from my computer to my phone, and the usual methods were annoying. So I built a small paste app that sends text from a website straight to my phone via Telegram. Here's how I put it together.

The concept

Simple: a web page where I type a title and message, hit send, and it shows up on my phone via Telegram. Telegram has a solid bot API, so I used that as the delivery mechanism.

flow A sketch of the application flow

Tech stack

  • React for the UI
  • styled-components for styling
  • Telegram Bot API for message delivery

Key Components

1. User Interface

The UI consists of a sticky note-like component with two main input fields:

  • A title input (NoteInput)
  • A message textarea (NoteTextarea)

I used styled-components to create a visually appealing and responsive design that works well on both desktop and mobile devices.

ui User interface for the paste app

2. State Management

I utilized React's useState hook to manage the state of the title and message inputs:

const [title, setTitle] = useState(''); const [message, setMessage] = useState('');

3. Date and Time Display

To add context to each paste, I implemented a real-time date and time display using the useEffect hook:

useEffect(() => { const updateDateTime = () => { const now = new Date(); setCurrentDateTime(now.toLocaleString()); }; updateDateTime(); const timer = setInterval(updateDateTime, 1000); return () => clearInterval(timer); }, []);

4. Sending Messages to Telegram

The core functionality is implemented in the sendToTelegram function. This function:

  1. Cleans and escapes the input text to prevent XSS attacks
  2. Formats the message with HTML tags for better readability
  3. Sends a POST request to the Telegram Bot API.
    NOTE: Avoid exposing sensitive credentials (token and chat_id) in client-side code. Instead of making direct API calls to Telegram from the frontend, implement a secure middleware layer - either a proxy server or backend API - to handle authentication and protect your secrets. In this implementation, I used Netlify Functions as a serverless solution to securely manage API calls.

sendToTelegram (front end code)

const sendToTelegram = () => { // Clean and escape the title and message const cleanedTitle = cleanText(title); const cleanedMessage = cleanText(message); const escapedTitle = escapeHtml(cleanedTitle); const escapedMessage = escapeHtml(cleanedMessage); fetch('/.netlify/functions/send-telegram', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ title: escapedTitle, message: escapedMessage, dateTime: currentDateTime, }), }) .then((response) => { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); }) .then((data) => { if (data.success) { setTitle(''); setMessage(''); alert('Message sent successfully!'); } else { throw new Error(data.error || 'Unknown error occurred'); } }) .catch((error) => { console.error('Error sending message:', error); alert(`Error sending message: ${error.message}`); }); };

send-telegram (serverless function)

const axios = require('axios'); exports.handler = async function(event, context) { if (event.httpMethod !== 'POST') { return { statusCode: 405, body: 'Method Not Allowed' }; } const { title, message, dateTime } = JSON.parse(event.body); const telegram_bot_token = process.env.TELEGRAM_BOT_TOKEN; const telegram_chat_id = process.env.TELEGRAM_CHAT_ID; if (!telegram_bot_token || !telegram_chat_id) { return { statusCode: 500, body: JSON.stringify({ error: 'Missing Telegram configuration' }) }; } const telegram_message = `<b>${title}</b>\n\n<pre><code>${message}</code></pre>\n\n<i>${dateTime}</i>`; try { const response = await axios.post(`https://api.telegram.org/bot${telegram_bot_token}/sendMessage`, { chat_id: telegram_chat_id, text: telegram_message, parse_mode: 'HTML' }); if (response.data.ok) { return { statusCode: 200, body: JSON.stringify({ success: true }) }; } else { throw new Error(response.data.description || 'Unknown error occurred'); } } catch (error) { console.error('Error sending message:', error); return { statusCode: 500, body: JSON.stringify({ error: `Error sending message: ${error.message}` }) }; } };

Screenshot of message being sent to Telegram chat

proof Note sent to private Telegram chat with message body formatted to allow easier copying of code snippets

5. Security Considerations

For security, I added two helper functions:

  • cleanText: Removes non-printable characters (except newlines and spaces) and trims the input
  • escapeHtml: Escapes special HTML characters to prevent XSS attacks

What's next

The app works well for my daily needs. If I come back to it, I'd probably add:

  • Authentication so it's not just secured by obscurity
  • A history view for past pastes
  • File upload support
Buy Me A Coffee