Panth_CoreWebVitals collects Core Web Vitals (LCP, FID, INP and CLS) from real visitors of a Magento 2 storefront. When the module is enabled it renders an inline JavaScript snippet on every frontend page that registers PerformanceObserver listeners in the browser, rates each collected value, and optionally forwards the values to Google Analytics 4 and to a custom beacon endpoint. It also lets the administrator output resource hint link tags (dns-prefetch, preconnect, prefetch) and adds performance related HTTP headers (Server-Timing, X-DNS-Prefetch-Control, Link) to the response.
The module is aimed at merchants and developers who want field measurements of their store's Core Web Vitals without adding a third party library. It uses the standard after.body.start and before.body.end layout containers and contains no theme specific code, so it works on both Hyva and Luma themes.
Product page: kishansavaliya.com/magento-2-corewebvitals.html
- Collects LCP using the
largest-contentful-paintPerformanceObserver entry type (the last reported entry is used). - Collects FID using the
first-inputentry type. - Collects INP using the
evententry type with adurationThresholdof 16 ms; the worst interaction duration seen so far is reported. - Collects CLS using the
layout-shiftentry type, ignoring shifts that follow recent user input and aggregating shifts into session windows (gap under 1 s, window under 5 s). - Rates each value as
good,needs-improvementorpoorusing fixed thresholds (LCP 2500/4000 ms, FID 100/300 ms, INP 200/500 ms, CLS 0.1/0.25). - Sends each metric to GA4 through
gtag()whengtagis present on the page, with an optionalsend_tomeasurement ID. - Sends each metric as a JSON document to a custom endpoint through
navigator.sendBeacon. - Dispatches a DOM
CustomEvent(coreWebVitals:lcp,coreWebVitals:fid,coreWebVitals:inp,coreWebVitals:cls) onwindowfor every collected metric. - Debug mode logs every metric to the browser console, exposes
window.coreWebVitalsMetrics, and prints a final summary when the page becomes hidden. - Outputs
<link rel="dns-prefetch">,<link rel="preconnect" crossorigin>and<link rel="prefetch">tags from admin configured lists. - Adds a
Server-Timingheader with the PHP execution time, anX-DNS-Prefetch-Control: onheader when DNS prefetch domains are configured, and aLink: <origin>; rel=preconnect; crossoriginheader for each preconnect domain. - Per metric enable switches; all settings are scoped to default, website and store view.
- Unit tests for the helper, plugin and observer under
Test/Unit.
| Platform | Versions |
|---|---|
| Magento Open Source | 2.4.4, 2.4.5, 2.4.6, 2.4.7, 2.4.8 (as published on the product page) |
| Adobe Commerce | 2.4.4, 2.4.5, 2.4.6, 2.4.7, 2.4.8 (as published on the product page) |
| PHP | 8.1, 8.2, 8.3, 8.4 (`~8.1.0 |
| Themes | Hyva and Luma |
Composer constraints on Magento packages: magento/framework ^103.0, magento/module-store ^101.0, magento/module-config ^101.0, magento/module-backend ^102.0.
- Magento Open Source or Adobe Commerce 2.4.4 to 2.4.8.
- PHP 8.1, 8.2, 8.3 or 8.4.
mage2kishan/module-core^1.0(modulePanth_Core), which provides the "Panth Extensions" admin menu that this module attaches to. Composer installs it automatically.- No other packages are required or suggested by
composer.json.
composer require mage2kishan/module-corewebvitals
bin/magento module:enable Panth_Core Panth_CoreWebVitals
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:flushsetup:di:compile is only needed when Magento runs in production mode. The module ships no files under view/*/web, so setup:static-content:deploy is not required for it.
Check that the module is active:
bin/magento module:status Panth_CoreWebVitalsAdmin path: Stores > Configuration > Panth Extensions > Core Web Vitals (section id panth_corewebvitals). All fields can be set at default, website and store view scope. The module is disabled by default; nothing is rendered and no headers are added until "Enable Module" is set to Yes.
| Setting | Default | What it does |
|---|---|---|
| Enable Module | No | Master switch. Renders the monitoring snippet on frontend pages and activates the resource hints and response headers. All other fields depend on it. |
| Debug Mode | No | Logs collected metrics to the browser console and exposes window.coreWebVitalsMetrics. |
| Send Metrics to Analytics | Yes | Sends collected metrics to GA4 (when gtag exists on the page) and to the beacon endpoint below. |
| Custom Beacon Endpoint URL | (blank) | Absolute URL that receives a JSON POST through navigator.sendBeacon for every metric. Blank skips the beacon. Shown only when "Send Metrics to Analytics" is Yes. |
| GA4 Measurement ID | (blank) | Optional G-XXXXXXX value used as the send_to parameter of the gtag() call. Shown only when "Send Metrics to Analytics" is Yes. |
Config paths: panth_corewebvitals/general/enabled, panth_corewebvitals/general/debug_mode, panth_corewebvitals/general/real_user_monitoring, panth_corewebvitals/general/endpoint_url, panth_corewebvitals/general/ga4_measurement_id.
| Setting | Default | What it does |
|---|---|---|
| Monitor LCP | Yes | Registers the largest-contentful-paint observer. |
| Target LCP (milliseconds) | 2500 | Target value passed to the page in the script configuration. The shipped script rates LCP against fixed thresholds and does not read this value. |
Config paths: panth_corewebvitals/lcp/enabled, panth_corewebvitals/lcp/target_lcp.
| Setting | Default | What it does |
|---|---|---|
| Monitor FID and INP | Yes | Registers the first-input and event observers. |
| Target FID (milliseconds) | 100 | Target value passed to the page in the script configuration; not used by the rating logic. |
| Target INP (milliseconds) | 200 | Target value passed to the page in the script configuration; not used by the rating logic. |
Config paths: panth_corewebvitals/fid/enabled, panth_corewebvitals/fid/target_fid, panth_corewebvitals/fid/target_inp.
| Setting | Default | What it does |
|---|---|---|
| Monitor CLS | Yes | Registers the layout-shift observer. |
| Target CLS Score | 0.1 | Target value passed to the page in the script configuration; not used by the rating logic. |
Config paths: panth_corewebvitals/cls/enabled, panth_corewebvitals/cls/target_cls.
| Setting | Default | What it does |
|---|---|---|
| DNS Prefetch Domains | (blank) | One domain per line without protocol. Each line becomes <link rel="dns-prefetch" href="//domain">. Also turns on the X-DNS-Prefetch-Control: on response header. |
| Preconnect Domains | (blank) | One domain per line without protocol. Each line becomes <link rel="preconnect" href="//domain" crossorigin> and a Link: <https://domain>; rel=preconnect; crossorigin response header. |
| Prefetch URLs | (blank) | One full URL per line. Each line becomes <link rel="prefetch" href="url">. |
Config paths: panth_corewebvitals/resource_hints/dns_prefetch, panth_corewebvitals/resource_hints/preconnect, panth_corewebvitals/resource_hints/prefetch.
Blank lines and surrounding whitespace in the textarea fields are ignored.
Page output. With the module enabled, the frontend default.xml layout adds two blocks:
panth.corewebvitals.resource.hints(templateresource-hints.phtml) in theafter.body.startcontainer. It prints the dns-prefetch, preconnect and prefetch link tags, if any are configured, immediately after the opening<body>tag.panth.corewebvitals.monitor(templatecore-web-vitals.phtml) in thebefore.body.endcontainer. It prints an inline<script>that reads a JSON configuration object built byHelper\Data::getConfigJson()and registers the PerformanceObserver listeners. The script exits immediately ifPerformanceObserveris not available in the browser.
Metric collection. Each metric is reported with a name (LCP, FID, INP, CLS), a numeric value (milliseconds, or a unitless score for CLS), a rating, an id, a delta and the observed entries. Values are rated against the thresholds published for Core Web Vitals (see web.dev).
Reporting. When "Send Metrics to Analytics" is Yes:
- If
window.gtagexists, the script callsgtag('event', <metric name>, {...})withevent_category: 'Web Vitals',value(CLS multiplied by 1000 and rounded; other metrics rounded to whole milliseconds),event_label(the metric id),metric_ratingandnon_interaction: true. When a GA4 Measurement ID is configured it is added assend_to. - If a beacon URL is available, the script posts a JSON body with the fields
name,value,rating,id,delta,page(path and query string) andtimestampusingnavigator.sendBeacon. The URL comes from "Custom Beacon Endpoint URL"; if that is blank the script falls back towindow.panthCoreWebVitalsEndpointwhen a site defines it.
In addition, every metric dispatches window.dispatchEvent(new CustomEvent('coreWebVitals:<metric>', { detail })), so other scripts can listen with, for example, window.addEventListener('coreWebVitals:lcp', function (e) { console.log(e.detail); }).
Response headers. The plugin Plugin\AddPerformanceHeaders runs before Magento\Framework\App\Response\Http::sendResponse() and, when the module is enabled, sets:
Server-Timing: app;desc="PHP Execution";dur=<milliseconds since REQUEST_TIME_FLOAT>X-DNS-Prefetch-Control: onwhen at least one DNS prefetch domain is configuredLink: <https://domain>; rel=preconnect; crossorigin, ...for the configured preconnect domains
The plugin is declared in the global etc/di.xml, so it is not limited to the frontend area.
The module has no admin report pages, no scheduled cron jobs and no console commands. Collected metrics are not stored in Magento; they only exist in the browser and in whatever analytics destination is configured.
- Module name:
Panth_CoreWebVitals - Composer package:
mage2kishan/module-corewebvitals(version 1.0.10) - PHP namespace:
Panth\CoreWebVitals - Load sequence: after
Magento_Store,Magento_ConfigandPanth_Core - Key classes:
Helper\Datareads all configuration values (store scope) and builds the JSON configuration for the script (getConfigJson()).Block\CoreWebVitalsexposesisEnabled()andgetConfigJson()tocore-web-vitals.phtml.Block\ResourceHintsexposesisEnabled(),getDnsPrefetchDomains(),getPreconnectDomains()andgetPrefetchUrls()toresource-hints.phtml.Plugin\AddPerformanceHeaders::beforeSendResponse()adds the response headers (plugin namepanth_corewebvitals_performance_headers, sort order 10).Cron\CollectMetricsandObserver\LayoutRenderBeforeare empty placeholders; no cron job or observer is registered for them.
- Extension points: the
coreWebVitals:*DOM events, thewindow.panthCoreWebVitalsEndpointglobal as a fallback beacon URL, and the two named layout blocks, which can be moved or removed in a theme'sdefault.xml. - ACL resources:
Panth_CoreWebVitals::corewebvitals("Core Web Vitals") andPanth_CoreWebVitals::config("Configuration"), both underMagento_Config::config. - Admin menu: "Core Web Vitals" > "Configuration" under the "Panth Extensions" menu provided by
Panth_Core, linking to the configuration section. - Database: the module ships no
db_schema.xmland creates no tables. - Translations:
i18n/en_US.csv.
bin/magento module:disable Panth_CoreWebVitals
composer remove mage2kishan/module-corewebvitals
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:flushNo database tables are created by the module, so nothing needs to be dropped. Saved configuration values under panth_corewebvitals/* remain in core_config_data and can be deleted manually if wanted. Remove Panth_Core only if no other Panth module depends on it.
- Product page: kishansavaliya.com/magento-2-corewebvitals.html
- Contact form: kishansavaliya.com/contact
- Email: kishansavaliyakb@gmail.com
- Bug reports: GitHub issues
USER_GUIDE.md is written for store administrators and covers installation, verifying that the module is active, every configuration field, what each metric means, resource hints, the performance HTTP headers, integrating with GA4 or a custom endpoint, and troubleshooting.
Commercial software license. See LICENSE.txt in this repository.
See CHANGELOG.md.
- Website: kishansavaliya.com
- All extensions: kishansavaliya.com/magento-extensions.html
- GitHub: github.com/mage2sk/module-corewebvitals
- Packagist: packagist.org/packages/mage2kishan/module-corewebvitals