OptimeleonOptimeleon
Request Access
Platform

Single-page apps

Next.js, React, Vue and other client-side routers need no extra setup. What Optimeleon does when the page changes without a full reload, and the few things to plan around.

On a single-page app the browser loads one document, and your app swaps the content as the visitor moves around. Optimeleon follows those navigations on its own. There is nothing to switch on and nothing to call: every route gets the right version, and every route is tracked.

It follows each route change your app makes through the browser's history, which is how the routers in Next.js, React Router, Vue, Nuxt, SvelteKit and Angular work, plus the back and forward buttons. A URL changed some other way is picked up a moment later.

Install it in the page your server sends

The snippet goes in the <head> of the HTML your server returns, as high as you can put it and exactly as the app gives it, the same as on any other site. In most frameworks that is the root layout or the document template.

Not from inside your app
Do not add the snippet from client-side code after your app has started, and do not load it through a component that defers scripts or rewrites their tags. Either way it runs after the page has painted, which is too late to prevent flicker.

For steps written for your framework, open Custom instructions on the script step in Setup. The AI Installation Kit detects your stack and writes them for it.

What happens on each navigation

  1. Optimeleon checks whether the new page is part of a campaign.
  2. If it is, it applies that visitor's version of the page. A page they already opened in this tab shows its version instantly.
  3. If it is not, it removes the previous page's changes, so the visitor sees your original content.

While a version is swapped in, only the elements being changed are hidden, and only briefly. The rest of the page stays on screen. If the version for a page cannot be fetched in time, that page shows your original version, and nothing on it breaks.

The list of pages with a campaign is read when the page first loads, so a campaign you start while someone is browsing reaches them on their next full page load.

Hash routes count as one page
Campaigns match on the path. The query string and anything after # are ignored, so /pricing?plan=pro is the same page as /pricing. If your app routes with URLs like /#/pricing, every route is the same page to Optimeleon, and a campaign on it runs on all of them. Give the pages you want to optimize their own paths.

When your app re-renders

If your framework re-renders part of the page Optimeleon changed, Optimeleon puts its change back. Content that appears late, after the route has rendered, is changed when it arrives.

The variant wins over live updates
Optimeleon keeps its version of every element a variant changes, even against your own app's updates to that element. Keep variants off elements your app updates live, such as a price, a stock level or a cart count.

On a server-rendered site, the first page waits for your framework to finish hydrating before anything is changed, so hydration sees exactly the HTML your server sent. If your framework hydrates unusually late, you may occasionally see a hydration warning in the browser console. The variant is re-applied and stays in place.

Tracking

  • A page view is recorded for every route change once the visitor has consented. There is nothing to call. Jumping to an anchor on the same page, such as #reviews, is not a new page view.
  • Fire conversions the same way as on any site, from whichever route they happen on. They count for the version the visitor saw, even when the conversion happens on a route that is not part of a campaign.
  • Using a tag manager? Never fire Optimeleon from a History Change trigger. See Google Tag Manager.

Consent

Consent carries across route changes. Your cookie banner passes the visitor's choice on each full page load, as described in Consent & cookies, but not again after each navigation inside the app.

To make going back instant, Optimeleon remembers the version of each page already opened in the tab. Before consent that is held in memory only. After consent it is kept in the tab's session storage as __opti_route_cache*, which is in the storage reference, and it is cleared when the tab closes or consent is withdrawn.

Event hooks on route changes

variant.decided and variant.applied fire again each time the visitor moves to another page that is being optimized, so a subscriber can follow the navigation without polling. ready, page.revealed and consent.resolved fire once per full page load. See Event hooks.