Visual Reaction Time

It is generally between 200 and 250 ms. This corresponds to the time it takes for a person to react to a visual signal, such as a light turning on.
A load time of 200 ms is similar to or less than the reaction time of a person to a visual stimulus.

This means that a web page displayed in 200 ms seems almost instantaneous to the user, because their brain has not yet begun to perceive a significant delay.
Creating a Chrome extension to measure the TTFB of a website.
Zip download
https://nicolas-dorriere.fr/assets/files/ttfb-extension.zip
background.js
chrome.runtime.onInstalled.addListener(() => {
chrome.action.setBadgeBackgroundColor({ color: "#000000" }); // Set default badge background
});
// Listen for tab updates
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if (changeInfo.status === 'complete' &&
tab.url &&
tab.url.startsWith('http') &&
!tab.url.includes('chrome-error')) {
try {
injectScript(tabId);
} catch (error) {
console.log('Failed to inject script:', error);
// Optionally clear the badge for error pages
chrome.action.setBadgeText({ text: '', tabId: tabId });
}
}
});
// Function to inject the TTFB measurement script into the tab
async function injectScript(tabId) {
try {
await chrome.scripting.executeScript({
target: { tabId: tabId },
func: getTTFB,
});
} catch (error) {
console.log('Injection error:', error);
// Clear badge if injection fails
chrome.action.setBadgeText({ text: '', tabId: tabId });
}
}
// Function to measure TTFB
function getTTFB() {
const performanceEntries = performance.getEntriesByType("navigation");
if (performanceEntries.length > 0) {
const ttfb = performanceEntries[0].responseStart - performanceEntries[0].requestStart;
chrome.runtime.sendMessage({ ttfb: Math.round(ttfb) });
}
}
// Listen for messages with TTFB and update badge
chrome.runtime.onMessage.addListener((message, sender) => {
if (message.ttfb) {
const ttfbValue = message.ttfb.toString();
// Update the badge text with the TTFB value
chrome.action.setBadgeText({ text: ttfbValue, tabId: sender.tab.id });
// Change badge background color based on TTFB thresholds
let badgeColor;
if (message.ttfb < 50) {
badgeColor = "#00FF00"; // Green for < 50ms
} else if (message.ttfb > 200) {
badgeColor = "#FF0000"; // Red for > 200ms
} else {
badgeColor = "#FFFF00"; // Yellow for 50ms - 200ms
}
chrome.action.setBadgeBackgroundColor({ color: badgeColor, tabId: sender.tab.id });
// Set white text on red background
if (badgeColor === "#FF0000") {
chrome.action.setBadgeTextColor({ color: "#FFFFFF", tabId: sender.tab.id });
}
}
});
manifest.json
{
"manifest_version": 3,
"name": "TTFB Display",
"description": "Displays the Time to First Byte (TTFB) of the current server.",
"version": "1.0",
"permissions": ["activeTab", "scripting", "tabs"],
"host_permissions": ["http://*/*", "https://*/*"],
"background": {
"service_worker": "background.js"
},
"icons": {
"16": "icon.png",
"48": "icon.png",
"128": "icon.png"
},
"action": {
"default_icon": {
"16": "icon.png",
"48": "icon.png",
"128": "icon.png"
},
"default_popup": "popup.html"
}
}
popup.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<style>
body {
width: 300px;
padding: 10px;
font-family: Arial, sans-serif;
}
p {
line-height: 1.4;
margin: 0;
color: #333;
}
</style>
</head>
<body>
<p>
Le temps de réaction d'un humain oscille entre 200 et 250 ms.<br />
Il faut donc un TTFB en dessous de 200 ms pour avoir l'impression
d'instantanéité.
</p>
</body>
</html>

Run


Download this blog post with all media included in a single HTML file (4,45 Mo)