EN
Language · same page NLNederlands/tools-en-plugins/core-web-vitals-meten/ ENEnglish (UK)/en/tools-and-plugins/measuring-core-web-vitals/ ESEspañolnot translated yet We do not remember your choice and never redirect you automatically.
SRV · plugin · core web vitals reg. T.000 · WordPress · GPLv2 or later

Measuring Core Web Vitals with your real visitors

There are plenty of plugins that promise to improve your Core Web Vitals. This one measures them, with the people who actually visit your site, and shows what they got. Every figure on the screen is the 75th percentile over the chosen period, separately for mobile and desktop, because that is how Google defines the thresholds. Nothing is estimated, nothing is simulated in a laboratory, and no advice is attached to a number the measurement cannot support.

Download the plugin ↓ Book a call theseo-webvitals-1.0.0.zip · 51 KB · version 1.0.0 · GPLv2 or later · no account, no registration, no key
Gianluca, who builds the tools and plugins on this site
image · whoever built the tool also explains it
FIG.01: What the 75th percentile issheet 1/3

Not the average, but the visitor right at the edge of the worst quarter

Google judges Core Web Vitals on the 75th percentile, not on the average. That is not a detail. An average hides the tail, and the tail is exactly where people give up. Out of every hundred measurements, you sort them in order, go to the seventy-fifth, and that figure is your score. Three in four visitors had it better, one in four worse.

LCP, mobile, 30 daysexample · sorted measurements
fastest measurement75th percentileslowest
Green up to 2.5 seconds, orange up to 4 seconds, red above that. The figure that appears on the screen is the seventy-fifth bar, not the average height of all the bars. For INP the thresholds are 200 and 500 milliseconds, for CLS 0.1 and 0.25, and for TTFB 800 and 1800 milliseconds.
TTFB is not a Core Web Vital, but it sits underneath LCP. If your TTFB is 1.4 seconds, every LCP improvement you make to your images is pointless until your server responds faster. That is why it is listed alongside them, not among them.
DOC.01

Why your own figures do not match those from PageSpeed Insights

This is the question that always comes up after a day of measuring, and the answer is not that one of the two is wrong.

The lab score in PageSpeed Insights is a simulated page load on a simulated device, over a simulated connection

Useful for comparison, but it is not what your visitors actually get.

The field data in PageSpeed Insights comes from the Chrome User Experience Report

That report covers Chrome users who have given permission for it, and it needs enough traffic before it publishes anything at all. On a quiet site it stays empty, leaving you empty-handed even though your site does have visitors.

This plugin measures every browser that supports the underlying feature, even on that quiet site

The two will therefore differ, and that is stated on the screen instead of in a footnote.

What Google does with those figures, and why one slow template page can turn a whole group red in your report even though the assessment is per page, is explained in Core Web Vitals: Google assesses your website per page. That page explains the rule, this plugin gives you the measurement.

DOC.02

What is measured, and how

Four metrics, with the thresholds Google publishes.

POINT 01

LCP

, Largest Contentful Paint. Good up to and including 2.5 seconds, poor above 4 seconds.
POINT 02

INP

, Interaction to Next Paint. Good up to and including 200 milliseconds, poor above 500.
POINT 03

CLS

, Cumulative Layout Shift. Good up to and including 0.1, poor above 0.25.
POINT 04

TTFB

, Time To First Byte. Not a Core Web Vital, but it sits underneath LCP. Good up to and including 800 milliseconds, poor above 1800.

The measuring is our own implementation of the definitions Google publishes, written out in readable JavaScript rather than pulled in as a library. This was a deliberate choice: you can open the file and simply read what happens. It runs on the browser features that produce these figures, PerformanceObserver for the largest paint, the layout shifts and the event timings, and navigation timing for the first byte.

INP, following the same rule

Events that belong to one interaction are grouped by their interactionId, and the longest event in an interaction is that interaction's delay. Below fifty interactions, the worst one is reported; above that, one interaction in every fifty is allowed to be worse than the reported figure. That is the rule that stops a single outlier from defining an entire page.

FIG.02: The fairness rulesheet 2/3

Below twenty measurements you get no figure, but a count

A percentile over four page views is not a percentile. It looks exactly as precise as a percentile over four thousand, and it means nothing. That is how this kind of screen sends people in exactly the wrong direction, and that is why this plugin refuses to print the figure in that case.

per pagethreshold · adjustable, default 20
3too few measurements (3)There is no figure. It shows how many measurements there are, so you know how far you still are from a figure.
202.1 s over 20 measurementsFrom the threshold onwards the figure appears, always with the number of measurements it rests on shown after it.
0Empty, and that is not a zeroA browser that cannot take a measurement sends nothing for it, and the plugin stores nothing for it. A zero is never written in place of a measurement that did not happen, because a zero reads as a perfect score that was never actually taken.
The result is that the number of measurements differs per metric, and that is correct rather than a mistake. LCP, CLS and INP each depend on a browser feature that not every browser has, while TTFB comes from navigation timing and is available almost everywhere. Every figure on the screen carries the number of real measurements behind it.
DOC.04

How to install it, in four steps

No account is needed, no key and no registration. An ordinary WordPress site where you are an administrator is enough.

WordPress6.0 or higher. The plugin states it has been tested up to and including 7.0.
PHP7.4 or higher. The code has been checked against 8.5.
PermissionsYou need manage_options, so administrator.
Screen languageDutch on a Dutch site, English otherwise.
Also available on Full source code on GitHub The zip above and the source code on GitHub are the same version. This plugin is not yet in the official WordPress plugin directory. It is ready for submission; until that is complete, the download above is the only place to get it. Status recorded on 19 August 2026.
STEP 1 · DOWNLOAD

Click the download button above. You get theseo-webvitals-1.0.0.zip, 51 KB. Do not unzip it: WordPress wants the zip file itself.

STEP 2 · UPLOAD

In your WordPress: Plugins, Add New Plugin, Upload Plugin. Choose the file and click Install Now.

STEP 3 · ACTIVATE

Click Activate Plugin. A new item appears in your admin menu. Your site does not change yet at this point.

STEP 4 · CONFIGURE

Open the settings screen and go through the statuses. Everything that touches your public site stays off until you switch it on yourself.

DOC.03

What the plugin is not

This is where this plugin sets itself apart from the rest of the category, because the rest of the category promises speed.

  • It is not a caching plugin and it does not make anything faster. Nothing is optimised, nothing is merged and nothing is deferred.
  • It does not say what causes a slow figure. That is diagnosis, and diagnosis guessed from four numbers is gambling with a chart attached.
  • It never suggests installing anything. There is no recommendation in it that happens to lead to a paid product.
  • Its figures are not the figures Google uses for the search results. That difference is explained above, and it is also stated on the screen itself.
What it does give you: you know which page is slow on which device, how many measurements that rests on, and whether or not it comes down to your server

That is all you need to decide where to start, and that is exactly where most speed conversations get stuck.

FIG.03: What is recorded per measurementsheet 3/3

Five fields in, and six things deliberately left out

Two rows from the same person cannot be recognised as belonging together. That is the design, not an accident. There is no session number, so nobody can be tracked, and in return there is also nothing to leak.

a row in the measurementsthe whole table · five columns
is recorded
  • The address of the page, without a query string and without an anchor
  • Which metric it was
  • The value
  • The device class, mobile or desktop, derived from the width of the window
  • The hour in which it happened
is not recorded
  • The IP address, not readable and not as a fingerprint either
  • A session, a visitor number or a user number
  • A cookie or anything in localStorage or sessionStorage
  • The user agent
  • The query string
  • Anything that leaves your server
The device class comes from the width of the window and not from the user agent, because a user agent is both a claim and a fingerprint, and a width is neither. The moment is rounded down to the full hour, so that a row cannot be matched to a single request in a server log. If a browser sends Do Not Track or Global Privacy Control, the script stops before it measures anything; that is on by default.
DOC.05

Privacy: what is and is not recorded

This is the plugin in this series that comes closest to a visitor, because it measures inside that visitor's browser. That is also why this is the section most worth checking.

POINT 01

No IP address in the table

The address appears exactly once, in the rate limit, where it becomes a value through a key hash that expires within a minute. It never reaches the measurements table.
POINT 02

No session and no visitor number

Two rows from the same person cannot be linked to each other. So there is nothing to track, and that is also why there is nothing to leak.
POINT 03

No cookie and no browser storage

Search the unpacked zip for setcookie, localStorage and sessionStorage. The only hits are in comments and in the readme.
POINT 04

No user agent

Mobile or desktop is derived from the width of the window.
POINT 05

No outgoing request

The script talks to your own admin-ajax.php and nothing else. There is no external address anywhere in the plugin.
POINT 06

Do Not Track and Global Privacy Control are on

If the browser sends one, the script stops before it measures anything. You can switch this off, and it is on by default.
POINT 07

Retention period

A daily task deletes measurements older than the configured period, ninety days by default. Deleting the plugin drops the table, the settings and the task.

Why there is no nonce on the collection endpoint is explained in the frequently asked questions below, with the reason and the four measures that stand in its place.

DOC.06

Frequently asked questions

Why is there no nonce on the collection endpoint? Because a nonce quietly breaks the measurement without adding anything. A nonce is printed into the page, so on a site with full-page caching every visitor gets the same nonce and it stops working within a day. On a public endpoint that anonymous visitors need to be able to reach, it is not security either. What is in place instead: the master switch, a same-origin check, a rate limit per address, and validation that only accepts the four known metrics, only figures within their published range, and only an address from this site. Every admin action does use a nonce plus a permissions check.

Does it slow down my site?

The script is a single file of a few kilobytes, loaded in the footer, with no dependencies, and it does not block rendering. It sends one request per page view, at the moment the page is left, via sendBeacon.

Does it work with a caching plugin?

Yes, and that is part of the point. Nothing in the markup expires, so a page served from cache keeps measuring, and what gets measured then is what your visitors actually get from that cache.

Why does one metric have fewer measurements than another?

Because not every browser has every measuring feature. A browser that cannot measure something contributes nothing for it, and that gap is not filled with a zero.

Why does a page say too few measurements?

Because it has fewer measurements than the threshold on the settings screen, twenty by default. Set it to 1 temporarily if you want to see the first figures, then set it back.

Does it work on multisite?

Yes. Every site in the network gets its own table and its own settings. Deleting the plugin cleans up every site.

DOC.07 · Next step

What it gives you in the first week

The practical route: switch it on, let it run for a week, and only then take a look. Before that you will have too few measurements, and the plugin says so too. If you then see that a page is slow but do not know why visitors get stuck on it, the heatmap and scrollmap shows what they do on that same page. If your site runs on WordPress and you also want to check it for accessibility, the accessibility plugin does that on the points that can be tested automatically. If you would like to talk it through, book a call.

Section · Next step24/7 available · sales@theseo.nl
Book a call ↗
Written by GianlucaFounder. Has been building visibility for Dutch businesses since 2017, in Google and in AI answers. More about the institute.