All Articles

Using Cookies, Puppeteer & NodeJS To Mirror A Chrome Profile on macOS


Puppeteer!

Rationale

Mirroring the state of one of your existing Chrome Profiles using Puppeteer can prove extremely useful for local projects and testing.

If you can trust that your browser will be in a predictable state that you’d like to use (e.g. logged in to a specific website) you can utilise existing cookies - rather than simulating a login process - to reduce the amount of code you need to write.

The following process requires NodeJS, NPM and Puppeteer. You’ll need to install all of those items in that order before going any further. Follow the instructions on their respective websites to get them installed on your system


Accessing The Cookies

Cookies are encrypted, and for good reason: they contain sensitive information. On macOS, they’re ‘signed’ with a Chrome encryption key into an SQLite database which is managed by the OS keychain. In order to decrypt the signed cookies, your Node application must have access to the Chrome key inside the keychain. This requires authorisation by the logged in macOS user.

Node-Auth

Thankfully, there is an NPM module chrome-cookies-secure that is designed to handle this process. Copy and run the following code in your terminal (in the root of your project directory) to add chrome-cookies-secure to your project:

npm i --save chrome-cookies-secure

If you’re not prompted to authorise Node access to your keychain on the module install, don’t worry. You will be prompted when you run the basic NodeJS app described a little further down.


The Chrome Profile Path

Next you’ll need to identify the path to the Chrome Profile you want to mirror.

Open Chrome and select your browser profile (there’s an icon you can click to switch between profiles, highlighted by a blue box in the image below). Once you’re satisfied you’re on the correct account, navigate to chrome://version.

You’ll find the path to the profile of the current session under Profile Path.

Chrome-Profile

For reference, you can view all of your Chrome Profiles at Users/yourName/Library/Application Support/Google/Chrome.


Putting It Together - Iteration 1

Now you have the basic information you need to retrieve your cookies within your Node app.

Now for the code. Let’s take a look at our https://www.google.com cookies.

Create a new folder called chrome-cookies-test and run npm init -y followed by npm i chrome-cookies-secure.

Create a file inside that directory called index.js, and paste the following code:

const chrome = require('chrome-cookies-secure');

const url = 'https://www.google.com';

chrome.getCookies(url, 'puppeteer', function(err, cookies) {
    if (err) {
        console.log(err, 'error');
        return
    }
    // do stuff here...
    console.log(cookies, 'cookies');
}, 'yourProfile') // e.g. 'Profile 2'

The module does not yet fully support Promises or async/await but I’ve created a PR for a Promise wrapper which is awaiting approval here.

Next, ensuring you’re in the project root directory in your terminal, run node index.js.

You should see the cookies for the given profile and url you have chosen appear right there in the terminal, e.g:

Cookie-Output

In this example, we are looking at Google’s cookies. In the next section you will want to change this to a website where you are currently logged in

If you can see your cookies in the terminal output, you’re ready to load them into Puppeteer.


Putting It Together - Iteration 2

Install puppeteer by running npm i puppeteer, then update your index.js code to the below:

const chrome = require('chrome-cookies-secure');
const puppeteer = require('puppeteer');

const url = 'https://www.YOUR_URL.com';

const getCookies = callback => {
    chrome.getCookies(url, 'puppeteer', function(err, cookies) {
        if (err) {
            console.log(err, 'error');
            return
        }
        console.log(cookies, 'cookies');
        callback(cookies);
    }, 'yourProfile') // e.g. 'Profile 2'
}

getCookies(async cookies => {
    const browser = await puppeteer.launch({
        headless: false
    });
    const page = await browser.newPage();

    await page.setCookie(...cookies);
    await page.goto(url);
    await page.waitFor(1000);
    browser.close()
});

Run node index.js again, and you’ll see Puppeteer open and navigate to your chosen site. Hopefully, providing there are no further security measures such as 2FA, you’ll see that you are logged in.

It’s worth noting there can be a thirty minute delay between new cookies added to your Chrome Profile being reflected on your hard-drive (and thus being accessible in your Node app). This is because Chrome persists cookies to storage once every thirty minutes. So if you have new cookies, give it 30 minutes and check it again.

You’ll also need to fully qualify URLs in order to retrieve all possible cookies for a given site i.e https://www.google.com not https://google.com.

But that’s it.

You should now be able to utilise a login state, site preferences, or whatever else, from one of your Chrome Profiles in Puppeteer.


Problem Solved

If you have any questions you’d like to ask me about this post, feel free to reach me on Twitter or Github.

If you found this post useful and would like to show you’re appreciation, join the Brave movement and send me a tip :)

Alternatively, start investing in crypto via one of my referall links, at Binance or Coinbase.