@@ -40,7 +40,7 @@ export const ProfilesBuilders: Record<string, SimpleQueryConfig> = {
4040 client_id = {websiteId:String}
4141 AND time >= parseDateTimeBestEffort({startDate:String})
4242 AND time <= parseDateTimeBestEffort({endDate:String})
43- ${ combinedWhereClause }
43+ ${ combinedWhereClause }
4444 GROUP BY anonymous_id
4545 ORDER BY last_visit DESC
4646 LIMIT {limit:Int32} OFFSET {offset:Int32}
@@ -79,7 +79,7 @@ export const ProfilesBuilders: Record<string, SimpleQueryConfig> = {
7979 FROM analytics.events e
8080 INNER JOIN visitor_profiles vp ON e.anonymous_id = vp.visitor_id
8181 WHERE e.client_id = {websiteId:String}
82- ${ combinedWhereClause }
82+ ${ combinedWhereClause }
8383 GROUP BY vp.visitor_id, e.session_id
8484 ORDER BY vp.visitor_id, session_start DESC
8585 )
@@ -127,6 +127,142 @@ export const ProfilesBuilders: Record<string, SimpleQueryConfig> = {
127127 } ,
128128 } ,
129129
130+ profile_detail : {
131+ customSql : (
132+ websiteId : string ,
133+ startDate : string ,
134+ endDate : string ,
135+ filters ?: Filter [ ] ,
136+ _granularity ?: unknown ,
137+ _limit ?: number ,
138+ _offset ?: number ,
139+ _timezone ?: string ,
140+ _filterConditions ?: string [ ] ,
141+ _filterParams ?: Record < string , Filter [ 'value' ] >
142+ ) => {
143+ const visitorId = filters ?. find ( ( f ) => f . field === 'anonymous_id' ) ?. value ;
144+
145+ if ( ! visitorId || typeof visitorId !== 'string' ) {
146+ throw new Error (
147+ 'anonymous_id filter is required for profile_detail query'
148+ ) ;
149+ }
150+
151+ return {
152+ sql : `
153+ WITH user_profile AS (
154+ SELECT
155+ anonymous_id as visitor_id,
156+ MIN(time) as first_visit,
157+ MAX(time) as last_visit,
158+ COUNT(DISTINCT session_id) as total_sessions,
159+ COUNT(*) as total_pageviews,
160+ SUM(CASE WHEN time_on_page > 0 THEN time_on_page ELSE 0 END) as total_duration,
161+ formatReadableTimeDelta(SUM(CASE WHEN time_on_page > 0 THEN time_on_page ELSE 0 END)) as total_duration_formatted,
162+ any(device_type) as device,
163+ any(browser_name) as browser,
164+ any(os_name) as os,
165+ any(country) as country,
166+ any(region) as region
167+ FROM analytics.events
168+ WHERE
169+ client_id = {websiteId:String}
170+ AND anonymous_id = {visitorId:String}
171+ AND time >= parseDateTimeBestEffort({startDate:String})
172+ AND time <= parseDateTimeBestEffort({endDate:String})
173+ GROUP BY anonymous_id
174+ ),
175+ user_sessions AS (
176+ SELECT
177+ e.session_id,
178+ CONCAT('Session ', ROW_NUMBER() OVER (ORDER BY MIN(e.time))) as session_name,
179+ MIN(e.time) as first_visit,
180+ MAX(e.time) as last_visit,
181+ LEAST(dateDiff('second', MIN(e.time), MAX(e.time)), 28800) as duration,
182+ formatReadableTimeDelta(LEAST(dateDiff('second', MIN(e.time), MAX(e.time)), 28800)) as duration_formatted,
183+ COUNT(DISTINCT e.path) as page_views,
184+ COUNT(DISTINCT e.path) as unique_pages,
185+ any(e.device_type) as device,
186+ any(e.browser_name) as browser,
187+ any(e.os_name) as os,
188+ any(e.country) as country,
189+ any(e.region) as region,
190+ any(e.referrer) as referrer,
191+ groupArray(
192+ tuple(
193+ e.id,
194+ e.time,
195+ e.event_name,
196+ e.path,
197+ CASE
198+ WHEN e.event_name NOT IN ('screen_view', 'page_exit', 'web_vitals', 'link_out')
199+ AND e.properties IS NOT NULL
200+ AND e.properties != '{}'
201+ THEN CAST(e.properties AS String)
202+ ELSE NULL
203+ END,
204+ NULL,
205+ NULL
206+ )
207+ ) as events
208+ FROM analytics.events e
209+ WHERE
210+ e.client_id = {websiteId:String}
211+ AND e.anonymous_id = {visitorId:String}
212+ AND e.time >= parseDateTimeBestEffort({startDate:String})
213+ AND e.time <= parseDateTimeBestEffort({endDate:String})
214+ GROUP BY e.session_id
215+ ORDER BY first_visit DESC
216+ )
217+ SELECT
218+ up.visitor_id,
219+ up.first_visit,
220+ up.last_visit,
221+ up.total_sessions,
222+ up.total_pageviews,
223+ up.total_duration,
224+ up.total_duration_formatted,
225+ up.device,
226+ up.browser,
227+ up.os,
228+ up.country,
229+ up.region,
230+ groupArray(
231+ tuple(
232+ us.session_id,
233+ us.session_name,
234+ us.first_visit,
235+ us.last_visit,
236+ us.duration,
237+ us.duration_formatted,
238+ us.page_views,
239+ us.unique_pages,
240+ us.device,
241+ us.browser,
242+ us.os,
243+ us.country,
244+ us.region,
245+ us.referrer,
246+ us.events
247+ )
248+ ) as sessions
249+ FROM user_profile up
250+ LEFT JOIN user_sessions us ON 1=1
251+ GROUP BY
252+ up.visitor_id, up.first_visit, up.last_visit, up.total_sessions,
253+ up.total_pageviews, up.total_duration, up.total_duration_formatted,
254+ up.device, up.browser, up.os, up.country, up.region
255+ ` ,
256+ params : {
257+ websiteId,
258+ visitorId,
259+ startDate,
260+ endDate : `${ endDate } 23:59:59` ,
261+ } ,
262+ } ;
263+ } ,
264+ } ,
265+
130266 profile_metrics : {
131267 table : Analytics . events ,
132268 fields : [
@@ -238,7 +374,7 @@ export const ProfilesBuilders: Record<string, SimpleQueryConfig> = {
238374 AND time >= parseDateTimeBestEffort({startDate:String})
239375 AND time <= parseDateTimeBestEffort({endDate:String})
240376 AND event_name = 'screen_view'
241- ${ combinedWhereClause }
377+ ${ combinedWhereClause }
242378 GROUP BY anonymous_id
243379 HAVING session_count > 1
244380 ORDER BY session_count DESC
0 commit comments