import { getPropertyId, formatPropertyPath, executeReport } from "../../client.js";
import { periodToDateRange } from "../../utils/date.js";
import { calculatePercentage } from "../../utils/percentage.js";
import type {
GetConversionFunnelInput,
GetConversionFunnelOutput,
FunnelStepResult,
} from "../../types.js";
/**
* コンバージョンファネル分析
*
* 注意: GA4 Data APIでは真のファネル分析(順序付きの経路分析)は制限されています。
* このツールは各ステップの個別アクセス数を取得し、概算のファネルを構築します。
* より正確なファネル分析にはBigQuery Export または Explorations APIが必要です。
*/
export async function getConversionFunnel(
input: GetConversionFunnelInput
): Promise<GetConversionFunnelOutput> {
const propertyId = getPropertyId(input.propertyId);
const property = formatPropertyPath(propertyId);
const dateRange = periodToDateRange(input.period);
if (input.steps.length < 2) {
throw new Error("ファネル分析には少なくとも2つのステップが必要です");
}
const funnel: FunnelStepResult[] = [];
let previousUsers = 0;
let firstStepUsers = 0;
// 各ステップのユーザー数を取得
for (let i = 0; i < input.steps.length; i++) {
const step = input.steps[i];
const response = await executeReport({
property,
dateRanges: [dateRange],
dimensions: [{ name: "pagePath" }],
metrics: [{ name: "totalUsers" }],
dimensionFilter: {
filter: {
fieldName: "pagePath",
stringFilter: {
matchType: "BEGINS_WITH",
value: step.pagePath,
},
},
},
});
const users =
response.totals?.[0]?.metricValues?.[0]?.value
? Math.round(parseFloat(response.totals[0].metricValues[0].value))
: 0;
if (i === 0) {
firstStepUsers = users;
previousUsers = users;
}
// 離脱率の計算
const dropoffRate =
i === 0
? "0%"
: calculatePercentage(previousUsers - users, previousUsers);
// コンバージョン率の計算(最初のステップからの通過率)
const conversionRate = calculatePercentage(users, firstStepUsers);
funnel.push({
step: i + 1,
name: step.name,
users,
dropoffRate,
conversionRate,
});
previousUsers = users;
}
// 全体のコンバージョン率(最初のステップから最後のステップへの通過率)
const lastStepUsers = funnel[funnel.length - 1]?.users || 0;
const overallConversionRate = calculatePercentage(lastStepUsers, firstStepUsers);
return {
funnel,
overallConversionRate,
};
}