import { getPropertyId, formatPropertyPath, executeReport } from "../../client.js";
import { periodToDateRange } from "../../utils/date.js";
import { calculatePercentage } from "../../utils/percentage.js";
import type {
GetUserJourneyInput,
GetUserJourneyOutput,
RelatedPage,
} from "../../types.js";
/**
* ユーザージャーニー(ページ遷移)分析
*
* 注意: GA4 Data APIでは直接的なページ遷移情報の取得が制限されています。
* このツールは、同じセッション内で閲覧されたページのパターンを分析します。
*/
export async function getUserJourney(
input: GetUserJourneyInput
): Promise<GetUserJourneyOutput> {
const propertyId = getPropertyId(input.propertyId);
const property = formatPropertyPath(propertyId);
const dateRange = periodToDateRange(input.period);
const limit = input.limit || 10;
// GA4では直接的なページ遷移情報が取得しにくいため、
// 対象ページと同じセッションで閲覧されたページを分析
// より正確な分析にはBigQuery Export が必要
// 対象ページにアクセスしたセッション数を取得
const targetResponse = await executeReport({
property,
dateRanges: [dateRange],
dimensions: [{ name: "pagePath" }],
metrics: [{ name: "sessions" }],
dimensionFilter: {
filter: {
fieldName: "pagePath",
stringFilter: {
matchType: "EXACT",
value: input.pagePath,
},
},
},
});
const targetSessions =
targetResponse.totals?.[0]?.metricValues?.[0]?.value
? Math.round(parseFloat(targetResponse.totals[0].metricValues[0].value))
: 0;
// 全ページのアクセス状況を取得
const allPagesResponse = await executeReport({
property,
dateRanges: [dateRange],
dimensions: [{ name: "pagePath" }],
metrics: [{ name: "sessions" }],
orderBys: [{ metric: { metricName: "sessions" }, desc: true }],
limit: limit + 1, // 対象ページ自体を除外するため+1
});
const relatedPages: RelatedPage[] = [];
for (const row of allPagesResponse.rows || []) {
const pagePath = row.dimensionValues?.[0]?.value || "";
// 対象ページ自体は除外
if (pagePath === input.pagePath) continue;
const count = row.metricValues?.[0]?.value
? Math.round(parseFloat(row.metricValues[0].value))
: 0;
relatedPages.push({
pagePath,
count,
percentage: calculatePercentage(count, targetSessions),
});
if (relatedPages.length >= limit) break;
}
return {
targetPage: input.pagePath,
direction: input.direction,
relatedPages,
};
}