Skip to content

Commit 36fb6f0

Browse files
authored
feat: complete tracking events #3 (#59)
1 parent 5caa208 commit 36fb6f0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+4007
-1646
lines changed

README.md

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
11
# Serverless Website Analytics
22

3+
- [Objectives](#objectives)
4+
- [Getting started](#getting-started)
5+
* [Serverside setup](#serverside-setup)
6+
+ [Certificate Requirements](#certificate-requirements)
7+
* [Client side setup](#client-side-setup)
8+
+ [Standalone Import Script Usage](#standalone-import-script-usage)
9+
+ [SDK Client Usage](#sdk-client-usage)
10+
- [Worst case projected costs](#worst-case-projected-costs)
11+
- [What's in the box](#what-s-in-the-box)
12+
* [Frontend](#frontend)
13+
* [Backend](#backend)
14+
* [Ingestion API](#ingestion-api)
15+
- [Upgrading](#upgrading)
16+
- [Sponsors](#sponsors)
17+
- [Contributing](#contributing)
18+
- [Roadmap](#roadmap)
19+
320
This is a CDK serverless website analytics construct that can be deployed to AWS. This construct creates backend,
421
frontend and the ingestion APIs.
522

@@ -145,10 +162,17 @@ Then include the standalone script in your HTML:
145162
<head> ... </head>
146163
<body>
147164
...
148-
<script src="<YOUR BACKEND ORIGIN>/cdn/client-script.js" site="<THE SITE YOU ARE TRACKING>"></script>
165+
<script src="<YOUR BACKEND ORIGIN>/cdn/client-script.js" site="<THE SITE YOU ARE TRACKING>" attr-tracking="true"></script>
149166
</body>
150167
</html>
151168
```
169+
You need to replace `<YOUR BACKEND ORIGIN>` with the origin of your deployed backend. Available attributes on the script
170+
are:
171+
- `site` - Required. The name of your site, this must correspond with the name you specified when deploying the
172+
`serverless-website-analytics` backend.
173+
- `attr-tracking` - Optional. If `"true"`, the script will track all `button` and `a` HTML elements that have the
174+
`swa-event` attribute on them. Example: `<button swa-event="download">Download</button>`, it is also possible to
175+
specify a category(`swa-event-category`) and the data(`swa-event-data`).
152176

153177
See the [client-side library](https://www.npmjs.com/package/serverless-website-analytics-client) for more options.
154178

@@ -166,12 +190,12 @@ Irrelevant of the framework, you have to do the following to track page views on
166190
site's `Origin` is whitelisted in the backend config.
167191
2. On each route change call the `analyticsPageChange` function with the name of the new page.
168192

169-
The following sections show you how to do it in Vue, see [the readme of the client](https://github.com/rehanvdm/serverless-website-analytics-client-development#usage)
193+
The following sections show you how to do it in Vue, see [the readme of the client](https://github.com/rehanvdm/serverless-website-analytics-client#usage)
170194
for React and Svelte usage, but again the SDK allows for usage in **ANY framework**.
171195

172196
#### Vue
173197

174-
[_./serverless-website-analytics-client/usage/vue/vue-project/src/main.ts_](https://github.com/rehanvdm/serverless-website-analytics-client-development/blob/master/usage/vue/vue-project/src/main.ts)
198+
[_./serverless-website-analytics-client/usage/vue/vue-project/src/main.ts_](https://github.com/rehanvdm/serverless-website-analytics-client/blob/master/usage/vue/vue-project/src/main.ts)
175199
```typescript
176200
...
177201
import * as swaClient from 'serverless-website-analytics-client';
@@ -190,9 +214,22 @@ router.afterEach((event) => {
190214
});
191215

192216
app.mount('#app');
217+
218+
export { swaClient };
219+
```
220+
221+
Event Tracking:
222+
223+
[_./usage/vue/vue-project/src/App.vue_](https://github.com/rehanvdm/serverless-website-analytics-client/blob/master/usage/vue/vue-project/src/App.vue)
224+
```typescript
225+
import {swaClient} from "./main";
226+
...
227+
// (event: string, data?: number, category?: string)
228+
swaClient.v1.analyticsTrack("subscribe", 1, "clicks")
193229
```
194230

195-
..Any other framework
231+
The `serverless-website-analytics` **any framework**. To demonstrate this, find examples for Svelte and React in the
232+
[_client project_](https://github.com/rehanvdm/serverless-website-analytics-client/tree/master/usage)
196233

197234
## Worst case projected costs
198235

@@ -259,9 +296,9 @@ the date will be stored after about 1min ± 1min.
259296
Location data is obtained by looking the IP address up in the [MaxMind GeoLite2](https://dev.maxmind.com/geoip/geoip2/geolite2/) database.
260297
We don't store any Personally Identifiable Information (PII) in the logs or S3, the IP address is never stored.
261298

262-
# Upgrading
299+
## Upgrading
263300

264-
## From V0 to V1
301+
### From V0 to V1
265302

266303
This upgrade brings two breaking changes:
267304
1. Daily partitions, querying is not backwards compatible. The data is still there, it is just in
@@ -273,15 +310,15 @@ Install the new version:
273310
npm install npm install serverless-website-analytics@~1
274311
```
275312

276-
### Data "loss" because of S3 path changes to accommodate daily partitions
313+
#### Data "loss" because of S3 path changes to accommodate daily partitions
277314

278315
Data will seem lost after upgrading to V1 because of the S3 path changes to accommodate daily partitions. The data is
279316
still there, it is just in a different location. The backend won't know about the old location and only use the new location
280317
so your dashboard will look empty after migrating. You can possibly run an Athena CTAS query to migrate the data to the new
281318
location, but it would need to be crafted carefully. If this is really important for you, please create a ticket and I can
282319
see if I can help.
283320

284-
### Recreate the old Route53 records (only if you specified the `domains' property)
321+
#### Recreate the old Route53 records (only if you specified the `domains' property)
285322

286323
This is because we needed to change the CDK construct IDs of the Route53 records and Route53 can not create duplicate
287324
record names. See issue: https://github.com/rehanvdm/serverless-website-analytics/issues/26

docs/API.md

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
11
# Serverless Website Analytics
22

3+
- [Objectives](#objectives)
4+
- [Getting started](#getting-started)
5+
* [Serverside setup](#serverside-setup)
6+
+ [Certificate Requirements](#certificate-requirements)
7+
* [Client side setup](#client-side-setup)
8+
+ [Standalone Import Script Usage](#standalone-import-script-usage)
9+
+ [SDK Client Usage](#sdk-client-usage)
10+
- [Worst case projected costs](#worst-case-projected-costs)
11+
- [What's in the box](#what-s-in-the-box)
12+
* [Frontend](#frontend)
13+
* [Backend](#backend)
14+
* [Ingestion API](#ingestion-api)
15+
- [Upgrading](#upgrading)
16+
- [Sponsors](#sponsors)
17+
- [Contributing](#contributing)
18+
- [Roadmap](#roadmap)
19+
320
This is a CDK serverless website analytics construct that can be deployed to AWS. This construct creates backend,
421
frontend and the ingestion APIs.
522

@@ -145,10 +162,17 @@ Then include the standalone script in your HTML:
145162
<head> ... </head>
146163
<body>
147164
...
148-
<script src="<YOUR BACKEND ORIGIN>/cdn/client-script.js" site="<THE SITE YOU ARE TRACKING>"></script>
165+
<script src="<YOUR BACKEND ORIGIN>/cdn/client-script.js" site="<THE SITE YOU ARE TRACKING>" attr-tracking="true"></script>
149166
</body>
150167
</html>
151168
```
169+
You need to replace `<YOUR BACKEND ORIGIN>` with the origin of your deployed backend. Available attributes on the script
170+
are:
171+
- `site` - Required. The name of your site, this must correspond with the name you specified when deploying the
172+
`serverless-website-analytics` backend.
173+
- `attr-tracking` - Optional. If `"true"`, the script will track all `button` and `a` HTML elements that have the
174+
`swa-event` attribute on them. Example: `<button swa-event="download">Download</button>`, it is also possible to
175+
specify a category(`swa-event-category`) and the data(`swa-event-data`).
152176

153177
See the [client-side library](https://www.npmjs.com/package/serverless-website-analytics-client) for more options.
154178

@@ -166,12 +190,12 @@ Irrelevant of the framework, you have to do the following to track page views on
166190
site's `Origin` is whitelisted in the backend config.
167191
2. On each route change call the `analyticsPageChange` function with the name of the new page.
168192

169-
The following sections show you how to do it in Vue, see [the readme of the client](https://github.com/rehanvdm/serverless-website-analytics-client-development#usage)
193+
The following sections show you how to do it in Vue, see [the readme of the client](https://github.com/rehanvdm/serverless-website-analytics-client#usage)
170194
for React and Svelte usage, but again the SDK allows for usage in **ANY framework**.
171195

172196
#### Vue
173197

174-
[_./serverless-website-analytics-client/usage/vue/vue-project/src/main.ts_](https://github.com/rehanvdm/serverless-website-analytics-client-development/blob/master/usage/vue/vue-project/src/main.ts)
198+
[_./serverless-website-analytics-client/usage/vue/vue-project/src/main.ts_](https://github.com/rehanvdm/serverless-website-analytics-client/blob/master/usage/vue/vue-project/src/main.ts)
175199
```typescript
176200
...
177201
import * as swaClient from 'serverless-website-analytics-client';
@@ -190,9 +214,22 @@ router.afterEach((event) => {
190214
});
191215

192216
app.mount('#app');
217+
218+
export { swaClient };
219+
```
220+
221+
Event Tracking:
222+
223+
[_./usage/vue/vue-project/src/App.vue_](https://github.com/rehanvdm/serverless-website-analytics-client/blob/master/usage/vue/vue-project/src/App.vue)
224+
```typescript
225+
import {swaClient} from "./main";
226+
...
227+
// (event: string, data?: number, category?: string)
228+
swaClient.v1.analyticsTrack("subscribe", 1, "clicks")
193229
```
194230

195-
..Any other framework
231+
The `serverless-website-analytics` **any framework**. To demonstrate this, find examples for Svelte and React in the
232+
[_client project_](https://github.com/rehanvdm/serverless-website-analytics-client/tree/master/usage)
196233

197234
## Worst case projected costs
198235

@@ -259,9 +296,9 @@ the date will be stored after about 1min ± 1min.
259296
Location data is obtained by looking the IP address up in the [MaxMind GeoLite2](https://dev.maxmind.com/geoip/geoip2/geolite2/) database.
260297
We don't store any Personally Identifiable Information (PII) in the logs or S3, the IP address is never stored.
261298

262-
# Upgrading
299+
## Upgrading
263300

264-
## From V0 to V1
301+
### From V0 to V1
265302

266303
This upgrade brings two breaking changes:
267304
1. Daily partitions, querying is not backwards compatible. The data is still there, it is just in
@@ -273,15 +310,15 @@ Install the new version:
273310
npm install npm install serverless-website-analytics@~1
274311
```
275312

276-
### Data "loss" because of S3 path changes to accommodate daily partitions
313+
#### Data "loss" because of S3 path changes to accommodate daily partitions
277314

278315
Data will seem lost after upgrading to V1 because of the S3 path changes to accommodate daily partitions. The data is
279316
still there, it is just in a different location. The backend won't know about the old location and only use the new location
280317
so your dashboard will look empty after migrating. You can possibly run an Athena CTAS query to migrate the data to the new
281318
location, but it would need to be crafted carefully. If this is really important for you, please create a ticket and I can
282319
see if I can help.
283320

284-
### Recreate the old Route53 records (only if you specified the `domains' property)
321+
#### Recreate the old Route53 records (only if you specified the `domains' property)
285322

286323
This is because we needed to change the CDK construct IDs of the Route53 records and Route53 can not create duplicate
287324
record names. See issue: https://github.com/rehanvdm/serverless-website-analytics/issues/26

docs/CONTRIBUTING.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,3 +195,9 @@ enables us to use `@src/backend/api/server.ts` instead of those nasty relative p
195195

196196
There is no separate TS config for the frontend, this is because the backend and frontend share the same TS paths and
197197
there were some strange results with tRPC not typing correctly.
198+
199+
### null vs undefined
200+
201+
The API will always return `null` to indicate that a value is not set. A value of `undefined` will indicate that the
202+
value is not set and that the key is not present in the object. This is important for the PageFilter and EventFilter.
203+
A value of `null` will search where that column has no value and `undefined` will ignore that column from the search.

src/backend.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,8 @@ export function backend(
284284
resources: [
285285
backendAnalyticsProps.analyticsBucket.arnForObjects('page_views/site=*/page_opened_at_date=*/*'),
286286
backendAnalyticsProps.analyticsBucket.arnForObjects('page_views/site=*/page_opened_at_date=*/*'),
287+
backendAnalyticsProps.analyticsBucket.arnForObjects('events/site=*/tracked_at_date=*/*'),
288+
backendAnalyticsProps.analyticsBucket.arnForObjects('events/site=*/tracked_at_date=*/*'),
287289
],
288290
})
289291
);

src/backendAnalytics.ts

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -302,12 +302,8 @@ export function backendAnalytics(scope: Construct, name: (name: string) => strin
302302
type: 'string',
303303
},
304304
{
305-
name: 'year',
306-
type: 'int',
307-
},
308-
{
309-
name: 'month',
310-
type: 'int',
305+
name: 'tracked_at_date',
306+
type: 'string',
311307
},
312308
],
313309
storageDescriptor: {
@@ -319,7 +315,7 @@ export function backendAnalytics(scope: Construct, name: (name: string) => strin
319315
},
320316
parameters: {
321317
'storage.location.template':
322-
's3://' + analyticsBucket.bucketName + '/events/site=${site}/year=${year}/month=${month}',
318+
's3://' + analyticsBucket.bucketName + '/events/site=${site}/tracked_at_date=${tracked_at_date}',
323319
},
324320
columns: [
325321
{
@@ -330,6 +326,14 @@ export function backendAnalytics(scope: Construct, name: (name: string) => strin
330326
name: 'session_id',
331327
type: 'string',
332328
},
329+
{
330+
name: 'event_id',
331+
type: 'string',
332+
},
333+
{
334+
name: 'category',
335+
type: 'string',
336+
},
333337
{
334338
name: 'event',
335339
type: 'string',
@@ -392,6 +396,16 @@ export function backendAnalytics(scope: Construct, name: (name: string) => strin
392396
},
393397
],
394398
},
399+
parameters: {
400+
'projection.enabled': 'true',
401+
'projection.tracked_at_date.type': 'date',
402+
'projection.tracked_at_date.format': 'yyyy-MM-dd',
403+
'projection.tracked_at_date.interval': '1',
404+
'projection.tracked_at_date.interval.unit': 'DAYS',
405+
'projection.tracked_at_date.range': '2023-01-01,NOW',
406+
'projection.site.type': 'enum',
407+
'projection.site.values': props.sites.join(','),
408+
},
395409
},
396410
});
397411
glueTableEvents.addDependency(glueDb);
@@ -406,8 +420,7 @@ export function backendAnalytics(scope: Construct, name: (name: string) => strin
406420
},
407421
bucketArn: analyticsBucket.bucketArn,
408422
roleArn: firehoseDeliveryRole.roleArn,
409-
prefix:
410-
'events/site=!{partitionKeyFromQuery:site}/year=!{partitionKeyFromQuery:year}/month=!{partitionKeyFromQuery:month}/',
423+
prefix: 'events/site=!{partitionKeyFromQuery:site}/tracked_at_date=!{partitionKeyFromQuery:tracked_at_date}/',
411424
errorOutputPrefix: 'error/!{firehose:error-output-type}/',
412425
bufferingHints: {
413426
intervalInSeconds: props.firehoseBufferInterval ?? defaultFirehoseBufferInterval,
@@ -426,7 +439,7 @@ export function backendAnalytics(scope: Construct, name: (name: string) => strin
426439
parameters: [
427440
{
428441
parameterName: 'MetadataExtractionQuery',
429-
parameterValue: '{site: .site,' + ' year: .year,' + ' month: .month}',
442+
parameterValue: '{site: .site, tracked_at_date: .tracked_at_date}',
430443
},
431444
//Required as property it seems
432445
{

0 commit comments

Comments
 (0)