Blog / Guide développeur
Comment analyser et normaliser les URL de profils de réseaux sociaux (Instagram, TikTok, YouTube, X)
Les créateurs collent leurs liens de profil sous toutes les formes possibles : avec ou sans www, depuis l’application mobile avec des paramètres de suivi, en liens courts, en anciennes URL twitter.com, ou en lien vers une publication plutôt que vers le profil. Si votre produit stocke ces chaînes telles quelles, le même créateur apparaît trois fois et vos jointures échouent sans bruit. Ce guide montre comment transformer n’importe quelle URL de profil Instagram, TikTok, YouTube ou X en une plateforme, un pseudo ou un ID de chaîne, et une URL canonique unique, avec du code testé en JavaScript et en Python.
Pourquoi normaliser les URL de profils
Une URL de profil est un identifiant, et un identifiant ne fonctionne que s’il s’écrit d’une seule façon. https://www.instagram.com/natgeo/, instagram.com/NatGeo?igsh=MWQ1ZGUxMzBkMA== et https://m.instagram.com/natgeo pointent toutes vers le même compte, mais en tant que chaînes ce sont trois valeurs différentes.
- Dédoublonnage. Quand un créateur s’inscrit deux fois, ou que deux membres de l’équipe ajoutent le même influenceur à une campagne, vous voulez un seul enregistrement, pas deux.
- Jointures. Rapprocher votre CRM d’un export d’un autre outil ne fonctionne que si les deux côtés utilisent la même clé.
- Rejeter tôt les saisies invalides. Un lien vers un Reel, une page de recherche ou un écran de connexion n’est pas un profil. Le repérer à la saisie coûte moins cher que de nettoyer plus tard.
- Appels d’API. Les API officielles attendent un pseudo ou un ID, pas une URL chargée de paramètres de suivi.
L’objectif est une petite fonction stricte : elle accepte ce que les utilisateurs collent réellement, renvoie un résultat normalisé pour les vraies URL de profil, et null pour tout le reste.
Les formes d’URL que vous rencontrerez
Les formes ci-dessous ont été vérifiées sur les sites en ligne en octobre 2026. Les plateformes modifient leur routage sans prévenir : voyez-y un instantané et tenez vos cas de test à jour.
- Les profils se trouvent à
https://www.instagram.com/<handle>/. Les hôtesinstagram.cometm.instagram.comredirigent verswww.instagram.com. - Les liens partagés depuis l’application portent souvent un paramètre
?igsh=. Supprimez toute la chaîne de requête et le fragment. - Les publications sont
/p/<code>/, les Reels/reel/<code>/et les stories/stories/<handle>/<id>/. Aucune n’est une URL de profil, même quand le pseudo figure dans le chemin. - Les routes de l’application comme
/explore/,/accounts/et/direct/partagent le premier segment du chemin avec les pseudos : il vous faut donc une liste de mots réservés. La liste du code ci-dessous n’est pas exhaustive.
TikTok
- Les profils sont
https://www.tiktok.com/@<handle>. L’hôtetiktok.comredirige verswww. - Les vidéos sont
/@<handle>/video/<id>. Le pseudo est celui de l’auteur, mais l’URL est un lien de vidéo : l’analyseur ci-dessous la rejette donc. - Les liens courts sur
vm.tiktok.com,vt.tiktok.cometwww.tiktok.com/t/<code>/ne contiennent aucun pseudo. Il faut suivre la redirection HTTP pour voir où ils mènent, puis analyser l’URL finale. - Un chemin sans
@(par exempletiktok.com/khaby.lame) n’est pas une URL de profil.
YouTube
- URL de pseudo :
https://www.youtube.com/@<handle>. Le centre d’aide de YouTube indique qu’un pseudo devient automatiquement l’URL de la chaîne. - URL d’ID de chaîne :
https://www.youtube.com/channel/UC.... C’est la forme stable. En pratique, les ID de chaîne font 24 caractères et commencent parUC. Google ne documente pas ce format : la vérification ci-dessous est un garde-fou, pas une règle. - Anciennes formes :
/user/<username>et/c/<customname>. Les deux fonctionnent encore aujourd’hui, et le centre d’aide indique que les anciennes URL personnalisées continuent de fonctionner. Aucune ne donne l’ID de chaîne sans recherche. - Un simple
youtube.com/<name>fonctionne aussi encore pour certaines chaînes, mais il partage l’espace de noms avec les routes du site : l’analyseur ci-dessous ne l’accepte donc pas. - Les onglets comme
/@handle/videoset/channel/UC.../featuredappartiennent à la chaîne et peuvent être acceptés sans risque. m.youtube.comredirige verswww.youtube.com. Les liens de vidéo (/watch?v=,/shorts/,youtu.be/<id>) ne sont pas des chaînes.
X (anciennement Twitter)
- Les profils sont
https://x.com/<handle>.twitter.com,www.twitter.com,www.x.com,mobile.twitter.cometmobile.x.comredirigent tous vers un profil surx.comoutwitter.com: traitez-les comme une seule plateforme. - Les publications sont
/<handle>/status/<id>. Comme les vidéos TikTok, elles nomment l’auteur mais ne sont pas des URL de profil. - Les routes de l’application comme
/home,/explore,/search,/settings,/notifications,/messageset tout ce qui est sous/i/ne sont pas des pseudos. - Les liens partagés ajoutent souvent les paramètres
?s=et?t=. Supprimez-les.
Règles de caractères des pseudos par plateforme
Valider le pseudo permet d’attraper les fautes de frappe et la plupart des chemins qui ne sont pas des profils. Appliquez les règles des plateformes là où elles les publient, et gardez des vérifications souples là où elles ne le font pas, pour ne jamais rejeter un vrai compte.
| Plateforme | Caractères autorisés | Longueur | Casse | Source |
|---|---|---|---|---|
| Lettres, chiffres, points, tirets bas | 30 est souvent cité ; introuvable dans les pages d’aide d’Instagram | À traiter comme insensible à la casse ; stocker en minuscules | Le centre d’aide Instagram mentionne points, chiffres et tirets bas | |
| TikTok | Lettres, chiffres, tirets bas, points ; ne peut pas finir par un point | 2 à 24 | Insensible à la casse dans les URL (@TikTok renvoie vers tiktok) | Assistance TikTok, modifier son nom d’utilisateur |
| YouTube | Lettres ou chiffres des langues prises en charge, plus tirets bas, traits d’union, points et points médians latins (ni en premier ni en dernier) | 3 à 30 pour la plupart des écritures ; limites plus courtes pour le han, le hangûl et quelques autres écritures | Insensible à la casse | Aide YouTube, règles sur les pseudos |
| X | Lettres, chiffres et tirets bas | Jusqu’à 15 ; les nouveaux noms doivent dépasser 4 caractères, mais d’anciens pseudos courts existent | Insensible à la casse (x.com/JACK devient x.com/jack) | Centre d’aide X, règles des noms d’utilisateur |
Un algorithme de normalisation
- Step 1Nettoyez et ajoutez un schéma
Retirez les espaces et les chevrons parasites. Si la saisie n’a pas de schéma, ajoutez
https://devant pour queinstagram.com/natgeosoit analysable. - Step 2Analysez avec un vrai analyseur d’URL
Utilisez
new URL()en JavaScript ouurllib.parse.urlspliten Python, jamais une expression régulière sur toute la chaîne. Un analyseur gère les ports, les informations d’utilisateur et les caractères encodés, et empêchehttps://instagram.com@evil.com/natgeode passer pour Instagram. - Step 3Normalisez l’hôte
Passez-le en minuscules et retirez un éventuel préfixe
www.,m.oumobile.. Cherchez-le ensuite dans une liste blanche exacte d’hôtes. N’utilisez jamaisincludes("instagram.com"), qui accepte aussiinstagram.com.evil.com. - Step 4Supprimez la chaîne de requête et le fragment
Les paramètres de suivi comme
igsh,s,tetlangne changent jamais le profil vers lequel pointe une URL. - Step 5Découpez et décodez le chemin
Découpez sur
/, supprimez les segments vides (ce qui retire les barres obliques finales) et décodez chacun en pourcentage. Traitez un encodage mal formé comme une saisie invalide. - Step 6Aiguillez selon la plateforme
Appliquez la forme de chaque plateforme : un segment sur Instagram et X, un segment
@sur TikTok, et@handle,channel/UC...,user/nameouc/namesur YouTube. Rejetez les mots réservés. - Step 7Validez le pseudo et passez-le en minuscules
Vérifiez le pseudo selon les règles de caractères de la plateforme, puis passez-le en minuscules. Ne mettez pas en minuscules les ID de chaîne YouTube : ils sont sensibles à la casse.
- Step 8Construisez l’URL canonique
Reconstruisez l’URL à partir de ses parties sur un hôte fixe, pour que toutes les saisies équivalentes produisent exactement la même chaîne.
- Step 9Traitez les liens courts à part
Détectez les liens courts TikTok, suivez la redirection avec une requête HTTP, et repassez l’URL finale dans l’analyseur. Gardez cela hors de la fonction pure pour que l’analyse reste rapide et testable.
Le code en JavaScript et en Python
Les deux fonctions renvoient les mêmes objets pour la même saisie : { platform, handle, canonicalUrl } pour les URL de pseudo, { platform, channelId, canonicalUrl } pour les ID de chaîne YouTube, username ou customName pour les deux anciennes formes YouTube, et null pour tout ce qui n’est pas une URL de profil. Aucune n’a besoin de dépendance.
JavaScript (Node 18+)
const HOSTS = {
"instagram.com": "instagram",
"tiktok.com": "tiktok",
"youtube.com": "youtube",
"x.com": "x",
"twitter.com": "x",
};
const IG_RESERVED = new Set(["p", "reel", "reels", "tv", "stories", "explore", "accounts", "direct"]);
const X_RESERVED = new Set([
"home", "explore", "search", "i", "settings", "notifications", "messages",
"compose", "intent", "hashtag", "login", "signup", "logout", "tos", "privacy",
]);
const IG_HANDLE = /^[a-z0-9._]{1,30}$/;
const TIKTOK_HANDLE = /^[a-z0-9._]{2,24}$/;
const X_HANDLE = /^[a-z0-9_]{1,15}$/;
const YT_HANDLE = /^[\p{L}\p{M}\p{N}._\-·]{1,30}$/u;
const YT_CHANNEL_ID = /^UC[A-Za-z0-9_-]{22}$/;
const YT_LEGACY_NAME = /^[A-Za-z0-9._-]{1,100}$/;
export function parseProfileUrl(input) {
if (typeof input !== "string") return null;
let raw = input.trim().replace(/^<|>$/g, "");
if (!raw) return null;
if (!/^[a-z][a-z0-9+.-]*:\/\//i.test(raw)) raw = "https://" + raw;
let url;
try {
url = new URL(raw);
} catch {
return null;
}
if (url.protocol !== "https:" && url.protocol !== "http:") return null;
const host = url.hostname.toLowerCase().replace(/^(www|m|mobile)\./, "");
const platform = HOSTS[host];
if (!platform) return null;
let segments;
try {
segments = url.pathname.split("/").filter(Boolean).map(decodeURIComponent);
} catch {
return null; // malformed percent-encoding
}
const [first = "", second] = segments;
if (platform === "instagram") {
const handle = first.toLowerCase();
if (segments.length !== 1 || IG_RESERVED.has(handle) || !IG_HANDLE.test(handle)) return null;
return { platform, handle, canonicalUrl: `https://www.instagram.com/${handle}/` };
}
if (platform === "tiktok") {
if (segments.length !== 1 || !first.startsWith("@")) return null;
const handle = first.slice(1).toLowerCase();
if (!TIKTOK_HANDLE.test(handle) || handle.endsWith(".")) return null;
return { platform, handle, canonicalUrl: `https://www.tiktok.com/@${handle}` };
}
if (platform === "x") {
const handle = first.toLowerCase();
if (segments.length !== 1 || X_RESERVED.has(handle) || !X_HANDLE.test(handle)) return null;
return { platform, handle, canonicalUrl: `https://x.com/${handle}` };
}
// YouTube: /@handle[/tab], /channel/UC...[/tab], /user/name, /c/name
if (first.startsWith("@")) {
const handle = first.slice(1).toLowerCase();
if (!YT_HANDLE.test(handle) || /^[._\-·]|[._\-·]$/.test(handle)) return null;
return { platform, handle, canonicalUrl: `https://www.youtube.com/@${encodeURIComponent(handle)}` };
}
if (first === "channel" && second && YT_CHANNEL_ID.test(second)) {
return { platform, channelId: second, canonicalUrl: `https://www.youtube.com/channel/${second}` };
}
if ((first === "user" || first === "c") && second && segments.length === 2 && YT_LEGACY_NAME.test(second)) {
const key = first === "user" ? "username" : "customName";
return { platform, [key]: second, canonicalUrl: `https://www.youtube.com/${first}/${second}` };
}
return null; // videos, shorts, playlists, search and anything else
}
const SHORT_HOSTS = new Set(["vm.tiktok.com", "vt.tiktok.com"]);
export function isShortLink(input) {
try {
const url = new URL(/^https?:\/\//i.test(input) ? input : "https://" + input);
const host = url.hostname.toLowerCase();
return SHORT_HOSTS.has(host) || (host.replace(/^www\./, "") === "tiktok.com" && url.pathname.startsWith("/t/"));
} catch {
return false;
}
}
export async function resolveShortLink(input) {
const res = await fetch(/^https?:\/\//i.test(input) ? input : "https://" + input, {
redirect: "follow",
signal: AbortSignal.timeout(10_000),
});
await res.body?.cancel();
return res.url; // the final URL after every redirect
}resolveShortLink utilise le fetch intégré, qui suit les redirections et expose l’adresse finale dans res.url. Appelez parseProfileUrl(await resolveShortLink(link)) quand isShortLink(link) est vrai. Un lien court peut aussi mener à une vidéo plutôt qu’à un profil ; l’analyseur renvoie alors à juste titre null.
Python 3
import re
import unicodedata
import urllib.request
from urllib.parse import quote, unquote, urlsplit
HOSTS = {
"instagram.com": "instagram",
"tiktok.com": "tiktok",
"youtube.com": "youtube",
"x.com": "x",
"twitter.com": "x",
}
IG_RESERVED = {"p", "reel", "reels", "tv", "stories", "explore", "accounts", "direct"}
X_RESERVED = {
"home", "explore", "search", "i", "settings", "notifications", "messages",
"compose", "intent", "hashtag", "login", "signup", "logout", "tos", "privacy",
}
IG_HANDLE = re.compile(r"[a-z0-9._]{1,30}")
TIKTOK_HANDLE = re.compile(r"[a-z0-9._]{2,24}")
X_HANDLE = re.compile(r"[a-z0-9_]{1,15}")
YT_CHANNEL_ID = re.compile(r"UC[A-Za-z0-9_-]{22}")
YT_LEGACY_NAME = re.compile(r"[A-Za-z0-9._-]{1,100}")
YT_PUNCT = "._-·"
def _is_youtube_handle(handle):
if not 1 <= len(handle) <= 30 or handle[0] in YT_PUNCT or handle[-1] in YT_PUNCT:
return False
return all(
ch.isalnum() or ch in YT_PUNCT or unicodedata.category(ch).startswith("M")
for ch in handle
)
def parse_profile_url(value):
if not isinstance(value, str):
return None
raw = value.strip().strip("<>")
if not raw:
return None
if not re.match(r"^[a-z][a-z0-9+.-]*://", raw, re.I):
raw = "https://" + raw
try:
url = urlsplit(raw)
host = (url.hostname or "").lower()
except ValueError:
return None
if url.scheme.lower() not in ("http", "https"):
return None
host = re.sub(r"^(www|m|mobile)\.", "", host)
platform = HOSTS.get(host)
if not platform:
return None
try:
segments = [unquote(s, errors="strict") for s in url.path.split("/") if s]
except UnicodeDecodeError:
return None # malformed percent-encoding
first = segments[0] if segments else ""
second = segments[1] if len(segments) > 1 else None
if platform == "instagram":
handle = first.lower()
if len(segments) != 1 or handle in IG_RESERVED or not IG_HANDLE.fullmatch(handle):
return None
return {"platform": platform, "handle": handle,
"canonicalUrl": f"https://www.instagram.com/{handle}/"}
if platform == "tiktok":
if len(segments) != 1 or not first.startswith("@"):
return None
handle = first[1:].lower()
if not TIKTOK_HANDLE.fullmatch(handle) or handle.endswith("."):
return None
return {"platform": platform, "handle": handle,
"canonicalUrl": f"https://www.tiktok.com/@{handle}"}
if platform == "x":
handle = first.lower()
if len(segments) != 1 or handle in X_RESERVED or not X_HANDLE.fullmatch(handle):
return None
return {"platform": platform, "handle": handle, "canonicalUrl": f"https://x.com/{handle}"}
# YouTube: /@handle[/tab], /channel/UC...[/tab], /user/name, /c/name
if first.startswith("@"):
handle = first[1:].lower()
if not _is_youtube_handle(handle):
return None
return {"platform": platform, "handle": handle,
"canonicalUrl": f"https://www.youtube.com/@{quote(handle, safe='._-')}"}
if first == "channel" and second and YT_CHANNEL_ID.fullmatch(second):
return {"platform": platform, "channelId": second,
"canonicalUrl": f"https://www.youtube.com/channel/{second}"}
if first in ("user", "c") and second and len(segments) == 2 and YT_LEGACY_NAME.fullmatch(second):
key = "username" if first == "user" else "customName"
return {"platform": platform, key: second,
"canonicalUrl": f"https://www.youtube.com/{first}/{second}"}
return None # videos, shorts, playlists, search and anything else
SHORT_HOSTS = {"vm.tiktok.com", "vt.tiktok.com"}
def is_short_link(value):
url = urlsplit(value if re.match(r"^https?://", value, re.I) else "https://" + value)
host = (url.hostname or "").lower()
return host in SHORT_HOSTS or (
re.sub(r"^www\.", "", host) == "tiktok.com" and url.path.startswith("/t/")
)
def resolve_short_link(value, timeout=10):
if not re.match(r"^https?://", value, re.I):
value = "https://" + value
request = urllib.request.Request(value, headers={"User-Agent": "Mozilla/5.0"})
with urllib.request.urlopen(request, timeout=timeout) as response:
return response.geturl() # the final URL after every redirectEn Python, \w et str.isalnum() couvrent les lettres et chiffres Unicode, mais pas les signes combinants utilisés par des écritures comme le devanagari : c’est pourquoi la vérification YouTube accepte aussi les caractères des catégories Unicode M.
Cas limites et tests
Chaque ligne ci-dessous fait partie de la suite de tests que les deux implémentations réussissent.
| Saisie | Résultat | Pourquoi |
|---|---|---|
instagram.com/NatGeo?igsh=MWQ1ZGUxMzBkMA== | instagram, natgeo, https://www.instagram.com/natgeo/ | Pas de schéma, casse mixte, paramètre de partage |
https://m.instagram.com/nat.geo_/#bio | instagram, nat.geo_ | Hôte mobile et fragment |
https://www.instagram.com/p/C9xYzAbCdEf/ | null | Une publication, pas un profil |
https://www.instagram.com/stories/natgeo/1234567890/ | null | Une story, même si le pseudo est dans le chemin |
tiktok.com/@Khaby.Lame/ | tiktok, khaby.lame, https://www.tiktok.com/@khaby.lame | Barre oblique finale et casse |
https://www.tiktok.com/@khaby.lame/video/7106594312292453675 | null | Une URL de vidéo |
https://vm.tiktok.com/ZMabc123/ | null (suivez d’abord la redirection) | Lien court sans pseudo |
https://m.youtube.com/@GoogleDevelopers/videos?app=desktop | youtube, googledevelopers | Hôte mobile, onglet de chaîne, requête |
https://www.youtube.com/channel/UC_x5XG1OV2P6uZZ5FSM9Ttw/featured | youtube, channelId UC_x5XG1OV2P6uZZ5FSM9Ttw | L’ID de chaîne garde sa casse |
https://www.youtube.com/c/GoogleDevelopers | youtube, customName GoogleDevelopers | Ancienne URL personnalisée ; une recherche est nécessaire pour l’ID |
https://www.youtube.com/@%E3%83%86%E3%82%B9%E3%83%88 | youtube, pseudo テスト | Pseudo Unicode encodé en pourcentage |
https://youtu.be/dQw4w9WgXcQ | null | Une vidéo, pas une chaîne |
https://mobile.twitter.com/jack?s=21&t=abc | x, jack, https://x.com/jack | Ancien domaine et paramètres de partage |
https://x.com/i/flow/login | null | Route de l’application |
https://x.com/this_handle_is_too_long | null | Plus de 15 caractères |
https://instagram.com.evil.com/natgeo | null | Hôte imitant le vrai |
https://instagram.com@evil.com/natgeo | null | Piège des informations d’utilisateur ; le vrai hôte est evil.com |
@natgeo | null | Un pseudo seul n’a pas de plateforme |
Gardez ces cas dans votre dépôt et exécutez-les en CI. Quand une plateforme ajoute une route ou un paramètre de partage, vous ajoutez une ligne et la correction devient évidente.
import assert from "node:assert/strict";
import { parseProfileUrl } from "./parse.mjs";
const cases = [
["instagram.com/NatGeo?igsh=MWQ1ZGUxMzBkMA==", { platform: "instagram", handle: "natgeo", canonicalUrl: "https://www.instagram.com/natgeo/" }],
["https://www.instagram.com/reel/C9xYzAbCdEf/", null],
["https://www.instagram.com/explore/", null],
["tiktok.com/@Khaby.Lame/", { platform: "tiktok", handle: "khaby.lame", canonicalUrl: "https://www.tiktok.com/@khaby.lame" }],
["https://www.tiktok.com/@khaby.lame/video/7106594312292453675", null],
["https://vm.tiktok.com/ZMabc123/", null],
["https://m.youtube.com/@GoogleDevelopers/videos", { platform: "youtube", handle: "googledevelopers", canonicalUrl: "https://www.youtube.com/@googledevelopers" }],
["https://www.youtube.com/channel/UC_x5XG1OV2P6uZZ5FSM9Ttw/featured", { platform: "youtube", channelId: "UC_x5XG1OV2P6uZZ5FSM9Ttw", canonicalUrl: "https://www.youtube.com/channel/UC_x5XG1OV2P6uZZ5FSM9Ttw" }],
["https://www.youtube.com/user/GoogleDevelopers", { platform: "youtube", username: "GoogleDevelopers", canonicalUrl: "https://www.youtube.com/user/GoogleDevelopers" }],
["https://youtu.be/dQw4w9WgXcQ", null],
["https://twitter.com/Jack/", { platform: "x", handle: "jack", canonicalUrl: "https://x.com/jack" }],
["https://mobile.twitter.com/jack?s=21", { platform: "x", handle: "jack", canonicalUrl: "https://x.com/jack" }],
["https://x.com/jack/status/20", null],
["https://x.com/i/flow/login", null],
["https://instagram.com.evil.com/natgeo", null],
];
for (const [input, expected] of cases) {
assert.deepEqual(parseProfileUrl(input), expected, input);
}
console.log(`${cases.length} cases passed`);from parse_profile import parse_profile_url
CASES = [
("instagram.com/NatGeo?igsh=MWQ1ZGUxMzBkMA==", {"platform": "instagram", "handle": "natgeo", "canonicalUrl": "https://www.instagram.com/natgeo/"}),
("https://www.instagram.com/reel/C9xYzAbCdEf/", None),
("tiktok.com/@Khaby.Lame/", {"platform": "tiktok", "handle": "khaby.lame", "canonicalUrl": "https://www.tiktok.com/@khaby.lame"}),
("https://vm.tiktok.com/ZMabc123/", None),
("https://m.youtube.com/@GoogleDevelopers/videos", {"platform": "youtube", "handle": "googledevelopers", "canonicalUrl": "https://www.youtube.com/@googledevelopers"}),
("https://www.youtube.com/channel/UC_x5XG1OV2P6uZZ5FSM9Ttw/featured", {"platform": "youtube", "channelId": "UC_x5XG1OV2P6uZZ5FSM9Ttw", "canonicalUrl": "https://www.youtube.com/channel/UC_x5XG1OV2P6uZZ5FSM9Ttw"}),
("https://youtu.be/dQw4w9WgXcQ", None),
("https://twitter.com/Jack/", {"platform": "x", "handle": "jack", "canonicalUrl": "https://x.com/jack"}),
("https://x.com/i/flow/login", None),
("https://instagram.com.evil.com/natgeo", None),
]
for value, expected in CASES:
assert parse_profile_url(value) == expected, value
print(f"{len(CASES)} cases passed")Stockez la saisie brute et la forme canonique
La normalisation perd de l’information par nature, et vos règles s’amélioreront avec le temps. Stockez les deux valeurs :
- `raw_url` : exactement ce que l’utilisateur ou l’import vous a donné. Cela vous permet de relancer plus tard un meilleur analyseur, et c’est ce que vous montrez à l’utilisateur quand il modifie son profil.
- `platform` et `handle` ou `channel_id` : les parties, avec un index unique sur
(platform, handle). C’est votre clé de dédoublonnage et de jointure. - `canonical_url` : l’URL reconstruite, pour l’affichage et pour appeler la plateforme.
- `parsed_at` et une version de l’analyseur : pour retrouver les lignes normalisées par une ancienne version de vos règles.
Les pseudos ne sont pas permanents. Les créateurs renomment leurs comptes sur toutes les plateformes, et un pseudo stocké l’an dernier peut appartenir aujourd’hui à quelqu’un d’autre. Quand une API officielle vous donne un ID stable, comme un ID de chaîne YouTube, stockez-le comme clé à long terme et traitez le pseudo comme une valeur d’affichage à mettre à jour. Le guide complémentaire sur l’obtention de l’ID d’une chaîne YouTube à partir d’un pseudo explique comment.
D’un profil aux autres
Une fois une URL de profil normalisée, la question suivante est en général : quels autres comptes appartiennent au même créateur ? sociallinks.dev est une API qui prend une URL de profil Instagram, TikTok, YouTube ou X et renvoie les comptes du créateur sur les autres plateformes, avec un score de confiance et la preuve de chaque correspondance.
FAQ
Faut-il mettre les pseudos en minuscules avant de les stocker ?
Oui pour la clé de recherche. YouTube et X indiquent que les pseudos sont insensibles à la casse, et TikTok renvoie @TikTok vers le même compte que @tiktok. Instagram ne documente pas de règle de casse, mais les noms d’utilisateur s’affichent en minuscules : les mettre en minuscules est donc le choix sûr par défaut. Gardez la casse d’origine dans l’URL brute si vous voulez l’afficher. Ne mettez pas en minuscules les ID de chaîne YouTube, qui sont sensibles à la casse.
Peut-on extraire le pseudo d’une URL de publication ou de vidéo ?
Pour les vidéos TikTok (/@handle/video/id) et les publications X (/handle/status/id), le pseudo du chemin est celui de l’auteur : vous pouvez donc l’extraire si c’est ce que vous voulez. Les URL de publications et de Reels Instagram (/p/ et /reel/) ne contiennent pas le pseudo. Les fonctions de ce guide renvoient null pour tous ces cas, car ce ne sont pas des liens de profil.
Comment traiter les liens vm.tiktok.com ?
Les liens courts ne contiennent qu’un code. Faites une requête HTTP, suivez les redirections et analysez l’URL finale. Faites-le dans une étape séparée, avec un délai d’expiration et un cache, car c’est un appel réseau et le code peut expirer.
twitter.com est-elle encore une URL de profil valide ?
Oui. Les URL de profil twitter.com redirigent vers x.com : traitez les deux domaines comme la plateforme X et stockez la forme x.com comme canonique.
Pourquoi ne pas utiliser une seule grande expression régulière ?
Une seule regex sur toute la chaîne est difficile à lire et facile à tromper avec des hôtes imitant le vrai, des informations d’utilisateur ou des caractères encodés. Analysez d’abord l’URL avec la bibliothèque standard, puis n’utilisez de petites regex que sur le pseudo.
Comment transformer une URL YouTube /c/ ou /user/ en ID de chaîne ?
Les URL /user/<name> correspondent au filtre forUsername de l’API YouTube Data. Il n’existe aucun filtre d’API pour les noms personnalisés /c/. Consultez le guide sur l’obtention de l’ID d’une chaîne YouTube à partir d’un pseudo pour les deux cas.