Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add worker which allows a user's landing UTM to be carried forward in a cookie through their site journey #3

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ Worker for handling common operations when using Cloudflare as a frontend cache:
* Skip cache when private cookies are present
* Strip querystring keys that don't need to hit the server

## common-caching-utm-cookie.js
Similar to the above worker, with the following extra feature to allow for a user's landing UTM to be carried forward
through their site journey without impacting cacheability:

* Checks for UTM querystring keys (which will be stripped before passing on to the server)
* If any are present, append a cookie containing the querystring to the response (unless the cookie already exists)

## holding-page.js
Worker for putting up a holding page from an external source.

Expand Down
94 changes: 94 additions & 0 deletions common-caching-utm-cookie.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// NOTE: A 'Cache Level' page rule set to 'Cache Everything' will
// prevent private cookie cache skipping from working, as it is
// applied after this worker runs.

const PRIVATE_COOKIES = ['wagtailcsrftoken', 'sessionid'];
const UTM_COOKIE = 'initialutm';

const STRIP_QUERYSTRING_KEYS = [
'utm_source',
'utm_campaign',
'utm_medium',
'utm_term',
'utm_content',
];

addEventListener('fetch', (event) => {
event.respondWith(main(event));
});

async function main(event) {
const cache = caches.default;
let request = event.request;

// get value for setting a new UTM cookie
newUtmCookieValue = getUtmCookieValue(request);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
newUtmCookieValue = getUtmCookieValue(request);
const newUtmCookieValue = getUtmCookieValue(request);


request = stripIgnoredQuerystring(request);

if (hasPrivateCookie(request)) {
return fetch(request);
}

let response = await cache.match(request);
if (!response) {
response = await fetch(request);
event.waitUntil(cache.put(request, response.clone()));
}

// set UTM cookie if required
if (newUtmCookieValue) {
const newResponse = new Response(response.body, response);
newResponse.headers.append(
'Set-Cookie',
`${UTM_COOKIE}=${newUtmCookieValue}; path=/`,
);
return newResponse;
}

return response;
}

function hasPrivateCookie(request) {
// Check if the request includes any of the specified 'private' cookies
const cookieString = request.headers.get('Cookie');
return (
cookieString !== null &&
PRIVATE_COOKIES.some((item) => {
return cookieString.includes(item);
})
);
}

function hasUtmCookie(request) {
// Check if the request already has the UTM cookie set
const cookieString = request.headers.get('Cookie');
return cookieString !== null && cookieString.includes(UTM_COOKIE);
}

function getUtmCookieValue(request) {
// If there's no existing UTM cookie, and the querystring contains a UTM key,
// return the querystring to save into a new UTM cookie
if (!hasUtmCookie(request)) {
const url = new URL(request.url);
if (STRIP_QUERYSTRING_KEYS.some((key) => url.searchParams.get(key))) {
return url.search;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't you return only the utm searchParams instead of the whole url.search? I have no idea how this cookie will be used so it might not matter too much.

}
}
return null;
}

function stripIgnoredQuerystring(request) {
// Return a request with specified querystring keys stripped out
const url = new URL(request.url);
const stripKeys = STRIP_QUERYSTRING_KEYS.filter((v) =>
url.searchParams.has(v),
);

if (stripKeys.length) {
stripKeys.forEach((v) => url.searchParams.delete(v));

return new Request(url, request);
}
return request;
}