The browser agent's SPA tracking is a heuristic. These APIs let you override it by hand.Read the docs
Checking for browser agent…
New Relic SPA API
Take the wheel.
events.html showed you the heuristic: route change, then DOM update, in that order, or nothing gets saved. This page shows you how to override it by hand: force a save, suppress one on purpose, name a route yourself, mark a page finished.
interaction()Only .setName(), .actionText(), .setAttribute(), .save(), .ignore() and .end() are methods on the handle newrelic.interaction() returns. setCurrentRouteName(), setPageViewName() and finished() are separate top-level calls, not handle methods, even though they're all part of the same story.
// Force a save, bypassing the route+DOM heuristic entirely
newrelic.interaction().setName('Open settings').save().end()
// Suppress one that would have qualified normally
newrelic.interaction().ignore()
// Name the route yourself, not a handle method
newrelic.setCurrentRouteName('/users/:id')
// A separate timing marker, not part of interaction() at all
newrelic.finished()
Your data is tagged as…NR-XXXXChange
Everyone shares one New Relic account, so your clicks are tagged as demoUser and demoCode custom attributes (your name is also set as your end-user ID via setUserId()), carried onto every interaction, page view and action you control by hand below.
Write this code down. You will search for NR-XXXX in the queries further down. It stays the same on every page until you click New code or close this tab.
Try it / Override it
Take control by hand
Four buttons, four overrides, plus one that already ran before you clicked anything. The agent decides what actually gets saved, and this page has no way to read that verdict back. The activity feed on the right only shows what you did locally. Give it a minute or two, then check the queries below for what New Relic actually recorded.
Handle methods vs. top-level calls
Two different APIs telling one story
newrelic.interaction([options]) (Pro+SPA v963+) returns a handle bound to whatever interaction is currently in progress, or a new API-driven one if nothing is. The agent prioritizes real clicks: if one is already running, you get a handle to that, not a new one. An API-created interaction with no waitForEnd has no 30-second timeout the way a click does; it just sits open until something else displaces it, which is why the demos below always pair .save() or .ignore() with .end().
Chained off that handle: .setName(name, trigger), .actionText(text), .setAttribute(key, value), .save() (forces the interaction to be reported even if the route+DOM heuristic was never met), .ignore() (forces it to never be reported, even if the heuristic would have passed), and .end().
setCurrentRouteName(name) (v998+) and setPageViewName(name, host) (v593+) and finished(time) (v593+) are not handle methods. They're separate top-level newrelic.X() calls that happen to be part of the same "control it yourself" story. setCurrentRouteName() labels the SPA interaction's route; setPageViewName() renames the initial PageView, a different event entirely; finished() is a timing marker, unrelated to either.
1 · Force a save
interaction().save().end()
Opening a settings panel is purely client-side: no route change, no AJAX. On events.html, that kind of click could never become its own BrowserInteraction. .save() forces it anyway.
Nothing sent yet.
2 · Suppress on purpose
interaction().ignore()
Changes the URL, then updates this card: the exact recipe that normally qualifies as a BrowserInteraction. .ignore() kills it anyway. It will not show up in the queries below.
Nothing sent yet.
3 · Name the route yourself
setCurrentRouteName()
Names the route as a pattern, alternating between /spa-demo/:code and /spa-demo/:code/detail on each click, not literal URLs, then changes it. Real SPA routers call this every time a route changes; a static site has to fake the "every time" part by hand. The alternation is what makes previousRouteName and targetRouteName actually differ, instead of landing on the same string every time.
Nothing sent yet.
4 · Mark it finished
finished()
A timing marker for "the page is done, by my own definition," not the browser's load event. Useful for pages that keep loading content asynchronously after the page technically finishes loading.
Nothing sent yet.
5 · Already ran, no button
setPageViewName()
The docs are explicit: this one only works if it's called before the windowload event fires. By the time you could click a button, that's already happened. So this page called it automatically, the moment it loaded.
Running…
Find it / Search the shared account
Find your events
Allow a minute or two for events to arrive. Everything below is already filled in with your code, NR-XXXX.
Your BrowserInteraction rows, forced and named
Open the query builder in New Relic and run this. The forced-save row and the route-named row should both be here. The suppressed one should not be here at all; that's the proof .ignore() worked.
browserTransactionName should show the custom name this page set automatically on load, not the raw file path.
Your finished() call
finished() isn't flat-queryable on its own; it fires a PageAction named finished under the hood, which this is.
See it in the UI
Go to Browser, open the demo app, then Browser interactions or Page views to see these rows alongside the automatic ones from the other pages.
The forced-save and route-named interactions should look like any other BrowserInteraction there; nothing in the UI marks them as API-created.
Filter any of the above by demoCode = NR-XXXX to see only your events.
Still seeing the suppressed one?Give it a minute, harvesting lags a little. If it's still there after that, something's off; it shouldn't be.
Route name not showing on the first click?That's expected. previousRouteName only populates starting on your second click; the first has nothing to look back to.