LIFFアプリ開発ガイド2026:Next.js・TypeScriptで作る
2026年版のLIFF(LINE Front-end Framework)アプリ開発ガイドです。チャネルとエンドポイントURLの設定、liff.initのルール、サーバー側でのIDトークン検証、sendMessages、shareTargetPicker、ディープリンク、LIFF CLIでのテスト、v2.31.1のセキュリティ更新まで解説します。

#LIFFとは
LIFF(LINE Front-end Framework)は、LINEの中で動くWebアプリのためにLINEヤフー株式会社が提供するプラットフォームです。LIFFアプリの実体はLIFF SDKを読み込んだ普通のHTTPSのWebページで、LINEでLIFF URLから開くと、ログインフォームなしでユーザーのLINEアカウント情報を取得でき、開いたトークルームへのメッセージ送信やLINEのシェアターゲットピッカーの表示ができます。この記事では、Next.jsとTypeScriptでLIFFアプリを作る手順を、2026年10月時点のLINE Developersドキュメントで確認した内容に沿って解説します。
#LIFFアプリが動く環境
| 環境 | ユーザーの開き方 | 使える機能 |
|---|---|---|
| LIFFブラウザ | LINEでLIFF URL(https://liff.line.me/{liffId})をタップ | すべて:自動ログイン、画面サイズの指定、sendMessages、シェアターゲットピッカー、2次元コードリーダー、LIFF間遷移 |
| LINEのアプリ内ブラウザ | トークでエンドポイントURLそのものをタップ | 外部ブラウザ扱い:画面サイズ指定、sendMessages、シェアターゲットピッカーは使えません |
| 外部ブラウザ(Chrome、Safari、Edge、Firefox) | LINEの外でURLを開く | liff.login()によるLINEログイン。LINE固有の機能は限られます |
liff.isInClient()がtrueを返すのはLIFFブラウザだけです。共有するのはエンドポイントURLではなく、必ずLIFF URLにしてください。
#LIFFとLINEミニアプリ、どちらで作るか
LINEミニアプリは同じLIFF SDKを使いますが、LINEミニアプリチャネルに属し、LINEの審査(認証審査)に通ると認証バッジ、カスタムパス、ホーム画面へのショートカット追加、チャネル同意の簡略化といった機能が使えるようになります。LINEはLIFFをLINEミニアプリに統合すると発表しており、新しく作るLIFFアプリはLINEミニアプリとして作成することを推奨しています(2025年2月12日のニュース)。また2026年3月11日からは、LINEミニアプリポリシーで許可された事業者であれば誰でも、台湾とタイでも未認証ミニアプリを公開できるようになりました。両国で認証審査を申請できるのは認定プロバイダー配下のチャネルのみです(LINE Developersニュース 2026年)。以下の内容はどちらにも当てはまります。
#LIFFでできること・できないこと
- できること: ユーザーのプロフィールとIDトークンの取得、開いているトークへの最大5件のメッセージ送信、友だちやグループへのシェア、2次元コードの読み取り、LINE公式アカウントとの友だち関係の確認と友だち追加の促進、パーマネントリンクの作成。
- できないこと: バックエンドの代わりにはなりません。ボット、プッシュメッセージ、一斉配信は引き続きMessaging APIで行います。またLIFFブラウザはService Worker、
download属性、theme-colorのメタタグ、ホーム画面への追加に対応していません(外部ブラウザとの違い)。
開発を任せたい場合は、当社のLINEアプリ開発サービスでLIFFやLINEミニアプリを個別開発としてお受けしています。
#チャネルとLIFFアプリの設定
#1. 正しいチャネルを選ぶ
LIFFアプリを追加できるのはLINEログインチャネルかLINEミニアプリチャネルです。Messaging APIチャネルには新しいLIFFアプリを追加できません(2020年2月5日に終了)。LINE公式アカウントと連携するアプリなら、Messaging APIチャネルと同じプロバイダーにLINEログインチャネルを作り、公式アカウントをチャネルにリンクしておくと、友だち追加オプションや友だち関係を扱うメソッドが使えます。
#2. LIFFアプリを追加する
LINE Developersコンソールでチャネルを開き、[LIFF]タブの[追加]をクリックします。1つのチャネルに追加できるLIFFアプリは最大30個です(LIFFアプリの追加)。
| 設定項目 | 入力する内容 |
|---|---|
| LIFFアプリ名 | アプリ名。「LINE」やそれに類する文字列は使えません |
| サイズ | Compact、Tall、Fullのいずれか(LIFFブラウザの表示の高さ)。liff.requestFriendship()とモジュールモードはFullが必要です |
| エンドポイントURL | アプリのURL。httpsが必須で、URLフラグメント(#...)は指定できません |
| Scope | openid(IDトークン)、email(メールアドレス取得権限があるチャネルのみ)、profile(getProfile、getFriendship)、chat_message.write(sendMessages) |
| 友だち追加オプション | Off、On (normal)、On (aggressive)。同意画面で公式アカウントの友だち追加を案内します |
| Scan QR | liff.scanCodeV2()を使う場合にオンにします |
| モジュールモード | ヘッダーのアクションボタンを非表示にします(Fullのみ) |
保存するとLIFF ID(例:1234567890-AbcdEfgh)とLIFF URL(https://liff.line.me/1234567890-AbcdEfgh)が発行されます。
#3. プロジェクトを作る
# LINEのジェネレーターで新規作成(テンプレートにNext.jsがあります)
npx @line/create-liff-app
# 既存のNext.jsアプリにSDKを追加する場合
npm install @line/liff@^2.31.2
# .env.local
NEXT_PUBLIC_LIFF_ID=1234567890-AbcdEfgh
LINE_LOGIN_CHANNEL_ID=1234567890
2026年9月30日のセキュリティ更新: LINEはセキュリティに影響する可能性のある問題が見つかったとして、LIFF SDK v2.20.0〜v2.31.0を非推奨とし、v2.31.1以降への更新を求めています。
https://static.line-scdn.net/liff/edge/2/sdk.jsを読み込んでいるアプリは自動で更新済みですが、npmでインストールしている場合やCDNでバージョンを固定している場合(.../liff/edge/versions/2.x.y/sdk.js)は手動で更新が必要です。最新版はv2.31.2(2026年10月7日)です。詳しくはLIFFリリースノートをご覧ください。
#LIFFの初期化とユーザーの識別
#liff.init()のルール
LIFFアプリを開発するから要点をまとめます。
liff.init()はページを開くたびに実行します。同じアプリ内の別ページでも同様です。- エンドポイントURLと同じURL、またはその配下のURLで実行します。エンドポイントが
https://example.com/app/なら、https://example.com/での初期化は動作保証外です(LIFF v2.27.2以降はコンソールに警告が出ます)。 - Promiseが解決するまでURLを変更しないでください(ルーターのリダイレクト、
history.replaceState、URLを書き換えるスクリプトなど)。LIFFはliff.stateや認証情報をクエリ文字列で渡しています。 - 外部ブラウザではユーザーはログインしていません。
withLoginOnExternalBrowser: trueを指定するか、自分でliff.login()を呼びます。LIFFアプリからLINEログインの認可リクエストを送ってはいけません。
#Next.js App Router用のLiffProvider
SDKはwindowを使うため、ブラウザ側だけでuseEffectの中でimportします。
// components/liff-provider.tsx
"use client"
import { createContext, useContext, useEffect, useState, type ReactNode } from "react"
import type { Liff } from "@line/liff"
type Profile = Awaited<ReturnType<Liff["getProfile"]>>
type LiffState = {
liff: Liff | null
profile: Profile | null
error: string | null
ready: boolean
}
const initialState: LiffState = { liff: null, profile: null, error: null, ready: false }
const LiffContext = createContext<LiffState>(initialState)
// 開発モードでReactがeffectを2回実行しても、初期化はページ読み込みごとに1回だけ
let liffPromise: Promise<Liff> | null = null
function loadLiff(liffId: string): Promise<Liff> {
liffPromise ??= import("@line/liff").then(async ({ default: liff }) => {
await liff.init({ liffId, withLoginOnExternalBrowser: true })
return liff
})
return liffPromise
}
export function LiffProvider({ liffId, children }: { liffId: string; children: ReactNode }) {
const [state, setState] = useState<LiffState>(initialState)
useEffect(() => {
let cancelled = false
loadLiff(liffId)
.then(async (liff) => {
const profile = liff.isLoggedIn() ? await liff.getProfile() : null
if (!cancelled) setState({ liff, profile, error: null, ready: true })
})
.catch((err: unknown) => {
const message = err instanceof Error ? err.message : String(err)
if (!cancelled) setState({ ...initialState, error: message, ready: true })
})
return () => {
cancelled = true
}
}, [liffId])
return <LiffContext.Provider value={state}>{children}</LiffContext.Provider>
}
export const useLiff = () => useContext(LiffContext)
LIFFを使うルートをラップします。
// app/(liff)/layout.tsx
import type { ReactNode } from "react"
import { LiffProvider } from "@/components/liff-provider"
export default function LiffLayout({ children }: { children: ReactNode }) {
return <LiffProvider liffId={process.env.NEXT_PUBLIC_LIFF_ID!}>{children}</LiffProvider>
}
#プロフィールを表示する
// components/profile-card.tsx
"use client"
import { useLiff } from "./liff-provider"
export function ProfileCard() {
const { ready, error, profile } = useLiff()
if (!ready) return <p>読み込み中…</p>
if (error) return <p>LIFFエラー:{error}</p>
if (!profile) return null
return (
<div className="flex items-center gap-3">
{profile.pictureUrl && (
<img src={profile.pictureUrl} alt="" width={48} height={48} className="rounded-full" />
)}
<p className="font-semibold">{profile.displayName}</p>
</div>
)
}
liff.getProfile()にはprofileスコープが必要です。userIdとdisplayName、ユーザーが設定していればpictureUrlとstatusMessageも返します。userIdはプロバイダーごとに異なり、同じ人でも別のプロバイダーでは別のユーザーIDになります。
#サーバー側でユーザーを識別する
プロフィールや、ブラウザで読み取ったユーザーIDをそのままAPIに送ってはいけません。誰でも偽装できるからです。IDトークンかアクセストークンを送り、サーバーがLINEに問い合わせて検証します(LIFFアプリおよびサーバーでユーザー情報を使用する)。
// lib/verify-user.ts(ブラウザ側)
import type { Liff } from "@line/liff"
// プロフィールではなくIDトークンを送り、サーバーがLINEで検証する
export async function getVerifiedUserId(liff: Liff): Promise<string> {
const idToken = liff.getIDToken() // openidスコープが必要
if (!idToken) throw new Error("IDトークンがありません:openidスコープとログイン状態を確認してください")
const res = await fetch("/api/liff/verify", {
method: "POST",
headers: { Authorization: `Bearer ${idToken}` },
})
if (!res.ok) throw new Error(`検証に失敗しました:${res.status}`)
const { userId } = (await res.json()) as { userId: string }
return userId
}
// app/api/liff/verify/route.ts
export async function POST(request: Request) {
const idToken = request.headers.get("authorization")?.replace(/^Bearer /, "")
if (!idToken) return Response.json({ error: "Missing ID token" }, { status: 401 })
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,
// LIFFアプリを追加したLINEログインチャネルのチャネルID
client_id: process.env.LINE_LOGIN_CHANNEL_ID ?? "",
}),
})
if (!res.ok) return Response.json({ error: "Invalid ID token" }, { status: 401 })
const payload = (await res.json()) as { sub: string; name?: string; exp: number }
// payload.subが検証済みのLINEユーザーID。これでユーザーを検索・作成する
return Response.json({ userId: payload.sub })
}
IDトークン検証エンドポイントは、形式不正、期限切れ、別サイトで発行、別チャネル(client_id)向けのトークンを拒否し、ペイロードを返します。subがユーザーIDです。liff.getAccessToken()のアクセストークンを使う場合は、GET https://api.line.me/oauth2/v2.1/verify?access_token=...でclient_idが自分のチャネルIDと一致しexpires_inが正の値であることを確認してから、そのトークンでGET https://api.line.me/v2/profileを呼びます。アクセストークンはユーザーがLIFFアプリを閉じると取り消されます。
#メッセージ送信・シェア・友だち追加
#開いているトークにメッセージを送る
liff.sendMessages()は、LIFFアプリを開いたトークルームにユーザーとして最大5件のメッセージを送ります。使えるのは次の条件をすべて満たすときだけです。
- LIFFブラウザで動いていて、1対1のトーク、グループトーク、複数人トークから開かれている
chat_message.writeスコープが有効で、ユーザーが許可している- 「最近使用したサービス」から再読み込みされていない
条件を満たさないとPromiseは403エラー("user doesn't grant required permissions yet")でrejectされます。Keepメモから開いた場合や、Webサイトからのリダイレクトで開いた場合も失敗します。
import type { Liff } from "@line/liff"
export async function sendToChat(liff: Liff, text: string) {
if (!liff.isInClient()) {
alert("メッセージを送るには、LINEのトークからこのページを開いてください。")
return
}
try {
await liff.sendMessages([{ type: "text", text }])
} catch (err) {
// 403:トークから開かれていない、chat_message.writeが許可されていない、
// または「最近使用したサービス」から再読み込みされた
console.error("sendMessages failed", err)
}
}
#シェアターゲットピッカーでシェアする
シェアターゲットピッカーでは、ユーザーが友だち、グループ、トーク(オープンチャットは対象外)を選び、自分のアカウントからメッセージを送れます。事前に有効化が必要です。[LIFF]タブで[shareTargetPicker]をクリックし、「情報の利用に関する同意について」に同意して[有効にする]を押します。
export async function shareProduct(liff: Liff) {
if (!liff.isApiAvailable("shareTargetPicker")) return
const result = await liff.shareTargetPicker(
[
{
type: "flex",
altText: "唐揚げ定食 980円",
contents: {
type: "bubble",
hero: {
type: "image",
url: "https://example.com/images/chicken-set.jpg",
size: "full",
aspectRatio: "20:13",
aspectMode: "cover",
},
body: {
type: "box",
layout: "vertical",
contents: [
{ type: "text", text: "唐揚げ定食", weight: "bold", size: "lg" },
{ type: "text", text: "980円", color: "#06C755" },
],
},
footer: {
type: "box",
layout: "vertical",
contents: [
{
type: "button",
style: "primary",
color: "#06C755",
// シェアターゲットピッカーで送るメッセージに使えるのはURIアクションのみ
action: { type: "uri", label: "注文する", uri: "https://liff.line.me/1234567890-AbcdEfgh/menu/42" },
},
],
},
},
},
],
{ isMultiple: true },
)
if (result) console.log(`[${result.status}] シェアしました`)
else console.log("ユーザーがピッカーを閉じました")
}
リファレンスのポイント:
- 送れるメッセージは最大5件。Flex Messageとテンプレートメッセージで使えるのはURIアクションだけです。
- 送信できるとPromiseは
{ status: "success" }で解決し、ユーザーがピッカーを閉じるとfalsyな値で解決します。送信前にエラーが起きるとrejectされます。 - スマートフォンの外部ブラウザでは、ピッカーの表示にLINEのSSOセッションが必要なため、メールアドレスでのログイン画面が出ることがあります。
- シェアされたメッセージを何人が受け取ったかは、LINEから提供されません。
isMultiple: falseは1回の選択を友だち1人に制限しますが、何度もシェアすることは防げません。
#友だち関係と2次元コードリーダー
export async function askToAddFriend(liff: Liff) {
const { friendFlag } = await liff.getFriendship() // profileスコープが必要
if (!friendFlag) await liff.requestFriendship() // LIFF v2.28.0以降、Fullサイズのみ
}
export async function scanTableQr(liff: Liff) {
const { value } = await liff.scanCodeV2() // コンソールで「Scan QR」をオンにしておく
return value
}
liff.getFriendship()はチャネルにリンクした公式アカウントとの関係を確認します。liff.requestFriendship()(v2.28.0、2026年3月)はその公式アカウントの友だち追加またはブロック解除を促すサブウィンドウを開きますが、戻り値からユーザーの操作結果はわからないため、あとでgetFriendship()を呼び直します。liff.scanCodeV2()はLIFFブラウザではiOS 14.3以降とAndroidで、外部ブラウザではWebRTC対応ブラウザで動作します。
#ベストプラクティス
#3つのブラウザに対応する
// components/app-shell.tsx
"use client"
import type { ReactNode } from "react"
import { useLiff } from "./liff-provider"
export function AppShell({ children }: { children: ReactNode }) {
const { liff, ready } = useLiff()
if (!ready || !liff) return <p>読み込み中…</p>
// 外部ブラウザでは、withLoginOnExternalBrowserですでにLINEログインへ遷移済み
// ここではLIFFブラウザが必要な機能を隠すだけ
const inLine = liff.isInClient()
return (
<main style={{ paddingBottom: "env(safe-area-inset-bottom)" }}>
{children}
{!inLine && <p>シェアやトークへの送信は、LINEでこのページを開くと使えます。</p>}
</main>
)
}
ピッカーを呼ぶ前にはliff.isApiAvailable("shareTargetPicker")で確認します。liff.getContext()を使うと、アプリがどこから開かれたか(utou=1対1のトーク、group、room、external、none)がわかります。
#リンクは正しい方法で開く
liff.openWindow({ url, external })は、URLをLINEのアプリ内ブラウザ(デフォルトのexternal: false)またはLINEの外で開きます。LINE 15.20.0以降では、Universal LinksやApp Linksに対応したURLもexternal: trueを指定しない限りLINEのアプリ内ブラウザで開き、trueなら対応アプリに遷移します。LINE 14.20.0〜15.19.xでは常にアプリへ遷移していました(liff.openWindow())。どちらか一方の挙動を前提にしないでください。
#ルーティング、ディープリンク、LIFF間遷移
- シングルページアプリはHistory APIで作ります。LIFFはフラグメント(
#)によるルーティングへの対応が限定的です。 - LIFF URLにはパスとクエリを付けられます。
https://liff.line.me/1234567890-AbcdEfgh/menu/42?table=7は、liff.init()のあと{エンドポイントURL}/menu/42?table=7に遷移します。リッチメニュー、Flex Messageのボタン、QRコードに使えます。liff.permanentLink.createUrlBy()で現在のページのリンクを作れます。
export async function shareCurrentPage(liff: Liff) {
// https://liff.line.me/{liffId}/{path} はエンドポイントURL配下の同じパスを開く
const url = await liff.permanentLink.createUrlBy(window.location.href)
await navigator.clipboard.writeText(url)
}
- LIFFアプリから別のLIFFアプリを開くLIFF間遷移はLIFFブラウザでのみ動作し、遷移後は
chat_message.writeスコープが無効になることがあります。 - LIFF v2.31.2(2026年10月7日)以降、LIFFブラウザはクエリの値に含まれる
?を&に置き換えなくなりました。URLをクエリパラメータで受け取るページは確認してください。
#レイアウト、バージョン、制限
- 画面サイズは用途で選びます。複数ステップの操作は
Full、トークの上に出す短いフォームはCompactかTallです。高さは固定せず、env(safe-area-inset-bottom)で余白を取ります。 - LINE 26.7.0以降、LIFFブラウザのヘッダーは従来のマルチタブボタンの代わりに縦の三点リーダーになり、タップするとメニュー(すべてのタブ、更新、最小化、シェアなど)が開きます。
- CDNのedgeパスは新しいマイナー・パッチ版に自動で追従しますが、npmやバージョン固定は手動更新です。LINEは2025年12月にLIFFのロードマップ公開を終了したため、LINE Developersのニュースを確認してください。
https://liff.line.me/経由の負荷テストや、LIFF APIへの大量リクエストはLINEの開発ガイドラインで禁止されています。- 同意なくCookieやlocalStorageでユーザーを追跡したり、LINEの情報を別のセッション情報と紐付けたりしないでください。ユーザーがサービスを退会したら、LINEログインAPIでアプリの連携を解除します。
#デプロイとテスト
- HTTPSのホスティング(Vercel、Cloud Run、自社サーバーなど)にデプロイし、
NEXT_PUBLIC_LIFF_IDとLINE_LOGIN_CHANNEL_IDを設定します。 - LIFFアプリのエンドポイントURLを、デプロイしたURL(またはアプリを置いたサブパス)に変更します。
- iOSとAndroidで、トークからLIFF URLを開いて確認します。
#LIFF CLIでローカル開発する
LINEのLIFF CLIは、ローカルサーバーの前にHTTPSのプロキシを立て、LIFFアプリのエンドポイントURLをそのプロキシに向けます。
npm install -g @line/liff-cli
liff-cli channel add 1234567890 # チャネルシークレットの入力を求められます
liff-cli serve --liff-id 1234567890-AbcdEfgh --url http://localhost:3000/
# スマートフォンで開くなら、ローカルプロキシの代わりにngrokで公開する
NGROK_AUTHTOKEN=your-token liff-cli serve --liff-id 1234567890-AbcdEfgh --url http://localhost:3000/ --proxy-type ngrok
serveはエンドポイントURLを書き換えるので、公開中のLIFFアプリではなく開発用のLIFFアプリで実行してください。--inspectを付けるとLIFF Inspectorでデバッグでき、LIFF Playgroundではコードを書かずにSDKのメソッドを試せます。
#テストチェックリスト
- iOSとAndroidで、1対1のトークとグループからLIFF URLを開く
- LINEのアプリ内ブラウザでエンドポイントURLを開き、LIFF専用機能が隠れて何も壊れないこと
- 外部ブラウザ:ログイン後、同じページに戻ること
- トークからの
sendMessagesと、許可がないときの403処理 - シェアターゲットピッカー:送信した場合と閉じた場合
- パスとクエリ付きのディープリンク(URLを値に含むクエリも)
- 改ざん・期限切れのIDトークンをサーバーが拒否すること
- LIFF SDKが2.31.1以降であること
#LIFFアプリとLineBot.pro
LineBot.proはLIFFアプリの開発・ホスティング・テンプレート提供は行っておらず、LIFF SDKや公開APIもありません。LIFFのプロジェクトで役立つのは次の2つのツールです。
- アプリから送るメッセージ: AIのリッチメッセージ作成ツールは、Flex Messageのバブル(ヒーロー画像、テキスト、ボタン)を作り、JSONとしてダウンロードまたはコピーできます。それを
liff.sendMessages()やliff.shareTargetPicker()に渡せます。ピッカーで使う場合は、リンクを開くボタン(URIアクション)だけにしてください。テキストを送るボタンは使えません。リッチメッセージ1件の作成は8クレジットです。 - アプリへの入口: リッチメニュー作成ツールは、1〜6ボタンのメニュー画像とJSONを10クレジットで作ります。LineBot.proがLINEに公開するわけではないので、LINE Official Account Managerで画像をアップロードしてボタンのリンクにLIFF URLを設定するか、JSONをMessaging APIで登録します。
新規登録で50クレジットを無料で受け取れます。クレジットは買い切りのパックで、有効期限も月額料金もありません(料金)。LIFFアプリそのもの、LINEミニアプリ、Messaging APIと連携するバックエンドが必要な場合は、案件ごとにお見積もりする個別開発になります。
#よくある質問
Q: LIFFは何の略ですか?
LINE Front-end Frameworkの略で、LINEの中で開き、ユーザーのLINEアカウント情報を使えるWebアプリのためにLINEヤフー株式会社が提供するプラットフォームです。SDKはnpmパッケージ@line/liff、またはスクリプトhttps://static.line-scdn.net/liff/edge/2/sdk.jsで読み込みます。
Q: LIFFのエンドポイントURLはなぜHTTPSでなければならないのですか?
LINEが受け付けるエンドポイントURLは、#のフラグメントを含まないhttpsのURLだけだからです。アプリや、アプリが開くコンテンツがhttpだと、LINEのアプリ内ブラウザで表示され、LIFFアプリとして動作しなくなります。開発中はLIFF CLIのプロキシかngrokを使ってください。
Q: liff.getProfile()でユーザーIDは取得できますか?
できます。profileスコープが許可されていれば、userIdとdisplayName、設定されていればpictureUrlとstatusMessageも返ります。ただし表示用にとどめ、データベースに保存するIDはliff.getIDToken()をサーバーに送り、検証済みトークンのsubを使います。ユーザーIDはプロバイダーごとに異なります。
Q: LIFFアプリとLINEミニアプリ、どちらで作るべきですか? LINEはLIFFをLINEミニアプリに統合する方針のため、新規アプリはLINEミニアプリとして作ることを推奨しています。どちらも同じLIFF SDKを使い、ミニアプリチャネルでは認証審査と認証済みミニアプリ向けの機能が加わります。2026年3月11日からは、台湾とタイでも未認証ミニアプリを公開できます。
Q: liff.sendMessages()が403エラーになるのはなぜですか?
このメソッドは、LIFFブラウザで、トークから開かれたアプリで、chat_message.writeが許可されていて、「最近使用したサービス」から再読み込みされていない場合にのみ使えます。エンドポイントURLを直接開いた場合、Keepメモから開いた場合、Webサイトからのリダイレクト後も失敗します。
Q: どのバージョンのLIFF SDKを使えばよいですか? v2.31.1以降です。2026年10月時点の最新版はv2.31.2です。LINEは2026年9月30日に、セキュリティに影響する可能性のある問題によりv2.20.0〜v2.31.0を非推奨にしました。CDNのedgeパスは自動更新されますが、npmやバージョン固定のCDN URLは更新されません。
次のステップ:
- 開発を任せたい方はLIFF・LINEミニアプリのLINEアプリ開発へ
- バックエンドの連携はLINE API連携チュートリアルで
- 最近の変更点はLINE Messaging API 2026年のアップデートで確認
- アプリの裏側にボットを置くならLINE Bot開発チュートリアルへ
LineBot.proについて
LineBot.proは、LINE公式アカウント向けのAIツールです。リッチメニュー、リッチメッセージ、バナーの作成、一斉配信、キーワードによる自動応答に対応しています。本記事はLINE Messaging APIの実務経験をもとに、当チームが執筆しています。
お問い合わせ関連記事

@line/bot-sdk Expressミドルウェア実装例(v11)
@line/bot-sdk v11のExpress+TypeScriptによるWebhook実装例。middleware()を置く場所、Node.js・Python・PHPでのvalidateSignature、Flex Messageを使ったreplyMessage、sentMessagesと引用トークン、実際に出るエラーと対処を解説します。
続きを読む
LINE Messaging API 2026年の変更点まとめ(開発者向け)
2025年から2026年10月までのLINE Messaging API・LIFF・LINEミニアプリの変更のうち、稼働中のボットに影響するものをまとめました。新しいエンドポイント、レート制限の引き下げ、LIFF v2.31.1のセキュリティ更新、Node.js SDK v11、台湾・タイのミニアプリ、国別の無料メッセージ通数です。
続きを読む
LINE Botの作り方 2026:Messaging API開発入門
Messaging APIでLINE Botを作る手順を、チャネルの準備からWebhookの署名検証、Flexメッセージとクイックリプライ、ポストバックを使った予約フロー、FAQに限定したAI回答、デプロイまで解説します。Node.js(@line/bot-sdk v11)とPython(line-bot-sdk v3)のコード付きです。
続きを読む