debugging-surveys について
PostHog のサポート向けに、アプリ内アンケートが表示されない原因や回答データの不整合を調べるスキルです。表示条件、SDK の差異、回答処理の流れを分析します。
主な機能
- 01SDK ごとのアンケート対応状況を比較
- 02Web アンケートの表示条件を追跡
- 03回答の収集と統合を診断
- 04分岐と任意質問を解釈
- 05イベントやトレースでチケットを調査
活用シーン
- 01アンケートが表示されない原因の特定
- 02モバイル SDK 間の挙動差の説明
- 03回答数や未入力項目の調査
MCP 対応
PostHog MCP ツールまたはアンケート API で設定と回答を確認します。PostHog リポジトリのチェックアウトは不要です。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ posthog/ ai-plugin --skill debugging-surveysインストール後、Claude Code で/debugging-surveysを入力して読み込まれたか確認します。
同梱ファイルreferences/diagnostic-queries.mdreferences/reading-responses.md
詳細
翻訳後に原文が更新されています。最新の内容は原文をご確認ください。
アンケートのデバッグ
PostHog Surveys は、ノーコードのアプリ内フォームビルダーです。顧客が PostHog UI でアンケートを作成すると、そのアンケートを顧客のアプリが使用する SDK で評価し、表示する必要があります。 「アンケートが表示されない」という問い合わせの多くは、表示の不具合ではなく適格性の問題です。SDK はユーザーが適格ではないと正しく判断しており、どの条件で除外されたのか、そしてその理由を特定することが重要です。
アクセス要件
PostHog MCP ツールまたはアンケート API を使用して、アンケートの設定と回答を調べます。 これらの診断手順に PostHog リポジトリのチェックアウトは必要ありません。
SDK 間の機能差(最初に確認)
「顧客が、自分のプラットフォームでサポートされていない機能を期待している」という問い合わせが数多くあります。まず、他のことをする前にアンケートの lib と顧客のプラットフォームを確認し、次にこの表を参照してください。SDK のソースを確認した内容です。確認から数か月経っている場合は、再確認してください。時間とともに未対応機能は実装されていきます。
| 機能 | Web(posthog-js) | iOS | Android | Flutter | React Native |
|---|---|---|---|---|---|
| 表示 | DOM + shadow root | ネイティブ SwiftUI(SurveysWindow) | 組み込み UI なし — デリゲートのみ | Dart ウィジェット(SurveyBottomSheet) | RN コンポーネント(SurveyModal) |
| イベントベースのトリガー | はい(1.137.0、2024-06-05 以降) | はい | はい | はい(ネイティブ側) | はい |
| URL/画面ターゲティング | はい | デコード済みだが評価されない(// TODO) | デコード済みだが評価されない | 評価されない(ネイティブ側の未対応) | フィルターで明示的に除外 |
| フィーチャーフラグ/コホートターゲティング | はい | はい | はい | はい(ネイティブ側) | はい |
seenSurveyWaitPeriodInDays | はい | はい | はい | はい(ネイティブ側) | 保存されるが、比較処理はコメントアウト |
surveyPopupDelaySeconds | はい | 未実装 | 未実装 | 未実装 | 未実装(TODO) |
enable_partial_responses | はい(≥ 1.240.0) | いいえ | いいえ | いいえ | いいえ |
skipSubmitButton(自動送信) | はい(≥ 1.244.0) | いいえ | いいえ | いいえ | いいえ |
最後の 2 行は、SDK ごとのソースを調査した結果ではなく、エディターのヘルプテキスト(「現時点ではモバイル SDK では機能しません」/「現時点ではモバイル SDK では利用できません」)に基づいています。
覚えておくべき影響:
surveyPopupDelaySecondsはウェブ専用です。 モバイルのチケットで遅延が原因だとされていても、それは誤解を招く手掛かりです。- 部分回答と自動送信もウェブ専用です。 モバイルでは、アンケートの回答は最後に常に1件保存され、評価をタップしても自動送信されません。ウェブの診断をモバイルのチケットに当てはめないでください。
- URL ターゲティングは実質的にウェブ専用です。 モバイル SDK はフィールドをデコードしますが、適用することはありません。React Native では該当するアンケートがすべて除外されます。URL 条件を持つモバイルアンケートは、「URL 条件なし」(mobile/flutter)または「表示されない」(RN)として動作します。
- Android にはアンケート UI がありません。 アプリ(または Flutter プラグイン)が
PostHogSurveysDelegateを提供する必要があります。「Android でアンケートがまったく表示されない」場合、多くは PostHog のバグではなく、デリゲートの設定漏れです。 - Flutter はハイブリッドです。 トリガーと表示可否の判定はネイティブの iOS/Android レイヤーで実行され、描画は Dart(
SurveyService.showSurvey→showModalBottomSheet)で行われます。UI のために「単にネイティブを呼び出す」わけではありません。そのため、Flutter の描画に関するバグは Dart に、Flutter の表示可否判定に関するバグはネイティブにあります。 - React Native では待機期間が暗黙に無効化されています(チェックがコメントアウトされています)。RN で待機期間を原因にしないでください。
バージョンごとの機能をさらに詳しく監査するには、利用可能な場合は survey-sdk-audit スキルを参照してください。
アンケートが実際に表示される仕組み(ウェブの表示可否判定パイプライン)
ウェブ SDK は最も複雑で、チケットでも最もよく使われています。packages/browser/src/extensions/surveys.tsx(checkSurveyEligibility)に基づく考え方として、チェックは順番に実行され、最初に失敗したチェックで判定が終了します。
isSurveyRunning—start_dateがあり、end_dateがないこと。- アンケートの
typeがアプリ内(Popover/Widget/API)であること。 linked_flag_keyが有効であること(設定されている場合)。targeting_flag_keyが有効であること(設定されている場合)— 顧客が定義したプロパティによるターゲティング。_internalFlagCheckSatisfied— 自動生成された内部ターゲティングフラグ。hasWaitPeriodPassed—seenSurveyWaitPeriodInDaysとlocalStorage.lastSeenSurveyDateの比較。getSurveySeen— アンケートごとの閲覧済みフラグ。
続いて getActiveMatchingSurveys で、URL/デバイス/セレクターの一致、イベント/アクショントリガーの発火、フラグの再チェックが行われます。
実際のチケットで重要になる、見落としやすい点が2つあります。
- サーバーはアーカイブされていないアンケートをすべて返します(
SurveyViewSet、products/surveys/backend/api/survey.py)。内部ターゲティングフラグによる事前フィルタリングは行いません。表示可否はすべてクライアント側で判定されます。したがって、「バックエンドが除外した」とは結論づけられません。除外したのは SDK です。 - 待機期間には独立した実装が2つあります。
canActivateRepeatedly(schedule: 'always'の場合は true)は_internalFlagCheckSatisfied(ステップ5)を短絡するため、alwaysは$last_seen_survey_dateルールを含む内部フラグを回避します。一方、hasWaitPeriodPassed(ステップ6)はlocalStorage.lastSeenSurveyDateを直接読み取り、canActivateRepeatedlyでは回避されません。そのため、seenSurveyWaitPeriodInDays: 30を設定したschedule: 'always'のアンケートでも、localStorage を介して30日間の待機が適用されます。lastSeenSurveyDateは、完了したかどうかにかかわらず、アンケートが何か1つでも表示されるたびに更新されます。同じ短絡によって内部フラグの$survey_responded/<id> is_not_setルールも無効になるため、schedule: 'always'では同じ人が繰り返し回答できます。回答数を回答者数として扱う前に、survey sentのcount()とuniq(distinct_id)を照合してください。
回答が実際に保存される仕組み
アンケートの表示と回答の保存は、別々のパイプラインです。「データが間違っている」というチケットは2つ目のパイプラインに関するもので、その UI の文言は実際に誤解を招きます。ラベルではなく、コードを基に判断してください。
「Response collection」はenable_partial_responsesに対応します
ラジオボタンはfrontend/src/scenes/surveys/SurveyResponsesCollection.tsxにあります。「Any question: when at
least one question is answered…」はtrue、「Complete survey: the response is stored when all
questions are answered」はfalseです。
true->sendSurveyEventはonNextButtonClickの毎回実行されるため、回答した質問ごとにsurvey sentイベントが1件ずつ発生します。すべてのイベントで$survey_submission_idは共通し、$survey_completedはfalse ... trueと変化します。false-> 経路の最後にsurvey sentイベントが1件だけ発生します。
この設定が制御するのは回答の記録であり、回答の表示ではありません。結果には、すべてのsurvey sentに加え、$survey_partially_completed = trueが付いたすべてのsurvey dismissedまたはsurvey abandonedが含まれます。frontend/src/scenes/surveys/utils.tsのbuildMergedSubmissionsSubqueryは、各送信IDについて質問ごとの最新の回答をマージします。IDのないイベントは別々に扱われます。**生イベント数が回答数を上回ることがあります。**完了イベントは、それ以前の部分的な終了イベントより優先されます。それ以外の場合、最新の回答イベントが明示的な終了なら結果チップには「Dismissed」、未完了のその他の送信なら「Abandoned」と表示されます。「Abandoned」は、ページのアンロードイベントや非アクティブタイムアウトが発生したことを証明するものではありません。後から完了すると、同じ行が更新されます。
デフォルト値は作成経路によって異なります。NEW_SURVEYはtrue(frontend/src/scenes/surveys/constants.tsx)に設定しますが、DjangoモデルのデフォルトはFalse(products/surveys/backend/models.py)です。作成日から推測せず、値を確認してください。
「すべての質問に回答済み」は、文字どおりの意味ではありません
isSurveyCompletedはgetNextSurveyStep(...) === Endを意味します。つまり、回答者が自身の分岐経路の末尾に到達したということです。すべての質問に値が入っているかどうかは確認されません。また、完了した回答でも2つの理由でセルが空になります。分岐でスキップされた質問にはキー自体がありません(onNextButtonClickは記録前にvisitedIndicesに絞り込むため、""やnullではなくキーが存在しません)。また、optional: trueの質問をクリックして先に進むと、値はnullとして保存されます(submitDisabledはisNull(rating) && !question.optionalです)。
そのため、任意の末尾質問がある分岐アンケートで「最初の質問だけに回答済み」というのは、完全な回答として想定される状態です。空欄は未回答と同じではありません。不具合だと判断する前に、すべての質問のbranchingとoptionalを確認してください。
分岐情報はAPIにあります。確認してください。尋ねる必要はありません
分岐情報はquestions[].branchingにあり、管理APIとSDKペイロードの両方からそのまま返されます。形式はnext_question、end(確認メッセージ)、specific_question + index、response_based + responseValuesの4種類です。注意点が2つあります。ratingの質問では、responseValuesのキーは値ではなく_バケット_(negative/neutral/positive、またはNPSのdetractors/passives/promoters)です。また、responseValuesに存在しないバケットは、currentQuestionIndex + 1へ暗黙に進みます。そのため、5段階評価での{negative: 3, neutral: 3}は、設定漏れのように見えても、実際には完全で動作する設定です。尺度ごとのバケット境界はreferences/reading-responses.mdを参照してください。推測しないでください。尺度2は反転しています。
イベントの種類
survey shown(ポップアップが表示された時点、つまりsurveyPopupDelaySecondsの経過後にshowSurvey()内で発生するため、shownからsentまでの時間は実際のポップアップ表示時間です)、survey sent、survey dismissed(明示的な閉じる操作)、survey abandoned(handlePageUnloadからsendSurveyAbandonedEventを呼び出した場合)。$survey_partially_completedが付くのはdismissedとabandonedのみで、sentには付きません。どのイベントにもsessionRecordingUrlが含まれるため、意見の分かれる送信について、推測するのではなく録画を確認できることがよくあります。URLが設定されていても、証明されるのはセッションIDが取得されたことだけで、録画が存在するとは限りません。リプレイはデフォルトでオフになっており、クラウドのデフォルト保存期間である30日は、これらのクエリの180日間という期間よりかなり短いです。証拠として提示する前に、リンクを開いてください。
推測したキーではなく、getSurveyResponse で回答を読み取る
getSurveyResponse(<index>, '<questionId>') は、製品自体が回答の読み取りに使用する HogQL ヘルパーです(posthog/hogql/functions/survey.py。products/surveys/backend/responses/ 全体で使用)。プロパティキーを手書きするよりも、こちらを優先してください。回答キーには 3 つの形式があり、このヘルパーは現在の UUID キー形式($survey_response_<questionId>)と以前のインデックスキー形式を統合するため、顧客自身の結果テーブルに表示される回答が返されます。複数選択式の質問では、3 番目の引数に true を渡してください。properties.$survey_response_<uuid> を手書きすると、以前のキー形式の回答を見落とします。また、countIf 内では、実際の回答が「未回答」にひそかに変換され、未完了率が水増しされます。
どちらの方法を使う場合でも、インデックスと ID は、アンケート JSON の questions[] から取得する必要があります。 どの UUID がどの質問に対応するかを推測するのは、誤った結論に至る最短ルートです。ある質問の回答を別の質問のラベルで読み取ってしまい、その結果の比率が重大なバグのように見えてしまいます。アンケート JSON がない場合は、回答と質問文が含まれる $survey_questions を展開してください。形式とテンプレートについては、references/reading-responses.md と references/diagnostic-queries.md を参照してください。
数値を信頼する前に、マッピングが正しいか確認してください。 単一選択式の質問としてラベル付けした列に自由記述が含まれている場合、マッピングが誤っています。
デバッグのワークフロー
-
チケットを解析します。 組織/プロジェクト ID、インスタンス(US か EU か。URL が異なります)、アンケート ID、
lib(プラットフォーム)、症状の具体的な内容、顧客がすでに試したことを抽出します。チケットが古い場合や、以前にサポートから返信している場合は、スレッドの途中で設定が編集された可能性があります。以前の申告を古い情報として扱い、現在の状態を再取得してください。 -
「ゼロ」と「減少」を区別します。 顧客は「回答がない」と言っていても、実際には「回答が減った」という意味の場合があります。変更が疑われる前後の
survey shownとsurvey sentの件数を取得します(references/diagnostic-queries.md を参照)。回答率(sent/shown)が安定している場合、問題は表示や送信ではなく、上流の適格性(表示された人が減ったこと)にあります。この確認ひとつで、ほとんどの調査の進め方が正しく変わります。
2b. データ品質に関するチケットでは、「未完了」と「完了しているが回答が少ない」を区別します。 まず、空欄のセルが、回答者にそもそも尋ねられなかった質問なのかを確認してください。分岐と任意の質問があると、完了した回答が途中で放棄されたように見えることがあります。これは、実際には壊れていないのにアンケートが壊れていると報告される最も一般的な理由です。回答が実際に保存される仕組みを参照してください。
-
プラットフォームの対応状況を確認します。
libを確認し、対応状況の表を参照してください。調査を始める前に、そのプラットフォームがサポートしていない機能を除外します。 -
アンケート定義を取得します。
GET /api/projects/<id>/surveys/<sid>/。conditions(events、url、seenSurveyWaitPeriodInDays、repeatedActivation)、appearance.surveyPopupDelaySeconds、appearance.position、schedule、linked_flag、targeting_flag、internal_targeting_flag.filters、responses_limit、iteration_*、enable_partial_responsesを確認し、さらに各質問の中身も調べます。id、type、scale、optional、skipSubmitButton、branchingを確認してください。質問ごとのフィールドを見るだけで、ほとんどの「データがおかしい」というチケットの原因がわかります。トップレベルのキーだけをざっと見ても確認できず、見落としやすい項目です。 -
「表示されなくなった」というチケットでは、ターゲティングフラグのアクティビティログを取得します。 コホートの入れ替えやロールアウトの変更は現在の設定からは見えませんが、ここには記録されています。
GET /api/projects/<id>/activity_log/?scope=FeatureFlag&item_id=<flag_id>&limit=20。また、アンケート自体が編集されたか確認するには?scope=Survey&item_id=<sid>も使用します。 -
イベントで確認します。
$feature_flag_calledを使用して、対象ユーザーに対してゲートとなるフラグが実際に何を返したか、また$groupsが設定されているかを確認します(下記のグループ集計に関する原因を参照)。survey shownを使用して、実際のリーチと統計 UI の数値を比較します。 -
既知の原因の一覧と照らし合わせ、対象を絞ったクエリをひとつ実行して確認してから、返信を作成します。
SDK のバグと判断する前に
これらのチケットでは、特定の失敗パターンが起こりがちです。症状があり得ないように見えるため SDK のせいにして、アンケートを一時停止し、バグを報告して質問を作り直すよう顧客に伝えてしまいます。このアドバイスは費用がかかり、後から取り消すのも困難です。構成を変更すると、すでに収集したすべての回答との比較可能性が失われ、質問の並べ替えは下記の UUID 問題を招くおそれがあります。「これはバグです」と書く前に、次の4つの確認をすべて済ませてください。
- アンケートの JSON を読みます。 質問ごとの
branching、optional、skipSubmitButton、scaleも含めて確認してください。「あり得ない」挙動のほとんどは、設定どおりの動作です。 - Preview で再現します。
- 問題だと指摘しているハンドラーの SDK ソースコードを読みます。 シンボルを grep し、設定名から意味を推測しないでください。
enable_partial_responsesと「すべての質問に回答済み」は、どちらも名前から想像するより限定的な意味です。 - 異常な比率を信じる前に、自分のクエリを再確認します。 「回答の89%が未完了」は、実際の不具合というより、回答キーのマッピングが間違っている場合のほうがよくあります。
4つすべて確認しても問題が解消しない場合は、バグです。ファイル名とハンドラーを明記し、上流に報告してください。
既知の原因の一覧
回答となる頻度が高い順に、おおよそ並べています。
「アンケートが予想より少ないユーザーにしか表示されない」
surveyPopupDelaySeconds+ URL の再確認(ウェブのみ)。 イベントが発生して対象条件を満たした後、SDK は N 秒待ってから、表示の直前(handlePopoverSurvey)に現在の URL に対してdoesSurveyUrlMatchを再確認します。待機中にユーザーが移動した場合、アンケートは通知なしに破棄され、「アンケート表示」イベントも発生しません。待機時間が無視できない長さに設定された、画面遷移の多いアプリでよく起こります。対処法:待機時間を 0~2 秒に短縮します。seenSurveyWaitPeriodInDays+顧客のほかのアンケート。 ユーザーにアンケートを表示すると、そのたびにlastSeenSurveyDateが更新されます。このアンケートは、その後待機期間中はブロックされます。完了状況は関係ありません。_未表示_のグループが最近ほかのアンケートを見ていないか確認し、対照グループとも比較してください(_表示された_ユーザーには違いがありますか?)。対処法:待機期間を短縮するか、競合するアンケートを一時停止します。- コホートの構成が変わった。 アンケートがコホートを対象にしている場合、元の動的コホートが編集されると(例:行動フィルターの追加)、その後に作成されたすべての静的スナップショットにも、絞り込まれた定義が引き継がれます。アンケート側に変更がなくてもリーチが減少します。フラグのアクティビティログで確認し(コホートの切り替え)、
static_cohort_peopleでコホートのサイズを確認します。
「イベントベースのアンケートが一度も表示されない」
- セッション開始時のタイミング競合。
/api/surveysの応答が返る前にイベントがキャプチャされ、キャプチャフックが登録されていません。特徴:セッション開始直後にイベントが発生します。クライアント側では避けられません。少し後に発生するイベントをトリガーにして、影響を軽減してください。 - グループ集計される
linked_flagにグループコンテキストがない。linked_flag(またはターゲティングフラグ)にaggregation_group_type_indexが設定されている場合、その評価対象はユーザーではなく_グループ_です。イベント発生前にposthog.group(<index>, <key>)が設定されていないと、フラグは false を返し、アンケートは表示されません。特徴:$feature_flag_calledが空の$groupsとともにfalseを返し、トリガーイベントに$feature/<key>プロパティがありません。対処法:SDK でグループコンテキストを設定するか、アンケートをユーザーレベルのフラグに切り替えます。 - 顧客が誤ったフラグにアンケートを紐付けている。 メールアドレスやプロパティを使ったターゲティングでフラグを作成していても、アンケートの
linked_flag/targeting_flagが_別の_フラグを参照している場合があります。顧客の説明を鵜呑みにせず、API から実際のlinked_flag.key/targeting_flag.keyを必ず確認してください。 - リアルタイムフラグでの行動コホート。
performed_event/行動フィルターを含むコホートは、リアルタイムフラグのバイトコードでは評価できません("Unsupported behavioral filter for realtime bytecode"、posthog/api/cohort.py)。コホートにはbytecode_errorが表示されます。アンケート/フラグから直接利用することはできません。顧客はコホートの_静的_コピーを作成して、それをターゲットにする必要があります。
「回答が不完全で、最初の質問にしか値が入っていない」
通常はバグではありません。回答が実際にどのように保存されるかを参照してください。完了条件が本当に守られていないかを調べる前に、まず次の 4 点を確認します。
- 分岐によって未回答の質問がスキップされた。
questions[].branchingを自分でたどってください。顧客が説明する意図と実際に保存されている内容は異なる場合があり、responseValuesにない評価バケットは次のインデックスに進みます。 - 空欄の質問が
optional: trueで、回答者がそれらを飛ばした。 評価質問に続く任意の自由記述質問 2 つがスキップされても、回答が 1 つだけの完全な送信として扱われます。 - 部分回答が有効になっていて、UI が
$survey_submission_idごとにまとめて表示する中間イベントを、未加工の SQL で読み取っている。 - 回答キーを推測していた。
questions[].idを使って再実行してください。
「回答者が送信するつもりはなかったと言っている」
- エディターでは「選択時に自動送信」と表示される
skipSubmitButton。 true の場合、送信ボタンは一切表示されず(BottomSection.tsx)、1 回のクリックで回答が記録されて次へ進みます。同じハンドラー呼び出し内でsetRating(response)からhandleSubmit(response)、さらにonNextButtonClickが実行され、デバウンスも確認もありません。対象は評価と、自由回答の選択肢がない単一選択のみです(canQuestionSkipSubmitButton)。Web 専用です。すべてのアンケートテンプレート(constants.tsx)とクイック作成でデフォルトで有効になっているため、顧客は有効にしたことに気付いていない場合がほとんどです。 - ポップアップの配置と組み合わさると、問題が増幅します。
appearance.position: middle_center、大きなmaxWidth、ゼロ以外のsurveyPopupDelaySecondsを設定すると、トリガーの数秒後に、カーソルがまだ動いている状態でポップアップが表示され、次のクリックが回答に当たります。自動送信される質問が続くと、回答者が内容を読まずにアンケートの大半をクリックして進めてしまうことがあります。 - **表示から送信までの時間で診断し、**その後、リプレイ(
survey sentイベントのsessionRecordingUrl)で確認します。複数の質問があるアンケートで、完了までの時間が 10 秒未満のものが集中しているのが典型的な兆候です。実際に回答した人はより時間をかけ、テキストも入力します。修正するには設定のチェックを外してください。質問の位置を変えるのではありません。この動作は質問の配置場所に関係なく発生します。
「UI では回答数が 0 と表示されるが、生イベントは存在する」
- Max AI によってアンケートの定義が破損しています。 Max の
edit_surveyツール(products/surveys/backend/max_tools.py)には 2 つの障害モードがあります。(a)並べ替えや編集の際、各質問をQUESTION_TYPE_MAP(nps→10 段階評価、csat→5 段階評価など)から再構築するため、意味上の種類を誤って選ぶと、質問の尺度が通知なく変更されます。(b)idフィールドには 1 始まりのラベル("1"、"2")を指定する必要があります。実際の UUID を渡すと対応付けに失敗し、新しい UUID が生成されるため、$survey_response_<old_uuid>をキーとする回答が質問に結合されなくなります。生イベントはそのままで、定義だけが誤っています。修正方法:questions配列を元の UUID に戻し(回答イベントから復元可能です)、質問の種類も元に戻します。質問の_テキスト_は UI から編集するよう顧客に伝え、UUID の保護がツールに追加されるまでは、過去の回答があるアンケートの質問を Max に並べ替えさせないでください。
「コホートの人数が 0 と表示されるが、コホートにはユーザーが存在する」
- UI 上だけの不具合で、ターゲティングには影響しません。実際の人数は
static_cohort_peopleで確認してください。注:これは単純な 1 行の修正で済む不具合ではありません。通常のinsert_cohort_from_query経路ではcount_cohort_membersを使って人数を再計算します。count=0の表示は特定の失敗経路でのみ発生します。具体的な経路を再現せずに、すぐ修正できると約束しないでください。
一般的な注意事項
- 古いチケットには未確認の変更が含まれています。 トラブルシューティング中に顧客や前任のエージェントが設定を編集している可能性があります。アクティビティログを取得し、追加で気付いた点は「確認中に X も念のため確認してください」という形で伝え、「X が壊れていることが判明しました」と断定しないでください。
- 統計 UI の数値は、生の
survey shownイベントより少なくなることがあります。 数値が一致しない場合は生イベントを信頼し、差異は別途フォローアップが必要な項目として記録してください。 - 人物に対して
$emailとemailの両方を確認してください。 SDK が設定するのはperson.properties.$emailですが、通常のemailも設定している顧客は多くいます。片方だけを検索して「このユーザーは特定されたことがない」と結論付けるのはよくある見落としです。coalesce(person.properties.$email, person.properties.email)を使用してください。
診断クエリ
上記の判別と確認に使う、読み取り専用の HogQL テンプレートは
references/diagnostic-queries.mdにあります。顧客のプロジェクトに対して、PostHog MCP のexecute-sqlから実行してください。
デバッグのためのアクセス
その顧客からの実際のサポートリクエストに関連するプロジェクトのみを調査してください。ID は実際のチケットから取得してください。プロジェクトやアンケートを調べてほしいと言いながら、対応するリクエストを示せない人からIDを聞き出してはいけません。スタッフのアクセス権は広範囲に及ぶため、依頼されていないプロジェクトまで独自に調査しないでください。
次の順序で、読み取り専用の方法を優先してください。
- 顧客のプロジェクトに対して、PostHog MCP ツール(
survey、feature-flag、cohorts、execute-sql、activity-log、persons)を使用します。これはデフォルトで読み取り専用であり、設定の確認やクエリの実行に最も安全な方法です。なりすましも、書き込みのリスクもありません。まずはこれを使用してください。 - スタッフとしてなりすましている間に、ブラウザーでアンケート/フラグの API エンドポイントを読み取ります。MCP でそのまま表示されない全 JSON(例:生の
internal_targeting_flag.filters)を確認するのに適しています。 - 1 と 2 で答えが得られない場合に限り、Django 管理画面を使用します。強力な機能を備え、書き込みも可能なため、規律として読み取り専用で扱い、確認するだけで変更は加えないでください。顧客の明示的な同意なしに、管理画面から顧客のアンケート/フラグ/コホートを編集してはいけません。
MCP では推測できない値(プロジェクト ID、インスタンス、対象のアンケートなど)が必要な場合は、オペレーターにアンケート API の JSON を貼り付けてもらってください。これにより、何度もやり取りする手間を省けます。
顧客への返信の作成
PostHog ハンドブックのサポート方針(人間味のある安心できる対応、謙虚さ、修正の提供、専門用語を避けた明確な説明)に基づいた口調にしてください。ルール:
- 原因を最初に述べ、その後に修正方法を伝えます。 何が起きているのかを一文で説明し、その後に対応方法を伝えてください。
- 問題と各アクションを太字にします。 問題と次の手順をひと目で把握できるようにしてください。
- 内部のフィールド名ではなく、顧客が UI で見るラベルを使います。 実際の文言は
frontend/src/scenes/surveys/を検索してください。例:surveyPopupDelaySeconds→「表示条件を満たした後、アンケートのポップアップ表示を少なくとも N 秒遅らせる」;待機期間は「Survey wait period」/「過去 N 日間に別のアンケートがユーザーに表示されている場合、このアンケートを表示しない」;skipSubmitButton→「選択時に自動送信する」;enable_partial_responses→「Response collection」のラジオボタン(「Any question…」/「Complete survey…」);optional→ 質問の「Optional」トグル。顧客独自のイベント名はそのまま使用してください。 - 以前の誤った回答を訂正する場合は、率直に、早い段階でそう伝えてから、実際の原因を説明します。 訂正を埋もれさせたり、撤回した助言に顧客が従い続けたりしないようにしてください。すでに一時停止や再構築を案内している場合は、作業を中止してよいことを明確に伝えてください。
- すべての PostHog エンティティに ID を使ったリンクを付けます。 コホート:
https://<us|eu>.posthog.com/project/<id>/cohorts/<cohort_id>。フラグ:.../feature_flags/<flag_id>。アンケート:.../surveys/<survey_id>。顧客のインスタンス(US または EU)に合わせてください。 - 予想される結果を伝え、修正が機能したことを顧客が確認できるようにします(「今後は約 X 件が表示されるはずです」など)。
- 顧客の技術レベルを見極めます。 SQL を実行して API を利用できる場合は、パッチを適用する方法を案内してください。難しい場合は、破壊的な変更の詳細を事前に確認したうえで、こちらで修正を適用することを提案してください。
- 「通話しましょう」や会議の予約を提案してはいけません。 PostHog のサポートは非同期対応を基本としています。最後は「追加のサポートが必要な場合は、いつでもご連絡ください。」で締めくくってください。
- 内部情報を漏らしてはいけません。 MCP ツール名、コードパス、行番号、Django 管理画面、スタッフとしてのなりすまし、他の顧客に関する情報などには触れないでください。顧客が理解できるプロダクト上の概念だけを使ってください。
- 送信前に、最終案を humanizer スキルに通してください(利用できる場合。例:
humanizer)。em ダッシュ、導入句(「重要な点は次のとおりです:」「知っておくべき 3 つのこと」など)、三項構成の水増し、整いすぎた並列リストを取り除いてください。人が書いたような返信にしてください。
返信のひな形:
Hi <name>,
<one line: tracked it down + the cause in plain terms.>
**The problem:** <what's happening, with the evidence you pulled.>
**<Fastest fix / two ways to fix it>:**
1. **<action>** — <why / how.>
2. **<action>** — <why / how.>
**Also worth knowing while you're in there:** <secondary finding, softened.>
We're always here if you need a follow-up.