Store Model defines the schema and logic for retrieving query data via an HTTP request.
To use Google Analytics integration create a Store file that references a Store Preset. For custom API data sources (when no preset is available), you need to create a full Store file.
This page shows how to create a custom integration from scratch. Google Analytics is used as an example.
Each Store must be stored as store_name.store YAML file:
fields: # Time Dimensions- dimension: date # "20250127" result: string time_group: event_created_at detail: days description: 'The date of the event, formatted as YYYYMMDD' meta: apiName: date- dimension: iso_year_iso_week # "202504" label: 'Week Monday' result: string time_group: event_created_at detail: weeksMonday description: 'The combined values of isoWeek and isoYear. Example values include 201652 & 201701' meta: apiName: isoYearIsoWeek- dimension: year_week # "202505" label: 'Week Sunday' result: string time_group: event_created_at detail: weeksSunday description: 'The combined values of year and week. Example values include 202253 or 202301' meta: apiName: yearWeek- dimension: year_month # "202501" label: 'Month' result: string time_group: event_created_at detail: months description: 'The combined values of year and month. Example values include 202212 or 202301' meta: apiName: yearMonth- dimension: year # "2025" label: 'Year' result: string time_group: event_created_at detail: years description: 'The four-digit year of the event. For example, 2020 or 2024' meta: apiName: year- dimension: date_hour # "2025012722" label: 'Hour' result: string time_group: event_created_at detail: hours description: 'The combined values of date and hour formatted as YYYYMMDDHH' meta: apiName: dateHour- dimension: date_hour_minute # "202501272212" label: 'Minute' result: string time_group: event_created_at detail: minutes description: 'The combined values of date, hour, and minute formatted as YYYYMMDDHHMM' meta: apiName: dateHourMinute- dimension: hour # "4" result: string group: event description: "The two-digit hour of the day that the event was logged. This dimension ranges from 0-23 and is reported in your property's timezone" meta: apiName: hour- dimension: minute # "40" result: string group: event description: "The two-digit minute of the hour that the event was logged. This dimension ranges from 0-59 and is reported in your property's timezone" meta: apiName: minute- dimension: day # "26" result: string group: event description: 'The day of the month, a two-digit number from 01 to 31' meta: apiName: day- dimension: day_of_week # "0" label: 'Day of week' result: string group: event description: 'The integer day of the week. It returns values in the range 0 to 6 with Sunday as the first day of the week' meta: apiName: dayOfWeek- dimension: day_of_week_name # "Sunday" label: 'Day of week name' result: string group: event description: 'The day of the week in English. This dimension has values such as Sunday or Monday' meta: apiName: dayOfWeekName- dimension: week # "05" label: 'Week' result: string group: event description: 'The week of the event, a two-digit number from 01 to 53. Each week starts on Sunday. January 1st is always in week 01. The first and last week of the year have fewer than 7 days in most years. Weeks other than the first and the last week of the year always have 7 days. For years where January 1st is a Sunday, the first week of that year and the last week of the prior year have 7 days' meta: apiName: week- dimension: month # "01" result: string group: event description: 'The month of the event, a two digit integer from 01 to 12' meta: apiName: month- dimension: iso_year # "2025" label: 'ISO year' result: string group: event description: 'The ISO year of the event. For details, see http://en.wikipedia.org/wiki/ISO_week_date. Example values include 2022 & 2023' meta: apiName: isoYear- dimension: iso_week # "04" label: 'ISO week of the year' result: string group: event description: 'ISO week number, where each week starts on Monday. For details, see http://en.wikipedia.org/wiki/ISO_week_date. Example values include 01, 02, & 53' meta: apiName: isoWeek- dimension: nth_year # "0000" label: 'Nth year' result: string description: 'The number of years since the start of the date range. The starting year is 0000' group: event meta: apiName: nthYear- dimension: nth_month # "0000" label: 'Nth month' result: string group: event description: 'The number of months since the start of a date range. The starting month is 0000' meta: apiName: nthMonth- dimension: nth_week # "0001" label: 'Nth week' result: string group: event description: 'A number representing the number of weeks since the start of a date range' meta: apiName: nthWeek- dimension: nth_day # "0004" label: 'Nth day' result: string group: event description: 'The number of days since the start of the date range' meta: apiName: nthDay- dimension: nth_hour # "0142" label: 'Nth hour' result: string group: event description: 'The number of hours since the start of the date range. The starting hour is 0000' meta: apiName: nthHour- dimension: nth_minute # "8532" label: 'Nth minute' result: string group: event description: 'The number of minutes since the start of the date range. The starting minute is 0000' meta: apiName: nthMinute# Dimensions (full list is available on github)- dimension: "country" result: "string" description: "The country from which the user activity originated." group: "geography" label: "Country" meta: apiName: "country" uiName: "Country"- dimension: "city" result: "string" description: "The city from which the user activity originated." group: "geography" label: "City" meta: apiName: "city" uiName: "City"# Measures (full list is available on github)- measure: "active_users" result: "number" description: "The number of distinct users who visited your site or app." group: "user" label: "Active Users" meta: apiName: "activeUsers" uiName: "Active users" type: "TYPE_INTEGER"- measure: "sessions" result: "number" description: "The number of sessions that began on your site or app (event triggered: session_start)." group: "session" label: "Sessions" meta: apiName: "sessions" uiName: "Sessions" type: "TYPE_INTEGER"- measure: "screen_page_views" result: "number" description: "The number of app screens or web pages your users viewed. Repeated views of a single page or screen are counted. (screen_view + page_view events)." group: "page_screen" label: "Views" meta: apiName: "screenPageViews" uiName: "Views" type: "TYPE_INTEGER"
let data = $RESPONSE_DATA; let storeFields = $STORE_FIELDS; let dimensionHeaders = data.dimensionHeaders?.map(header => header.name); let metricHeaders = data.metricHeaders?.map(header => header.name); newData = data.rows?.map(row => { let newRow = {}; row.dimensionValues?.forEach((dimension, index) => { let dimensionName = dimensionHeaders[index]; let value = dimension.value; let date; if (dimensionName === 'year') { date = new Date(`${value}-01-01T00:00:00Z`); } else if (dimensionName === 'yearMonth') { date = new Date(`${value.slice(0, 4)}-${value.slice(4, 6)}-01T00:00:00Z`); } else if (dimensionName === 'isoYearIsoWeek') { // Parse ISO year and week (e.g., "202504" -> year=2025, week=4) // Create a date in week 1 of the ISO year (January 4th is always in week 1) // Get the Monday of week 1 // Add weeks to reach the target week let year = parseInt(value.slice(0, 4), 10); let week = parseInt(value.slice(4, 6), 10); date = new Date(Date.UTC(year, 0, 4)); let day = date.getUTCDay(); // 0 (Sunday) to 6 (Saturday) date.setUTCDate(date.getUTCDate() - (day === 0 ? 6 : day - 1)); date.setUTCDate(date.getUTCDate() + (week - 1) * 7); } else if (dimensionName === 'yearWeek') { // Parse year and week (e.g., "202505" -> year=2025, week=5) // Find the first Sunday of the year // Add weeks to reach the target week let year = parseInt(value.slice(0, 4), 10); let week = parseInt(value.slice(4, 6), 10); let firstDay = new Date(Date.UTC(year, 0, 1)); let day = firstDay.getUTCDay(); // 0 (Sunday) to 6 (Saturday) let firstSunday = new Date(firstDay); firstSunday.setUTCDate(firstDay.getUTCDate() - day); date = new Date(firstSunday); date.setUTCDate(firstSunday.getUTCDate() + (week - 1) * 7); } else if (dimensionName === 'date') { date = new Date(`${value.slice(0, 4)}-${value.slice(4, 6)}-${value.slice(6, 8)}T00:00:00Z`); } else if (dimensionName === 'dateHour') { date = new Date(`${value.slice(0, 4)}-${value.slice(4, 6)}-${value.slice(6, 8)}T${value.slice(8, 10)}:00:00Z`); } else if (dimensionName === 'dateHourMinute') { date = new Date(`${value.slice(0, 4)}-${value.slice(4, 6)}-${value.slice(6, 8)}T${value.slice(8, 10)}:${value.slice(10, 12)}:00Z`); } let storeField = storeFields.find(x => !!x.meta && x.meta['apiName'] === dimensionName); if (!!storeField) { let fieldId = storeField.name; newRow[fieldId] = !!date ? date.getTime()/1000 : value; } }); row.metricValues?.forEach((metric, index) => { let metricName = metricHeaders[index]; let value = metric.value; let storeField = storeFields.find(x => !!x.meta && x.meta['apiName'] === metricName); if (!!storeField) { let fieldId = storeField.name; newRow[fieldId] = value; } }); return newRow; }); return newData || [];
fields:# Time Dimensions- dimension: date # "20250127" result: string time_group: event_created_at detail: days description: 'The date of the event, formatted as YYYYMMDD' meta: apiName: date- dimension: iso_year_iso_week # "202504" label: 'Week Monday' result: string time_group: event_created_at detail: weeksMonday description: 'The combined values of isoWeek and isoYear. Example values include 201652 & 201701' meta: apiName: isoYearIsoWeek- dimension: year_week # "202505" label: 'Week Sunday' result: string time_group: event_created_at detail: weeksSunday description: 'The combined values of year and week. Example values include 202253 or 202301' meta: apiName: yearWeek- dimension: year_month # "202501" label: 'Month' result: string time_group: event_created_at detail: months description: 'The combined values of year and month. Example values include 202212 or 202301' meta: apiName: yearMonth- dimension: year # "2025" label: 'Year' result: string time_group: event_created_at detail: years description: 'The four-digit year of the event. For example, 2020 or 2024' meta: apiName: year- dimension: date_hour # "2025012722" label: 'Hour' result: string time_group: event_created_at detail: hours description: 'The combined values of date and hour formatted as YYYYMMDDHH' meta: apiName: dateHour- dimension: date_hour_minute # "202501272212" label: 'Minute' result: string time_group: event_created_at detail: minutes description: 'The combined values of date, hour, and minute formatted as YYYYMMDDHHMM' meta: apiName: dateHourMinute- dimension: hour # "4" result: string group: event description: "The two-digit hour of the day that the event was logged. This dimension ranges from 0-23 and is reported in your property's timezone" meta: apiName: hour- dimension: minute # "40" result: string group: event description: "The two-digit minute of the hour that the event was logged. This dimension ranges from 0-59 and is reported in your property's timezone" meta: apiName: minute- dimension: day # "26" result: string group: event description: 'The day of the month, a two-digit number from 01 to 31' meta: apiName: day- dimension: day_of_week # "0" label: 'Day of week' result: string group: event description: 'The integer day of the week. It returns values in the range 0 to 6 with Sunday as the first day of the week' meta: apiName: dayOfWeek- dimension: day_of_week_name # "Sunday" label: 'Day of week name' result: string group: event description: 'The day of the week in English. This dimension has values such as Sunday or Monday' meta: apiName: dayOfWeekName- dimension: week # "05" label: 'Week' result: string group: event description: 'The week of the event, a two-digit number from 01 to 53. Each week starts on Sunday. January 1st is always in week 01. The first and last week of the year have fewer than 7 days in most years. Weeks other than the first and the last week of the year always have 7 days. For years where January 1st is a Sunday, the first week of that year and the last week of the prior year have 7 days' meta: apiName: week- dimension: month # "01" result: string group: event description: 'The month of the event, a two digit integer from 01 to 12' meta: apiName: month- dimension: iso_year # "2025" label: 'ISO year' result: string group: event description: 'The ISO year of the event. For details, see http://en.wikipedia.org/wiki/ISO_week_date. Example values include 2022 & 2023' meta: apiName: isoYear- dimension: iso_week # "04" label: 'ISO week of the year' result: string group: event description: 'ISO week number, where each week starts on Monday. For details, see http://en.wikipedia.org/wiki/ISO_week_date. Example values include 01, 02, & 53' meta: apiName: isoWeek- dimension: nth_year # "0000" label: 'Nth year' result: string description: 'The number of years since the start of the date range. The starting year is 0000' group: event meta: apiName: nthYear- dimension: nth_month # "0000" label: 'Nth month' result: string group: event description: 'The number of months since the start of a date range. The starting month is 0000' meta: apiName: nthMonth- dimension: nth_week # "0001" label: 'Nth week' result: string group: event description: 'A number representing the number of weeks since the start of a date range' meta: apiName: nthWeek- dimension: nth_day # "0004" label: 'Nth day' result: string group: event description: 'The number of days since the start of the date range' meta: apiName: nthDay- dimension: nth_hour # "0142" label: 'Nth hour' result: string group: event description: 'The number of hours since the start of the date range. The starting hour is 0000' meta: apiName: nthHour- dimension: nth_minute # "8532" label: 'Nth minute' result: string group: event description: 'The number of minutes since the start of the date range. The starting minute is 0000' meta: apiName: nthMinute# Dimensions (full list is available on github)- dimension: "country" result: "string" description: "The country from which the user activity originated." group: "geography" label: "Country" meta: apiName: "country" uiName: "Country"- dimension: "city" result: "string" description: "The city from which the user activity originated." group: "geography" label: "City" meta: apiName: "city" uiName: "City"# Measures (full list is available on github)- measure: "active_users" result: "number" description: "The number of distinct users who visited your site or app." group: "user" label: "Active Users" meta: apiName: "activeUsers" uiName: "Active users" type: "TYPE_INTEGER"- measure: "sessions" result: "number" description: "The number of sessions that began on your site or app (event triggered: session_start)." group: "session" label: "Sessions" meta: apiName: "sessions" uiName: "Sessions" type: "TYPE_INTEGER"- measure: "screen_page_views" result: "number" description: "The number of app screens or web pages your users viewed. Repeated views of a single page or screen are counted. (screen_view + page_view events)." group: "page_screen" label: "Views" meta: apiName: "screenPageViews" uiName: "Views" type: "TYPE_INTEGER"
let data = $RESPONSE_DATA; let storeFields = $STORE_FIELDS; let dimensionHeaders = data.dimensionHeaders?.map(header => header.name); let metricHeaders = data.metricHeaders?.map(header => header.name); newData = data.rows?.map(row => { let newRow = {}; row.dimensionValues?.forEach((dimension, index) => { let dimensionName = dimensionHeaders[index]; let value = dimension.value; let date; if (dimensionName === 'year') { date = new Date(`${value}-01-01T00:00:00Z`); } else if (dimensionName === 'yearMonth') { date = new Date(`${value.slice(0, 4)}-${value.slice(4, 6)}-01T00:00:00Z`); } else if (dimensionName === 'isoYearIsoWeek') { // Parse ISO year and week (e.g., "202504" -> year=2025, week=4) // Create a date in week 1 of the ISO year (January 4th is always in week 1) // Get the Monday of week 1 // Add weeks to reach the target week let year = parseInt(value.slice(0, 4), 10); let week = parseInt(value.slice(4, 6), 10); date = new Date(Date.UTC(year, 0, 4)); let day = date.getUTCDay(); // 0 (Sunday) to 6 (Saturday) date.setUTCDate(date.getUTCDate() - (day === 0 ? 6 : day - 1)); date.setUTCDate(date.getUTCDate() + (week - 1) * 7); } else if (dimensionName === 'yearWeek') { // Parse year and week (e.g., "202505" -> year=2025, week=5) // Find the first Sunday of the year // Add weeks to reach the target week let year = parseInt(value.slice(0, 4), 10); let week = parseInt(value.slice(4, 6), 10); let firstDay = new Date(Date.UTC(year, 0, 1)); let day = firstDay.getUTCDay(); // 0 (Sunday) to 6 (Saturday) let firstSunday = new Date(firstDay); firstSunday.setUTCDate(firstDay.getUTCDate() - day); date = new Date(firstSunday); date.setUTCDate(firstSunday.getUTCDate() + (week - 1) * 7); } else if (dimensionName === 'date') { date = new Date(`${value.slice(0, 4)}-${value.slice(4, 6)}-${value.slice(6, 8)}T00:00:00Z`); } else if (dimensionName === 'dateHour') { date = new Date(`${value.slice(0, 4)}-${value.slice(4, 6)}-${value.slice(6, 8)}T${value.slice(8, 10)}:00:00Z`); } else if (dimensionName === 'dateHourMinute') { date = new Date(`${value.slice(0, 4)}-${value.slice(4, 6)}-${value.slice(6, 8)}T${value.slice(8, 10)}:${value.slice(10, 12)}:00Z`); } let storeField = storeFields.find(x => !!x.meta && x.meta['apiName'] === dimensionName); if (!!storeField) { let fieldId = storeField.name; newRow[fieldId] = !!date ? date.getTime()/1000 : value; } }); row.metricValues?.forEach((metric, index) => { let metricName = metricHeaders[index]; let value = metric.value; let storeField = storeFields.find(x => !!x.meta && x.meta['apiName'] === metricName); if (!!storeField) { let fieldId = storeField.name; newRow[fieldId] = value; } }); return newRow; }); return newData || [];
const STORE_FIELDS = [ // list of store parameters and store fields definitions in a single array { required: 'true', max_fractions: '1', fraction_controls: [ { label: 'Property', value: '123123123', options: [ { value: '123123123' } ], name: 'ga_property', controlClass: 'selector' }, { label: 'Start Date', value: '2025-02-24', name: 'start_date', controlClass: 'date_picker' }, { label: 'End Date', value: '2025-02-24', name: 'end_date', controlClass: 'date_picker' } ], name: 'top_config', fieldClass: 'filter', label: 'Top Config', group: 'mf' }, { result: 'string', group: 'geo', description: 'The country from which the user activity originated', meta: { name: 'country' }, name: 'country', fieldClass: 'dimension', label: 'Country', type: 'custom', }, { result: 'number', group: 'users', description: 'The number of distinct users who visited your site or app', meta: { name: 'activeUsers', type: 'TYPE_INTEGER', }, name: 'active_users', fieldClass: 'measure', label: 'Active Users', format_number: ',.0f', currency_prefix: '$', currency_suffix: '', }, // ... other store parameters definitions // ... other store fields definitions];
const QUERY_ORDER_BY = [ { fieldId: 'city', field: { result: 'string', group: 'geo', description: 'The city from which the user activity originated', meta: { name: 'city' }, name: 'city', fieldClass: 'dimension', label: 'City', type: 'custom', }, desc: false } ];
const QUERY_SELECTED_DIMENSIONS = [ { result: 'string', group: 'geo', description: 'The city from which the user activity originated', meta: { apiName: 'city', uiName: 'City' }, name: 'city', fieldClass: 'dimension', label: 'City', type: 'custom', }];
const QUERY_SELECTED_MEASURES = [ { result: 'number', group: 'users', description: 'The number of distinct users who visited your site or app', meta: { apiName: 'activeUsers', uiName: 'Active users', type: 'TYPE_INTEGER', }, name: 'active_users', fieldClass: 'measure', label: 'Active Users', format_number: ',.0f', currency_prefix: '$', currency_suffix: '', }];