Playing with Your Browser Cookie

Image for post
Image for post
Photo by Food Photographer | Jennifer Pallian on Unsplash

Recently I need to do restructuring the website for a piece of partnership project, and this work is blended with cookie and url manipulation. In this blog, I will explain about the usage of cookie in our project and how we do with it.

So first, how tasty is a cookie? I like choco flavour :) (…joking!).

We know that HTTP is a stateless protocol. But for a commercial website, we need to have session information for various purpose like:

  • Session management: Logins, shopping carts, game scores, or anything else the server should remember;
  • Personalisation: User preferences, themes, and other settings;
  • Tracking: Recording and analysing user behaviour;

That’s where we use the cookie for. A cookie is a small file with the maximum size of 4KB that the web server stores on the client computer. It allows us to track the state of the application. Now, when the visitor arrives at another page on your site, the browser sends the same cookie to the server for retrieval. Once retrieved, your server knows/remembers what was stored earlier.

Well. they are baked at 200 c obviously (…joking again).

In reality, these are done through following steps (between the server and browser):

  • After receiving an HTTP request, a server can send one or more Set-Cookie headers with the response to set a cookie with a unique “session identifier”.
  • The cookie is usually stored by the browser.
  • Then the cookie is sent with requests made to the same server inside a Cookie HTTP header.
  • An expiration date or duration can be specified, after which the cookie is no longer sent. Additional restrictions to a specific domain and path can be set, limiting where the cookie is sent.

Cookies are a plain text data record of 5 variable-length fields :

  • Name=Value (compulsory) − Cookies are set and retrieved in the form of key-value pairs

There are following optional fields:

  • Expires − The date the cookie will expire. If this is blank, the cookie will expire when the visitor quits the browser. This can be max-age or expires field. max-age=max-age-in-seconds (e.g., 60*60*24*365 or 31536000 for a year). expires=date-in-GMTString-format If neither expires nor max-age specified it will expire at the end of session.
  • Domain − The domain name of your site. If not specified, this defaults to the host portion of the current document location.
  • Path − The path to the directory or web page that set the cookie. path=path (e.g., '/', '/mydir') If not specified, defaults to the current path of the current document location.
  • Secure − If this field contains the word “secure”, then the cookie may only be retrieved with a secure server. If this field is blank, no such restriction exists.

Any of the following fields are linked together by a semi-colon separator:

document.cookie = "user=John; path=/; expires=Tue, 19 Jan 2038 03:14:07 GMT"

Since we are in JavaScript world, luckily we can manipulate cookies using the cookie property of the Document object. JavaScript can read, create, modify, and delete the cookies that apply to the current web page.

Reading all the cookies:

document.cookie; // cookie1=value1; cookie2=value2;…

Writing a certain cookie:

A write operation to document.cookie updates only cookies mentioned in it, but doesn’t touch other cookies.

For instance, this call sets a cookie with the name application :

document.cookie = "application=finish"; // update only cookie named 'application'

However to ensure valid information get passed, sincename and value can have any characters, to keep the valid formatting they should be escaped using a built-in encodeURIComponent function:

// special characters (spaces), need encoding
let name = "application";
let value = "half finish"
// encodes the cookie as application=half%finish
document.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value);

Also noted that the value part of the field can be a complicated and nested json object.

There are also ways to get specific cookie, set specific cookie, and delete cookie:

Get cookie
// returns the cookie with the given name,
// or undefined if not found
function getCookie(name) {
// find anything that matches: ; name=<value>.
let matches = document.cookie.match(new RegExp(
"(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"
));
return matches ? decodeURIComponent(matches[1]) : undefined;
}
//Set cookie:
function setCookie(name, value, options = {}) {
options = {
path: '/',
...options
};
if (options.expires instanceof Date) {
options.expires = options.expires.toUTCString();
}
let updatedCookie = encodeURIComponent(name) + "=" + encodeURIComponent(value); for (let optionKey in options) {
updatedCookie += "; " + optionKey;
let optionValue = options[optionKey];
if (optionValue !== true) {
updatedCookie += "=" + optionValue;
}
}
document.cookie = updatedCookie;
}
Delete cookiefunction deleteCookie(name) {
setCookie(name, "", {
'max-age': -1 // or expires date in the past or 0
})
}

But these seems to be tedious to remember. And there are tons of nice libraries our that to help you:

Image for post
Image for post

Personally, I like js-cookie :

You can pass in name-values as object which is very user friendly in JS environment.

For example, to create an expiring cookie, valid to the path of the current page:

Cookies.set('name', 'value', { expires: 7, path: '' })

It’s powerful to use it with lodash together. For example we can merge some cookie fields:

import Cookie from “js-cookie”;
import { merge } from “lodash”;
export function mergeCookieContent(
cookieName: string,
key: string,
value: any
): void {
const existingCookie = Cookie.getJSON(cookieName);
const updatedCookie = merge(existingCookie, {[key]: value});
Cookie.set(cookieName, updatedCookie, { domain: “.abc.com” });
}

Another example to update certain value field from the specific cookie :

import Cookie from "js-cookie";
import { omit } from "lodash";
// Get existing journey info and remove current selection
const userJourney = Cookie.getJSON(“application”);
const updatedUserJourney = omit(userJourney, purchasingPurpose);
Cookie.set(“application”, updatedUserJourney, { domain: “.abc.com” });

So the application field is

{%22details%22:{%22occupationStatus%22:%22EMPLOYED%22}%2C%22purchasingPurpose%22:%22PLAY%22%2C%22dealEnd%22:%22less_than_6_months%22}

After call getJson we have a json representative of the value field (instead of decode it ourselves):

dealEnd: “less_than_6_months”details: {occupationStatus: “EMPLOYED”}purchasingPurpose: “PLAY”

And then we delete the `purchasingPurpose` field before eset the cookie again aka updating it.

You can even mix it with url params:

import cookie from "cookie";
import querystring from "querystring";

export const getReferrerFromCookie: () => string | undefined = () => {
try {
const landingParamsCookie = cookie.parse(document.cookie)["landing-params"];
// we convert landing-params from referrer%3Dabc (raw) to
// referrer=abc
const landingParams = querystring.parse(landingParamsCookie);
// {referrer: "abc"}
return landingParams.referrer as string;
} catch (_) {
return undefined;
}
};

export const setLandingParamsCookie = () => {
// Set landing-params cookie
if (typeof window !== "undefined") {//make sure window object exist
if (window.location.search) {
// set expiry date to 30 minutes from now
const expiryDate = new Date(60 * 1000 * 30 + Date.now()).toUTCString();
const query = encodeURIComponent(
window.location.search.replace(/^\?/, "")
);
document.cookie = `landing-params=${query};domain=.abc.com;expires=${expiryDate}`;
}
}
};

So, that’s pretty much it. Hopefully you can bake your own cookie from now on.

Happy Reading!

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store