Skip to content

Commit 704ae2b

Browse files
authored
Add plausible and Fathom (GitbookIO#79)
* Update package-lock.json after resolving teh conflicts * Added changeset * Update the intercom and GA integrations to use the script injection * Update the changeset to reflect the changes to the GA and intercom integrations * Add the cookie injection scope to the integrations * Update to the new object model for CSPs * Fix google analytics
1 parent e5f1a35 commit 704ae2b

28 files changed

+441
-107
lines changed

.changeset/olive-bulldogs-dress.md

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
'@gitbook/integration-fathom': patch
3+
'@gitbook/integration-plausible': patch
4+
'@gitbook/integration-googleanalytics': patch
5+
'@gitbook/integration-intercom': patch
6+
'@gitbook/cli': patch
7+
'@gitbook/eslint-config': patch
8+
---
9+
10+
Added the Plausible and Fathom integrations.
11+
12+
Also added some logic to load script with the `.raw.js` extension as text in the integrations. This should make sure
13+
that script injection is as seamless to develop as the other parts of teh integration by allowing us to write code
14+
in script file, then loading it as a script during the build process.

integrations/fathom/.eslintrc.json

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": ["@gitbook/eslint-config/integration"]
3+
}

integrations/fathom/assets/icon.png

7.72 KB
Loading
126 KB
Loading
+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: fathom
2+
title: Fathom Analytics
3+
icon: ./assets/icon.png
4+
description: Track your GitBook analytics directly from your Fathom dashboard.
5+
previewImages:
6+
- ./assets/preview.png
7+
externalLinks:
8+
- label: Documentation
9+
url: https://docs.gitbook.com/integrations/fathom
10+
visibility: public
11+
script: ./src/index.ts
12+
scopes:
13+
- space:script:published
14+
contentSecurityPolicy:
15+
script-src: |
16+
usefathom.com;
17+
connect-src: |
18+
usefathom.com;
19+
summary: |
20+
The GitBook Fathom Analytics integration allows you to track traffic in your published spaces from your Fathom dashboard.
21+
22+
Automatic tracking in your documentation:
23+
Each of your connected GitBook spaces will fetch the light-weight Fathom tracking script and inject it in your public content.
24+
categories:
25+
- analytics
26+
configurations:
27+
space:
28+
properties:
29+
site_id:
30+
type: string
31+
title: Site ID
32+
description: Look for this in your Fathom analytics account
33+
required:
34+
- site_id

integrations/fathom/global.d.ts

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
declare module '*.raw.js' {
2+
const content: string;
3+
export default content;
4+
}

integrations/fathom/package.json

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"name": "@gitbook/integration-fathom",
3+
"version": "0.0.0",
4+
"private": true,
5+
"dependencies": {
6+
"@gitbook/api": "*",
7+
"@gitbook/runtime": "*"
8+
},
9+
"devDependencies": {
10+
"@gitbook/cli": "*"
11+
},
12+
"scripts": {
13+
"lint": "eslint ./src/**/*.ts",
14+
"typecheck": "tsc --noEmit",
15+
"publish-integrations": "gitbook publish ."
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
(function (doc, siteID) {
2+
const sibling = doc.getElementsByTagName('script')[0];
3+
const element = doc.createElement('script');
4+
element.defer = true;
5+
element.setAttribute('data-site', siteID);
6+
element.setAttribute('data-spa', 'auto');
7+
element.src = 'https://cdn.usefathom.com/script.js';
8+
sibling.parentNode.insertBefore(element, sibling);
9+
})(document, '<TO_REPLACE>');

integrations/fathom/src/index.ts

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import {
2+
createIntegration,
3+
FetchPublishScriptEventCallback,
4+
RuntimeContext,
5+
RuntimeEnvironment,
6+
} from '@gitbook/runtime';
7+
8+
import script from './fathomScript.raw.js';
9+
10+
type FathomRuntimeContext = RuntimeContext<
11+
RuntimeEnvironment<
12+
{},
13+
{
14+
site_id?: string;
15+
}
16+
>
17+
>;
18+
19+
export const handleFetchEvent: FetchPublishScriptEventCallback = async (
20+
event,
21+
{ environment }: FathomRuntimeContext
22+
) => {
23+
const siteId = environment.spaceInstallation.configuration.site_id;
24+
if (!siteId) {
25+
throw new Error(
26+
`The Fathom site ID is missing from the Space (ID: ${event.installationId}) installation.`
27+
);
28+
}
29+
30+
return new Response(script.replace('<TO_REPLACE>', siteId), {
31+
headers: {
32+
'Content-Type': 'application/javascript',
33+
'Cache-Control': 'max-age=604800',
34+
},
35+
});
36+
};
37+
38+
export default createIntegration<FathomRuntimeContext>({
39+
events: {
40+
fetch_published_script: handleFetchEvent,
41+
},
42+
});

integrations/fathom/tsconfig.json

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "@gitbook/tsconfig/integration.json"
3+
}

integrations/googleanalytics/gitbook-manifest.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ visibility: public
1111
script: ./src/index.ts
1212
scopes:
1313
- space:script:published
14+
- space:cookie:inject
1415
contentSecurityPolicy: |
1516
script-src
1617
https://www.google-analytics.com

integrations/googleanalytics/src/index.ts

+7-32
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import {
55
RuntimeEnvironment,
66
} from '@gitbook/runtime';
77

8+
import script from './script.raw.js';
9+
810
type GARuntimeContext = RuntimeContext<
911
RuntimeEnvironment<
1012
{},
@@ -25,39 +27,12 @@ export const handleFetchEvent: FetchPublishScriptEventCallback = async (
2527
);
2628
}
2729

28-
return new Response(
29-
`
30-
(function(w, d, s, l, i){
31-
w[l] = w[l] || [];
32-
w[l].push({
33-
'gtm.start': new Date().getTime(),
34-
event: 'gtm.js'
30+
return new Response(script.replace('<TO_REPLACE>', trackingId), {
31+
headers: {
32+
'Content-Type': 'application/javascript',
33+
'Cache-Control': 'max-age=604800',
34+
},
3535
});
36-
var f = d.getElementsByTagName(s)[0], j = d.createElement(s), dl = l != 'dataLayer' ? '&l=' + l : '';
37-
j.async = true;
38-
j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
39-
j.onload = function() {
40-
window.dataLayer = window.dataLayer || [];
41-
function gtag(){window.dataLayer.push(arguments);}
42-
gtag('js', new Date());
43-
44-
gtag('config', i, {
45-
send_page_view: false,
46-
anonymize_ip: true,
47-
groups: 'tracking_views',
48-
});
49-
};
50-
f.parentNode.insertBefore(j, f);
51-
52-
})(window, document, 'script', 'dataLayer', 'GTM-${trackingId}');
53-
`,
54-
{
55-
headers: {
56-
'Content-Type': 'application/javascript',
57-
'Cache-Control': 'max-age=604800',
58-
},
59-
}
60-
);
6136
};
6237

6338
export default createIntegration<GARuntimeContext>({
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
const trackingID = '<TO_REPLACE>';
2+
3+
const GANTED_COOKIE = '__gitbook_cookie_granted';
4+
5+
function getCookie(cname) {
6+
const name = `${cname}=`;
7+
const decodedCookie = decodeURIComponent(document.cookie);
8+
const ca = decodedCookie.split(';');
9+
for (let i = 0; i < ca.length; i++) {
10+
let c = ca[i];
11+
while (c.charAt(0) === ' ') {
12+
c = c.substring(1);
13+
}
14+
if (c.indexOf(name) === 0) {
15+
return c.substring(name.length, c.length);
16+
}
17+
}
18+
return '';
19+
}
20+
21+
function triggerView(win) {
22+
win.gtag('event', 'page_view', {
23+
page_path: win.location.pathname,
24+
page_location: win.location.href,
25+
page_title: win.document.title,
26+
send_to: 'tracking_views',
27+
});
28+
}
29+
30+
(function (win, doc, script, layer, id) {
31+
let disableCookies = false;
32+
const cookie = getCookie(GANTED_COOKIE);
33+
if (cookie === 'yes') {
34+
disableCookies = false;
35+
} else if (cookie === 'no') {
36+
disableCookies = true;
37+
}
38+
39+
win[layer] = win[layer] || [];
40+
win.gtag = function () {
41+
// eslint-disable-next-line prefer-rest-params
42+
win[layer].push(arguments);
43+
};
44+
45+
win.gtag('js', new Date());
46+
win.gtag('config', id);
47+
win.gtag('consent', 'default', {
48+
ad_storage: disableCookies ? 'denied' : 'granted',
49+
analytics_storage: disableCookies ? 'denied' : 'granted',
50+
});
51+
const f = doc.getElementsByTagName(script)[0],
52+
j = doc.createElement(script),
53+
dl = layer !== 'dataLayer' ? `&l=${layer}` : '';
54+
j.async = true;
55+
j.src = `https://www.googletagmanager.com/gtag/js?id=${id}${dl}`;
56+
j.onload = function () {
57+
win.gtag('config', id, {
58+
send_page_view: false,
59+
anonymize_ip: true,
60+
groups: 'tracking_views',
61+
});
62+
triggerView(win);
63+
64+
win.history.pushState = new Proxy(win.history.pushState, {
65+
apply: (target, thisArg, argArray) => {
66+
triggerView(win);
67+
return target.apply(thisArg, argArray);
68+
},
69+
});
70+
};
71+
f.parentNode.insertBefore(j, f);
72+
})(window, document, 'script', 'dataLayer', trackingID);

integrations/intercom/gitbook-manifest.yaml

+11-10
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,23 @@ visibility: public
1111
script: ./src/index.ts
1212
scopes:
1313
- space:script:published
14-
contentSecurityPolicy: |
15-
script-src
14+
- space:cookie:inject
15+
contentSecurityPolicy:
16+
script-src: |
1617
https://js.intercomcdn.com
1718
https://widget.intercom.io
1819
https://app.intercom.io;
19-
style-src
20+
style-src: |
2021
'unsafe-inline';
21-
frame-src
22+
frame-src: |
2223
www.intercom-reporting.com;
23-
child-src
24+
child-src: |
2425
www.intercom-reporting.com
2526
intercom-sheets.com
2627
www.youtube.com
2728
player.vimeo.com
2829
fast.wistia.net;
29-
img-src
30+
img-src: |
3031
data:
3132
blob:
3233
static.intercomassets.com
@@ -41,18 +42,18 @@ contentSecurityPolicy: |
4142
*.intercom-attachments-6.com
4243
*.intercom-attachments-7.com
4344
*.intercom-attachments-9.com;
44-
font-src
45+
font-src: |
4546
js.intercomcdn.com
4647
fonts.intercomcdn.com;
47-
connect-src
48+
connect-src: |
4849
*.intercom.io
4950
wss://*.intercom.io
5051
uploads.intercomcdn.com
5152
uploads.intercomusercontent.com;
52-
form-action
53+
form-action: |
5354
api-iam.intercom.io
5455
intercom.help;
55-
media-src
56+
media-src: |
5657
*.intercomcdn.com;
5758
summary: |
5859
The Intercom integration for GitBook allows you to be in contact with your readers through the Intercom chat widget.

0 commit comments

Comments
 (0)