見出し画像

Chrome拡張機能で「クレジットカード登録後3日間無料」有料サブスクリプションを実装する手

本記事の目的と内容の概要

「Chrome拡張にサブスクリプション課金を導入したいけど、公式の課金手段が使えないってホント!?
はい、残念ながらChrome Web Storeの公式決済は停止中。ですが、Stripeなどの外部ツールを駆使すれば、実はしっかりサブスク実装が可能なんです。
このノートの無料部分では、以下のような点にフォーカスします。

  • サブスク導入の大まかな仕組み

  • 導入の“良いところ”と“注意したいところ”

  • どんなメリットが得られるのか

そして有料部分では、実際に機能を作るための具体的なステップや、設定ファイルなどを余すことなく解説。
「無料部分で全体像を把握 → 有料部分で詳細を実装」という流れになっています。



Chrome拡張機能を 有料のサブスクリプション制 で提供し、最初の3日間は無料で利用できる仕組みを導入する方法をまとめました。

2022年以降、Chrome ウェブストアの公式課金機能(Chrome Web Store Payments)は新規/更新共に停止しているため、Stripeなどの外部決済サービスを使用するのが必須となります。
本記事では Firebase + Stripe を組み合わせ、クレジットカード登録後3日間無料トライアル、その後自動課金する仕組みを解説します。

ポイント
- Chrome Web Store公式の課金機能は利用不可。
- Stripeの「Trial period(トライアル期間)」を使うと、3日間無料 → 自動課金が容易。
- Webhook + Firestoreでユーザーのサブスク状態を管理し、拡張機能側はその状態を参照して機能をロック/アンロックする。
- Chrome拡張のCSP制約により、Stripe Checkoutを拡張機能内で直接動かすには工夫が必要。
 → 外部Webページ(例: Firebase Hostingなど)に誘導して決済させる構成がおすすめ。


全体的な流れ

  1. Firebaseプロジェクトを作成し、FirestoreFirebase Authentication を有効化。

  2. Stripeアカウントを作成し、3日間の無料トライアル付きのサブスクリプションプランを登録。

  3. Firebase FunctionsでWebhookエンドポイントを作成し、Stripeのイベント通知(決済成功/失敗)を受け取る。

  4. Chrome拡張のユーザーが料金プランを選び、決済情報入力 → 3日無料トライアル開始。

  5. Webhookで「サブスク有効ユーザー」をFirestoreに保存し、拡張機能はユーザーごとにサブスク状態を参照して機能を制限。


A. Firebase + Stripeのバックエンドを作る

1. Firebaseプロジェクト作成 & 初期設定

まずはFirebase Consoleで新しいプロジェクトを作成してください。
その後、「Authentication」と「Cloud Firestore」を有効化します。

Authentication

  • Firebaseコンソールの「Build > Authentication」から「始める」をクリック。

  • Googleログインやメール・パスワード認証など、使いたいログイン方法を有効にする。

Cloud Firestore

  • Firebaseコンソールの「Build > Firestore Database」から「データベースを作成」。

  • 「本番モード(Production mode)」を選択してリージョンを設定し、有効化。

2. Firebase CLI導入

npm install -g firebase-tools
firebase login

3. Functionsの初期化

mkdir my-extension-backend
cd my-extension-backend
firebase init functions

ここで言語選択を求められたら JavaScript または TypeScript を選択します。
初期設定が完了すると functions ディレクトリが生成されます。

B. Stripeアカウント作成・サブスクリプション商品設定

  1. Stripe公式サイトでアカウントを作成し、事業情報などを登録。

  2. Stripeダッシュボードでテスト用「Publishable key」「Secret key」を取得。
    本番運用時は「本番キー」を使用しますが、最初はテストキーで進めます。

  3. Stripeダッシュボードの「商品(Product)」で新規商品を作成。
    続いて「価格(Price)」を追加し、定期購読(月額など)に設定。
    この時、試用期間(Trial period)を3日に指定しておきましょう。

C. Firebase FunctionsでWebhook & Checkoutセッション作成

1. Stripeパッケージ導入

cd functions
npm install stripe

2. index.js (または index.ts) のサンプル

以下は最小限のサンプルコードです。コピペして利用可能ですが、実際の運用ではエラーハンドリングやセキュリティ強化をしてください。


// functions/index.js

const functions = require("firebase-functions");
const admin = require("firebase-admin");
const Stripe = require("stripe");

// Firebase初期化
admin.initializeApp();

// 環境変数からStripeのシークレットキーを読み込む
// (デプロイ時に firebase functions:config:set で設定)
const stripe = new Stripe(functions.config().stripe.secret_key);

// Checkoutセッション作成API (Callable Functions)
exports.createStripeCheckout = functions.https.onCall(async (data, context) => {
  // ログインしていない場合はエラー
  if (!context.auth) {
    throw new functions.https.HttpsError("unauthenticated", "ログインが必要です");
  }

  // Stripe Checkout セッションを作成
  const session = await stripe.checkout.sessions.create({
    payment_method_types: ["card"],
    mode: "subscription",
    line_items: [
      {
        price: data.priceId, // Stripeダッシュボードで作成した定期課金用のPrice ID
        quantity: 1,
      },
    ],
    success_url: data.successUrl,
    cancel_url: data.cancelUrl,
    customer_email: data.email, // Authのメールアドレスを利用
  });

  // セッションIDを返す
  return { sessionId: session.id };
});

// Stripe Webhookで支払いイベントを受け取る
exports.stripeWebhook = functions.https.onRequest(async (req, res) => {
  let event;
  const endpointSecret = functions.config().stripe.webhook_secret;

  try {
    const sig = req.headers["stripe-signature"];
    event = stripe.webhooks.constructEvent(req.rawBody, sig, endpointSecret);
  } catch (err) {
    console.error("Webhook signature verification failed.", err);
    return res.sendStatus(400);
  }

  switch (event.type) {
    case "checkout.session.completed": {
      // 3日無料トライアルを含むサブスク開始
      const session = event.data.object;
      const customerEmail = session.customer_email;

      // Firestoreでユーザーを探し、activeSubscriptionをtrueに更新
      const userSnapshot = await admin.firestore()
        .collection("users")
        .where("email", "==", customerEmail)
        .limit(1)
        .get();

      if (!userSnapshot.empty) {
        const userDoc = userSnapshot.docs[0];
        await userDoc.ref.update({
          activeSubscription: true,
          subscriptionStart: new Date()
        });
      }

      break;
    }

    case "invoice.payment_failed": {
      // トライアル後の引き落とし失敗など
      const invoice = event.data.object;
      // customerIdを使ってFirestore上の該当ユーザーを探して処理
      break;
    }

    case "customer.subscription.deleted": {
      // サブスク解約
      const subscription = event.data.object;
      // customerIdからFirestoreユーザーを探して activeSubscription = false にする等
      break;
    }

    default:
      console.log(`Unhandled event type ${event.type}`);
  }

  res.json({ received: true });
});

3. 環境変数設定 & デプロイ


// 環境変数にStripeのシークレットキーやWebhook Secretを設定
firebase functions:config:set stripe.secret_key="YOUR_STRIPE_SECRET_KEY" \
stripe.webhook_secret="YOUR_STRIPE_WEBHOOK_SECRET"

// デプロイ
firebase deploy --only functions

YOUR_STRIPE_SECRET_KEY」はStripeダッシュボードから取得したシークレットキーを入れてください。
同様に「YOUR_STRIPE_WEBHOOK_SECRET」はWebhook設定時にStripeから取得します。


D. StripeダッシュボードでWebhook設定

  1. Stripeダッシュボードの「Developers > Webhooks」で「Add endpoint」をクリック。

  2. URLに https://[YOUR_CLOUD_FUNCTIONS_DOMAIN]/stripeWebhook を入力。

  3. 「Event to send」は checkout.session.completed, invoice.payment_failed, customer.subscription.deleted あたりを送信しておけばOKです(運用に応じて追加)。

  4. 作成後、Webhook Secretが発行されます。これを使って firebase functions:config:set ... で設定します。


E. Chrome拡張側の実装

1. manifest.json (Manifest V3例)


{
  "name": "My Paid Extension",
  "version": "1.0.0",
  "manifest_version": 3,
  "description": "最初の3日間が無料の有料サブスクリプション拡張機能",
  "permissions": ["storage", "identity"],
  "background": {
    "service_worker": "background.js"
  },
  "action": {
    "default_popup": "popup.html"
  }
}

2. popup.html の例




  
    
    
    
    
    
  
  
    

My Paid Extension

Googleでログイン

3. popup.js の例

以下では Callable Function (createStripeCheckout) を呼び出し、Stripe Checkout セッションを作成してブラウザを遷移させる流れを示しています。
実際のCSP対策としては、外部サイトに一度飛ばして決済を完了させるほうが安全・簡単です。


// popup.js
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.17.2/firebase-app.js";
import {
  getAuth,
  signInWithPopup,
  GoogleAuthProvider,
  onAuthStateChanged
} from "https://www.gstatic.com/firebasejs/9.17.2/firebase-auth.js";

import { getFunctions, httpsCallable } from "https://www.gstatic.com/firebasejs/9.17.2/firebase-functions.js";

// 1. Firebase 初期化 (プロジェクトの設定情報を入力)
const firebaseConfig = {
  apiKey: "YOUR_API_KEY",
  authDomain: "YOUR_APP.firebaseapp.com",
  projectId: "YOUR_APP",
  storageBucket: "YOUR_APP.appspot.com",
  messagingSenderId: "SENDER_ID",
  appId: "APP_ID",
};
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const functions = getFunctions(app);

// DOM取得
const loginBtn = document.getElementById("login-btn");
const subscriptionSection = document.getElementById("subscription-section");
const subscriptionStatus = document.getElementById("subscription-status");
const subscribeBtn = document.getElementById("subscribe-btn");

// Googleログイン
loginBtn.addEventListener("click", async () => {
  const provider = new GoogleAuthProvider();
  try {
    await signInWithPopup(auth, provider);
  } catch (error) {
    console.error(error);
    alert("ログインに失敗しました");
  }
});

// ログイン状態監視
onAuthStateChanged(auth, (user) => {
  if (user) {
    // ログイン済み → サブスク登録画面を表示
    document.getElementById("login-section").style.display = "none";
    subscriptionSection.style.display = "block";

    // FirestoreやFunctions経由でサブスク状態を確認して表示
    checkSubscriptionStatus(user).then(isActive => {
      subscriptionStatus.innerText = isActive
        ? "サブスク有効です"
        : "サブスク未加入です";
    });
  } else {
    // 未ログイン → ログインボタン表示
    document.getElementById("login-section").style.display = "block";
    subscriptionSection.style.display = "none";
  }
});

// サブスク登録ボタン
subscribeBtn.addEventListener("click", async () => {
  const createStripeCheckout = httpsCallable(functions, "createStripeCheckout");
  try {
    // 事前にStripeダッシュボードで作成したPrice IDを設定
    const priceId = "price_xxx";
    const successUrl = "https://example.com/success"; // 決済完了後のリダイレクト先
    const cancelUrl = "https://example.com/cancel";   // キャンセル時の戻り先

    const result = await createStripeCheckout({
      priceId,
      successUrl,
      cancelUrl,
      email: auth.currentUser.email
    });

    // 受け取った sessionId を使い、Stripe Checkoutへリダイレクト
    if (result.data && result.data.sessionId) {
      const stripePublicKey = "YOUR_STRIPE_PUBLISHABLE_KEY";
      const stripe = Stripe(stripePublicKey); // 事前に  が必要
      await stripe.redirectToCheckout({ sessionId: result.data.sessionId });
    }
  } catch (error) {
    console.error(error);
    alert("サブスク登録ページの作成に失敗しました");
  }
});

// サブスク状態をチェックする仮関数 (FirestoreやカスタムClaimsを用いて実装)
async function checkSubscriptionStatus(user) {
  // カスタムClaimsを利用する場合の例
  const tokenResult = await user.getIdTokenResult(true);
  return tokenResult.claims.activeSubscription === true;
}

F. 拡張機能で機能制限する方法

本質的には「ユーザーがサブスクを持っているかどうか」をFirestoreやカスタムClaimsから確認して、サブスクが無効なら機能をロックする仕組みを作ればOKです。
例えば background.jspopup.js でユーザーがログインするたびにサブスク状態をチェックし、activeSubscription が true なら全機能解放、false なら制限する流れを実装します。


G. 全手順のまとめ (コピペ手順)

  1. Firebaseプロジェクトを用意し、Authentication(ログイン)とFirestore(データベース)を有効化。

  2. Stripeアカウントを作成し、商品(定期購読プラン)を登録。トライアル期間を3日に設定。

  3. mkdir my-extension-backend cd my-extension-backend firebase init functions cd functions npm install stripe

  4. functions/index.js を編集し、createStripeCheckout 関数と stripeWebhook 関数を定義。

  5. firebase functions:config:set stripe.secret_key="YOUR_STRIPE_SECRET_KEY" ^ stripe.webhook_secret="YOUR_STRIPE_WEBHOOK_SECRET" firebase deploy --only functions

  6. Stripeダッシュボードで Webhook を作成し、stripeWebhook のURLに通知を送信。
    Webhook Secretを取得して firebase functions:config:set で設定。

  7. Chrome拡張 (manifest.json, popup.html, popup.js など) を作成し、Firebase SDK & Stripe Checkoutを呼び出す。

  8. サブスク登録が完了すると Firestoreのユーザーデータに activeSubscription: true を記録し、拡張機能はそのフラグをチェックして機能のON/OFFを切り替える。


H. 注意事項 & ヒント

  • Chrome Web Storeの公式課金機能は廃止されたため、サブスク機能は自前で実装する必要があります。

  • 拡張機能内で Stripe.js を直接読み込む際には CSP(Content Security Policy) の制限に注意。外部CDNからのスクリプトを読み込めない可能性があります。

  • 安全策としては、拡張機能外のWebページ(Firebase Hostingや独自サイト)に移動させてStripe Checkoutを利用する構成が望ましいです。

  • Stripeの3日間無料トライアル設定を使うと、自動的にトライアル終了 → 課金が行われます。

  • Webhookで確実に課金状態を検知し、Firestore上でサブスクステータスを更新。拡張機能は常にFirestoreの状態を見て制御するようにしてください。

  • 決済周りはユーザーのクレジットカード情報を扱うため、セキュリティやエラーハンドリングを十分考慮する必要があります。ここでのサンプルはあくまで「最小限の動作例」です。

  • 本番運用に入る前に必ずテストモードでの動作確認を徹底しましょう。


まとめ

本記事の手順を踏めば、「クレジットカード登録後3日間無料 → 以降は自動課金」というサブスクリプション課金モデルをChrome拡張で実装できます。
Stripe を使えば、トライアル期間や月額・年額プランなどを柔軟に設定可能です。
Chrome拡張側はサブスク状態をチェックして、支払いが有効な間だけ機能をフル解放する仕組みを作るだけです。

ぜひ本ガイドを参考に、あなたのChrome拡張に有料サブスクを導入してみてください。
セキュリティやCSP対策など、実運用ではさらにブラッシュアップが必要ですが、まずは本記事の流れで「動く形」を構築してみることをおすすめします。

いいなと思ったら応援しよう!