On 18 August 2026, New Relic force-upgrades every enabled scripted browser monitor still running an older runtime. Chrome 134 becomes Chrome 147 or higher, and migrating the browser runtime pulls Node.js 16 up to Node.js 22 with it. A second deadline on 18 November 2026 retires Node.js 16 for everything still on it, which is mainly scripted API monitors.
The dates come from New Relic's own end-of-life notice, published 18 May 2026. It is worth being precise about which date is which, because third-party guides and infrastructure provider docs have been inconsistent about it, and the two dates affect different monitor populations.
This post is the migration guide New Relic did not write. It covers what breaks, how to find your own exposure, and the failure mode that matters most: the monitors that come through the upgrade green and stop testing anything.
The timeline, corrected#
New Relic staged this over six months. Most of it has already happened.
| Date | What happened or happens |
|---|---|
| 18 May 2026 | All non-scripted monitors (simple browser, step, cert check, broken links) force-upgraded. New scripted monitors default to the latest runtime. |
| 18 June 2026 | Scripted monitors that were disabled as of 17 June force-upgraded. |
| 18 July 2026 | The latest Docker tag for both the browser and API runtimes repointed to Chrome 147+/Node 22. Private locations tracking latest moved then. |
| 18 Aug 2026 | Enabled scripted browser monitors on older runtimes force-upgraded. This is the one still ahead of you. |
| 18 Nov 2026 | Node.js 16 support ends for anything remaining. |
New Relic's stated driver is security rather than housekeeping: Chrome 134 sits outside Google's supported channels, Node.js 16 reached end of life in September 2023, and the notice points at a recent Chrome CVE. That framing matters because it means the date is unlikely to slip.
What actually breaks#
1. Unhandled open handles under Node 22#
This is the most common failure, and New Relic says so directly:
The most common issue when upgrading to Node.js 22 is unhandled open handles. If your monitor scripts contain unhandled open handles (such as unresolved promises, lingering timers, or unclosed network connections), your monitors will fail.
Node 22 is stricter about process lifecycle than Node 16. A script that left a setInterval running, held an unresolved promise, or kept a socket open used to get away with it. Now the process does not exit cleanly and the check fails.
The things to grep for:
setIntervalwithout a matchingclearInterval- A custom
http.AgentwithoutkeepAlive: false - Promises created but never awaited or chained
- Any explicit connection you open and never close
2. Chrome 147 is heavier, so marginal monitors start flapping#
Chrome 147 needs more CPU and memory than Chrome 134 for identical work. New Relic quantifies the overhead: scripted browser monitors carry an average container overhead of 6 to 10 seconds, and scripted API monitors 2 to 4 seconds. Their own guidance is blunt about the consequence:
Monitors that were close to timeout thresholds on the old runtime may now exceed them.
Nothing about your application changed. A fleet that comfortably ran in 45 seconds now takes 51 to 55, and whichever monitors sat nearest the line begin failing intermittently. On JS-heavy pages you may instead see Error: tab crashed, because pages near the memory ceiling on Chrome 134 exceed it on Chrome 147.
On private locations you have knobs for this: raise HEAVY_WORKER_MEMORY from its 3.256 GiB default, reduce HEAVYWEIGHT_WORKERS, or raise CHECK_TIMEOUT from its 180 second default. On public locations you do not, so the fix is to make the script faster or the assertions tighter.
This class is worth dwelling on because of how it gets diagnosed. Intermittent slowness after an infrastructure change looks exactly like an application performance regression. Teams that do not connect the flapping to the runtime upgrade go looking in their own code first.
3. Private locations: the dropdowns and the telemetry both mislead you#
If you run private locations, two things are true that make self-auditing harder than it looks.
First, the settings do not do what they appear to do:
For private locations, the Browser and Runtime version dropdowns in General settings have no effect. The version is determined entirely by the image the SJM is running.
Second, and more consequential, the attribute you would naturally query is unreliable:
As such, the
runtimeTypeVersionattribute inSyntheticCheckis not a reliable way to identify the runtime version for private monitor jobs.
So the obvious NRQL audit gives you a confident, wrong answer for private locations. You have to check the image tag your synthetics job manager is actually running instead. Also budget for the pull: the browser runtime image is roughly 3 GB, and if it is not pre-pulled the SJM can time out on first start.
4. The legacy promise-manager class, if you still have Node 10-era scripts#
This one is frequently misattributed to the 18 August wave. It is not that population. It affects monitors coming from the genuinely legacy runtime, Chrome 72 with Node 10.15.0 and Selenium WebDriver 3.6.0 exposed as $browser and $driver. If you are on Chrome 134 and Node 16, this section does not apply to you.
If you do have scripts that old, this is the one that bites hardest:
Selenium WebDriver promise manager and control flow allowed some functions to execute in order in legacy runtimes, without managing promises. This capability was removed in Selenium WebDriver 4.0 and is no longer available in the runtime. All async functions and promises need to be managed with
awaitor with.thenpromise chains.
Code of this shape used to work because the promise manager serialised it for you:
// Broken once the promise manager is gone: nothing sequences these.$browser.get("http://example.com");$browser.findElement($driver.By.css("h1"));
// Broken once the promise manager is gone: nothing sequences these.$browser.get("http://example.com");$browser.findElement($driver.By.css("h1"));
// Explicit sequencing, which is now mandatory.await $browser.get("http://example.com");await $browser.findElement($driver.By.css("h1"));
// Explicit sequencing, which is now mandatory.await $browser.get("http://example.com");await $browser.findElement($driver.By.css("h1"));
The reason this matters more than a simple error is that racing Selenium scripts do not reliably throw. They intermittently assert against a DOM that has not rendered yet. Sometimes they pass. New Relic's own diagnostic tell for it: if the monitor passes on the legacy runtime, fails on the new one, and the element is visible in the screenshot, the problem is your promise handling.
How to audit your own exposure#
For public locations, query SyntheticCheck and group by runtimeTypeVersion to find monitors still on older runtimes. That is the straightforward part.
For private locations, ignore that attribute entirely, per the caveat above, and inventory the image tags your SJMs are running instead.
Then read the scripts themselves. The static checks worth running across your whole monitor corpus:
setIntervalwith noclearInterval- Custom
http.Agentconstruction withoutkeepAlive: false - Anything relying on
http.globalAgentdefaults, which is the nastiest of these because nobody wrote that line. The keep-alive default is inherited, so a script with no networking code of its own can still hold a socket open and fail to exit - Promises created but never awaited or chained
- Any monitor whose median duration exceeds roughly 60% of its configured timeout, since those are the ones the 6 to 10 second overhead will push over
That last one is the check most teams skip, and it is the one that predicts the flapping.
New Relic's own migration path, and where it stops#
New Relic ships a Runtime Upgrades page under Synthetic Monitoring that lists monitors failing auto-validation, with a manual edit-and-revalidate loop and an AI-assisted rewrite. It is genuinely useful. It also has four documented limits worth knowing before you rely on it.
The AI only targets the easy half. In their words, the AI-assisted script generation "is mainly geared toward fixing timeout errors incurred during runtime upgrades. For monitors with script errors, the script potentially needs other changes." Timeout errors are the mechanical class from section 1. Script errors, which is the actual work, are explicitly out of scope.
It is paywalled and compliance-gated. The feature requires Advanced Compute and is not available for FedRAMP accounts. The customers under the strictest uptime obligations get the least automated help.
They disclaim the output. "Always test AI-generated scripts before deploying the monitors in production." Which is reasonable advice, and also circular: the thing being rewritten is your test, and there is no second system to test it with.
Private locations get no automated pre-migration validation at all. The recommended alternative is standing up a parallel private location on a second location key and running both runtimes side by side to compare. That is a multi-day infrastructure project. Ten days out, it is not happening for most teams.
The failure that matters is the one that passes#
Everything above is recoverable. A monitor that goes red after the upgrade is annoying, and you will fix it that afternoon.
The expensive case is the monitor that comes through green and no longer tests anything. Validation confirms that a script executes without errors. It does not confirm that the script still asserts what it used to assert. A racing script that reads a not-yet-rendered DOM, or one whose selector now resolves to a different element, will often execute cleanly and report success.
New Relic warns about this class in its own troubleshooting docs, which is to their credit. But the practical consequence is worth stating plainly: after a forced runtime upgrade, a green board is weaker evidence than it was the week before. If a monitor's duration dropped sharply on 18 August, that is not a performance win. That is a check that stopped doing its job.
The concrete follow-up is to verify that each monitor still fails when it should. Point a copy at a deliberately broken state, a staging environment with the checkout disabled or a URL that should 404, and confirm it goes red. Monitors that cannot fail are not monitoring.
The wider point about owning your test artifact#
There is a structural reason this migration is painful, and it is not that New Relic handled it badly. The scripts live in New Relic's database, in a runtime New Relic controls, in a dialect specific to their platform. When the runtime moves, every script moves with it, on their schedule, and your only tooling is the tooling they chose to build.
Tests that live as ordinary code in your own repository have a different failure profile. You upgrade when you choose. Your changes go through code review. You can grep the whole suite, run a codemod across it, and see the diff before it ships. The vendor supplies a runner, not custody of your test suite.
That is the model ObserveOne is built around: tests are Playwright files you own, and promoting one to a scheduled production monitor does not convert it into something only we can read. If you are auditing New Relic scripts this week, the Playwright migration guide is a reasonable place to look at what the code-owned version costs.
Either way, the deadline is real, the audit is worth doing, and the monitors to worry about are the quiet ones.