بلاگ / ڈویلپر گائیڈ
ہینڈل سے YouTube چینل ID کیسے حاصل کریں (اور ID سے ہینڈل)
کریئیٹرز اپنا YouTube چینل @handle کی صورت میں شیئر کرتے ہیں، لیکن YouTube Data API میں تقریباً ہر چیز چینل ID پر چلتی ہے۔ اگر آپ صرف ہینڈل محفوظ کریں تو نام بدلتے ہی آپ کا ریکارڈ ٹوٹ جاتا ہے؛ اگر صرف ID محفوظ کریں تو آپ صارفین کو وہ نام نہیں دکھا سکتے جسے وہ پہچانتے ہیں۔ یہ گائیڈ بتاتی ہے کہ ایک API کال سے ہینڈل کو چینل ID میں کیسے بدلیں، ایک وقت میں 50 ID سے واپس ہینڈل کیسے لیں، پرانے /user/ اور /c/ URLs کا کیا کریں، اور ڈیفالٹ کوٹا کے اندر کیسے رہیں۔
ہینڈل، چینل ID اور پرانے نام
ایک YouTube چینل تک زیادہ سے زیادہ چار قسم کے شناخت کنندہ (identifier) سے پہنچا جا سکتا ہے۔ ان میں سے صرف ایک کے مستقل رہنے کی ضمانت ہے۔
| شناخت کنندہ | مثال | URL کی شکل | نوٹس |
|---|---|---|---|
| چینل ID | UC_x5XG1OV2P6uZZ5FSM9Ttw | youtube.com/channel/UC... | وہ ID جس سے YouTube چینل کی شناخت کرتا ہے۔ چھوٹے بڑے حروف کا فرق اہم ہے۔ اسے اپنی بنیادی کلید (primary key) بنائیں۔ |
| ہینڈل | @GoogleDevelopers | youtube.com/@GoogleDevelopers | منفرد، چھوٹے بڑے حروف سے فرق نہیں پڑتا، اور مالک اسے YouTube Studio میں بدل سکتا ہے۔ |
| پرانا یوزرنیم | GoogleDevelopers | youtube.com/user/GoogleDevelopers | پرانے یوزرنیم سسٹم سے۔ API کے forUsername فلٹر سے حل ہو جاتا ہے۔ |
| پرانا کسٹم URL | GoogleDevelopers | youtube.com/c/GoogleDevelopers | پرانے ذاتی URLs، جن کے بارے میں YouTube کہتا ہے کہ یہ کام کرتے رہیں گے۔ کوئی API فلٹر انہیں حل نہیں کرتا۔ |
چینل ID کو کلید کے طور پر محفوظ کریں اور ہینڈل کو دکھانے والی قدر کے طور پر رکھیں جسے آپ تازہ کرتے رہیں۔ باقی گائیڈ اسی بارے میں ہے کہ صارف نے جو کچھ دیا، اس سے اس ID تک کیسے پہنچیں۔
API key بنائیں اور کوٹا سمجھیں
- Step 1Google Cloud پروجیکٹ بنائیں
Google Cloud console میں نیا پروجیکٹ بنائیں یا موجودہ پروجیکٹ چنیں۔
- Step 2YouTube Data API v3 فعال کریں
APIs and services کھولیں، لائبریری میں YouTube Data API v3 تلاش کریں اور اسے پروجیکٹ کے لیے فعال کریں۔
- Step 3API key بنائیں
Credentials میں جا کر API key بنائیں۔ عوامی چینل ڈیٹا، جیسے ہینڈل یا ID سے
channels.list، کے لیے صرف key کافی ہے، OAuth کی ضرورت نہیں۔ key کو YouTube Data API تک محدود کر دیں۔ - Step 4key کو کوڈ سے باہر رکھیں
اسے کسی environment variable میں رکھیں، مثلاً
YOUTUBE_API_KEY، اور رن ٹائم پر پڑھیں۔ نیچے کی مثالیں یہی کرتی ہیں۔ - Step 5اپنا کوٹا چیک کریں
console میں اس API کا Quotas صفحہ آپ کی روزانہ حد اور استعمال دکھاتا ہے۔
Google کی دستاویزات کے مطابق اہم اعداد:
- ایک
channels.listکال کی قیمت 1 یونٹ ہے، چاہے آپ کوئی بھی فلٹر استعمال کریں۔ - پروجیکٹس کو تمام endpoints کے لیے روزانہ 10,000 یونٹ کی ڈیفالٹ حد ملتی ہے، سوائے
search.listاورvideos.insertکے، جن کی اب اپنی الگ حد ہے: ہر ایک کی روزانہ 100 کالز۔ - ہر درخواست پر کم از کم 1 یونٹ لگتا ہے، غلط درخواستوں پر بھی۔
- روزانہ کوٹا Pacific Time کے مطابق آدھی رات کو ری سیٹ ہوتا ہے۔
یعنی ڈیفالٹ کوٹا میں روزانہ تقریباً 10,000 ہینڈل تلاش ہو سکتے ہیں، اور ID سے تلاش اس سے 50 گنا تک زیادہ، کیونکہ ایک کال اسی ایک یونٹ میں ID کے ذریعے 50 چینلز لا سکتی ہے۔
forHandle سے ہینڈل کو چینل ID میں بدلیں
channels.list بالکل ایک فلٹر لیتا ہے۔ forHandle فلٹر YouTube ہینڈل لیتا ہے، اور ریفرنس کے مطابق قدر کے شروع میں @ لگایا جا سکتا ہے، اس لیے GoogleDevelopers اور @GoogleDevelopers دونوں چلتے ہیں۔ اگر صرف ID چاہیے تو part=id مانگیں؛ جواب چھوٹا ہوتا ہے اور قیمت وہی رہتی ہے۔
curl -s "https://www.googleapis.com/youtube/v3/channels?part=id&forHandle=@GoogleDevelopers&key=$YOUTUBE_API_KEY"نیچے کی Node مثال درخواست کو ایک ہیلپر listChannels میں لپیٹتی ہے جو باقی گائیڈ میں بار بار استعمال ہوتا ہے۔ کچھ نہ ملے تو یہ خالی فہرست لوٹاتا ہے اور اصل غلطیوں پر، جیسے غلط key یا ختم شدہ کوٹا، error پھینکتا ہے۔
const API = "https://www.googleapis.com/youtube/v3/channels";
async function listChannels(params) {
const key = process.env.YOUTUBE_API_KEY;
if (!key) throw new Error("Set YOUTUBE_API_KEY");
const url = new URL(API);
url.search = new URLSearchParams({ ...params, key }).toString();
const res = await fetch(url, { signal: AbortSignal.timeout(10_000) });
const data = await res.json();
if (!res.ok) {
const reason = data.error?.errors?.[0]?.reason;
if (reason === "channelNotFound") return [];
throw new Error(`YouTube API ${res.status} ${reason ?? ""}: ${data.error?.message}`);
}
return data.items ?? []; // no match: items is empty or missing
}
/** "@GoogleDevelopers" or "GoogleDevelopers" -> "UC_x5XG1OV2P6uZZ5FSM9Ttw" or null */
export async function channelIdFromHandle(handle) {
const items = await listChannels({ part: "id", forHandle: handle.trim() });
return items[0]?.id ?? null;
}
/** Legacy username from a youtube.com/user/<name> URL -> channel ID or null */
export async function channelIdFromUsername(username) {
const items = await listChannels({ part: "id", forUsername: username.trim() });
return items[0]?.id ?? null;
}
/** Any number of channel IDs -> Map(id -> { title, customUrl }) */
export async function channelsById(ids) {
const unique = [...new Set(ids)];
const found = new Map();
for (let i = 0; i < unique.length; i += 50) {
const batch = unique.slice(i, i + 50);
const items = await listChannels({ part: "snippet", id: batch.join(","), maxResults: "50" });
for (const ch of items) {
found.set(ch.id, { title: ch.snippet.title, customUrl: ch.snippet.customUrl ?? null });
}
}
return found; // IDs missing from the map were not found
}import os
import requests
API = "https://www.googleapis.com/youtube/v3/channels"
def list_channels(**params):
key = os.environ.get("YOUTUBE_API_KEY")
if not key:
raise RuntimeError("Set YOUTUBE_API_KEY")
response = requests.get(API, params={**params, "key": key}, timeout=10)
data = response.json()
if not response.ok:
errors = data.get("error", {}).get("errors") or [{}]
reason = errors[0].get("reason")
if reason == "channelNotFound":
return []
raise RuntimeError(f"YouTube API {response.status_code} {reason}: {data.get('error', {}).get('message')}")
return data.get("items", []) # no match: items is empty or missing
def channel_id_from_handle(handle):
"""'@GoogleDevelopers' or 'GoogleDevelopers' -> 'UC_x5XG1OV2P6uZZ5FSM9Ttw' or None"""
items = list_channels(part="id", forHandle=handle.strip())
return items[0]["id"] if items else None
def channel_id_from_username(username):
"""Legacy username from a youtube.com/user/<name> URL -> channel ID or None"""
items = list_channels(part="id", forUsername=username.strip())
return items[0]["id"] if items else None
def channels_by_id(ids):
"""Any number of channel IDs -> {id: {"title", "customUrl"}}; missing IDs were not found"""
unique = list(dict.fromkeys(ids))
found = {}
for i in range(0, len(unique), 50):
batch = unique[i:i + 50]
for ch in list_channels(part="snippet", id=",".join(batch), maxResults=50):
found[ch["id"]] = {
"title": ch["snippet"]["title"],
"customUrl": ch["snippet"].get("customUrl"),
}
return foundہینڈل ویسے ہی بھیجیں جیسے صارف نے لکھا، البتہ URL کی percent-encoding پہلے ڈی کوڈ کر لیں۔ ہینڈل میں صرف ASCII نہیں بلکہ کئی رسم الخط کے حروف ہو سکتے ہیں، اور URLSearchParams اور requests دونوں پیرامیٹر کو خود encode کر دیتے ہیں۔
پرانے یوزرنیم اور /c/ کسٹم URLs
کریئیٹرز کے بائیو اور اسپریڈشیٹس میں پرانے لنکس اکثر ہینڈل سے پہلے والی کسی شکل میں ہوتے ہیں۔
- `youtube.com/user/<name>`: اوپر والے
channelIdFromUsernameکے ذریعے نام کوforUsernameمیں بھیجیں۔ اس پر بھی کسی اورchannels.listکال کی طرح 1 یونٹ لگتا ہے۔ - `youtube.com/c/<name>`: کسٹم URLs کے لیے کوئی
channels.listفلٹر نہیں۔ بہت سے چینلز نے اپنے پرانے کسٹم نام جیسا ہینڈل چنا، اس لیے اسی لفظ کے ساتھforHandleآزمانا کام کر سکتا ہے، لیکن مل جانا اس بات کا ثبوت نہیں کہ یہ وہی چینل ہے۔ اس پر بھروسہ کرنے سے پہلے کسی اور طریقے سے تصدیق کریں، مثلاً عنوان دیکھ کر یا صفحے کا canonical لنک پڑھ کر (نیچے بیان کیا گیا ہے)۔ - `search.list` کسی سوال کے لیے درجہ بند نتائج دیتا ہے، درست تلاش نہیں، اور اس کی ڈیفالٹ حد روزانہ 100 کالز ہے۔ شناخت کنندہ حل کرنے کے لیے اس سے بچیں۔
چینل ID سے ہینڈل، ایک وقت میں 50
الٹی سمت میں id فلٹر استعمال ہوتا ہے، جو کاما سے الگ چینل IDs کی فہرست لیتا ہے۔ part=snippet مانگیں اور snippet.customUrl پڑھیں۔ اوپر والا channelsById دہرائی گئی IDs ہٹاتا ہے، انہیں 50 کے حصوں میں بھیجتا ہے، اور ID کے حساب سے ایک map لوٹاتا ہے۔ جو IDs map میں نہیں، وہ نہیں ملیں، حذف ہو چکی ہیں یا API کو نظر نہیں آتیں۔
- بیچ کا سائز۔ ریفرنس
idکو کاما سے الگ فہرست بتاتا ہے اورmaxResultsکی حد 50 رکھتا ہے۔ IDs کی تعداد کی کوئی الگ حد نہیں بتاتا، اس لیے کوڈ ہر کال میں 50 بھیجتا ہے اورmaxResults=50رکھتا ہے تاکہ ڈیفالٹ 5 کبھی بیچ کو نہ کاٹے۔ - ترتیب۔ یہ نہ سمجھیں کہ نتائج اسی ترتیب میں آئیں گے جس میں آپ نے بھیجے۔ جواب کو
idکے حساب سے انڈیکس کریں۔ - `customUrl` اختیاری ہے۔ ریفرنس اسے صرف چینل کا کسٹم URL بتاتا ہے، اور 2016 کے ایک ریویژن نوٹ کے مطابق ہر چینل کے پاس یہ نہیں ہوتا۔ اسے nullable سمجھیں، شروع کا
@ہو تو ہٹا دیں، اور اس پر کچھ بنانے سے پہلے چند جانے پہچانے چینلز پر اس کی شکل جانچ لیں۔ - عنوان ہینڈل نہیں ہوتے۔
snippet.titleدکھایا جانے والا نام ہے۔ یہ منفرد نہیں اور اس میں اسپیس اور ایموجی ہو سکتے ہیں۔
نہ ملنا، غلطیاں اور کیشنگ
جس تلاش سے کچھ نہ ملے وہ غلطی نہیں۔ forHandle اور forUsername کے لیے جواب میں بس کوئی items نہیں ہوتے، اس لیے خالی یا غائب items array چیک کریں۔ channels.list کی دستاویزی غلطیاں یہ ہیں:
| غلطی کی وجہ | HTTP | کب ہوتی ہے | کیا کریں |
|---|---|---|---|
200 جواب میں کوئی items نہیں | 200 | ہینڈل یا یوزرنیم موجود نہیں | null لوٹائیں؛ نہ ملنے کو تھوڑی دیر کے لیے کیش کریں |
channelNotFound | 404 | id پیرامیٹر میں کوئی چینل نہیں مل سکا | اسے نہ ملا سمجھیں، جیسے اوپر کے ہیلپرز کرتے ہیں |
invalidCriteria | 400 | درخواست میں ایک سے زیادہ فلٹر | forHandle، forUsername یا id میں سے بالکل ایک بھیجیں |
channelForbidden | 403 | چینل اس درخواست کو سپورٹ نہیں کرتا یا درست اجازت نہیں | لاگ کریں اور چینل چھوڑ دیں |
quotaExceeded | 403 | آپ کے پروجیکٹ نے روزانہ کوٹا استعمال کر لیا | رک جائیں اور Pacific Time کی آدھی رات کے بعد دوبارہ کوشش کریں، یا زیادہ کوٹا مانگیں |
badRequest (API key درست نہیں) | 400 | key غائب یا غلط | کنفیگریشن ٹھیک کریں؛ دوبارہ کوشش نہ کریں |
کوٹا اور وقت بچانے کے لیے نتائج کیش کریں، لیکن ڈیٹا محفوظ کرنے کے بارے میں YouTube کے اصولوں کا خیال رکھیں۔ YouTube API Services Developer Policies (سیکشن III.E.4) کے مطابق آپ غیر مجاز API ڈیٹا زیادہ سے زیادہ 30 کیلنڈر دن محفوظ رکھ سکتے ہیں، اس کے بعد اسے حذف یا تازہ کرنا ضروری ہے۔ چھوٹے حروف والے ہینڈل کو کلید بنا کر 30 دن سے کافی کم TTL والا کیش زیادہ تر فائدہ دے دیتا ہے:
import { channelIdFromHandle } from "./youtube.mjs";
const TTL_MS = 7 * 24 * 60 * 60 * 1000; // refresh well inside YouTube's 30-day limit
const cache = new Map(); // lowercase handle -> { id, at }
export async function cachedChannelId(handle) {
const key = handle.trim().replace(/^@/, "").toLowerCase();
const hit = cache.get(key);
if (hit && Date.now() - hit.at < TTL_MS) return hit.id;
const id = await channelIdFromHandle(handle);
cache.set(key, { id, at: Date.now() }); // caches misses (null) too
return id;
}پروڈکشن میں یہی منطق Redis یا expires_at کالم والی ڈیٹا بیس ٹیبل میں رکھیں، اور نہ ملنے والے نتائج کا TTL ملنے والوں سے کم رکھیں تاکہ نیا بنا ہینڈل جلد پکڑا جائے۔
API key کے بغیر متبادل: چینل کا صفحہ پڑھنا
عوامی چینل صفحات کے HTML میں چینل ID موجود ہوتی ہے۔ https://www.youtube.com/@GoogleDevelopers کی درخواست اس وقت ایسا صفحہ لوٹاتی ہے جس کا <link rel="canonical"> https://www.youtube.com/channel/UC_x5XG1OV2P6uZZ5FSM9Ttw کی طرف اشارہ کرتا ہے، اور /c/ اور /user/ صفحات کا بھی یہی حال ہے، اس لیے اندازے کے بغیر /c/ نام حل کرنے کا یہی ایک طریقہ ہے۔
// Unofficial fallback: reads the public channel page. Fragile, prefer the API.
export async function channelIdFromPage(handle) {
const url = `https://www.youtube.com/@${encodeURIComponent(handle.replace(/^@/, ""))}`;
const res = await fetch(url, {
headers: { "Accept-Language": "en-US" },
signal: AbortSignal.timeout(10_000),
});
if (!res.ok) return null;
const html = await res.text();
const match = html.match(/<link rel="canonical" href="https:\/\/www\.youtube\.com\/channel\/(UC[A-Za-z0-9_-]{22})"/);
return match?.[1] ?? null;
}import re
from urllib.parse import quote
import requests
CANONICAL = re.compile(r'<link rel="canonical" href="https://www\.youtube\.com/channel/(UC[A-Za-z0-9_-]{22})"')
def channel_id_from_page(handle):
"""Unofficial fallback: reads the public channel page. Fragile, prefer the API."""
url = "https://www.youtube.com/@" + quote(handle.lstrip("@"), safe="._-")
response = requests.get(url, headers={"Accept-Language": "en-US"}, timeout=10)
if not response.ok:
return None
match = CANONICAL.search(response.text)
return match.group(1) if match else Noneاسے کم سے کم اور صرف وہاں استعمال کریں جہاں API مدد نہ کر سکے۔ یہ غیر سرکاری اور نازک طریقہ ہے:
- markup کوئی دستاویزی انٹرفیس نہیں اور کسی بھی وقت بدل سکتا ہے۔
- YouTube خودکار درخواستوں کو، خاص طور پر کلاؤڈ IP رینجز سے، consent صفحات، ریٹ لمٹ یا CAPTCHA دکھا سکتا ہے۔ ہماری جانچ میں کلاؤڈ سرور سے
youtu.beلنک کھولنے پر آخر میں Google کا CAPTCHA صفحہ آیا۔ - سائٹ تک خودکار رسائی YouTube کی Terms of Service سے ٹکرا سکتی ہے۔ انہیں پڑھیں اور سرکاری API کو ترجیح دیں۔
طریقوں کا موازنہ
| طریقہ | ان پٹ | قیمت | فائدے | نقصانات |
|---|---|---|---|---|
channels.list مع forHandle | ہینڈل، @ کے ساتھ یا بغیر | فی ہینڈل 1 یونٹ | سرکاری، بالکل درست، ہر ہینڈل پر کام کرتا ہے | ہر کال میں ایک ہینڈل |
channels.list مع forUsername | پرانا /user/ نام | فی نام 1 یونٹ | سرکاری، بالکل درست | صرف پرانے یوزرنیمز کے لیے |
channels.list مع id | 50 تک چینل IDs | ہر 50 IDs پر 1 یونٹ | سرکاری، بیچ میں، عنوان اور customUrl دیتا ہے | customUrl غائب ہو سکتا ہے |
search.list | آزاد متن | الگ حد، ڈیفالٹ روزانہ 100 کالز | نام سے چینل ڈھونڈتا ہے | درجہ بند اندازے، درست نہیں؛ کم گنجائش |
| چینل صفحے کا canonical لنک | کوئی بھی چینل URL، /c/ سمیت | کوئی API کوٹا نہیں | key کے بغیر چلتا ہے؛ /c/ نام حل کرتا ہے | غیر سرکاری، نازک، بلاک ہو سکتا ہے، شرائط سے ٹکرا سکتا ہے |
زیادہ تر پروڈکٹس کے لیے درست ترتیب سادہ ہے: forHandle سے ہینڈل حل کریں، چینل ID محفوظ کریں، id فلٹر سے 50 کے بیچ میں ہینڈل تازہ کریں، اور کبھی کبھار آنے والے /c/ لنک کے لیے صفحے والا متبادل ایک فلیگ کے پیچھے رکھیں۔ اگر آپ کو دوسرے پلیٹ فارمز پر کریئیٹر کے اکاؤنٹس بھی چاہییں تو sociallinks.dev ایک API ہے جو ایک Instagram، TikTok، YouTube یا X پروفائل URL لیتا ہے اور دوسرے پلیٹ فارمز پر کریئیٹر کے اکاؤنٹس لوٹاتا ہے، ہر میچ کے ساتھ اعتماد کا اسکور اور ثبوت۔
عام سوالات
کیا forHandle میں ہینڈل بھیجتے وقت @ ضروری ہے؟
نہیں۔ channels.list ریفرنس کہتا ہے کہ forHandle کی قدر کے شروع میں @ لگایا جا سکتا ہے، اور مثال میں GoogleDevelopers اور @GoogleDevelopers دونوں دیتا ہے۔
ہینڈل کی ایک تلاش پر کتنا کوٹا لگتا ہے؟
ایک یونٹ۔ ہر channels.list کال پر 1 یونٹ لگتا ہے، اور ڈیفالٹ حد روزانہ 10,000 یونٹ ہے جو Pacific Time کی آدھی رات کو ری سیٹ ہوتی ہے۔ غلط درخواستوں پر بھی کم از کم 1 یونٹ لگتا ہے۔
کیا ایک کال میں کئی ہینڈل تلاش ہو سکتے ہیں؟
نہیں۔ forHandle ایک ہی ہینڈل لیتا ہے۔ صرف id فلٹر کاما سے الگ فہرست قبول کرتا ہے، اس لیے الٹی سمت (IDs سے ہینڈل) کو بیچ میں کریں اور سیدھی سمت کو کیش کریں۔
کیا چینل ID کبھی بدلتی ہے؟
چینل ID وہ شناخت کنندہ ہے جس سے YouTube چینل کی منفرد شناخت کرتا ہے۔ ہینڈل یا عنوان بدلنے سے یہ نہیں بدلتی۔ اسی لیے یہ درست بنیادی کلید ہے۔ ہینڈل، عنوان اور کسٹم URLs سب بدل سکتے ہیں۔
snippet.customUrl خالی کیوں آتا ہے؟
ہر چینل کے پاس کسٹم URL نہیں ہوتا، جیسا کہ YouTube کی اپنی ریویژن ہسٹری میں لکھا ہے۔ اس فیلڈ کو اختیاری سمجھیں اور اس کی جگہ /channel/UC... URL دکھائیں۔
نتائج کتنی دیر کیش کر سکتا ہوں؟
YouTube کی Developer Policies محفوظ API ڈیٹا کو حذف یا تازہ کرنے سے پہلے 30 کیلنڈر دن تک محدود کرتی ہیں۔ ملنے والے نتائج کے لیے ایک ہفتہ یا کم اور نہ ملنے والوں کے لیے اس سے کم TTL آپ کو اس حد کے اندر رکھتا ہے۔