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など)に誘導して決済させる構成がおすすめ。
全体的な流れ
Firebaseプロジェクトを作成し、Firestore と Firebase Authentication を有効化。
Stripeアカウントを作成し、3日間の無料トライアル付きのサブスクリプションプランを登録。
Firebase FunctionsでWebhookエンドポイントを作成し、Stripeのイベント通知(決済成功/失敗)を受け取る。
Chrome拡張のユーザーが料金プランを選び、決済情報入力 → 3日無料トライアル開始。
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アカウント作成・サブスクリプション商品設定
Stripe公式サイトでアカウントを作成し、事業情報などを登録。
Stripeダッシュボードでテスト用「Publishable key」「Secret key」を取得。
本番運用時は「本番キー」を使用しますが、最初はテストキーで進めます。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設定
Stripeダッシュボードの「Developers > Webhooks」で「Add endpoint」をクリック。
URLに https://[YOUR_CLOUD_FUNCTIONS_DOMAIN]/stripeWebhook を入力。
「Event to send」は checkout.session.completed, invoice.payment_failed, customer.subscription.deleted あたりを送信しておけばOKです(運用に応じて追加)。
作成後、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.js や popup.js でユーザーがログインするたびにサブスク状態をチェックし、activeSubscription が true なら全機能解放、false なら制限する流れを実装します。
G. 全手順のまとめ (コピペ手順)
Firebaseプロジェクトを用意し、Authentication(ログイン)とFirestore(データベース)を有効化。
Stripeアカウントを作成し、商品(定期購読プラン)を登録。トライアル期間を3日に設定。
mkdir my-extension-backend cd my-extension-backend firebase init functions cd functions npm install stripe
functions/index.js を編集し、createStripeCheckout 関数と stripeWebhook 関数を定義。
firebase functions:config:set stripe.secret_key="YOUR_STRIPE_SECRET_KEY" ^ stripe.webhook_secret="YOUR_STRIPE_WEBHOOK_SECRET" firebase deploy --only functions
Stripeダッシュボードで Webhook を作成し、stripeWebhook のURLに通知を送信。
Webhook Secretを取得して firebase functions:config:set で設定。Chrome拡張 (manifest.json, popup.html, popup.js など) を作成し、Firebase SDK & Stripe Checkoutを呼び出す。
サブスク登録が完了すると 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対策など、実運用ではさらにブラッシュアップが必要ですが、まずは本記事の流れで「動く形」を構築してみることをおすすめします。
