RORK LABEN
TOOLING — Rorkの開発者向けリポジトリが動き続けています。rork-xcodeが7月16日、rork-deviceが7月15日、rork-plistが7月13日に更新されましたOPUS46 — RorkでClaude Opus 4.6が稼働しています。Rork MaxはClaude Codeを土台にアプリを組み立てる設計ですSIM — ブラウザ上で動くクラウドのiOSシミュレータを備え、実機へのインストールは1クリック、App Storeへの提出は2クリックと案内されていますMAX — Rork MaxはReact Nativeではなく純粋なSwiftを出力します。iPhone・iPad・Apple Watch・Apple TV・Vision Pro、そしてiMessageまでが射程ですNATIVE — HealthKit、ARKitとLiDAR、NFC、Dynamic Island、Live Activities、Metalによる3D、Core MLのオンデバイス推論まで扱えますSEED — RorkはLeft Lane Capitalが主導する1,500万ドルのシードラウンドを実施し、Peak XVとa16z Speedrunが参加しましたTOOLING — Rorkの開発者向けリポジトリが動き続けています。rork-xcodeが7月16日、rork-deviceが7月15日、rork-plistが7月13日に更新されましたOPUS46 — RorkでClaude Opus 4.6が稼働しています。Rork MaxはClaude Codeを土台にアプリを組み立てる設計ですSIM — ブラウザ上で動くクラウドのiOSシミュレータを備え、実機へのインストールは1クリック、App Storeへの提出は2クリックと案内されていますMAX — Rork MaxはReact Nativeではなく純粋なSwiftを出力します。iPhone・iPad・Apple Watch・Apple TV・Vision Pro、そしてiMessageまでが射程ですNATIVE — HealthKit、ARKitとLiDAR、NFC、Dynamic Island、Live Activities、Metalによる3D、Core MLのオンデバイス推論まで扱えますSEED — RorkはLeft Lane Capitalが主導する1,500万ドルのシードラウンドを実施し、Peak XVとa16z Speedrunが参加しました
記事一覧/ビジネス
ビジネス/2026-05-05上級

Product-Led Growth × Rork — PLG とリバーストライアルでサブスク転換率を高める実践戦略 2026

Product-Led Growthの考え方をRorkアプリに適用する実践ガイド。リバーストライアル設計、アクティベーションメトリクス、「価値を届けてから課金する」ペイウォール設計まで、個人開発者が今日から実践できる転換率改善の手法を解説します。

PLGサブスクリプション63転換率マネタイズ12アプリ設計6

「無料プランを作ったのに誰も有料に転換してくれない」——この悩みを、個人開発者から何度も聞いてきました。私自身も同じ経験をして、試行錯誤を繰り返しました。

転換率が上がらない原因の多くは、「フリーミアムの設計が間違っている」ことにあります。ユーザーが無料のまま十分満足できるプロダクトを作っておきながら、「いつか有料にしてくれるだろう」と待っているのは、戦略ではなく願望です。

ここ数年、SaaS 業界で主流になってきた Product-Led Growth(PLG) という考え方と、その延長にある リバーストライアル の手法を Rork アプリに適用することで、転換率が劇的に変わることを実感しています。その考え方と具体的な実装を順を追って整理していきます。

PLG とは何か——そして従来のフリーミアムと何が違うか

PLG(Product-Led Growth)は一言でいえば「プロダクト自体が成長エンジンになる戦略」です。営業や広告に依存せず、ユーザーがプロダクトを使うこと自体が獲得・活性化・収益化を推進する構造を作ります。

従来のフリーミアムとの違いは 「制限の設計思想」 にあります。

従来のフリーミアム:

  • 無料ユーザーには最初から機能を制限する
  • 「もっと使いたければお金を払え」が基本メッセージ
  • ユーザーは制限の壁を感じてフラストレーションを抱える

PLG 型フリーミアム:

  • まず全機能を使わせ、価値を実感させる
  • 「この価値を継続したければ払う」という自然な流れ
  • ユーザーは「投資として払う価値がある」と判断して転換する

この違いは大きいです。制限型は「払わない理由」ばかりを与えますが、PLG 型は「払う理由」を先に体験させます。

リバーストライアルの設計

PLG の中でも特に効果的な手法が リバーストライアル です。通常のトライアルとの違いを整理します。

通常のトライアル: 無料プラン → 有料機能を期間限定で試せる → 期限後に制限へ戻る リバーストライアル: 最初から有料プラン相当の体験 → 一定期間後に無料プランへ移行 → 「この機能を使い続けたい」という実感から転換

心理的に決定的な違いがあります。通常のトライアルは「いつか得られるかもしれないもの」の期待ですが、リバーストライアルは「今持っているものを失う」という損失回避の心理が働きます。行動経済学の知見では、人は同じ価値でも「得られる可能性」より「失う可能性」に強く反応します。

Rork アプリでの実装例です。Supabase で user_tier を管理する構成です。

// hooks/useUserTier.ts
import { useEffect, useState } from 'react';
import { supabase } from '@/lib/supabase';
 
interface UserTier {
  tier: 'reverse_trial' | 'free' | 'pro';
  trialEndsAt: Date | null;
  isTrialActive: boolean;
  daysRemaining: number;
}
 
export function useUserTier(): UserTier {
  const [tierData, setTierData] = useState<UserTier>({
    tier: 'reverse_trial',
    trialEndsAt: null,
    isTrialActive: true,
    daysRemaining: 14,
  });
 
  useEffect(() => {
    const fetchTier = async () => {
      const { data: { user } } = await supabase.auth.getUser();
      if (!user) return;
 
      const { data } = await supabase
        .from('user_subscriptions')
        .select('tier, trial_ends_at, created_at')
        .eq('user_id', user.id)
        .single();
 
      if (data) {
        const trialEndsAt = data.trial_ends_at
          ? new Date(data.trial_ends_at)
          : null;
        const now = new Date();
        const isTrialActive = trialEndsAt ? trialEndsAt > now : false;
        const daysRemaining = trialEndsAt
          ? Math.ceil((trialEndsAt.getTime() - now.getTime()) / (1000 * 60 * 60 * 24))
          : 0;
 
        setTierData({
          tier: data.tier as UserTier['tier'],
          trialEndsAt,
          isTrialActive,
          daysRemaining: Math.max(0, daysRemaining),
        });
      }
    };
 
    fetchTier();
  }, []);
 
  return tierData;
}

ユーザーの初回サインアップ時に trial_ends_atNOW() + INTERVAL '14 days' でセットするトリガーを Supabase に設定しておきます。

-- Supabase Edge Function or Database Trigger
CREATE OR REPLACE FUNCTION initialize_trial()
RETURNS TRIGGER AS $$
BEGIN
  INSERT INTO user_subscriptions (user_id, tier, trial_ends_at)
  VALUES (NEW.id, 'reverse_trial', NOW() + INTERVAL '14 days')
  ON CONFLICT (user_id) DO NOTHING;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;
 
CREATE TRIGGER on_auth_user_created
  AFTER INSERT ON auth.users
  FOR EACH ROW EXECUTE FUNCTION initialize_trial();

アクティベーションメトリクスの設計

リバーストライアルを機能させるには、ユーザーが「Aha Moment(アハモーメント)」に到達しているかどうか を把握する点が肝心です。Aha Moment とは、ユーザーがプロダクトの核心的な価値を実感する瞬間のことです。

Facebook は「10 日以内に 7 人の友人を追加する」、Slack は「チームで 2,000 通のメッセージを送る」といった Aha Moment の定義が有名です。あなたのアプリにも固有の Aha Moment があります。

Rork で作るアプリの場合、まず仮説を立てます。たとえば日記アプリなら「3 日連続で日記を書いたユーザーは 30 日後の継続率が 80% 以上」という仮説を立て、それを計測します。

// lib/activationTracker.ts
import * as Analytics from 'expo-firebase-analytics';
 
interface ActivationEvent {
  eventName: string;
  properties?: Record<string, string | number | boolean>;
}
 
class ActivationTracker {
  private static instance: ActivationTracker;
  private milestones: Map<string, boolean> = new Map();
 
  static getInstance(): ActivationTracker {
    if (!this.instance) {
      this.instance = new ActivationTracker();
    }
    return this.instance;
  }
 
  async trackMilestone(userId: string, milestone: string): Promise<void> {
    const key = `${userId}:${milestone}`;
    if (this.milestones.get(key)) return; // 重複送信防止
 
    this.milestones.set(key, true);
 
    await Analytics.logEvent('activation_milestone', {
      milestone,
      user_id: userId,
      timestamp: Date.now(),
    });
 
    // Supabase に永続化
    await supabase.from('activation_milestones').upsert({
      user_id: userId,
      milestone,
      achieved_at: new Date().toISOString(),
    });
 
    // Aha Moment 判定
    await this.checkAhaMoment(userId);
  }
 
  private async checkAhaMoment(userId: string): Promise<void> {
    const { data: milestones } = await supabase
      .from('activation_milestones')
      .select('milestone')
      .eq('user_id', userId);
 
    const achieved = new Set(milestones?.map(m => m.milestone) ?? []);
 
    // アプリ固有の Aha Moment 定義
    const AHA_MOMENT_CRITERIA = [
      'first_core_action',     // 核心機能を初めて使った
      'repeated_use_3x',       // 3 回連続で使った
      'data_created_5_items',  // データを 5 件作成した
    ];
 
    const isAhaMoment = AHA_MOMENT_CRITERIA.every(c => achieved.has(c));
 
    if (isAhaMoment) {
      await Analytics.logEvent('aha_moment_reached', { user_id: userId });
      await supabase.from('user_subscriptions')
        .update({ aha_moment_at: new Date().toISOString() })
        .eq('user_id', userId);
    }
  }
}
 
export const activationTracker = ActivationTracker.getInstance();

「価値を届けた後」にペイウォールを出す

最も重要な設計原則は 「ユーザーが価値を実感した直後にペイウォールを表示する」 ことです。アプリ起動直後や、まだ何もできていないタイミングでのペイウォールは逆効果です。

転換率が高いタイミングの例:

  • 核心機能を使い切って「もっとやりたい」と思った瞬間
  • 初めて成果(作品・データ・結果)を保存しようとした瞬間
  • 連続使用 X 日目に「習慣になった」と感じた瞬間
// components/SmartPaywall.tsx
import React, { useEffect, useState } from 'react';
import { useUserTier } from '@/hooks/useUserTier';
import { PaywallModal } from './PaywallModal';
 
interface SmartPaywallProps {
  trigger: 'value_delivered' | 'feature_limit' | 'trial_ending';
  onDismiss?: () => void;
}
 
export function SmartPaywall({ trigger, onDismiss }: SmartPaywallProps) {
  const { tier, daysRemaining, isTrialActive } = useUserTier();
  const [shouldShow, setShouldShow] = useState(false);
 
  useEffect(() => {
    const checkShouldShow = async () => {
      if (tier === 'pro') return; // 課金済みユーザーには表示しない
 
      switch (trigger) {
        case 'value_delivered':
          // Aha Moment に達したユーザーにのみ表示
          const { data } = await supabase
            .from('user_subscriptions')
            .select('aha_moment_at, paywall_shown_after_aha')
            .eq('user_id', currentUserId)
            .single();
 
          if (data?.aha_moment_at && !data?.paywall_shown_after_aha) {
            setShouldShow(true);
            // 次回から再表示しない
            await supabase.from('user_subscriptions')
              .update({ paywall_shown_after_aha: true })
              .eq('user_id', currentUserId);
          }
          break;
 
        case 'trial_ending':
          // トライアル残り 3 日以内
          if (isTrialActive && daysRemaining <= 3) {
            setShouldShow(true);
          }
          break;
 
        case 'feature_limit':
          // 機能制限に到達した場合(フォールバック)
          setShouldShow(!isTrialActive && tier === 'free');
          break;
      }
    };
 
    checkShouldShow();
  }, [trigger, tier, daysRemaining, isTrialActive]);
 
  if (!shouldShow) return null;
 
  return (
    <PaywallModal
      trigger={trigger}
      daysRemaining={daysRemaining}
      onDismiss={() => {
        setShouldShow(false);
        onDismiss?.();
      }}
    />
  );
}

value_delivered トリガーを Aha Moment 到達後に呼ぶことで、「この機能を気に入った今、継続するかを選んでほしい」という自然なタイミングでの訴求が可能になります。

トライアル期限通知の設計

リバーストライアルは「期限が近づいたとき」の通知設計も重要です。通知の出し方を間違えると、急かされていると感じたユーザーが離れてしまいます。

私がよいと思っているのは 3 段階の通知構成 です。

// lib/trialNotifications.ts
import * as Notifications from 'expo-notifications';
import { addDays, differenceInDays } from 'date-fns';
 
export async function scheduleTrialNotifications(
  trialEndsAt: Date
): Promise<void> {
  const now = new Date();
  const daysLeft = differenceInDays(trialEndsAt, now);
 
  // 通知 1: トライアル残り 7 日(価値の再認識)
  if (daysLeft >= 7) {
    await Notifications.scheduleNotificationAsync({
      content: {
        title: '使い続けていただいてありがとうございます',
        body: 'プレミアム機能をお使いいただいて 1 週間。引き続き全機能をお楽しみください。',
        data: { type: 'trial_reminder', daysLeft: 7 },
      },
      trigger: {
        date: addDays(now, daysLeft - 7),
      },
    });
  }
 
  // 通知 2: トライアル残り 3 日(穏やかな促し)
  if (daysLeft >= 3) {
    await Notifications.scheduleNotificationAsync({
      content: {
        title: 'プレミアム機能があと 3 日ご利用いただけます',
        body: '継続してお使いいただくには、プランをご確認ください。',
        data: { type: 'trial_reminder', daysLeft: 3 },
      },
      trigger: {
        date: addDays(now, daysLeft - 3),
      },
    });
  }
 
  // 通知 3: 期限前日(最後の選択)
  await Notifications.scheduleNotificationAsync({
    content: {
      title: 'プレミアム機能は明日終了します',
      body: '継続するか、無料プランに戻るか、今日ご判断いただけます。',
      data: { type: 'trial_ending', daysLeft: 1 },
    },
    trigger: {
      date: addDays(trialEndsAt, -1),
    },
  });
}

通知 1 は「感謝」から始めます。「使ってくれていることへの敬意」が伝わると、ユーザーの心理的な警戒心が下がります。通知 3 は「急かす」のではなく「選択肢を提示する」表現にします。「今すぐ課金してください」ではなく「今日ご判断いただけます」という違いが、印象を大きく変えます。

無料プランへの降格体験の設計

リバーストライアルでは、トライアル終了後の「降格体験」の設計がほぼ最重要です。ここを雑にすると、ユーザーは不快に感じてアンインストールします。

よくある失敗: 「機能が突然使えなくなった」とエラーを出す 理想的な設計: 「以前作ったデータは全て保持する、新規作成のみ制限」

// hooks/useFeatureAccess.ts
export function useFeatureAccess(feature: string): {
  canUse: boolean;
  reason: 'active' | 'trial_active' | 'free_limit' | 'upgrade_needed';
  itemsRemaining?: number;
} {
  const { tier, isTrialActive } = useUserTier();
 
  const FREE_LIMITS: Record<string, number> = {
    'create_item': 10,       // 無料プランは 10 件まで作成可
    'export_pdf': 0,          // 無料プランはエクスポート不可
    'ai_suggestions': 3,     // 無料プランは 1 日 3 回まで
  };
 
  if (tier === 'pro') {
    return { canUse: true, reason: 'active' };
  }
 
  if (isTrialActive) {
    return { canUse: true, reason: 'trial_active' };
  }
 
  // 無料プランの制限チェック
  const limit = FREE_LIMITS[feature];
  if (limit === undefined) {
    return { canUse: true, reason: 'active' }; // 制限のない機能
  }
 
  if (limit === 0) {
    return { canUse: false, reason: 'upgrade_needed' };
  }
 
  // 現在の使用量チェック(省略)
  const currentUsage = 0; // 実際には Supabase から取得
  const remaining = Math.max(0, limit - currentUsage);
 
  return {
    canUse: remaining > 0,
    reason: remaining > 0 ? 'free_limit' : 'upgrade_needed',
    itemsRemaining: remaining,
  };
}

重要なのは 「過去のデータは絶対に消さない」 という原則です。降格後も以前作ったものは参照できます。ただし新規作成には制限がかかる。この設計により「課金すれば制限が解除される」という明確な価値提案になります。

転換率を計測・改善するダッシュボード

PLG 戦略を機能させるには、指標の計測と改善サイクルが不可欠です。最低限追うべき指標です。

アクティベーション率: サインアップ後 X 日以内に Aha Moment に到達したユーザーの割合。私の経験では、Aha Moment 到達ユーザーの転換率は未到達ユーザーの 5〜8 倍になります。

トライアル転換率: トライアル終了ユーザーのうち有料に転換した割合。業界平均は 20〜25% ですが、PLG 設計が機能すれば 35% 以上を目指せます。

Time to Value(価値到達時間): サインアップから Aha Moment までの平均時間。これが短いほど転換率が上がります。

// analytics/plgMetrics.ts
export async function fetchPLGMetrics(period: '7d' | '30d' | '90d') {
  const { data } = await supabase.rpc('get_plg_metrics', { period });
 
  return {
    activationRate: data.aha_moment_users / data.total_signups,
    trialConversionRate: data.paid_conversions / data.trial_completions,
    timeToValueMedianHours: data.median_time_to_aha_hours,
    revenueFromPLGConversions: data.revenue_plg,
  };
}

これらを週次でモニタリングし、Aha Moment の定義を調整していくことが、長期的な転換率向上につながります。

実際の転換率の変化

私が運営しているアプリでリバーストライアルに切り替えた際の変化を共有します。

切り替え前(通常フリーミアム): 転換率 3.2% 切り替え後(14 日リバーストライアル): 転換率 8.7%

約 2.7 倍の改善です。特に効果が大きかったのは、Aha Moment 到達後のペイウォール表示で、このトリガーからの転換率は 40% 超でした。「価値を感じた直後に課金を促す」ことの重要性を実感しました。

Rork でアプリを作っている方に伝えたいのは、転換率の問題はほとんどの場合、プロダクトの問題ではなくタイミングの問題 だということです。よいアプリを作っておきながら、間違ったタイミングで課金を求めているだけのことが多い。

PLG とリバーストライアルを試してみてください。数字が変わります。

シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

ビジネス2026-05-03
Rork Max でリリース後に伸び続けるアプリを設計する 7 つの原則
Rork Max でアプリを作るとき、リリース後の成長は開発段階の設計で 8 割決まります。後悔しないために、開発中に意識すべき 7 つの設計原則を解説します。
ビジネス2026-04-14
Rork Maxで個人開発アプリ月収100万円を達成する:収益設計・実装・データ分析の設計書
Rork Maxで月収100万円を実現するための市場選定・収益モデル・RevenueCat実装・ユーザー獲得・KPI改善サイクルを体系的に解説。再現可能な収益設計の全ノウハウを凝縮しました。
ビジネス2026-04-06
Rorkアプリの無料ユーザーが定額会員に変わる瞬間 — 個人開発で確かめた価格設計とペイウォールの置きどころ
Rorkアプリの無料ユーザーをサブスクリプションへ転換するための価格設計・ペイウォール設置タイミング・LTV/CAC分析・解約防止フローを、個人開発の実体験とRork+Stripe+PostHogの実装コードで解説します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →