آنالیتیکس داخلی Telegram
Telegram ابزارهایی برای تحلیل نتایج جایگاههای تبلیغاتی با استفاده از لینکهای یکتا ارائه میدهد. میتوانید برای هر جایگاه تبلیغاتی یک لینک جداگانه بسازید. برای کانالها و گروهها، آمار عضویت مستقیماً در Telegram در دسترس است، اما برای رباتها و Mini Appها باید ذخیره پارامترهای لینک و جمعآوری داده را در سمت پروژه خود جداگانه پیکربندی کنید.
توجه
یک جایگاه تبلیغاتی = یک لینک یکتا. اگر از یک لینک در چند تبلیغ استفاده شود، منابع ترافیک با هم مخلوط میشوند و بعداً قابل تفکیک نیستند.
این نوع آنالیتیکس جدا از آمار کمپینها و ردیابی تبدیل AdsGram کار میکند.
بخش ۱. برای مدیران کمپین در سمت تبلیغدهنده
۱. از کدام لینک استفاده کنیم؟
برای مقایسه نتایج جایگاههای تبلیغاتی مختلف، برای هر کدام از یک لینک یکتا استفاده کنید.
برای مثال، اگر پروژهای را در سه کانال Telegram تبلیغ میکنید، سه لینک جداگانه بسازید. این کار به شما امکان میدهد مشخص کنید کدام جایگاهها کاربران بیشتری جذب میکنند.
نوع لینک به مقصد تبلیغ بستگی دارد:
| مقصد تبلیغ | فرمت لینک | محل پیگیری نتایج |
|---|---|---|
| کانال یا گروه Telegram | یک لینک دعوت جداگانه | Telegram: تنظیمات کانال یا گروه → Invite links |
| ربات | t.me/YourBot?start=ad_sep_anna | ربات شما، اگر پارامتر را ذخیره کند |
| Mini App | t.me/YourBot?startapp=ad_sep_anna | سرور اپلیکیشن شما، اگر پارامتر را ذخیره کند |
YourBot را با نام کاربری ربات خود و ad_sep_anna را با یک پارامتر یکتا برای جایگاه تبلیغاتی جایگزین کنید.
۲. کانالها و گروهها: لینکهای دعوت
برای هر جایگاه تبلیغاتی یک لینک دعوت جداگانه بسازید.
- کانال یا گروه را باز کنید و روی نام آن بزنید.
- تنظیمات ویرایش یا مدیریت را باز کنید. در نسخه دسکتاپ میتوانید از ⋮ →
Manage channel/Manage groupاستفاده کنید. Invite linksرا باز کنید و گزینه ساخت لینک جدید را انتخاب کنید.- لینک را به نام جایگاه نامگذاری کنید، برای مثال
ad_sep_anna. این نام فقط برای مدیران قابل مشاهده است، نه برای کاربرانی که لینک را باز میکنند. - در صورت نیاز، تاریخ انقضا، محدودیت تعداد کاربران یا الزام به تأیید مدیر را تنظیم کنید.
- از لینک فقط در یک جایگاه تبلیغاتی استفاده کنید.
محل مشاهده آمار: صفحه Invite links در Telegram نشان میدهد چند کاربر از طریق هر لینک عضو شدهاند. برای دیدن فهرست کاربران، لینک مورد نظر را باز کنید.
یک لینک عمومی معمولی مانند t.me/yourchannel امکان تفکیک عضویتها بر اساس جایگاه تبلیغاتی را نمیدهد. کانالهای عمومی هم میتوانند لینک دعوت بسازند، پس در تبلیغات خود از لینکهای دعوت جداگانه استفاده کنید.
۳. رباتها: لینکهایی با پارامتر start
از فرمت لینک زیر استفاده کنید:
https://t.me/<bot>?start=<parameter>برای مثال:
https://t.me/YourBot?start=ad_sep_annaوقتی کاربر لینک را باز میکند و Start را میزند، ربات دستوری حاوی پارامتر دریافت میکند:
/start ad_sep_annaTelegram انتساب تبلیغاتی این اجراهای ربات را بهطور خودکار گزارش نمیکند. ربات باید پارامتر را هنگام اولین ایجاد رکورد کاربر ذخیره کند.
اگر معیار شما جذب کاربر جدید است، فقط کاربران جدید را بشمارید. باز کردن لینک تبلیغاتی توسط کاربر موجود، او را به کاربر جدید تبدیل نمیکند.
۴. Mini Appها: لینکهایی با پارامتر startapp
برای Mini App اصلی ربات از این لینک استفاده کنید:
https://t.me/<bot>?startapp=<parameter>برای Mini Appی که با /newapp در @BotFather ساخته شده، میتوانید از این فرمت استفاده کنید:
https://t.me/<bot>/<app>?startapp=<parameter>برای مثال:
https://t.me/YourBot?startapp=ad_sep_annaدر صورت نیاز، پارامتر حالت نمایش را اضافه کنید:
&mode=compact— حالت فشرده.&mode=fullscreen— حالت تمامصفحه.
Mini App پارامتر را در فیلد start_param دریافت میکند. سرور اپلیکیشن شما باید آن را هنگام اولین اجرای اپلیکیشن توسط کاربر ذخیره کند.
اگر کاربر Mini App را بدون لینک تبلیغاتی باز کند — مثلاً از طریق دکمه منو یا پروفایل ربات — ممکن است پارامتر تبلیغاتی وجود نداشته باشد. چنین اجرایی را ارگانیک در نظر بگیرید، مگر اینکه منبع انتساب قابل اعتماد دیگری وجود داشته باشد.
۵. قوانین پارامترها
حداکثر طول:
- پارامتر
start— ۶۴ کاراکتر - پارامتر
startapp— ۵۱۲ کاراکتر
- پارامتر
کاراکترهای مجاز:
A-Z،a-z،0-9،_،-- از فاصله، حروف سیریلیک یا نقطه استفاده نکنید. برای جلوگیری از مشکلات سازگاری، فقط از مجموعه کاراکترهای مجاز استفاده کنید.
دادههای شخصی کاربران را در پارامترها قرار ندهید.
الگوی نامگذاری پیشنهادی. از یک قالب یکسان استفاده کنید تا جایگاهها بهراحتی در گزارشها پیدا شوند:
ad_<month>_<source>_<creative>نمونهها:
ad_sep_tgads_video1ad_sep_blogger_anna
۶. لینکهای کمپین لینک ارجاع نیستند
لینک ارجاع به کاربر اجازه میدهد افراد دیگر را دعوت کند و پاداش بگیرد.
لینک تبلیغاتی ترافیک یک جایگاه تبلیغاتی را میسنجد. این لینک بهتنهایی نباید باعث پرداخت پاداش ارجاع شود.
این دو نوع را با پیشوندها از هم جدا کنید:
ref_…— لینکهای ارجاع کاربران.ad_…— لینکهای جایگاههای تبلیغاتی.
ساختن یک لینک ارجاع جداگانه برای هر کمپین تبلیغاتی فقط یک راهحل موقت است. این کار ممکن است باعث پرداخت پاداش ارجاع برای ترافیک تبلیغاتی و مخلوط شدن آمار شود.
۷. نحوه شمارش کلیکها
Telegram آمار کلیک برای لینکهای t.me ارائه نمیدهد.
اگر نیاز به شمارش کلیک دارید، کاربران را ابتدا از طریق ریدایرکت خودتان عبور دهید و سپس به Telegram بفرستید.
مثال:
https://yourdomain.com/go/ad_sep_anna → https://t.me/YourBot?start=ad_sep_annaسرور شما کلیک را ثبت میکند و کاربر را به لینک مقصد هدایت میکند. این کار به پیادهسازی خودتان نیاز دارد و جایگزین شمارش اجراها، کاربران جدید یا عضویت در کانال نمیشود.
۸. نگهداری جدول نتایج
یک جدول با یک ردیف برای هر لینک یکتا بسازید.
ستونهای پیشنهادی:
| فیلد | چه چیزی ثبت شود |
|---|---|
| پارامتر لینک | برای مثال، ad_sep_anna |
| جایگاه | نام کانال، پست، اینفلوئنسر یا تبلیغ |
| تاریخها | دوره جایگاه |
| هزینه | هزینه تبلیغ |
| کاربران جدید | تعداد کاربران جدید منتسب به لینک |
| هزینه هر کاربر | هزینه ÷ تعداد کاربران جدید |
۹. چکلیست پیش از راهاندازی
پیش از انتشار تبلیغ، مطمئن شوید که:
- هر جایگاه لینک مخصوص خود را دارد؛ لینکها در جایگاههای دیگر دوباره استفاده نمیشوند.
- پارامتر از حداکثر طول بیشتر نیست و فقط کاراکترهای مجاز دارد.
- لینک با یک حساب دوم آزمایش شده است: عضویت شمرده میشود یا پارامتر توسط ربات یا Mini App ذخیره میشود.
- لینک، نام جایگاه و هزینه به جدول اضافه شدهاند.
بخش ۲. پیادهسازی برای توسعهدهندگان
نمونههای زیر از Python، SQL و aiogram 3 برای ربات استفاده میکنند. همین اصول را میتوان با فناوریهای دیگر هم پیادهسازی کرد.
این کد پایهای برای پیادهسازی است، نه یک یکپارچهسازی کامل و آماده. توابع دسترسی به پایگاه داده و برخی جزئیات یکپارچهسازی باید با اپلیکیشن شما تطبیق داده شوند.
۱۰. چه دادههایی ذخیره شود
انتساب به سه موجودیت نیاز دارد:
- فهرستی از لینکهای تبلیغاتی و کمپینها.
- منبع جذب کاربر که هنگام ایجاد رکورد کاربر ذخیره میشود.
- تاریخچه بازدید از لینکهای کمپین، از جمله بازدیدهای کاربران موجود.
نمونه طرح SQL:
-- یک ردیف برای هر لینک تبلیغاتی.
-- برای مثال، پارامتر "ad_sep_anna" با کد "sep_anna" متناظر است.
CREATE TABLE campaigns (
code text PRIMARY KEY,
name text NOT NULL,
created_at timestamptz NOT NULL DEFAULT now()
);
-- منبع جذب کاربر هنگام ایجاد او تعیین میشود.
-- NULL یعنی کاربر ارگانیک.
ALTER TABLE users
ADD COLUMN campaign text REFERENCES campaigns (code);
-- همه کاربرانی که لینکهای کمپین را باز کردهاند،
-- شامل کاربران جدید و موجود.
CREATE TABLE campaign_visits (
code text REFERENCES campaigns (code),
user_id bigint,
first_at timestamptz NOT NULL DEFAULT now(),
PRIMARY KEY (code, user_id)
);فیلد code باید یک کد کوتاه کمپین مانند sep_anna داشته باشد. فیلد name جایگاه را توصیف میکند، برای مثال کانال آنا، پست سپتامبر.
جدول campaign_visits بازدیدها را جدا از منبع جذب اولیه کاربر ثبت میکند. منبع اولیه نباید هر بار که کاربر لینک دیگری را باز میکند بازنویسی شود.
۱۱. تجزیه پارامترها: یک parser برای ربات و Mini App
برای پارامترهای تبلیغاتی و ارجاع از یک parser واحد استفاده کنید.
import re
AD = re.compile(r"ad_([A-Za-z0-9_-]{1,61})")
REF = re.compile(r"ref_([A-Za-z0-9]{4,32})")
def parse_start(param: str | None) -> tuple[str, str] | None:
"""("ad", code)، ("ref", code) یا در غیر این صورت None را برمیگرداند."""
if not param:
return None
if m := AD.fullmatch(param):
return "ad", m[1]
if m := REF.fullmatch(param):
return "ref", m[1]
return Noneپس از تجزیه، بررسی کنید که آیا کد بهدستآمده در جدول campaigns وجود دارد.
- یک کد ناشناخته را به کمپین موجود نسبت ندهید. چنین بازدیدی را ارگانیک یا بدون انتساب در نظر بگیرید.
- مقادیر خام پارامتر را بدون اعتبارسنجی ذخیره نکنید.
- قوانین تجزیه یکسانی را برای پارامترهای دریافتی ربات و Mini App اعمال کنید.
۱۲. ربات: پردازش /start
وقتی کاربر ربات را اجرا میکند، Telegram پارامتر را در آرگومانهای دستور /start ارسال میکند.
نمونه با aiogram 3:
@router.message(CommandStart())
async def start(message: Message, command: CommandObject):
source = parse_start(command.args)
# "/start ad_sep_anna" -> ("ad", "sep_anna")
async with db.transaction():
await create_user_if_new(message.from_user, source)
if source and source[0] == "ad":
await record_visit(source[1], message.from_user.id)تابع create_user_if_new باید فقط در صورتی رکورد کاربر را بسازد که کاربر هنوز وجود نداشته باشد.
برای جلوگیری از رکوردهای تکراری، از یک عملیات اتمی مانند این استفاده کنید:
-- create_user_if_new: اتمی، در صورت درخواست همزمان ربات و Mini App ایمن است
INSERT INTO users (id, campaign, referrer_id)
VALUES ($1, $2, $3)
ON CONFLICT (id) DO NOTHING
RETURNING id; -- بازگشت یک ردیف = کاربر جدید؛ هیچ = کاربر موجود، بدون تغییراگر کوئری یک ردیف برگرداند، کاربر ساخته شده است. اگر هیچ ردیفی برنگرداند، کاربر از قبل وجود دارد و منبع جذب اولیه او باید بدون تغییر بماند.
برای ثبت بازدید از لینک کمپین، از این استفاده کنید:
-- record_visit
INSERT INTO campaign_visits (code, user_id)
VALUES ($1, $2)
ON CONFLICT DO NOTHING;اگر کاربر موجود لینک دیگری را باز کند و /start ad_… دریافت کند، بازدید را ثبت کنید، اما فیلد campaign او را بازنویسی نکنید.
برای انتساب ارجاع، referrer_id را فقط برای کاربران جدید تنظیم کنید. اجازه ندهید کاربران خودشان را ارجاع دهند.
۱۳. Mini App: پردازش اولین اجرا
Mini App میتواند پارامتر start_param را بهعنوان بخشی از دادههای اجرای Telegram Web App دریافت کند.
در سمت فرانتاند، دادههای امضاشده Telegram را به سرور خود بفرستید:
// فرانتاند: هر درخواست دادههای اولیه امضاشده Telegram را همراه دارد
fetch("/api/me", { headers: { Authorization: `tma ${Telegram.WebApp.initData}` } })در سرور، پیش از استفاده از شناسه کاربر یا start_param، اصالت initData و عمر آن را اعتبارسنجی کنید.
نمونه تابع اعتبارسنجی در Python:
import hashlib, hmac, json, time
from urllib.parse import parse_qsl
def check_init_data(
raw: str,
bot_token: str,
max_age: int = 86400
) -> dict:
fields = dict(
parse_qsl(
raw,
keep_blank_values=True,
strict_parsing=True
)
)
received = fields.pop("hash", "")
# همه فیلدها به جز hash، از جمله "signature"، مرتبشده، یک جفت key=value در هر خط
data = "\n".join(
f"{k}={v}" for k, v in sorted(fields.items())
)
secret = hmac.new(
b"WebAppData",
bot_token.encode(),
hashlib.sha256
).digest()
expected = hmac.new(
secret,
data.encode(),
hashlib.sha256
).hexdigest()
if not hmac.compare_digest(expected, received):
raise PermissionError("bad signature")
if time.time() - int(fields["auth_date"]) > max_age:
raise PermissionError("expired")
return {
"user": json.loads(fields["user"]),
"start_param": fields.get("start_param")
}پس از اعتبارسنجی موفق، همان فرایند ربات را دنبال کنید (create_user_if_new و record_visit):
userوstart_paramرا از دادههای اعتبارسنجیشده استخراج کنید.- پارامتر را با
parse_startتجزیه کنید. - کاربر را فقط در صورتی بسازید که هنوز وجود نداشته باشد.
- اگر پارامتر با یک کمپین تبلیغاتی شناختهشده مطابقت دارد، بازدید از لینک کمپین را ثبت کنید.
امنیت: فقط از initData اعتبارسنجیشده استفاده کنید. به initDataUnsafe یا پارامترهای URL بهعنوان منبع هویت کاربر یا انتساب اعتماد نکنید، زیرا قابل جعل هستند.
پارامتر start_param هنگام اجرای اپلیکیشن از طریق لینک مربوطه ارسال میشود. ممکن است در اجراهای بعدی از منو وجود نداشته باشد. بنابراین منبع جذب اولیه را هنگام ایجاد کاربر تنظیم کنید، نه در هر بار اجرای اپلیکیشن.
۱۴. یک کاربر، دو نقطه ورود
ربات و Mini App میتوانند از یک جدول users مشترک استفاده کنند که در آن هر کاربر با Telegram user ID خود شناسایی میشود.
برای مثال، کاربر ممکن است ابتدا ربات را اجرا کند و سپس Mini App را باز کند، یا برعکس.
قوانین انتساب:
- اولین handler که رکورد کاربر را میسازد، منبع جذب اولیه را تعیین میکند.
- handler دوم نباید این منبع را بازنویسی کند.
- بازدیدهای بعدی را میتوان جداگانه در
campaign_visitsثبت کرد.
از یک درج اتمی مانند INSERT … ON CONFLICT DO NOTHING استفاده کنید. این کار به جلوگیری از خطا در صورتی که درخواستهای ربات و Mini App تقریباً همزمان برسند کمک میکند.
۱۵. کانالها: ردیابی عضویت بر اساس لینک دعوت
اگر به ردیابی عضویت مخصوص خود نیاز دارید و نمیخواهید فقط به رابط Telegram تکیه کنید، برای هر کمپین یک لینک دعوت جداگانه بسازید و آن را همراه با کد کمپین ذخیره کنید.
نمونه ساخت لینک در Python:
# برای هر کمپین یک لینک بسازید و آن را همراه با کد ذخیره کنید
link = await bot.create_chat_invite_link(
CHANNEL_ID,
name="ad_sep_anna"
) # نام: ۱ تا ۳۲ کاراکتر
save_channel_link("ad_sep_anna", link.invite_link)نام لینک دعوت در این مثال به ۱ تا ۳۲ کاراکتر محدود است.
برای دریافت رویدادهای عضویت، ربات باید ادمین کانال باشد و بهروزرسانیهای chat_member مربوطه را دریافت کند. اگر درخواستهای عضویت به تأیید نیاز دارند، باید بهروزرسانیهای chat_join_request را هم دریافت کند.
نمونه پیکربندی polling:
# عضویتها به صورت بهروزرسانیهای chat_member میرسند: ربات باید ادمین باشد و آنها را درخواست کند
await dp.start_polling(
bot,
allowed_updates=[
"message",
"chat_member",
"chat_join_request"
]
)نمونه handler عضویت:
@router.chat_member()
async def member(update: ChatMemberUpdated):
joined = (
update.old_chat_member.status in ("left", "kicked")
and update.new_chat_member.status == "member"
)
if joined and update.invite_link:
save_channel_join(
update.invite_link.name,
update.new_chat_member.user.id
)اگر لینکی به تأیید مدیر نیاز دارد، chat_join_request را پردازش کنید. لینک دعوت در update.invite_link در دسترس است؛ پس از بررسی درخواست میتوانید approve_chat_join_request را فراخوانی کنید.
همچنین میتوانید خروج کاربران از کانال را ثبت کنید تا بفهمید چه کسانی ماندند.
Telegram از قبل تعداد عضویتها برای هر لینک دعوت را به مدیران نشان میدهد. پایگاه داده اختصاصی زمانی مفید است که بخواهید دادههای عضویت در کانال را با اطلاعات کاربران ربات یا آنالیتیکس دیگر ترکیب کنید.
۱۶. اختیاری: ردیابی کلیکها با ریدایرکت
برای شمارش کلیکها پیش از رسیدن کاربران به Telegram، یک endpoint ریدایرکت اختصاصی بسازید.
نمونه Python برای Mini App:
@app.get("/go/{code}")
async def go(code: str, request: Request):
agent = request.headers.get("user-agent", "")
if code_exists(code) and "TelegramBot" not in agent: # نادیده گرفتن خزنده پیشنمایش لینک Telegram
record_click(code)
return RedirectResponse(
f"https://t.me/{BOT}?startapp=ad_{code}",
status_code=302
)این مثال کد را اعتبارسنجی میکند و درخواستهایی را که User-Agent آنها شامل TelegramBot است کنار میگذارد تا درخواستهای پیشنمایش لینک Telegram بهعنوان کلیک عادی کاربر شمرده نشوند.
پیادهسازی را با زیرساخت خود تطبیق دهید و با لینکهای واقعی آزمایش کنید. ریدایرکت باید کاربر را به لینک درست ربات یا Mini App با پارامتر مناسب هدایت کند.
۱۷. نمونه گزارش
کوئری زیر برای هر کمپین تعداد بازدیدکنندگان یکتای لینکهای کمپین، کاربران جدید و کاربران فعالشده را نشان میدهد.
SELECT
c.code,
c.name,
(
SELECT count(*)
FROM campaign_visits v
WHERE v.code = c.code
) AS visitors,
(
SELECT count(*)
FROM users u
WHERE u.campaign = c.code
) AS new_users,
(
SELECT count(*)
FROM users u
WHERE u.campaign = c.code
AND u.first_action_at IS NOT NULL
) AS active
FROM campaigns c
ORDER BY new_users DESC;
-- first_action_at: زمانی که کاربر برای اولین بار اقدامی را انجام داد که کمپین برای آن پرداخت میکند (وظیفه، خرید)در این مثال، first_action_at زمانی است که کاربر برای اولین بار اقدام هدفی را انجام میدهد که تبلیغدهنده برای آن پرداخت میکند، مانند انجام یک وظیفه یا خرید.
معیار visitors کاربرانی را نشان میدهد که بازدید ثبتشدهای از کمپین مربوطه در campaign_visits دارند. این معیار با تعداد کلیکهای لینک برابر نیست، مگر اینکه کلیکها جداگانه از طریق ریدایرکت ثبت شوند.
۱۸. خطاهای رایج و محدودیتها
- ربات فقط وقتی کاربر
Startرا بزند پارامتر را دریافت میکند. همه کسانی که روی لینک کلیک میکنند ربات را اجرا نمیکنند، بنابراین تعداد اجراها ممکن است کمتر از تعداد کلیکها باشد. - اجرای دوباره به معنای کاربر جدید نیست. اگر کاربر چت را حذف کند و ربات را دوباره اجرا کند، ممکن است پارامتر دوباره ارسال شود، اما کاربر جدید نیست.
- منبع جذب اولیه را بازنویسی نکنید. برای تحلیل بازدیدهای بعدی از یک جدول بازدید جداگانه با برچسب زمانی استفاده کنید.
- حسابهای جدید و موجود را از هم جدا کنید. اگر هدف جذب کاربر است، بازدیدهای تکراری نباید تعداد کاربران جدید را افزایش دهند.
- رباتها و خودارجاعیها را حذف کنید.
is_botرا بررسی کنید و اجازه ندهید کاربران خودشان را ارجاع دهند. - محدودیتهای پارامتر را رعایت کنید. طول کل پارامتر
startنباید از ۶۴ کاراکتر بیشتر شود. از کدهای کوتاه مانندsep_annaاستفاده کنید تا برای پیشوندad_یاref_جا بماند. - انتساب ارجاع و تبلیغات را جدا نگه دارید. پیشوندها و قوانین پردازش متفاوت به جلوگیری از پاداشها و گزارشهای نادرست کمک میکنند.