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
BotandDispatcher. - Sets up basic logging.
- Defines handlers for
/startand/helpcommands. 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)./capturecommand: 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 instate.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:
- Enable Google Sheets API: In your Google Cloud Console.
- Create a Service Account: In your Google Cloud Console.
- Download JSON Key: For the service account. Save it as
credentials.json(or as specified in.env). - Share Your Google Sheet: With the email address of your service account (found in the JSON key).
- Get your Google Sheet ID: From the URL (e.g.,
https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID/edit). - 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_userwith your actual username on the VPS. - Ensure all paths in
WorkingDirectoryandExecStartare correct. - Make sure your
.envfile 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
.envfile. - Google Sheets Permissions: Ensure the service account has access to the sheet.
- API Limits: Be mindful of Telegram API rate limits.
aiogramhandles some of this, but aggressive usage can still cause issues. - Environment Variables: Ensure
.envis correctly loaded and variables are accessible. - Systemd Paths: Incorrect paths in the
.servicefile 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
loggingextensively 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). - [ ]
.envfile created with correct credentials. - [ ]
main.pywith 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.txtcreated. - [ ]
telegram_lead_bot.servicefile 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
Комментарии
Отправить комментарий