Search code examples
javascriptcookies

Can I be notified of cookie changes in client side JavaScript?


Can I somehow follow changes to cookies (for my domain) in my client side JavaScript? For example, is there a function that gets called if a cookie gets changed, deleted or added?

In order of preference:

  • standard cross browser
  • cross browser
  • browser specific
  • extension / plugin

Why? Because cookies I depend on in window / tab #1 can get changed in window / tab #2.

I found out that Chrome allows extensions to be notified of cookie changes. But that's my least favorite option.


Solution

  • Method 1: Periodic Polling

    Poll document.cookie

    function listenCookieChange(callback, interval = 1000) {
      let lastCookie = document.cookie;
      setInterval(()=> {
        let cookie = document.cookie;
        if (cookie !== lastCookie) {
          try {
            callback({oldValue: lastCookie, newValue: cookie});
          } finally {
            lastCookie = cookie;
          }
        }
      }, interval);
    }
    

    Usage

    listenCookieChange(({oldValue, newValue})=> {
      console.log(`Cookie changed from "${oldValue}" to "${newValue}"`);
    }, 1000);
    
    document.cookie = 'a=1; Path=/';
    

    Method 2: API Interception

    Intercept document.cookie

    (()=> {
      let lastCookie = document.cookie;
      // rename document.cookie to document._cookie, and redefine document.cookie
      const expando = '_cookie';
      let nativeCookieDesc = Object.getOwnPropertyDescriptor(Document.prototype, 'cookie');
      Object.defineProperty(Document.prototype, expando, nativeCookieDesc);
      Object.defineProperty(Document.prototype, 'cookie', {
        enumerable: true,
        configurable: true,
        get() {
          return this[expando];
        },
        set(value) {
          this[expando] = value;
          // check cookie change
          let cookie = this[expando];
          if (cookie !== lastCookie) {
            try {
              // dispatch cookie-change messages to other same-origin tabs/frames
              let detail = {oldValue: lastCookie, newValue: cookie};
              this.dispatchEvent(new CustomEvent('cookiechange', {
                detail: detail
              }));
              channel.postMessage(detail);
            } finally {
              lastCookie = cookie;
            }
          }
        }
      });
      // listen cookie-change messages from other same-origin tabs/frames
      const channel = new BroadcastChannel('cookie-channel');
      channel.onmessage = (e)=> {
        lastCookie = e.data.newValue;
        document.dispatchEvent(new CustomEvent('cookiechange', {
          detail: e.data
        }));
      };
    })();
    

    Usage

    document.addEventListener('cookiechange', ({detail: {oldValue, newValue}})=> {
      console.log(`Cookie changed from "${oldValue}" to "${newValue}"`);
    });
    
    document.cookie = 'a=1; Path=/';
    

    Notes

    1. not for IE
    2. require BroadcastChannel polyfill for Safari

    Conclusion

    | Metric \ Method  | Periodic Polling            | API Interception |
    | ---------------- | --------------------------- | ---------------- |
    | delay            | depends on polling interval | instant          |
    | scope            | same-domain                 | same-origin      |