How to Download Older Version of Google Chrome

But why?

Why would you want to use the old, insecure, rusty version of Chrome? The typical use case is for automated testing, e.g. using Selenium framework. Tests passed on the old version of Chrome, the browser auto-updated itself, and now the Continues Integration system shows a lot of red.

Google Chrome

Google doesn't provide links to the older versions of Chrome, once the new versions are released, so you need to either have a copy of the installers or browse around looking for legitimate links.

TL;DR

You can get links to the older version of Chrome using Google Update API. Using this method, you can go around 15 versions back (2 years).

Powershell code for Windows 64-bit (change chrome version to number to the desired version).

$ChromeVersion = '115'

$requestId = ([String][Guid]::NewGuid()).ToUpper()
$sessionId = ([String][Guid]::NewGuid()).ToUpper()

$xml = @"
<?xml version="1.0" encoding="UTF-8"?>
<request protocol="3.0" updater="Omaha" updaterversion="1.3.36.111" shell_version="1.3.36.111"
    ismachine="1" sessionid="{$sessionId}"
    installsource="update3web-ondemand" requestid="{$requestId}"
    dedup="cr" domainjoined="0">
    <hw physmemory="4" sse="1" sse2="1" sse3="1" ssse3="1" sse41="1" sse42="1" avx="1" />
    <os platform="win" version="10.0" sp="" arch="x64" />
    <app appid="{8A69D345-D564-463C-AFF1-A69D9E530F96}" version="5.0.375" nextversion=""
        ap="x64-stable-statsdef_0" lang="" brand="GCEB" client="" installage="0">
        <updatecheck targetversionprefix="$ChromeVersion"/>
    </app>
</request>
"@

$webRequest = @{
    Method    = 'Post'
    Uri       = 'https://tools.google.com/service/update2'
    Headers   = @{
        'Content-Type' = 'application/x-www-form-urlencoded'
        'X-Goog-Update-Interactivity' = 'fg'
    }
    Body      = $Xml
}

$result = Invoke-WebRequest @webRequest -UseBasicParsing
$contentXml = [xml]$result.Content
$status = $contentXml.response.app.updatecheck.status
if ($status -eq 'ok') {
    $package = $contentXml.response.app.updatecheck.manifest.packages.package
    $urls = $contentXml.response.app.updatecheck.urls.url | ForEach-Object { $_.codebase + $package.name }
    Write-Output "--- Chrome Windows 64-bit found. Hash=$($package.hash) Hash_sha256=$($package.hash_sha256)). ---"
    Write-Output $urls
}
else {
    Write-Output "Chrome not found (status: $status)"
}

Powershell script to discover links for Mac and Windows 32-bit is here.

How it works

I captured the Chrome conversation with the update server using Fiddler.

The browser asks https://tools.google.com/service/update2 server for the latest version of Chrome.

<?xml version="1.0" encoding="UTF-8"?>
<request protocol="3.0" updater="Omaha" updaterversion="1.3.36.111" shell_version="1.3.36.111"
    ismachine="1" sessionid="{F8EE27C3-8B43-43F7-8D57-1375A97E0C6B}"
    installsource="update3web-ondemand" requestid="{BAC01935-31FB-48AB-AE8A-6267D865194E}"
    dedup="cr" domainjoined="0">
    <hw physmemory="4" sse="1" sse2="1" sse3="1" ssse3="1" sse41="1" sse42="1" avx="1" />
    <os platform="win" version="10.0.22000.1574" sp="" arch="x64" />
    <app appid="{8A69D345-D564-463C-AFF1-A69D9E530F96}" version="97.0.4692.99" nextversion=""
        ap="x64-stable-statsdef_0" lang="" brand="GCEB" client="" installage="0"
        iid="{31FDF25B-CC90-55E2-E8A6-6947A311CC60}">
        <updatecheck />
        <ping active="1" a="-1" r="-1" ad="-1" rd="-1"
            ping_freshness="{5F810510-70A5-4C1E-B5CE-6E5E8E9E7965}" />
    </app>
</request>

There is a lot of noise there, but the main thing is that the client provides the current Chrome version and operating system details.

It uses the Omaha protocol version 3, which is documented here.

The response looks as follows.

<?xml version="1.0" encoding="UTF-8"?>
<response protocol="3.0" server="prod">
    <daystart elapsed_days="5896" elapsed_seconds="16440" />
    <app appid="{8A69D345-D564-463C-AFF1-A69D9E530F96}" cohort="1:gu/i19:"
        cohortname="Stable Installs &amp; Version Pins" status="ok">
        <updatecheck status="ok">
            <urls>
                <url codebase="http://edgedl.me.gvt1.com/edgedl/release2/chrome/acul64cchfvvq4is5vc4icaz2yma_110.0.5481.104/" />
                <url codebase="https://edgedl.me.gvt1.com/edgedl/release2/chrome/acul64cchfvvq4is5vc4icaz2yma_110.0.5481.104/" />
                <url codebase="http://dl.google.com/release2/chrome/acul64cchfvvq4is5vc4icaz2yma_110.0.5481.104/" />
                <url codebase="https://dl.google.com/release2/chrome/acul64cchfvvq4is5vc4icaz2yma_110.0.5481.104/" />
                <url codebase="http://www.google.com/dl/release2/chrome/acul64cchfvvq4is5vc4icaz2yma_110.0.5481.104/" />
                <url codebase="https://www.google.com/dl/release2/chrome/acul64cchfvvq4is5vc4icaz2yma_110.0.5481.104/" />
            </urls>
            <manifest version="110.0.5481.104">
                <actions>
                    <action arguments="--verbose-logging --do-not-launch-chrome --channel=stable"
                        event="update" run="110.0.5481.104_chrome_installer.exe" />
                    <action Version="110.0.5481.104" event="postinstall"
                        onsuccess="exitsilentlyonlaunchcmd" />
                </actions>
                <packages>
                    <package fp="1.0533b4e730c7b5d0373f231cc4531441424c3c8222a2cfc595d6f0e50af52847"
                        hash="WFqQXdHYS/ePdc2XBLqxvVGDyIQ="
                        hash_sha256="0533b4e730c7b5d0373f231cc4531441424c3c8222a2cfc595d6f0e50af52847"
                        name="110.0.5481.104_chrome_installer.exe" required="true" size="93741608" />
                </packages>
            </manifest>
        </updatecheck>
        <ping status="ok" />
    </app>
</response>

Again, lot of noise, but if you combine any url codebase:

<url codebase="https://dl.google.com/release2/chrome/acul64cchfvvq4is5vc4icaz2yma_110.0.5481.104/"/>

with package name:

<package name="110.0.5481.104_chrome_installer.exe" />

You will get a valid download url:

https://dl.google.com/release2/chrome/acul64cchfvvq4is5vc4icaz2yma_110.0.5481.104/110.0.5481.104_chrome_installer.exe

The missing part of the puzzle is how to download versions older than the latest.

Looking at the Update Protocol I've noticed that the updatecheck parameter has optional targetversionprefix attribute. So, you can specify '97.0', and the update server will look for links to versions of Chrome starting with 97.0.

Also, because the update server doesn't suggests downgrades by default, I am sending "5.0.375" as a current version of Chrome, which is from the age of dinosaurs.

The difference between a captured request and the one which asks for an older version is the following:

<request>
    <app version="5.0.375">
        <updatecheck targetversionprefix="95.0"/>
    </app>
</request>

Other approaches

Check Stack Overflow Discussion for alternative solutions.

Helpful links