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-11上級

Rorkで作る引き寄せ・運勢系アプリ — 累計5,000万DLから学んだ日替わり配信とリピート設計

占い・引き寄せ・運勢系アプリは初日のDLは取れても3日で離脱されがちなジャンルです。日替わりコンテンツ配信・通知タイミング・ウィジェットを統合した、Rorkでの実装パターンを実体験ベースで整理しました。

引き寄せアプリ運勢アプリ占いアプリ2リテンション17プッシュ通知19ウィジェット7個人開発187Rork515

プレミアム記事

Rorkで作る引き寄せ・運勢系アプリ — 累計5,000万DLから学んだ日替わり配信とリピート設計

「占い系アプリを作ったが、3日後にはほとんど起動されていない」——個人開発を始めたばかりの頃、私自身が直面した壁です。インストール数のグラフは初日に大きく跳ねるのですが、3日目を境にだいたい1/5から1/10に落ち込みます。広告収益のグラフも同じ形で落ちますから、月末になって「あの初動は何だったのだろう」と振り返ることになります。

このジャンル特有の構造があります。引き寄せ・運勢・占いアプリは「コンテンツが日々入れ替わる」という前提で設計しないと、ユーザーの中で役割を持たないまま忘れられていきます。今回は、2014年から個人開発でアプリを運用してきた経験と、累計5,000万DLを超えたアプリ事業の現場で繰り返し検証してきた「日替わり配信」の設計を、Rorkでどう組み立てるかという視点で整理します。

私は壁紙・癒し・引き寄せ系のアプリを長く運営してきました。AdMob 月収のピークは150万円を超える月もありましたが、その月の裏側には「日替わりで届くコンテンツの設計」を地道に直し続けた時期が必ずあります。一発でうまくいったケースは、振り返ってもひとつもありませんでした。

なぜ運勢系アプリはリピートで負けるのか — 構造的な3つの理由

まず、なぜこのジャンルが特にリピートで脱落しやすいのかを言語化しておきます。原因が見えていないと、対策も的を外します。

理由1: 「結果型コンテンツ」と「日課型コンテンツ」が混同される

占いも引き寄せも、ユーザー側の体験としては「結果を知って終わる」コンテンツに見えがちです。今日の運勢を見たら、その日はもう開く理由がありません。これを翌日も開いてもらう構造に変えるには、「結果」を「日課」に翻訳する設計が必要になります。

理由2: 通知のタイミングが「思想」ではなく「実装の都合」で決まる

朝の通知を朝9時に送るアプリは多いですが、9時という時刻が選ばれた理由を説明できる開発者は意外と少ないです。実際には「夜は反応が悪いから昼にしておこう」程度の理由で決まっていることが多く、結果としてジャンルとの相性が悪い時間に届きます。

理由3: コンテンツの「ストック」と「フロー」が設計されていない

毎日新しいコンテンツを作るのは個人開発者にとって持続不可能です。ストック(基礎データセット)から日替わりで切り出すフロー(提示順序)を分けて設計しないと、3週間でネタが尽きます。

この3つは、ジャンル特有の落とし穴です。技術力ではなく設計判断の問題で、ここを言語化しないままRorkで実装に入ると、必ず似たような形で詰まります。

日替わり配信の核心 — 「ユーザーごとに固有・かつ再現可能」を成立させる

日替わり配信の中心にあるのは「ユーザーAさんに今日表示される運勢は、Aさんにとって唯一であり、かつ同じ日中は何度開いても同じ結果を返す」という性質です。これを成立させるためには、サーバー側で毎朝バッチ処理を回す方法と、クライアント側でシード付き擬似乱数を使う方法の2通りがあります。

個人開発の規模では、後者を強く勧めます。理由は単純で、サーバー側で毎ユーザー分のレコードを毎日作るより、クライアント側で「ユーザーID + 日付」をシードとして擬似乱数を生成するほうがコストが明確に小さいからです。

ここでまず、シード付き擬似乱数のコア部分を実装します。Rorkはローカル状態管理にTypeScriptを使いますから、Mulberry32という軽量な決定論的擬似乱数を使います。

// src/lib/dailyFortune.ts
// 日付ベースで決定論的に運勢を返す擬似乱数
 
/**
 * Mulberry32: 軽量な決定論的擬似乱数
 * 同じシードからは同じシーケンスが返る性質を利用する
 */
function mulberry32(seed: number): () => number {
  return function () {
    seed |= 0;
    seed = (seed + 0x6d2b79f5) | 0;
    let t = seed;
    t = Math.imul(t ^ (t >>> 15), t | 1);
    t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
  };
}
 
/**
 * 文字列を32bit整数のハッシュに変換する (FNV-1a)
 * userId と日付文字列をシードに変換するために使う
 */
function hash32(input: string): number {
  let h = 0x811c9dc5;
  for (let i = 0; i < input.length; i++) {
    h ^= input.charCodeAt(i);
    h = Math.imul(h, 0x01000193);
  }
  return h >>> 0;
}
 
export type FortuneResult = {
  date: string;        // "2026-05-11"
  rank: number;        // 1-12 (1が大吉、12が凶)
  rankLabel: string;   // "大吉" など
  themeId: string;     // テーマ別の固有ID(恋愛・仕事・健康など)
  message: string;     // メッセージ本文
};
 
const RANK_LABELS = [
  "大吉", "中吉", "吉", "小吉", "末吉", "半吉",
  "平", "末小吉", "下吉", "小凶", "末凶", "凶",
] as const;
 
export function generateDailyFortune(
  userId: string,
  dateISO: string, // "2026-05-11"
  messages: { themeId: string; rankMin: number; rankMax: number; body: string }[],
): FortuneResult {
  const seed = hash32(`${userId}:${dateISO}`);
  const rand = mulberry32(seed);
 
  // 12段階の運勢ランク(重み付きで「大吉」「凶」を出にくくする)
  const rankRoll = rand();
  let rank = 7;
  if (rankRoll < 0.05) rank = 1;
  else if (rankRoll < 0.20) rank = 2;
  else if (rankRoll < 0.55) rank = Math.floor(rand() * 4) + 3; // 3-6
  else if (rankRoll < 0.85) rank = Math.floor(rand() * 4) + 6; // 6-9
  else if (rankRoll < 0.97) rank = Math.floor(rand() * 2) + 9; // 9-10
  else rank = 12;
 
  // ランクに合うメッセージ群から1件選ぶ
  const candidates = messages.filter(
    (m) => rank >= m.rankMin && rank <= m.rankMax,
  );
  const picked = candidates[Math.floor(rand() * candidates.length)] ?? messages[0];
 
  return {
    date: dateISO,
    rank,
    rankLabel: RANK_LABELS[rank - 1] ?? "吉",
    themeId: picked.themeId,
    message: picked.body,
  };
}

このコードのポイントは、サーバー通信を一切必要としないことです。userIdは初回起動時にローカルで発行したUUIDで構いません。同じ日付の間は何度呼び出しても同じ結果を返しますし、日付が変われば自動的に別の結果が出ます。

実装直前にハマりやすい点を一つ挙げておくと、new Date().toISOString().slice(0, 10)を使ってISO日付を取り出すと、UTC基準になるため、ユーザーの体感日付とずれる場合があります。私のアプリではJSTオフセットを明示的に加える形に切り替えてから、深夜帯のユーザーから「日付が変わってないのに運勢が変わった」というレビューがなくなりました。

// src/lib/dateInUserTimezone.ts
// ユーザーのローカルタイムゾーンで「今日」を返す
 
export function todayInUserTimezone(now: Date = new Date()): string {
  // Intl.DateTimeFormat を使ってローカルタイムゾーンでフォーマット
  const fmt = new Intl.DateTimeFormat("en-CA", {
    timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
    year: "numeric",
    month: "2-digit",
    day: "2-digit",
  });
  // "2026-05-11" 形式(en-CA は YYYY-MM-DD 区切り)
  return fmt.format(now);
}

Intl.DateTimeFormatは端末のタイムゾーンを自動的に取得しますから、海外ユーザー対応も同じコードで済みます。私の引き寄せ系アプリ(『引き寄せの法則アプリ』)は台湾・タイ・ベトナムにユーザーが広がっていますが、この実装にしてから時差クレームが消えました。

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

この記事の続きを読む

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

この記事で得られること
「日替わりコンテンツアプリを作ったが3日で離脱される」状態から、毎日開かれる日課アプリへ転換するための日替わり配信設計とリピートの仕掛けを手に入れられる
Rorkで動かせる日替わりシード生成・通知スケジューリング・ロック画面ウィジェットの3点を、コピーして調整できるコードで実装する手順がわかる
スピリチュアル文脈と技術実装をどう接続するか、個人開発者の倫理と収益性のバランスを取るための判断軸を持てる
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

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

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

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

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

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

関連記事

ビジネス2026-05-22
AdMob オープンアプリ広告の頻度設計 — 復帰時の体感ストレスを抑えながら eCPM を取りに行く運用メモ
壁紙アプリの最新アップデートで AdMob オープンアプリ広告のフリークエンシー設計を作り直した実装メモです。最小間隔・コールドスタート除外・ホーム戻り抑制を Remote Config で動的制御し、Claude in Chrome で日次の傾向確認を半自動化した工程をまとめています。
ビジネス2026-04-29
Rork で作ったアプリを『削除されない』ものにする — 個人開発のための継続率設計
Rork で作ったアプリは数日で消されることが多いという現実から、削除されないアプリを作るための初週設計を、廣川政樹のアプリ運営経験とともに掘り下げます。
ビジネス2026-04-11
Rorkアプリのリテンション・LTV最大化 — Day1から長期ユーザーを育てる設計
Rorkで開発したアプリのリテンション率とLTV(ライフタイムバリュー)を最大化する実践的な戦略ガイド。Day1/Day7/Day30の改善手法から、チャーン防止、バイラルループ設計まで個人開発者向けに体系的に解説します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →