Chart of answered CR posts percentages over time - Part 2
An error and a logic problem.
The code would fail if you ran it as a module or in strict mode due to undefined variable. There is also a problem when parsing the HTML, if there is missing data the timestamps and the percentages will go out of sync because you fail to increase i.
Async functions handle errors by assigning them to the returned promise catch callback. You have wrapped a try catch around code that may throw unrelated development error which you would see as &quot;Error loading data&quot; and not differentiate a legit error from source/logic error.
It is unclear what you intend to happen when fetched data is bad (eg 404 page) asd this will not throw error and you ignore such errors without giving any feedback.
A clearer separation of roles with fetch and parsing as functions rather than the single async function.
Data is also all over the place with the graph settings declared at the top and then more in the function that creates the graph.
General points

You use an undeclared variable contentElement in getGraphData

Why the if (matches.length) { Will that ever happen??? And if it does doesn't that mean that i as index to timeStamps no longer matches the the for loop position?

window is the default object and not needed for direct references. If you are defining globals, clearly define them in the global scope. If they are external use comments to indicate that they external globals.

Why assign to a variable that is never used? window.myLine = new Chart(

Keep it DRY. Axis object could be a function, also several other parts can be reduced using functions.

Reduce number of lines of source code by avoiding single use variable declarations.

Avoid using innerHTML when possible as it is much slower than textContent.

Use direct element id referencing when you are in control of content.

Only wrap the relevant code in try catch. ECMAScript 2018 lets you drop the error object after the catch token. Better yet separate the async part of the function and use promise catch function.

Use the shortest form when possible. Eg you used datasets: [Object.assign(dataset, {data})] that can be datasets: [{...dataset, data}]

Why the if (contents.length === timestamps.length) and no warning if the data is bad?.

Double/same line open [{, ({, or [[... etc should be followed by single indent and matching double close. See rewrite.

Redundant repeated X axis label content &quot; 12:00 AM&quot; can be removed

Graph heading and page heading are different. Maybe assign the graph heading from the page heading??


Possible rewrite
This rewrite reduces the number of lines and encapsulates most of the requirements within a single function reducing the global namespace pollution.
Data vetting was a little unclear so just added that to the graphing function to show a warning if no data found.


"use strict";
// uses chartColors defined in ???.js

document.addEventListener("DOMContentLoaded", displayAnswerRate);

function displayAnswerRate() {
    const CORS_PROXY = "https://cors-escape.herokuapp.com/"; 
    const url = "https://chat.stackexchange.com/search?q=%22RELOAD!+There+are%22&amp;user=125580&amp;room=8595&amp;pagesize=150";
       
    const showError = message =&gt; {
        errorEl.style.display = "block";
        errorEl.textContent = message;
    }
    getDataURL(url)
        .then(parseDataAndChart)
        .catch(() =&gt; {
            loading.style.display = "none";
            showError("Error loading data");
        });

    async function getDataURL(url) { return (await fetch(CORS_PROXY + url)).text() }    

    function parseDataAndChart(markup){        
        const elsByClass = cName =&gt; [...html.querySelectorAll("." + cName)].reverse();
        const html = document.createElement('div');
        html.innerHTML = markup;
        drawChart(
            elsByClass("content").map(el =&gt; el.textContent.split("(")[1].split("%")[0]),
            elsByClass("timestamp").map(el =&gt; el.textContent.replace(" 12:00 AM",""))
        );
        loading.style.display = "none";
    }

    function drawChart(data, labels) {
        const axis = name =&gt; [{display: true, scaleLabel: {display: true, labelString: name}}];      
        if (data.length &gt; 0) {
            Chart.defaults.global.legend.display = false;
            new Chart(canvas.getContext('2d'), {
                type: 'line',
                data: {
                    labels,
                    datasets: [{
                        label: 'Answered Percentage',
                        backgroundColor: chartColors.red,
                        borderColor: chartColors.red,
                        data,
                        fill: false
                    }]
                },
                options: {
                    title: {display: true, text: heading.textContent},
                    scales: { xAxes: axis("Date"), yAxes: axis("Percentage") }
                }
            });
        } else {
            showError("No data found???");
        }
    }    
}
body {
  font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
}
h2 {
  text-align : center;
}
#errorEl { 
  display : none;
  color: red;
}
&lt;script src="//www.chartjs.org/dist/2.7.2/Chart.bundle.js"&gt;&lt;/script&gt;
&lt;script src="//www.chartjs.org/samples/latest/utils.js"&gt;&lt;/script&gt;

&lt;div style="width:75%;"&gt;
  &lt;h2 id="heading"&gt;Answered percentage in recent months&lt;/h2&gt;
  &lt;div id="errorEl"&gt;&lt;/div&gt;
  &lt;canvas id="canvas"&gt;&lt;/canvas&gt;
  
  &lt;img src="https://loading.io/spinners/bars/index.progress-bar-facebook-loader.gif" id="loading" /&gt;
&lt;/div&gt;