How to Build a Telegram Bot That Captures Leads 24/7

Building a Lead-Capturing Telegram Bot with Python

This guide outlines the steps to build a robust lead-capturing Telegram bot using Python. We'll cover commands, inline buttons, data storage, anti-spam measures, and deployment.

Prerequisites

  • Python 3.7+: Ensure Python is installed on your development machine.
  • Telegram Bot Token: Obtain from BotFather on Telegram.
  • Google Sheets API Credentials (for sheet storage): Or your preferred CRM API key.
  • Basic Python and API knowledge.
  • Linux VPS: For deployment.

Choosing Your Library: aiogram vs. Telethon

  • aiogram: Asynchronous, modern, and generally preferred for bot development due to its ease of use and features.
  • Telethon: Asynchronous, more powerful for interacting with Telegram as a user (not just a bot), but can be overkill for a simple bot.

We'll focus on aiogram for this guide due to its suitability for bot development.


Phase 1: Development Environment Setup

1. Project Directory and Virtual Environment

mkdir telegram_lead_bot
cd telegram_lead_bot
python3 -m venv venv
source venv/bin/activate

2. Install Dependencies

pip install aiogram python-dotenv google-api-python-client google-auth-httplib2 google-auth-oauthlib
  • aiogram: The Telegram bot framework.
  • python-dotenv: For managing environment variables (like your bot token).
  • google-api-python-client, google-auth-httplib2, google-auth-oauthlib: For Google Sheets integration.

3. Create Configuration File

Create a .env file in your project root:

TELEGRAM_BOT_TOKEN=YOUR_TELEGRAM_BOT_TOKEN
# For Google Sheets:
GOOGLE_SHEET_ID=YOUR_GOOGLE_SHEET_ID
GOOGLE_SHEET_RANGE=Sheet1!A1
GOOGLE_CREDENTIALS_FILE=credentials.json

Replace placeholders with your actual values. For Google Sheets, you'll need to set up a service account and download credentials.json.


Phase 2: Bot Core Functionality

1. Bot Skeleton (main.py)

import logging
import os

from aiogram import Bot, Dispatcher, types
from aiogram.contrib.middlewares.logging import LoggingMiddleware
from aiogram.utils import executor
from dotenv import load_dotenv

# Load environment variables
load_dotenv()

# Configure logging
logging.basicConfig(level=logging.INFO)

# Initialize bot and dispatcher
bot = Bot(token=os.getenv('TELEGRAM_BOT_TOKEN'))
dp = Dispatcher(bot)

# Middleware for logging
dp.middleware.setup(LoggingMiddleware())

# --- Command Handlers ---
@dp.message_handler(commands=['start'])
async def send_welcome(message: types.Message):
    """
    This handler will be called when user sends `/start` command
    """
    await message.reply("Hi!\nI'm your lead capture bot. Use /help to see available commands.")

@dp.message_handler(commands=['help'])
async def send_help(message: types.Message):
    """
    Handles the /help command.
    """
    help_text = """
    Available commands:
    /start - Start the bot
    /help - Show this message
    /capture - Start capturing leads
    """
    await message.reply(help_text)

# --- Inline Button Handlers ---
# (To be implemented later)

# --- Lead Capture Logic ---
# (To be implemented later)

if __name__ == '__main__':
    executor.start_polling(dp, skip_updates=True)

Explanation:

  • Loads the bot token from .env.
  • Initializes Bot and Dispatcher.
  • Sets up basic logging.
  • Defines handlers for /start and /help commands.
  • executor.start_polling() keeps the bot running and listening for updates.

2. Running the Bot Locally

python main.py

Test by sending /start and /help to your bot on Telegram.


Phase 3: Lead Capture Mechanism

1. /capture Command and Inline Buttons

We'll use inline buttons to guide the user through lead data collection.

Modify main.py:

# ... (previous imports and setup) ...

from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher.filters.state import State, StatesGroup

# --- States for FSM (Finite State Machine) ---
class LeadCaptureState(StatesGroup):
    name = State()
    email = State()
    phone = State()
    company = State()

# --- Command Handlers ---
@dp.message_handler(commands=['start'])
async def send_welcome(message: types.Message):
    # ... (same as before) ...

@dp.message_handler(commands=['help'])
async def send_help(message: types.Message):
    # ... (same as before) ...

@dp.message_handler(commands=['capture'])
async def start_capture(message: types.Message):
    """
    Initiates the lead capture process.
    """
    keyboard = InlineKeyboardMarkup()
    keyboard.add(InlineKeyboardButton("Start Capture", callback_data="start_lead_capture"))
    await message.reply("Ready to capture a lead? Click the button below.", reply_markup=keyboard)

# --- Inline Button Handlers ---
@dp.callback_query_handler(lambda c: c.data == 'start_lead_capture')
async def process_start_capture_callback(callback_query: types.CallbackQuery):
    await bot.answer_callback_query(callback_query.id)
    await callback_query.message.reply("Please enter your Name:")
    await LeadCaptureState.name.set() # Set the first state

@dp.message_handler(state=LeadCaptureState.name)
async def process_name(message: types.Message, state: FSMContext):
    async with state.proxy() as data:
        data['name'] = message.text
    await LeadCaptureState.next()
    await message.reply("Please enter your Email:")

@dp.message_handler(state=LeadCaptureState.email)
async def process_email(message: types.Message, state: FSMContext):
    # Basic email validation (can be improved)
    if "@" not in message.text:
        await message.reply("Invalid email format. Please try again.")
        return
    async with state.proxy() as data:
        data['email'] = message.text
    await LeadCaptureState.next()
    await message.reply("Please enter your Phone Number:")

@dp.message_handler(state=LeadCaptureState.phone)
async def process_phone(message: types.Message, state: FSMContext):
    async with state.proxy() as data:
        data['phone'] = message.text
    await LeadCaptureState.next()
    await message.reply("Please enter your Company Name (optional, press Enter to skip):")

@dp.message_handler(state=LeadCaptureState.company)
async def process_company(message: types.Message, state: FSMContext):
    async with state.proxy() as data:
        data['company'] = message.text if message.text else "N/A"

    # --- Save Lead ---
    lead_data = data.as_dict()
    await save_lead_to_sheet(lead_data) # Call the saving function

    await message.reply("Thank you! Your lead information has been captured.")
    await state.finish() # End the FSM

# --- Lead Saving Function ---
async def save_lead_to_sheet(lead_data: dict):
    """
    Saves lead data to a Google Sheet.
    (Implementation details below)
    """
    logging.info(f"Saving lead: {lead_data}")
    # Placeholder for actual sheet saving logic
    pass

# ... (executor.start_polling) ...

Explanation:

  • LeadCaptureState: Defines states for the FSM (e.g., name, email).
  • /capture command: Sends an inline button to start.
  • process_start_capture_callback: Handles the button click, sets the first state (LeadCaptureState.name), and prompts for the name.
  • State Handlers (process_name, process_email, etc.): Each handler receives user input based on the current state, stores it in state.proxy(), and transitions to the next state.
  • state.finish(): Resets the FSM after all data is collected.

2. Saving Leads to Google Sheets

Create a new file google_sheets.py:

import os
import logging
from dotenv import load_dotenv
from google.oauth2 import service_account
from googleapiclient.discovery import build

load_dotenv()

# Google Sheets API setup
SCOPES = ['https://www.googleapis.com/auth/spreadsheets']
SERVICE_ACCOUNT_FILE = os.getenv('GOOGLE_CREDENTIALS_FILE')
SPREADSHEET_ID = os.getenv('GOOGLE_SHEET_ID')
RANGE_NAME = os.getenv('GOOGLE_SHEET_RANGE')

creds = None
if SERVICE_ACCOUNT_FILE:
    creds = service_account.Credentials.from_service_account_file(
        SERVICE_ACCOUNT_FILE, scopes=SCOPES)

service = build('sheets', 'v4', credentials=creds)

async def save_lead_to_sheet(lead_data: dict):
    """
    Appends lead data as a new row to the specified Google Sheet.
    """
    if not creds or not service:
        logging.error("Google Sheets credentials or service not initialized.")
        return

    values = [
        [
            lead_data.get('name', ''),
            lead_data.get('email', ''),
            lead_data.get('phone', ''),
            lead_data.get('company', ''),
            # Add timestamp if needed
        ]
    ]

    body = {
        'values': values
    }

    try:
        result = service.spreadsheets().values().append(
            spreadsheetId=SPREADSHEET_ID,
            range=RANGE_NAME,
            valueInputOption='USER_ENTERED',
            body=body
        ).execute()
        logging.info(f"{result.get('updates').get('updatedCells')} cells updated.")
    except Exception as e:
        logging.error(f"Error saving to Google Sheet: {e}")

Now, update main.py to import and use this function:

# ... (in main.py, at the top) ...
from google_sheets import save_lead_to_sheet

# ... (rest of main.py, ensure save_lead_to_sheet is called correctly) ...

Google Sheets Setup Checklist:

  1. Enable Google Sheets API: In your Google Cloud Console.
  2. Create a Service Account: In your Google Cloud Console.
  3. Download JSON Key: For the service account. Save it as credentials.json (or as specified in .env).
  4. Share Your Google Sheet: With the email address of your service account (found in the JSON key).
  5. Get your Google Sheet ID: From the URL (e.g., https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID/edit).
  6. Define your Sheet Range: E.g., Sheet1!A1 (where data will be appended).

Phase 4: Anti-Spam Measures

1. Rate Limiting

We'll limit how often a user can initiate the capture process.

Add to main.py:

# ... (imports) ...
from datetime import datetime, timedelta

# Anti-spam configuration
USER_COOLDOWNS = {}
COOLDOWN_PERIOD = timedelta(minutes=5) # 5 minutes cooldown

# ... (inside start_capture function) ...
@dp.message_handler(commands=['capture'])
async def start_capture(message: types.Message):
    user_id = message.from_user.id
    current_time = datetime.now()

    if user_id in USER_COOLDOWNS:
        last_used = USER_COOLDOWNS[user_id]
        if current_time - last_used < COOLDOWN_PERIOD:
            await message.reply(f"Please wait {COOLDOWN_PERIOD.total_seconds() / 60:.0f} minutes before starting another capture.")
            return

    USER_COOLDOWNS[user_id] = current_time
    # ... (rest of the start_capture function) ...

# --- Add a handler to reset cooldown if user cancels ---
@dp.message_handler(state="*", commands='cancel')
async def cancel_handler(message: types.Message, state: FSMContext):
    """Allow user to cancel any action."""
    current_state = await state.get_state()
    if current_state is None:
        await message.reply('Nothing to cancel.')
        return

    logging.info('Cancelling state %r', current_state)
    # Remove user from cooldown if they cancel
    if message.from_user.id in USER_COOLDOWNS:
        del USER_COOLDOWNS[message.from_user.id]

    await state.finish()
    await message.reply('Cancelled.', reply_markup=types.ReplyKeyboardRemove())

2. Basic Input Validation

  • Email: Already added a basic @ check.
  • Phone: You can add regex validation if needed.
  • Text Length Limits: Consider limiting the length of captured fields.

Phase 5: Deployment on VPS with systemd

1. Prepare Your VPS

  • SSH Access: Ensure you can SSH into your VPS.
  • Python 3 Installed: sudo apt update && sudo apt install python3 python3-venv
  • Git Installed: sudo apt install git

2. Transfer Your Project

Use scp or rsync to copy your project files to the VPS.

# From your local machine
scp -r /path/to/your/telegram_lead_bot user@your_vps_ip:/home/user/

3. Set Up Virtual Environment on VPS

# On your VPS
cd /home/user/telegram_lead_bot
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt # Create requirements.txt: pip freeze > requirements.txt

4. Create systemd Service File

Create a file named telegram_lead_bot.service in /etc/systemd/system/:

[Unit]
Description=Telegram Lead Capture Bot
After=network.target

[Service]
User=your_vps_user # Replace with your VPS username
WorkingDirectory=/home/your_vps_user/telegram_lead_bot # Replace with your project path
ExecStart=/home/your_vps_user/telegram_lead_bot/venv/bin/python /home/your_vps_user/telegram_lead_bot/main.py # Adjust paths
Restart=always
RestartSec=10 # Restart after 10 seconds if it crashes
EnvironmentFile=/home/your_vps_user/telegram_lead_bot/.env # Ensure .env is in the project dir

[Install]
]
WantedBy=multi-user.target

Important:

  • Replace your_vps_user with your actual username on the VPS.
  • Ensure all paths in WorkingDirectory and ExecStart are correct.
  • Make sure your .env file is in the project directory on the VPS.

5. Manage the Service

# On your VPS
sudo systemctl daemon-reload # Reload systemd to recognize the new service
sudo systemctl start telegram_lead_bot
sudo systemctl enable telegram_lead_bot # Start on boot
sudo systemctl status telegram_lead_bot # Check status
sudo journalctl -u telegram_lead_bot -f # View logs

6. Firewall (Optional but Recommended)

If you're running other services, ensure your firewall is configured correctly. For a Telegram bot, you generally don't need to open specific ports unless you're using webhooks (which we aren't here).


Common Mistakes and Troubleshooting

  • Incorrect Bot Token: Double-check your .env file.
  • Google Sheets Permissions: Ensure the service account has access to the sheet.
  • API Limits: Be mindful of Telegram API rate limits. aiogram handles some of this, but aggressive usage can still cause issues.
  • Environment Variables: Ensure .env is correctly loaded and variables are accessible.
  • Systemd Paths: Incorrect paths in the .service file are a common deployment issue.
  • Virtual Environment Activation: Always activate the virtual environment before running your bot or installing dependencies on the VPS.
  • Logging: Use logging extensively to debug issues, especially on the VPS.
  • skip_updates=True: Useful during development to avoid processing old messages, but consider removing it for production if you need to guarantee message delivery.

Checklist

  • [ ] Python 3 installed.
  • [ ] Telegram Bot Token obtained.
  • [ ] Google Sheets API enabled and service account configured (or CRM API ready).
  • [ ] Project directory created.
  • [ ] Virtual environment set up.
  • [ ] Dependencies installed (aiogram, python-dotenv, Google libraries).
  • [ ] .env file created with correct credentials.
  • [ ] main.py with basic commands and FSM structure.
  • [ ] google_sheets.py (or equivalent CRM integration) created.
  • [ ] Google Sheet shared with service account.
  • [ ] Rate limiting logic implemented.
  • [ ] Basic input validation added.
  • [ ] Project files transferred to VPS.
  • [ ] Virtual environment set up on VPS.
  • [ ] requirements.txt created.
  • [ ] telegram_lead_bot.service file created and configured.
  • [ ] systemd service started, enabled, and status checked.
  • [ ] Logs reviewed for errors.

This provides a solid foundation for your lead-capturing Telegram bot. You can extend it further with more advanced features like data validation, more sophisticated anti-spam, integration with other CRMs, and user management.


Need this done for you? Hire me on Freelancehunt: https://freelancehunt.com/freelancer/sspoisk

Originally posted at https://guardlabs.online/care/

Комментарии

Популярные сообщения из этого блога

Beyond the Sandbox: Why Paper Trading Lies and What to Actually Validate

Why Your European Amazon Store is Bleeding Cash (And It's Not the Demand)

Regime Detection: Why Your Strategy Fails and How to Spot the Shift