LIFF getProfile and userId: How to Get (and Verify) a LINE User ID
5 October 2026 · by Yunmin Shin
The Short Answer
Call liff.init(), then liff.getProfile() — the returned object has the user's userId. But only use that value for display. To identify the user on your server, send the ID token from liff.getIDToken() and verify it with LINE; the verified sub claim is the userId you can trust.
import liff from "@line/liff";
await liff.init({ liffId: "1234567890-AbCdEfGh" });
if (!liff.isLoggedIn()) liff.login(); // only needed outside the LINE app
const profile = await liff.getProfile();
console.log(profile.userId); // "U4af4980629..."
console.log(profile.displayName); // shown name
console.log(profile.pictureUrl); // may be undefined
const idToken = liff.getIDToken(); // send THIS to your server
Which Scopes Do You Need?
In the LINE Developers Console, on the LIFF app's settings:
profile— required forliff.getProfile().openid— required forliff.getIDToken()andliff.getDecodedIDToken().email— only if you need the email address, and your channel must have applied for email permission.
If you change scopes after users have already authorised the app, they may need to re-consent.
What Is the LIFF ID?
The LIFF ID identifies one LIFF app and looks like 1234567890-AbCdEfGh — the first part is the channel ID it belongs to. You find it on the LIFF tab of your LINE Login (or LINE MINI App) channel. The same ID builds the entry URL: https://liff.line.me/1234567890-AbCdEfGh. Pass it to liff.init({ liffId }).
getProfile vs getDecodedIDToken vs getContext
liff.getProfile()— makes a request and returnsuserId,displayName,pictureUrl,statusMessage. Needsprofilescope.liff.getDecodedIDToken()— decodes the ID token locally and returns its claims (subis the userId, plusname,picture, andemailif granted). Convenient, but it is not verified — fine for UI, never for authorisation.liff.getContext()— information about where the app was opened (type of chat, view type, and the userId when available). Useful for knowing if you were opened from a 1-on-1 chat or a group.
How to Verify the User on Your Server
Send the raw ID token and verify it with LINE's endpoint. client_id is the channel ID of the LINE Login channel that owns the LIFF app:
// app/api/me/route.ts (Next.js route handler)
export async function POST(req: Request) {
const { idToken } = await req.json();
const res = await fetch("https://api.line.me/oauth2/v2.1/verify", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
id_token: idToken,
client_id: process.env.LINE_LOGIN_CHANNEL_ID!,
}),
});
if (!res.ok) return Response.json({ error: "invalid token" }, { status: 401 });
const claims = await res.json();
const userId: string = claims.sub; // verified LINE userId
// look up or create the customer keyed on userId
return Response.json({ userId, name: claims.name });
}
The endpoint checks the signature, expiry and audience for you. ID tokens expire, so verify on each sensitive request (or exchange the verified identity for your own session) rather than storing the token.
An alternative is to send the access token (liff.getAccessToken()), verify it with GET https://api.line.me/oauth2/v2.1/verify?access_token=... (check that client_id in the response is your channel), then call the profile endpoint with it. The ID-token route is simpler for most apps.
Why userIds Differ Between Your Channels
A LINE userId is unique per provider. The same person has the same userId across all channels under one provider, and a different one under another provider. This bites when:
- the LIFF app lives under one provider and the Official Account (Messaging API channel) under another — push messages to the IDs you collected will fail;
- an agency created channels under their provider — move or recreate them under the business's own provider before launch.
Common Errors and Fixes
- "LIFF has not been initialised" / getProfile rejects — await
liff.init()before anything else, and only call LIFF in client-side code (in Next.js, insideuseEffectin a client component). - Works in LINE, fails in Chrome/Safari — the user is not logged in in the external browser. Check
liff.isLoggedIn()and callliff.login(). getIDToken()returns null — theopenidscope isn't enabled, or init hasn't finished.- Push message fails with an invalid user — provider mismatch (see above), or the user hasn't added your Official Account as a friend.
- Endpoint URL mismatch — the page URL must sit under the endpoint URL registered for the LIFF app, on HTTPS.
Where This Fits
Identity is the first step of every LIFF app — a booking system, a membership card, a loyalty stamp card. For the full build, see our LINE LIFF development guide and how a LINE booking system works. Always check LINE's official LIFF API reference for the current method list.
Need it built rather than debugged? Get a free quote. We reply within 24 hours.
Frequently asked questions
How do I get the userId in LIFF?
Call liff.init({ liffId }) first, then liff.getProfile(). The returned object contains userId, displayName, pictureUrl and statusMessage. The LIFF app must have the profile scope enabled in the LINE Developers Console.
Why does liff.getProfile() fail?
The usual causes are calling it before liff.init() has resolved, the profile scope not being enabled on the LIFF app, or the user not being logged in when the page is opened in an external browser — call liff.login() first in that case.
Is the LINE userId the same across different channels?
A userId is consistent across channels under the same provider, but differs between providers. Keep your LIFF (LINE Login) channel and your Messaging API channel under one provider so the IDs your LIFF app collects can receive push messages from your Official Account.
Can I trust the userId sent from the LIFF app to my server?
No. Any value from the browser can be forged. Send the ID token from liff.getIDToken() and verify it with LINE's https://api.line.me/oauth2/v2.1/verify endpoint; use the verified sub claim as the userId.
What does a LINE userId look like?
It is a string starting with U followed by 32 hexadecimal characters, for example U4af4980629... It is not the user's LINE ID (the handle people search for) and cannot be used to look them up in the LINE app.
Want this working for your business in Thailand?
We build and run the same systems on 16 live sites of our own. Tell us your business — we reply within 24 hours with what the search data shows.