mcpField
A
analytics-events

analytics-events

github.com/metabaseデータ・データベース49.9k2.0k 回インストール今日更新
リポジトリ

analytics-events について

Metabase のフロントエンド開発者向けに、Snowplow のプロダクト分析イベント追加手順をまとめたスキルです。型付きの `trackSimpleEvent` を使い、追跡関数やフィールド型を各機能内に置く方法を示します。

主な機能

  1. 01`trackSimpleEvent` によるイベント記録
  2. 02標準フィールドに基づくペイロード検証
  3. 03追跡コードと型の機能単位での管理
  4. 04命名規則とプライバシー規則の適用
  5. 05開発中のイベント発火確認

活用シーン

  1. 01UI 操作の分析イベント追加
  2. 02処理結果や所要時間の記録
  3. 03開発中の Snowplow イベント確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/metabase/metabase --skill analytics-events

インストール後、Claude Code で/analytics-eventsを入力して読み込まれたか確認します。

詳細

フロントエンド分析イベントスキル

このスキルは、Metabase フロントエンドコードベースでユーザーの操作をトラッキングするためのプロダクト分析(Snowplow)イベントを追加するのに役立ちます。

クイックリファレンス

Metabase の分析イベントは、型付きイベントスキーマを備えた Snowplow を使用します。シンプルなイベントは使用される場所で宣言します — trackSimpleEvent はジェネリックであり、呼び出し箇所でペイロードを検証します。

主要なファイル:

  • frontend/src/metabase/analytics/event.ts - コアのトラッキング関数、trackSimpleEvent / trackSchemaEvent(metabase/analytics からインポート)
  • frontend/src/metabase-types/analytics/event.ts - 共有の SimpleEventSchema のみ。ここにイベント型を追加しないでください(以下を参照)
  • frontend/src/metabase-types/analytics/schema.ts - スキーマレジストリ(カスタム/レガシースキーマのみ)
  • 機能固有の analytics.ts ファイル - トラッキング関数とローカル型が置かれる場所

クイックチェックリスト

新しい分析イベントを追加する場合:

  • イベント名を選ぶ(snake_case、過去形)
  • その機能の analytics.ts ファイルに、trackSimpleEvent() を呼び出すトラッキング関数を追加する
  • フィールドのユニオン(例: "success" | "failure")は、同じファイル内のローカル型として保持する
  • 操作ポイントでトラッキング関数をインポートして呼び出す
  • metabase-types/analytics/event.ts やいずれかのユニオンにイベント型を追加しない

イベントスキーマの種類

1. シンプルイベント(最も一般的)

基本的なトラッキングには SimpleEventSchema を使用します。以下の標準フィールドをサポートしています:

type SimpleEventSchema = {
  event: string;                    // Required: Event name (snake_case)
  target_id?: number | null;        // Optional: ID of affected entity
  triggered_from?: string | null;   // Optional: UI location/context
  duration_ms?: number | null;      // Optional: Duration in milliseconds
  result?: string | null;           // Optional: Outcome (e.g., "success", "failure")
  event_detail?: string | null;     // Optional: Additional detail/variant
};

使用する場合: イベントの 90% はこのスキーマに当てはまります。クリック、開く、閉じる、作成、削除などに使用します。

trackSimpleEvent はジェネリックであり、渡されたオブジェクトリテラルに対してこのスキーマを強制します:

// frontend/src/metabase/analytics/event.ts
export function trackSimpleEvent<
  T extends SimpleEventSchema &
    Record<Exclude<keyof T, keyof SimpleEventSchema>, never>,
>(event: T) {
  trackSchemaEvent("simple_event", event);
}

つまり、event の欠落や SimpleEventSchema 以外のフィールドは、呼び出し箇所でコンパイルエラーになります。宣言すべき別個のイベント型はなく、追加すべき satisfies 句もありません — 以前の ValidateEvent<...> ヘルパーはエクスポートされなくなり、ワークフローの一部ではありません。

trackSchemaEvent もジェネリックです: スキーマ名とペイロード型を関連付けるため、simple_event スキーマの下でダッシュボードイベントを送信することはできません。

2. カスタムスキーマ(レガシー、イベントは追加されていません)

新しいイベントスキーマの追加は、ごく特殊なケースでのみ検討してください。

例: DashboardEventSchema、CleanupEventSchema、QuestionEventSchema

ステップバイステップ: シンプルイベントの追加

例: ユーザーがテーブルピッカーでフィルターを適用したときをトラッキングする
ステップ 1: トラッキング関数を作成する

その機能の analytics.ts ファイル(例: enterprise/frontend/src/metabase-enterprise/data-studio/analytics.ts)に記述します:

import { trackSimpleEvent } from "metabase/analytics";

export const trackDataStudioTablePickerFiltersApplied = () => {
  trackSimpleEvent({
    event: "data_studio_table_picker_filters_applied",
  });
};

export const trackDataStudioTablePickerFiltersCleared = () => {
  trackSimpleEvent({
    event: "data_studio_table_picker_filters_cleared",
  });
};
ステップ 2: コンポーネントで使用する

操作ポイントでトラッキング関数をインポートして呼び出します:

import {
  trackDataStudioTablePickerFiltersApplied,
  trackDataStudioTablePickerFiltersCleared,
} from "metabase-enterprise/data-studio/analytics";

function FilterPopover({ filters, onSubmit }) {
  const handleReset = () => {
    trackDataStudioTablePickerFiltersCleared(); // <- Track here
    onSubmit(emptyFilters);
  };

  return (
    <form
      onSubmit={(event) => {
        event.preventDefault();
        trackDataStudioTablePickerFiltersApplied(); // <- Track here
        onSubmit(form);
      }}
    >
      {/* form content */}
    </form>
  );
}

SimpleEventSchema のフィールドの使用

以下のすべての例は、その機能自身の analytics.ts に置かれます — 中央に登録されるものはありません。

例: target_id を持つイベント
export const trackDataStudioLibraryCreated = (id: CollectionId) => {
  trackSimpleEvent({
    event: "data_studio_library_created",
    target_id: Number(id),
  });
};

// Usage
trackDataStudioLibraryCreated(newLibrary.id);
例: triggered_from を持つイベント
// Local union, exported only if another feature needs to pass the same value
export type NewButtonLocation = "app-bar" | "empty-collection";

export const trackNewButtonClicked = (location: NewButtonLocation) => {
  trackSimpleEvent({
    event: "new_button_clicked",
    triggered_from: location,
  });
};

// Usage
<Button onClick={() => {
  trackNewButtonClicked("app-bar");
  handleCreate();
}}>
  New
</Button>
例: event_detail を持つイベント

実際の例 — frontend/src/metabase/metadata/pages/shared/analytics.ts:

export type MetadataEditEventDetail =
  | "type_casting"
  | "semantic_type_change"
  | "visibility_change";

export const trackMetadataChange = (detail: MetadataEditEventDetail) => {
  trackSimpleEvent({
    event: "metadata_edited",
    event_detail: detail,
    triggered_from: "admin",
  });
};

// Usage
trackMetadataChange("semantic_type_change");
例: result と duration を持つイベント

この実際のバージョンについては frontend/src/metabase/archive/analytics.ts を参照してください。

export const trackMoveToTrash = (params: {
  targetId: number | null;
  triggeredFrom: "collection" | "detail_page" | "cleanup_modal";
  durationMs: number | null;
  result: "success" | "failure";
  itemType: "question" | "model" | "metric" | "dashboard";
}) => {
  trackSimpleEvent({
    event: "moved-to-trash",
    target_id: params.targetId,
    triggered_from: params.triggeredFrom,
    duration_ms: params.durationMs,
    result: params.result,
    event_detail: params.itemType,
  });
};

// Usage with timing
const startTime = Date.now();
try {
  await moveToTrash(item);
  trackMoveToTrash({
    targetId: item.id,
    triggeredFrom: "collection",
    durationMs: Date.now() - startTime,
    result: "success",
    itemType: "question",
  });
} catch (error) {
  trackMoveToTrash({
    targetId: item.id,
    triggeredFrom: "collection",
    durationMs: Date.now() - startTime,
    result: "failure",
    itemType: "question",
  });
}

命名規則

イベント名(snake_case)
// Good
"data_studio_library_created"
"table_picker_filters_applied"
"metabot_chat_opened"

// Bad
"DataStudioLibraryCreated"  // Wrong case
"tablePickerFiltersApplied" // Wrong case
"filters-applied"            // Use underscore, not hyphen
ローカルフィールド型(PascalCase、フィールドにちなんで命名)

名前を付けるべき ...Event 型は、もはや通常は存在しません。フィールドにユニオンが必要な場合は、それが供給するフィールドにちなんで命名します:

// Good
type MetricDimensionResult = "success" | "failure";     // -> result
export type MetadataEditEventDetail = "type_casting";   // -> event_detail
type NewButtonLocation = "app-bar" | "empty-collection"; // -> triggered_from
トラッキング関数名(「track」プレフィックスを付けた camelCase)
// Good
trackDataStudioLibraryCreated
trackTablePickerFiltersApplied
trackMetabotChatOpened

// Bad
DataStudioLibraryCreated      // Missing "track" prefix
track_library_created         // Wrong case
logLibraryCreated             // Use "track" prefix

一般的なパターン

パターン 1: 機能間でフィールド型を共有する

2 つの機能が異なる triggered_from で同じイベントを送信する場合、所有する機能の analytics.ts からフィールドユニオンをエクスポートしてインポートします — metabase-types に何も持ち上げないでください:

// frontend/src/metabase/data-studio/data-model/analytics.ts
import { trackSimpleEvent } from "metabase/analytics";
import type { MetadataEditEventDetail } from "metabase/metadata/pages/shared/analytics";

export function trackMetadataChange(detail: MetadataEditEventDetail) {
  trackSimpleEvent({
    event: "metadata_edited",
    event_detail: detail,
    triggered_from: "data_studio",
  });
}

これが拡張可能イベント設計の要点です: エンタープライズおよび機能階層の型は、共有ユニオンにインポートされるのではなく、自身のモジュールに留まります。

パターン 2: 条件付きトラッキング

ユーザーのアクションに基づいて異なるイベントをトラッキングします。

const handleSave = async () => {
  if (isNewItem) {
    await createItem(data);
    trackItemCreated(newItem.id);
  } else {
    await updateItem(id, data);
    trackItemUpdated(id);
  }
};

よくある落とし穴

やってはいけない: シンプルなイベントにカスタムフィールドを追加する
// WRONG - SimpleEventSchema doesn't support custom fields (this is a compile error)
export const trackFiltersApplied = (filters: FilterState) => {
  trackSimpleEvent({
    event: "filters_applied",
    data_layer: filters.dataLayer,      // ❌ Not in SimpleEventSchema
    data_source: filters.dataSource,    // ❌ Not in SimpleEventSchema
    with_owner: filters.hasOwner,       // ❌ Not in SimpleEventSchema
  });
};

// RIGHT - Use only standard SimpleEventSchema fields
export const trackFiltersApplied = () => {
  trackSimpleEvent({
    event: "filters_applied",
  });
};

// Or use event_detail for a single variant
export const trackFilterApplied = (filterType: string) => {
  trackSimpleEvent({
    event: "filter_applied",
    event_detail: filterType,  // ✓ "data_layer", "data_source", etc.
  });
};
やってはいけない: metabase-types/analytics/event.ts にイベント型を追加する

中央の SimpleEvent ユニオンは削除されました — これにより、機能層の型を共有コードに インポートせざるを得なくなり、モジュール境界の違反を引き起こしていました。trackSimpleEvent は 現在ジェネリックであるため、この型は重複以外の何ももたらしません。

// ❌ WRONG - central declaration + re-import for a `satisfies` clause
// frontend/src/metabase-types/analytics/event.ts
export type NewFeatureClickedEvent = ValidateEvent<{
  event: "new_feature_clicked";
  target_id: number;
}>;

// frontend/src/metabase/my-feature/analytics.ts
import type { NewFeatureClickedEvent } from "metabase-types/analytics";

export const trackNewFeatureClicked = (id: number) => {
  trackSimpleEvent({
    event: "new_feature_clicked",
    target_id: id,
  } satisfies NewFeatureClickedEvent);
};

// ✓ RIGHT - the object literal is already checked by the generic
// frontend/src/metabase/my-feature/analytics.ts
export const trackNewFeatureClicked = (id: number) => {
  trackSimpleEvent({
    event: "new_feature_clicked",
    target_id: id,
  });
};

いくつかの ...Event 型はまだ metabase-types/analytics/event.ts に残っています。これらは リファクタリングの前後にマージされた PR の残骸です — コピーしないでください。また、これらに追加しないでください。

やってはいけない: イベント名の形式を混同する
// WRONG
event: "dataStudioLibraryCreated"  // camelCase
event: "data-studio-library-created"  // kebab-case
event: "Data_Studio_Library_Created"  // Mixed case

// RIGHT
event: "data_studio_library_created"  // snake_case
やってはいけない: PII や機密データをトラッキングする
// WRONG - Don't track user emails, names, or sensitive data
trackSimpleEvent({
  event: "user_logged_in",
  event_detail: user.email,  // ❌ PII
});

// RIGHT - Track non-sensitive identifiers only
trackSimpleEvent({
  event: "user_logged_in",
  target_id: user.id,  // ✓ Just the ID
});
やってはいけない: 成功と失敗の両方をトラッキングし忘れる
// WRONG - Only tracking success
try {
  await saveData();
  trackDataSaved();
} catch (error) {
  // ❌ No tracking for failure case
}

// RIGHT - Track both outcomes
try {
  await saveData();
  trackDataSaved({ result: "success" });
} catch (error) {
  trackDataSaved({ result: "failure" });
}

アナリティクスイベントのテスト

開発中は、イベントが発火していることを確認できます。

  1. ブラウザコンソールを確認する - 開発環境で SNOWPLOW_ENABLED=true の場合、イベントがログに記録されます
  2. shouldLogAnalytics を使用する - metabase/env で設定すると、すべてのアナリティクスがコンソールに表示されます
  3. Snowplow デバッガーを確認する - Snowplow イベント用のブラウザ拡張機能です

コンソール出力の例:

[SNOWPLOW EVENT | event sent:true], data_studio_table_picker_filters_applied

ファイル構成

トラッキング関数を置く場所:
Tracking functions AND their local field types (this is where new events live):
frontend/src/metabase/{feature}/analytics.ts
enterprise/frontend/src/metabase-enterprise/{feature}/analytics.ts

Core tracking utilities:
frontend/src/metabase/analytics/ (import from `metabase/analytics`)

Shared SimpleEventSchema only — nothing new goes here:
frontend/src/metabase-types/analytics/event.ts

埋め込み SDK のコードでは、代わりに trackSdkSimpleEvent (frontend/src/embedding-sdk-bundle/analytics/snowplow.ts) を使用してください — メインアプリの "sp" トラッカーは 顧客のページでは初期化されないため、trackSimpleEvent の Snowplow 部分はそこでは何も行いません。

実例

参考として以下のファイルを参照してください:

  • シンプルなイベント + ローカルフィールドユニオン: frontend/src/metabase/metadata/pages/shared/analytics.ts
  • 別の機能のフィールド型を再利用する: frontend/src/metabase/data-studio/data-model/analytics.ts
  • 結果 + 所要時間の計測: frontend/src/metabase/archive/analytics.ts
  • エンタープライズ機能のイベント: enterprise/frontend/src/metabase-enterprise/google_drive/analytics.ts

ワークフローまとめ

  1. トラッキングするユーザーインタラクションを特定する
  2. イベント名を決める (snake_case、説明的なもの)
  3. 機能の analytics.ts にトラッキング関数を作成する (trackSimpleEvent() を呼び出します)
  4. フィールドが固定の値の集合を持つ場合は、同じファイルにローカルフィールドユニオンを追加する
  5. インタラクションの箇所でインポートして呼び出す
  6. イベントが正しく発火することをテストする

ヒント

  • 具体的にする - action_performed よりも filters_applied のほうがよい
  • 過去形を使う - create_library ではなく library_created
  • 関連するイベントをグループ化する - 機能のトラッキング関数はその analytics.ts にまとめておく
  • 意味のあるアクションをトラッキングする - すべてのクリックをトラッキングする必要はありません
  • データを考慮する - 後で何を分析したいですか?
  • 一貫性を保つ - コードベース内の既存の命名パターンに従う
  • コンテキストを記録する - triggered_from を使ってアクションがどこで発生したかをトラッキングする

コメント