Simple 3 Steps — Create a Free GA4 Automated Data Notification Bot
Use Google Apps Script to complete RPA, integrating GA4 + Telegram Bot for data notifications
ℹ️ℹ️ℹ️ The following content is translated by OpenAI.
Click here to view the original Chinese version. | 點此查看本文中文版
Simple 3 Steps — Create a Free GA4 Automated Data Notification Bot
Use Google Apps Script to complete RPA, integrating GA4 + Telegram Bot for data notifications.
Photo by BoliviaInteligente
Introduction
Since around 2020, I have been exploring how to implement RPA using the tools at hand. Initially, it was just to automate personal routine tasks, but as I joined larger organizations, I often encountered cross-team tasks or tasks reliant on human interaction, as well as repetitive tasks. This is when I realized the benefits of RPA automation.
For example, if a repetitive task occurs 10 times a month, taking 30 minutes each time, and affects 60 people, the team effectively spends 3,600 hours a year on it. If we can invest 100 hours to develop automation, the time freed up can be redirected to more valuable work; this translates to 3,600 wasted work hours plus 3,600 hours of more worthwhile output.
For more details, refer to my previous articles:
- 2021 Pinkoi Tech Career Talk — Secrets of High-Efficiency Engineering Teams
- Using Google Apps Script to Achieve Daily Data Report RPA Automation
Other RPA projects I have worked on:
- [GMail to Slack] Using Google Apps Script to Forward Gmail Messages to Slack
- [Google Form x Google Sheet x Slack] Creating a Fully Automated WFH Employee Health Reporting System in Slack
- [Big Query x Slack] Building a More Instant and Convenient Crash Tracking Tool with Crashlytics + Big Query
- [Google Analytics x Slack] Automatically Querying App Crash-Free Users Rate with Crashlytics + Google Analytics
- [Github Webhook x Line Notify] Using Google Apps Script to Create a Free Github Repo Star Notifier in Three Steps
- [Slack x OpenAI (ChatGPT)] Slack & ChatGPT Integration
- [Google Analytics x Google Sheet] Using Google Apps Script to Achieve Daily Data Report RPA Automation
- [iOS Shortcut x Line x Reminders] iOS Shortcut Automation Use Case — Automatically Forwarding Messages and Creating Reminder Tasks
- [Apple Store API x Google Play Console API x Github Action] Github Action x ZReviewTender Free and Fast Deployment of Your App Store Review Monitoring Bot
- [Telegram Bot] Quickly Transitioning from Line Notify to Telegram Bot Notifications in 10 Minutes
- [Medium to Jekyllrb] Seamlessly Migrating from Medium to Self-Hosted Websites
From the backend data, I noticed that many of my articles have been indexed by ChatGPT or various GenAI services, indirectly helping many friends without an engineering background who want to try using RPA to solve problems. Therefore, I will continue to share RPA scenarios and my solutions encountered in my life or work with everyone — ZRealm Robotic Process Automation.
Advertisement Time
If you and your team have automation tools or process integration needs, whether it’s Slack App development, Notion, Asana, Google Sheets, Google Forms, GA data, or various integration requirements, feel free to contact me for development.
This Article: Google Analytics 4 x Telegram Bot
In this article, I will introduce the integration scenario that follows the previous one, “Quickly Transitioning from Line Notify to Telegram Bot Notifications in 10 Minutes.” I realized that my Medium backup site “zhgchg.li” has not been monitoring its GA4 website data, so I thought it would be good to create a notification bot that sends the website data for the past 7 days to a designated Telegram Channel daily.
This article is just a small piece. For a complete automated data report, please refer to my previous article “Using Google Apps Script to Achieve Daily Data Report RPA Automation.” Additionally, I have previously integrated GA4 to fetch App Crash-free rates; you can refer to this article “Automatically Querying App Crash-Free Users Rate with Crashlytics + Google Analytics.”
- This article will not cover the free limitations, detailed usage, deployment, or feature introduction of Google Apps Script; please refer to previous articles.
- This article will also not cover the creation and usage of Telegram Bots; please refer to previous articles.
Results
Here’s the final effect: Google Apps Script will automatically fetch the desired Google Analytics 4 website data between 12 PM and 1 PM daily and combine it into a message sent via Telegram Bot to my Telegram Channel, allowing me to quickly review the website data for the past 7 days.
The data I want to observe includes:
- Total page views for the last 7 days
7daysAgo ~ today
screenPageViews
- Active users
active7DayUsers
- New users
newUsers
- Top 10 viewed pages
screenPageViews
/pageTitle
- The initial source medium of new users
newUsers
/firstUserSourceMedium
You can adjust according to your own needs using GA Dev Tools.
Step 1. Use GA4 Query Explorer Official Tool to Generate Data Report Query Parameters
First, we need to use the official tool GA4 Query Explorer to generate the query parameters for the data report we need:
- Select Property: Note down your
property ID
. The property ID will be used later in the Google Apps Script. - Start date, end date: The date range for the report can use
YYYY-MM-DD
or the magic variablesyesterday
,today
,NdaysAgo
. - Metrics: Choose the metrics you want to query.
- Dimensions: Choose the dimensions you want to query.
- Metric aggregations: Rules for aggregating the data.
For my scenario:
- Property ID:
318495208
- Start date:
7daysAgo
- End date:
yesterday
Since GA data reports have a delay, querying from the previous day to seven days back is the most accurate. - Metric aggregations:
total
Other filters and limits can be set according to your needs:
I left the filter empty as I don’t need it; I entered 10 for the limit because I only want to know the Top 10.
Click “MAKE REQUEST” to generate the corresponding data report query parameters and results:
Note down the following request parameters, which will be used later in the Google Apps Script:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"dimensions": [
{
"name": "pageTitle"
}
],
"metrics": [
{
"name": "screenPageViews"
}
],
"dateRanges": [
{
"startDate": "7daysAgo",
"endDate": "yesterday"
}
],
"limit": "10",
"metricAggregations": [
"TOTAL"
]
}
Results:
- Compare with the data on GA to see if it is correct; it matches ✅✅✅
Step 2. Create Google Apps Script & Use Google Analytics Data API to Query Data
- Go to https://script.google.com/home
- Create a new project and name it.
- Click “Services” -> “+” to add a service.
- Select “Google Analytics Data API”.
- Click “Add”.
Paste the Google Analytics Data API query code and combine it:
Use the report query data parameters generated in the previous steps:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"dimensions": [
{
"name": "pageTitle"
}
],
"metrics": [
{
"name": "screenPageViews"
}
],
"dateRanges": [
{
"startDate": "7daysAgo",
"endDate": "yesterday"
}
],
"limit": "10",
"metricAggregations": [
"TOTAL"
]
}
Convert it into code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
function execute() {
Logger.log(JSON.stringify(fetchScreenPageViews("318495208")));
}
// Split into independent methods for easy reuse...
// Default startDate=7daysAgo, endDate=yesterday
// Other usages:
// e.g. fetchScreenPageViews("1111", "3daysAgo", "yesterday")
// e.g. fetchScreenPageViews("2222", "yesterday", "today")
function fetchScreenPageViews(propertyId, startDate = "7daysAgo", endDate = "yesterday") {
const screenPageViewsMetric = AnalyticsData.newMetric();
screenPageViewsMetric.name = "screenPageViews";
const dateRange = AnalyticsData.newDateRange();
dateRange.startDate = startDate;
dateRange.endDate = endDate;
const pageTitleDimension = AnalyticsData.newDimension();
pageTitleDimension.name = "pageTitle";
const request = AnalyticsData.newRunReportRequest();
request.dimensions = [pageTitleDimension];
request.metrics = [screenPageViewsMetric];
request.dateRanges = dateRange;
request.limit = 10;
request.metricAggregations = "TOTAL";
return AnalyticsData.Properties.runReport(request, "properties/" + propertyId);
}
Code explanation:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// Metrics can be multiple; declare them separately...
const screenPageViewsMetric = AnalyticsData.newMetric();
screenPageViewsMetric.name = "screenPageViews";
// For example, another metric active1DayUsers:
const active1DayUsersMetric = AnalyticsData.newMetric();
active1DayUsersMetric.name = "active1DayUsers";
// Declare the date range
const dateRange = AnalyticsData.newDateRange();
dateRange.startDate = startDate;
dateRange.endDate = endDate;
// Dimensions can be multiple; declare them separately...
const pageTitleDimension = AnalyticsData.newDimension();
pageTitleDimension.name = "pageTitle";
// For example, another dimension:
const firstUserSourceMediumDimension = AnalyticsData.newDimension();
firstUserSourceMediumDimension.name = "firstUserSourceMedium";
// Generate the Request object
const request = AnalyticsData.newRunReportRequest();
request.metrics = [active1DayUsersMetric, screenPageViewsMetric]; // Include multiple...
request.dimensions = [pageTitleDimension, firstUserSourceMediumDimension]; // Include multiple...
request.dateRanges = dateRange;
// Only need the top 10 records (Top 10)
request.limit = 10;
// Set the data aggregation logic: Total (SUM)
request.metricAggregations = "TOTAL";
// Generate the query result
return AnalyticsData.Properties.runReport(request, "properties/" + propertyId).rows;
The first execution will require authorization (you will need to re-authenticate if you add new permissions later):
Essentially, this authorizes Google Apps Script to execute these programs using your account identity, so ensure that the account you choose has the corresponding access rights to the GA reports.
- After writing the code, click “Debug” -> Click “Review Permissions”.
- Select the account to execute, which usually equals the current Google Apps Script account.
- Choose “Advanced” to expand -> Click “Go to XXX”. This is an application we wrote for our own use, so it does not need to go through Google verification.
- Click “Allow”.
After allowing, click “Debug” or “Run” to execute the program:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159

Here, we first use `Logger.log(JSON.stringify())` to obtain the output result:
```json
{
"kind": "analyticsData#runReport",
"dimensionHeaders": [
{
"name": "pageTitle"
}
],
"rowCount": 71,
"metadata": {
"currencyCode": "TWD",
"timeZone": "Asia/Taipei"
},
"rows": [
{
"dimensionValues": [
{
"value": "ZhgChgLi"
}
],
"metricValues": [
{
"value": "166"
}
]
},
{
"metricValues": [
{
"value": "109"
}
],
"dimensionValues": [
{
"value": "Unboxing the Apple Watch Original Stainless Steel Milanese Loop | ZhgChgLi"
}
]
},
{
"dimensionValues": [
{
"value": "Using the 'Shortcuts' Automation Feature with Mijia Smart Home on iOS ≥ 13.1 | ZhgChgLi"
}
],
"metricValues": [
{
"value": "101"
}
]
},
{
"dimensionValues": [
{
"value": "The Medium Partner Program is Finally Open to Global (Including Taiwan) Writers! | ZhgChgLi"
}
],
"metricValues": [
{
"value": "85"
}
]
},
{
"metricValues": [
{
"value": "77"
}
],
"dimensionValues": [
{
"value": "iOS Shortcuts Automation Use Cases — Automatically Forwarding Messages and Creating Reminders | ZhgChgLi"
}
]
},
{
"metricValues": [
{
"value": "51"
}
],
"dimensionValues": [
{
"value": "Travel Diary 9/11 One-Day Flash Trip to Nagoya | ZhgChgLi"
}
]
},
{
"metricValues": [
{
"value": "42"
}
],
"dimensionValues": [
{
"value": "The Past and Present of iOS Privacy and Convenience | ZhgChgLi"
}
]
},
{
"dimensionValues": [
{
"value": "iOS Vision Framework x WWDC 24 Discover Swift Enhancements in the Vision Framework Session | ZhgChgLi"
}
],
"metricValues": [
{
"value": "34"
}
]
},
{
"dimensionValues": [
{
"value": "iOS ≥ 18 NSAttributedString Attributes Range Merging Behavior Change | ZhgChgLi"
}
],
"metricValues": [
{
"value": "30"
}
]
},
{
"metricValues": [
{
"value": "30"
}
],
"dimensionValues": [
{
"value": "The Story of Building an HTML Parser by Hand | ZhgChgLi"
}
]
}
],
"metricHeaders": [
{
"type": "TYPE_INTEGER",
"name": "screenPageViews"
}
],
"totals": [
{
"dimensionValues": [
{
"value": "RESERVED_TOTAL"
}
],
"metricValues": [
{
"value": "1229"
}
]
}
]
}
- Google Apps Script successfully requested GA data! 🎉🎉🎉
Step 3. Putting It All Together! Google Apps Script + GA4 + Telegram Bot
Based on the previous article “Quickly Transitioning from Line Notify to Telegram Bot Notifications in 10 Minutes”, create your Telegram Bot to obtain the Bot Token
and the Channel Chat ID
you want to send messages to.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
const telegramToken = "XXXX" // Insert your Telegram Bot Token
//
function execute() {
const screenPageViewsReport = fetchScreenPageViews("318495208");
//
const total = parseInt(screenPageViewsReport.totals[0].metricValues[0].value);
var message = "Total Views: " + total.toLocaleString() + "\n";
screenPageViewsReport.rows.forEach(function(element, index) {
const pageTitle = element.dimensionValues[0].value;
const value = parseInt(element.metricValues[0].value);
message += "[Top " + (index + 1) + "] " + pageTitle + ": " + value.toLocaleString() + "\n";
});
sendNotifyMessage(message, -xxxx); // Insert your Channel Chat ID
}
// Send message to the specified Telegram Channel Chat ID
function sendNotifyMessage(message, chatId) {
var url = "https://api.telegram.org/bot" + telegramToken + "/sendMessage";
const payload = {
"chat_id": chatId,
"text": message,
"disable_web_page_preview": true
}
const options = {
'method': 'post',
'contentType': 'application/json',
'muteHttpExceptions': true,
'payload': JSON.stringify(payload)
};
const response = UrlFetchApp.fetch(url, options);
const data = JSON.parse(response.getContentText());
if (data["ok"] == undefined || data["ok"] != true) {
if (data["error_code"] != undefined && data["error_code"] == 429) {
Utilities.sleep(1000);
sendNotifyMessage(message, chatId);
}
}
}
function fetchScreenPageViews(propertyId, startDate = "7daysAgo", endDate = "yesterday") {
const screenPageViewsMetric = AnalyticsData.newMetric();
screenPageViewsMetric.name = "screenPageViews";
const dateRange = AnalyticsData.newDateRange();
dateRange.startDate = startDate;
dateRange.endDate = endDate;
const pageTitleDimension = AnalyticsData.newDimension();
pageTitleDimension.name = "pageTitle";
const request = AnalyticsData.newRunReportRequest();
request.dimensions = [pageTitleDimension];
request.metrics = [screenPageViewsMetric];
request.dateRanges = dateRange;
request.limit = 10;
request.metricAggregations = "TOTAL";
return AnalyticsData.Properties.runReport(request, "properties/" + propertyId);
}
Code Explanation:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//...
// Find the total position in the returned JSON from the report, parseInt converts the string to INT format
// .toLocaleString() -> formats the number, 123456 -> 123,456
const total = parseInt(screenPageViewsReport.totals[0].metricValues[0].value);
var message = "Total Views: " + total.toLocaleString() + "\n";
// Iterate through the data returned from the report JSON to assemble the message
screenPageViewsReport.rows.forEach(function(element, index) {
const pageTitle = element.dimensionValues[0].value;
const value = parseInt(element.metricValues[0].value);
message += "[Top " + (index + 1) + "] " + pageTitle + ": " + value.toLocaleString() + "\n";
});
//...
Execution: Click the “Run” or “Debug” button above and ensure the method name is set to “ execute
“:
- Success! 🎉🎉🎉
Setting Up Scheduled Automatic Execution
The final step is to have the report bot execute automatically on a schedule. Go to “Triggers” from the left menu:
- Click the “Add Trigger” button in the bottom right corner
- Choose the function to execute: select the “
execute
“ method name - Choose the deployment to run: select “
Head
“ - Select the event source: choose “
Time-driven
“ - Select the type of time-based trigger: choose your desired trigger frequency
- Select the time period: choose the time you want it to automatically trigger daily
- If execution fails… set the frequency for notification emails
- Save
Done! It will automatically execute at the scheduled time. 🎉🎉🎉
Extended Tasks
Other data such as new user counts, source mediums, etc., can also be achieved using the previous code, so I won’t repeat it here. Consider it as homework for everyone.
If you have any questions or suggestions, feel free to contact me.
```
This article was first published on Medium ➡️ Click Here
Automatically converted and synchronized using ZMediumToMarkdown and Medium-to-jekyll-starter.