Track resume with GTM + Heroku + Github + SendGrid [Part2]
On this part will focus on how to build back-end app to work as a server with gtm.We will use rest-api with flask for work as get request to run our service when calling it.
Step by step, you will understand what I mean.
before we start, we need
SendGrid:
- Create account on SendGrid
- Create Single Sender Verification
- Create SendGrid API Key
Github:
- Create account on Github
- Create Creating a personal access token - GitHub
First setup back-end app:
1git clone https://github.com/hsayed21/gtm-server.git
{: lang=“bash”}
After clone repo open app.py file and goto send function and modify with your data.‘fromMail@gmail.com’{: .bg-yellow-400} change to your email that you added to SendGrid | Single Sender Verification’toMail@gmail.com’{: .bg-yellow-400} change to your email for receive messages"<sendGrid-APi-key>"{: .bg-yellow-400} change to your SendGrid API Key | SendGrid API Key
1def send(_json, _test=False):
2 # using SendGrid's Python Library
3 message = Mail(
4 from_email='fromMail@gmail.com',
5 to_emails='toMail@gmail.com',
6 subject='Track Resume',
7 html_content= send_template(_json,_test))
8 try:
9 sg = SendGridAPIClient("<sendGrid-APi-key>")
10 response = sg.send(message)
11 return json.dumps(True)
12 except Exception as e:
13 print(e.message)
14 return json.dumps(False)
{: lang=“python”}
After that go to update function and modify "<github-token>"{: .bg-yellow-400} change to your github token | Creating a personal access token - GitHub
In github create repo with name gtm-json then create file name data.json
1g = Github("<github-token>")
2repo = g.get_user().get_repo("gtm-json")
3file_content = repo.get_contents("data.json")
4clear_data_from_github = file_content.decoded_content.decode()
5data_json = json.loads(clear_data_from_github)
{: lang=“python”}
After modifying everything, deploy to heroku
- Create account on Heroku
- Install the Heroku CLI on your computer
- Open the terminal and log in then follow the instructions
1heroku login
{: lang=“bash”}
- Create a project
1heroku create my-gtm-server-app
{: lang=“bash”}
- Push your app to Heroku
1git add .
2git commit -m "modify app"
3git push heroku master
{: lang=“bash”}
Back to Custom HTML on Google Tag Manager
from [Part 1]({{page.url | replace:‘part2’,‘part1’}}){: .underline}, we will continue
On this code from update function modify“https://your-server.herokuapp.com”{: .bg-yellow-400} change to your app that was deployed on heroku
1update("https://your-server.herokuapp.com/update?ip="+res+"&event=Resume Page View")
Google Tag Manager: Custom HTML Final Result
1<script>
2
3// array of free api for get public ip
4var urls = ['https://api.ipify.org/?format=json',
5 'https://jsonip.com', 'https://ipapi.co/json/',
6 'https://ident.me', 'https://ipinfo.io/json',
7 'https://ifconfig.me/ip',
8 'https://ipecho.net/json',
9 'https://icanhazip.com/',
10 'https://wtfismyip.com/text',
11 'https://api.hostip.info/get_json.php',
12 'https://api.db-ip.com/v2/free/self'];
13
14//create instance
15var xhr = new XMLHttpRequest();
16//recursive function
17(function loop(i, length) {
18 /*
19 i => index
20 length => length of array
21 */
22 // check if reach to end of array | last element of array
23 if (i>= length) {
24 return; //go out of function
25 }
26 // get item from array
27 var url = urls[i];
28 // ajax request to open url
29 xhr.open("GET", url);
30 xhr.onreadystatechange = function() {
31 // if request success
32 if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
33 // save response
34 var res = xhr.responseText;
35 // check if respone is json data or string
36 // because of different data type
37 if (isJSON(res)){
38 if ("ip" in JSON.parse(res))
39 res = JSON.parse(res)['ip'];
40 else
41 res = JSON.parse(res)['ipAddress'];
42 }
43
44 // after get ip send to back-end website
45 update("https://cors-proxy.herokuapp.com/https://my-gtm-server-app.herokuapp.com/update?ip="+res+"&event=Resume Page View")
46 return;
47 }
48
49 }
50
51 // if happend error or failed request
52 // start again with different api (recursive)
53 xhr.onerror = function() {
54 loop(i + 1, length);
55 };
56
57 xhr.send();
58
59})(0, urls.length); // start with index 0 and length of urls array
60
61// update data
62function update (url) {
63 var xhr2 = new XMLHttpRequest();
64 xhr2.open("GET", url, true);
65 xhr2.send();
66 xhr2.onreadystatechange = function () {
67 if (xhr2.readyState === 4 && xhr2.status === 200) {
68 //var json2 = JSON.parse(xhr2.responseText);
69 }
70 }
71}
72
73// check data type
74function isJSON(str) {
75try {
76 return (JSON.parse(str) && !!str);
77} catch (e) {
78 return false;
79 }
80}
81
82</script>
{: lang=“javascript”}
Issues
CORS Error
Create proxy to add CORS header to the request
After creating your CORS Proxy web add a web link before your gtm server in Custom HTML
1update("https://your-cors-proxy.herokuapp.com/https://my-gtm-server-app.herokuapp.com/update?ip="+res+"&event=Resume Page View")
Sample Json Data
1{
2"page_url": "https://your-resume-website.github.io/resume/",
3"page_view_count": 3,
4"last_seen": "2021-11-21 09:55:06 AM",
5"dataSet": [
6 {
7 "IP": "64.233.172.110",
8 "event": "Resume Page View",
9 "page_view_count": 1,
10 "timestamp": [
11 "2021-11-19 09:55:06 AM"
12 ],
13 "country": "United States of America",
14 "city": "Mountain View",
15 "region": "California",
16 "latitude": "37.405992",
17 "longitude": "-122.078515",
18 "isp": "Google LLC",
19 "hostname": "google-proxy-64-233-172-110.google.com",
20 "device": "unknown",
21 "os": "unknown",
22 "browser": "DefaultProperties"
23 }
24]
25
26}
{: lang=“json”}
API Testing
Free API
Reference
- DEPLOYING REST-API BASED FLASK APP ON HEROKU — Part 1 | by Ashiq KS | Medium
- Deploying Fake Back-End Server & DataBase Using JSON-SERVER, GitHub, and Heroku. - DEV Community
- Automate Sending Daily Mails Using Python | by Rohan Krishna Ullas | Level Up Coding
- 3 Ways to Fix the CORS Error — and How the Access-Control-Allow-Origin Header Works | by David Katz | Medium