⚛️

Next.js アプリに LINE を連携させるガイド

に公開

はじめに

先日、Next.js の勉強会で、LINE と連携した実装について取り上げました 🫐

LINE は、日本国内で、月間 9,700 万人が利用するサービスです。

なので、実務・ビジネス面でも、
ユーザー獲得や継続的なエンゲージメント向上において、非常に強力なチャネルの 1 つです

今回は、Next.js と LINE の連携について調査したので、基礎的な内容をまとめました!
時間の節約になれば、嬉しいです 🙌

LINE との連携とは?

そもそも、Web サイト・アプリに、LINE を連携させる方法は、複数あります

これは、LINE のプラットフォームが、開発者向け・非開発者向けに、
様々な種類のサービスを提供しているためです!

特に有名なものを、3 つ紹介します:

1. LINE 公式アカウント

https://lymcampus.jp/line-official-account/courses/operation/lessons/oa-3-1-1

これは、すでに一般的ですよね。
飲食店や、実店舗などで、採用しているケースが多い印象です。

特徴として、:

  • ダッシュボード上から情報発信が可能
  • 登録してくれたフォロワーの属性や行動を分析可能
  • ユーザーからの問い合わせ対応など

公式アカウントを使用することで、
ビジネスやサービスが、顧客とのコミュニケーションを簡単に実現します 👍

2. LINE Bot(Messaging API)

https://developers.line.biz/ja/docs/messaging-api/

LINE ボットは、自動化されたメッセージの受信・返信を提供する仕組みです

  • 公式アカウントを通じて自動メッセージを送信可能
  • Webhook でユーザーからのメッセージを受け取り、ボットによる自動応答
  • リッチコンテンツ(カルーセル、ボタンなど)の送信

開発者向けの、Messaging API を使用することで、簡単にチャットボットなどが構築できます 😎

3. LINE Front-end Framework (LIFF)

https://developers.line.biz/ja/docs/liff/

LIFF は、LINE 内で動作するウェブアプリを作成するために用意された、フレームワークです

特徴として

  • LINE アプリ内のブラウザで、ウェブアプリを動作させることが可能
  • LINE のユーザー情報を利用した認証が可能

LIFF を使用することで、LINE 内で完結する手軽なアプリを、構築できます 🎉

実際には、ここまでで紹介した機能を柔軟に組み合わせることで、
より自由度の高いユーザー体験が可能です!!

Next.js を LINE と連携する例

ここまでで紹介した連携方法をそれぞれ、
Next.js で実装する例を見ていきましょう。

1. LINE 公式アカウントの作成

https://entry.line.biz/start/jp/

これは、特に開発者向けの設定などは不要です!

下記の流れで、簡単にユーザーと繋がることができます

  • 上記の URL より、line official account manager にアクセス
  • 必要な情報を入力し、公式アカウントを作成
  • 作成したアカウントの URL を取得
  • Web サイトに、リンクする
~
<Button
  asChild
  size={"lg"}
  className="bg-green-500 hover:bg-green-500/90 font-semibold"
>
    <Link target="_blank" href={process.env.NEXT_PUBLIC_LINE_URL || ""}>
        <Plus className="mr-1" />
        LINEから追加
    </Link>
</Button>
~

環境変数からリンクしています 👍

2. LINE Bot (Messaging API)の作成

LINE Bot を作成するには、LINE Developers Console でプロジェクトを設定する必要があります。

LINE Developers Console での設定:

そしたら、LINE 関連の機能を実装に、便利なパッケージをインストールします:

npm install @line/bot-sdk @line/liff

では、Next.js 側で、Webhook を受け取る API を構築します:

// app/api/line-webhook/route.tsx
import { NextRequest, NextResponse } from "next/server";
import { Client, middleware, WebhookEvent } from "@line/bot-sdk";

// LINE Bot SDKの設定
const config = {
  channelAccessToken: process.env.LINE_CHANNEL_ACCESS_TOKEN || "",
  channelSecret: process.env.LINE_CHANNEL_SECRET || "",
};

// BOT SDKクライアントの初期化
const client = new Client(config);

export async function POST(req: NextRequest) {
  try {
    const body = await req.text();
    const signature = req.headers.get("x-line-signature") || "";

    // ミドルウェアによるシグネチャ検証
    if (!middleware(config).verify(body, signature)) {
      return NextResponse.json({ error: "Invalid signature" }, { status: 403 });
    }

    // イベントの処理
    const events: WebhookEvent[] = JSON.parse(body).events;

    for (const event of events) {
      await handleEvent(event);
    }

    return NextResponse.json({ status: "ok" });
  } catch (error) {
    console.error("Webhook error:", error);
    return NextResponse.json(
      { error: "Internal server error" },
      { status: 500 }
    );
  }
}

// イベント処理関数
async function handleEvent(event: WebhookEvent) {
  if (event.type !== "message" || event.message.type !== "text") {
    return;
  }

  const { text } = event.message;
  const { replyToken } = event;

  // メッセージ内容に応じた処理
  if (text.includes("こんにちは")) {
    await client.replyMessage(replyToken, {
      type: "text",
      text: "👋 こんにちは!何かお手伝いできることはありますか?",
    });
  } else if (text.includes("ヘルプ")) {
    await client.replyMessage(replyToken, {
      type: "text",
      text: "このBotでは以下のことができます:\n・挨拶\n・ヘルプ表示\n・クイックリプライ",
    });
  } else {
    // デフォルトの返信
    await client.replyMessage(replyToken, {
      type: "text",
      text: `${text}」というメッセージを受け取りました!`,
    });
  }
}

App Router では、Route Handler で API を構築できます!!

3. LINE Front-end Framework (LIFF) の作成

LIFF アプリを作成するには、先ほどと同様に、LINE Developers Console で設定を行います。

LINE Developers Console での設定:

そして、Next.js で LIFF を実装します!

// app/liff/page.tsx
"use client";

import { useEffect, useState } from "react";
import { Button } from "@/components/ui/button"; // UIコンポーネントはプロジェクトに合わせて調整
import liff from "@line/liff";

export default function LiffPage() {
  const [profile, setProfile] = useState<any>(null);
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    // LIFFの初期化
    const initializeLiff = async () => {
      try {
        await liff.init({ liffId: process.env.NEXT_PUBLIC_LIFF_ID || "" });

        // ログイン状態の確認
        if (liff.isLoggedIn()) {
          setIsLoggedIn(true);
          fetchUserProfile();
        }
      } catch (error) {
        console.error("LIFF initialization failed", error);
      } finally {
        setIsLoading(false);
      }
    };

    initializeLiff();
  }, []);

  // ユーザープロフィールの取得
  const fetchUserProfile = async () => {
    try {
      const profile = await liff.getProfile();
      setProfile(profile);
    } catch (error) {
      console.error("Failed to fetch user profile", error);
    }
  };

  // ログイン処理
  const handleLogin = () => {
    liff.login();
  };

  // ログアウト処理
  const handleLogout = () => {
    liff.logout();
    setIsLoggedIn(false);
    setProfile(null);
  };

  // メッセージ送信
  const handleSendMessage = () => {
    liff
      .sendMessages([
        {
          type: "text",
          text: "LIFFアプリからのメッセージです!",
        },
      ])
      .then(() => {
        console.log("Message sent");
      })
      .catch((error: any) => {
        console.error("Error sending message", error);
      });
  };

  if (isLoading) {
    return (
      <div className="flex justify-center items-center h-screen">
        読み込み中...
      </div>
    );
  }

  return (
    <div className="container mx-auto p-4">
      <h1 className="text-2xl font-bold mb-6">LINE LIFF アプリ</h1>

      {isLoggedIn ? (
        <div className="space-y-4">
          {profile && (
            <div className="border p-4 rounded-lg">
              <img
                src={profile.pictureUrl}
                alt="プロフィール画像"
                className="w-24 h-24 rounded-full mx-auto mb-2"
              />
              <p className="text-center font-bold">{profile.displayName}</p>
            </div>
          )}

          <div className="flex flex-col space-y-2">
            <Button
              onClick={handleSendMessage}
              className="bg-green-500 hover:bg-green-600"
            >
              メッセージを送信
            </Button>
            <Button onClick={handleLogout} variant="outline">
              ログアウト
            </Button>
          </div>
        </div>
      ) : (
        <Button
          onClick={handleLogin}
          className="bg-green-500 hover:bg-green-600 w-full"
        >
          LINEでログイン
        </Button>
      )}
    </div>
  );
}

これらの実装例で、
Next.js アプリケーションと LINE プラットフォームの連携が可能になります

LINE と連携すると何が良いのか?

個人的には、LINE 連携 の魅力は、
ユーザーとの直接的なコミュニケーションチャネルが、簡単に構築できる点です

  • 国内トップレベルのアクティブユーザー
  • 多くのユーザーが日常的に利用しているので、エンゲージメント(反応)も高くなる

開発者向けのツールなら、GitHub ログインを実装するのと同じですね!

特に、toC サービス、EC サイト、接客業などでは、
有力な選択肢になります。

なので、仕事・個人開発などでも、さまざまな形で応用できる技術です

個人開発

初期のプロダクトでは、LINE の活用で、ユーザーと素早く繋がることができます。

フィードバックフォームを送れるだけでなく、
興味を持ってくれたユーザーと直接コミュニケーションが取れます。

自分でユーザーデータを抱える必要もないので、たった 1 日で MVP を立ち上げることも可能ですね

単純にランディングページだけ作って、LINE 登録でユーザー獲得や検証を始められます 👍

学習コスト

しかも、ここまで確認した通り、Next.js などを利用することで、
追加の学習コストは、ほとんどない点も嬉しいです。

ただし、LINE Login の実装には、少し注意が必要です。

https://authjs.dev/getting-started/providers/line

https://clerk.com/docs/authentication/social-connections/line

認証周りの実装は複雑になりがちなので、
Auth.js や Clerk のような認証サービスとの併用をお勧めします

おわりに

最後まで読んでいただき、ありがとうございます 🥳

下記の、Next.js ハンズオン勉強会での、振り返りのような記事ですが、
少しでも参考になれば、嬉しいです!

https://b13o.com/services/handson-workshop

そして、もし、間違いや補足情報などがありましたら、
ぜひコメントを追加してください!

Happy Hacking :)

参考

https://developers.line.biz/ja/reference/messaging-api/#signature-validation
https://developers.line.biz/ja/docs/liff/overview/
https://qiita.com/koda-momo/items/f7f92615505212358cd7
https://qiita.com/yuchi1128/items/012618800a17f7705388
https://note.com/10mohi6/n/n66c6b83e982f
https://zenn.dev/kou_pg_0131/articles/line-push-text-message

GitHubで編集を提案
b13o Tech Blog

Discussion