チュートリアル

LIFFアプリ開発ガイド2026:Next.js・TypeScriptで作る

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

LineBot.pro Team· 更新 18 分で読めます
LIFFアプリ開発ガイド2026:Next.js・TypeScriptで作る

#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フラグメント(#...)は指定できません
Scopeopenid(IDトークン)、email(メールアドレス取得権限があるチャネルのみ)、profile(getProfile、getFriendship)、chat_message.write(sendMessages)
友だち追加オプションOff、On (normal)、On (aggressive)。同意画面で公式アカウントの友だち追加を案内します
Scan QRliff.scanCodeV2()を使う場合にオンにします
モジュールモードヘッダーのアクションボタンを非表示にします(Fullのみ)

保存するとLIFF ID(例:1234567890-AbcdEfgh)とLIFF URL(https://liff.line.me/1234567890-AbcdEfgh)が発行されます。

#3. プロジェクトを作る

bash
# LINEのジェネレーターで新規作成(テンプレートにNext.jsがあります)
npx @line/create-liff-app

# 既存のNext.jsアプリにSDKを追加する場合
npm install @line/liff@^2.31.2
bash
# .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します。

tsx
// 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を使うルートをラップします。

tsx
// 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>
}

#プロフィールを表示する

tsx
// 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アプリおよびサーバーでユーザー情報を使用する)。

ts
// 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
}
ts
// 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サイトからのリダイレクトで開いた場合も失敗します。

ts
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]をクリックし、「情報の利用に関する同意について」に同意して[有効にする]を押します。

ts
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次元コードリーダー

ts
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つのブラウザに対応する

tsx
// 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()で現在のページのリンクを作れます。
ts
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でアプリの連携を解除します。

#デプロイとテスト

  1. HTTPSのホスティング(Vercel、Cloud Run、自社サーバーなど)にデプロイし、NEXT_PUBLIC_LIFF_IDとLINE_LOGIN_CHANNEL_IDを設定します。
  2. LIFFアプリのエンドポイントURLを、デプロイしたURL(またはアプリを置いたサブパス)に変更します。
  3. iOSとAndroidで、トークからLIFF URLを開いて確認します。

#LIFF CLIでローカル開発する

LINEのLIFF CLIは、ローカルサーバーの前にHTTPSのプロキシを立て、LIFFアプリのエンドポイントURLをそのプロキシに向けます。

bash
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は更新されません。


次のステップ:

LineBot.proについて

LineBot.proは、LINE公式アカウント向けのAIツールです。リッチメニュー、リッチメッセージ、バナーの作成、一斉配信、キーワードによる自動応答に対応しています。本記事はLINE Messaging APIの実務経験をもとに、当チームが執筆しています。

お問い合わせ
LineBot.pro

LINEビジネスを自動化する準備はできましたか?

LineBot.proでLINEコミュニケーションの自動化を今すぐ始めましょう。