Skip to content

Commit

Permalink
adds ga4 plugin leveraged from how the fresh site does it
Browse files Browse the repository at this point in the history
  • Loading branch information
revgum committed Sep 12, 2023
1 parent c452c57 commit 841839e
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 3 deletions.
1 change: 1 addition & 0 deletions deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"imports": {
"@/": "./",
"$fresh/": "https://deno.land/x/[email protected]/",
"$ga4": "https://raw.githubusercontent.com/denoland/ga4/main/mod.ts",
"$gfm": "https://deno.land/x/[email protected]/mod.ts",
"preact": "https://esm.sh/[email protected]",
"preact/": "https://esm.sh/[email protected]/",
Expand Down
8 changes: 5 additions & 3 deletions fresh.config.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
// Copyright 2023 the Deno authors. All rights reserved. MIT license.
import twindPlugin from "$fresh/plugins/twindv1.ts";
import twindConfig from "./twind.config.ts";
import { FreshOptions } from "$fresh/server.ts";
import errorHandling from "./plugins/error_handling.ts";
import ga4 from "./plugins/ga4.ts";
import kvOAuthPlugin from "./plugins/kv_oauth.ts";
import protectedRoutes from "./plugins/protected_routes.ts";
import errorHandling from "./plugins/error_handling.ts";
import { FreshOptions } from "$fresh/server.ts";
import twindConfig from "./twind.config.ts";

export default {
plugins: [
ga4,
kvOAuthPlugin,
protectedRoutes,
twindPlugin(twindConfig),
Expand Down
117 changes: 117 additions & 0 deletions plugins/ga4.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Copyright 2023 the Deno authors. All rights reserved. MIT license.
import type { MiddlewareHandlerContext, Plugin } from "$fresh/server.ts";
import type { Event } from "$ga4";
import { GA4Report, isDocument, isServerError } from "$ga4";
import type { State } from "@/middleware/session.ts";

let showedMissingEnvWarning = false;

function ga4(
request: Request,
conn: MiddlewareHandlerContext,
response: Response,
_start: number,
error?: unknown,
) {
const GA4_MEASUREMENT_ID = Deno.env.get("GA4_MEASUREMENT_ID");

if (GA4_MEASUREMENT_ID === undefined) {
if (!showedMissingEnvWarning) {
showedMissingEnvWarning = true;
console.warn(
"GA4_MEASUREMENT_ID environment variable not set. Google Analytics reporting disabled.",
);
}
return;
}
Promise.resolve().then(async () => {
// We're tracking page views and file downloads. These are the only two
// HTTP methods that _might_ be used.
if (!/^(GET|POST)$/.test(request.method)) {
return;
}

// If the visitor is using a web browser, only create events when we serve
// a top level documents or download; skip assets like css, images, fonts.
if (!isDocument(request, response) && error == null) {
return;
}

let event: Event | null = null;
const contentType = response.headers.get("content-type");
if (/text\/html/.test(contentType!)) {
event = { name: "page_view", params: {} }; // Probably an old browser.
}

if (event == null && error == null) {
return;
}

// If an exception was thrown, build a separate event to report it.
let exceptionEvent;
if (error != null) {
exceptionEvent = {
name: "exception",
params: {
description: String(error),
fatal: isServerError(response),
},
};
} else {
exceptionEvent = undefined;
}

// Create basic report.
const measurementId = GA4_MEASUREMENT_ID;
// @ts-ignore GA4Report doesn't even use the localAddress parameter
const report = new GA4Report({ measurementId, request, response, conn });

// Override the default (page_view) event.
report.event = event;

// Add the exception event, if any.
if (exceptionEvent != null) {
report.events.push(exceptionEvent);
}

await report.send();
}).catch((err) => {
console.error(`Internal error: ${err}`);
});
}

export default {
name: "ga4",
middlewares: [
{
path: "/",
middleware: {
async handler(req, ctx) {
let err;
let res: Response;
const start = performance.now();
try {
const resp = await ctx.next();
const headers = new Headers(resp.headers);
res = new Response(resp.body, { status: resp.status, headers });
return res;
} catch (e) {
res = new Response("Internal Server Error", {
status: 500,
});
err = e;
throw e;
} finally {
ga4(
req,
ctx as MiddlewareHandlerContext,
res!,
start,
err,
);
}
},
},
},
],
} as Plugin<State>;

0 comments on commit 841839e

Please sign in to comment.