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-03-29上級

Rork アプリのプッシュ通知マスタープラン — セグメント配信・A/Bテスト・自動化パイプラインの実装ガイド

Rork アプリにおけるプッシュ通知の上級実装ガイド。ユーザーセグメント配信、A/Bテスト、自動化パイプライン、リテンション向上戦略まで体系的に解説します。

Rork515プッシュ通知19セグメント配信A/Bテスト9Firebase Cloud MessagingExpo Notificationsリテンション17自動化12

プレミアム記事

取り組みの背景 — なぜ「送るだけ」の通知では足りないのか

プッシュ通知はモバイルアプリのリテンション施策として最も強力なチャネルです。しかし、全ユーザーに同じメッセージを一斉送信するだけでは、通知疲れによるオプトアウト率の上昇を招き、逆効果になりかねません。

実際に App Store や Google Play のトップアプリを分析すると、ほぼすべてがユーザーの行動履歴や属性に基づいたセグメント配信を行い、通知文面や配信タイミングをA/Bテストで最適化しています。さらに、これらを手動で運用するのではなく、イベントドリブンな自動化パイプラインで回しているのが特徴です。

ここでは Rork(React Native / Expo)アプリを対象に、プッシュ通知をプロダクション運用に耐える品質まで引き上げるための設計と実装をまとめます。前提として、プッシュ通知の基本実装は一度自分で動かしたことがある方(プッシュ通知の基本実装ガイド を読了済みの方)を想定しています。

セグメント配信の設計 — ユーザーを「理解して」届ける

セグメントの種類と設計原則

効果的なセグメント配信を行うには、まずユーザーをどのような軸で分類するかを設計する必要があります。実務で使われる代表的なセグメント軸は以下の通りです。

属性ベースセグメント: ユーザー登録時の情報(言語、地域、プラン種別、登録日)に基づく分類です。最もシンプルですが、パーソナライズの精度は限定的です。

行動ベースセグメント: アプリ内のアクション(最終利用日、利用頻度、特定機能の使用回数、課金履歴)に基づく分類です。ユーザーの「今の状態」を反映するため、精度の高い通知配信が可能になります。

ライフサイクルセグメント: ユーザーの利用段階(新規・アクティブ・休眠・離脱リスク・復帰)に基づく分類です。段階に応じて最適なメッセージを送り分けることで、リテンション率を大幅に改善できます。

Supabase でセグメント管理テーブルを設計する

セグメント情報を管理するためのデータベース設計を見てみましょう。Supabase(PostgreSQL)を使った実装例です。

-- ユーザーセグメント管理テーブル
CREATE TABLE user_segments (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
  -- 属性セグメント
  locale TEXT DEFAULT 'ja',
  plan_type TEXT DEFAULT 'free', -- free / pro / premium
  registered_at TIMESTAMPTZ NOT NULL,
  -- 行動セグメント
  last_active_at TIMESTAMPTZ,
  session_count INTEGER DEFAULT 0,
  feature_usage JSONB DEFAULT '{}',
  -- ライフサイクルセグメント(自動計算)
  lifecycle_stage TEXT GENERATED ALWAYS AS (
    CASE
      WHEN last_active_at IS NULL THEN 'new'
      WHEN last_active_at > NOW() - INTERVAL '3 days' THEN 'active'
      WHEN last_active_at > NOW() - INTERVAL '14 days' THEN 'inactive'
      WHEN last_active_at > NOW() - INTERVAL '30 days' THEN 'at_risk'
      ELSE 'churned'
    END
  ) STORED,
  -- 通知設定
  push_token TEXT,
  push_enabled BOOLEAN DEFAULT true,
  quiet_hours_start TIME DEFAULT '22:00',
  quiet_hours_end TIME DEFAULT '08:00',
  timezone TEXT DEFAULT 'Asia/Tokyo',
  updated_at TIMESTAMPTZ DEFAULT NOW()
);
 
-- セグメントクエリ用インデックス
CREATE INDEX idx_segments_lifecycle ON user_segments(lifecycle_stage);
CREATE INDEX idx_segments_plan ON user_segments(plan_type);
CREATE INDEX idx_segments_push ON user_segments(push_enabled) WHERE push_token IS NOT NULL;

ポイントは lifecycle_stage カラムです。PostgreSQL の GENERATED ALWAYS AS ... STORED を使うことで、last_active_at が更新されるたびにライフサイクルステージが自動的に再計算されます。アプリケーション側でのロジック管理が不要になり、常に最新の状態を参照できます。

Rork アプリ側でのセグメントデータ更新

ユーザーの行動データをリアルタイムでセグメントテーブルに反映するフックを実装します。

// hooks/useSegmentTracker.ts
import { useEffect, useCallback } from 'react';
import { AppState, AppStateStatus } from 'react-native';
import { supabase } from '@/lib/supabase';
import { useAuth } from '@/hooks/useAuth';
 
export function useSegmentTracker() {
  const { user } = useAuth();
 
  // アプリがフォアグラウンドに復帰したときにセッションを記録
  useEffect(() => {
    if (!user) return;
 
    const subscription = AppState.addEventListener(
      'change',
      (nextState: AppStateStatus) => {
        if (nextState === 'active') {
          updateActivity(user.id);
        }
      }
    );
 
    // 初回マウント時にも記録
    updateActivity(user.id);
 
    return () => subscription.remove();
  }, [user]);
 
  const updateActivity = useCallback(async (userId: string) => {
    const { error } = await supabase
      .from('user_segments')
      .upsert(
        {
          user_id: userId,
          last_active_at: new Date().toISOString(),
          session_count: supabase.rpc('increment_session_count', {
            target_user_id: userId,
          }),
        },
        { onConflict: 'user_id' }
      );
 
    if (error) {
      console.warn('Segment update failed:', error.message);
    }
  }, []);
 
  // 特定機能の利用を記録するヘルパー
  const trackFeatureUsage = useCallback(
    async (featureName: string) => {
      if (!user) return;
 
      const { data: current } = await supabase
        .from('user_segments')
        .select('feature_usage')
        .eq('user_id', user.id)
        .single();
 
      const usage = (current?.feature_usage as Record<string, number>) || {};
      usage[featureName] = (usage[featureName] || 0) + 1;
 
      await supabase
        .from('user_segments')
        .update({ feature_usage: usage })
        .eq('user_id', user.id);
    },
    [user]
  );
 
  return { trackFeatureUsage };
}

このフックをアプリのルートレイアウトで呼び出すことで、ユーザーのセッション情報が自動的に記録されます。trackFeatureUsage は特定の画面やアクションで個別に呼び出し、機能ごとの利用回数を蓄積します。

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

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
5,000万DL累計のアプリ運営で気づいた、セグメント設計とオプトアウト率の実数値
マルチアプリ並行運営での共通通知基盤の設計パターンと配信レート制御の実装
BigQuery+Looker Studioを使った継続的KPIモニタリングと改善サイクルの回し方
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

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

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

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

関連記事

開発ツール2026-07-17
許可を聞かずに通知を届ける — Rork アプリの provisional 認可と、Expo の定番コードが握りつぶすもの
iOS には許可ダイアログを出さずに通知を配り始める provisional 認可があります。ところが Expo 公式が載せている定番の登録コードをそのまま使うと、provisional で通った端末が「拒否」として扱われ、避けたかったはずのダイアログが出ます。granted が false になる仕組みから、5値で許可状態を扱うフック、静かな配信を前提にした通知設計、昇格を求める判断、計測の分離までを実装込みで整理しました。
開発ツール2026-06-14
Rork アプリのプッシュ許可、いきなり出して断られていませんか — 事前許諾で取りこぼしを減らす設計
Rork(Expo)で作ったアプリの起動直後に OS のプッシュ許可ダイアログを出すと、断られた瞬間にもう二度と出せなくなります。一度断られると再表示できない iOS の仕様を踏まえ、自前の事前許諾画面で許可率を底上げする設計を、実装コード込みで整理しました。
開発ツール2026-06-13
通知の許可は一度しか聞けない — Rork アプリにソフトアスク(事前確認)を実装して opt-in を底上げする
iOS の通知許可は一度拒否されると二度とダイアログを出せません。Rork(Expo)アプリで、起動直後に system prompt を撃つのではなく自前のソフトアスク画面を一枚挟み、価値が伝わった瞬間に許可を求める実装を expo-notifications で組みます。Android 13 の POST_NOTIFICATIONS、拒否後の設定誘導、opt-in 計測まで通します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →