BOOMR.plugins. Continuity

The Continuity plugin measures performance and user experience metrics beyond just the traditional Page Load timings.


The goal of the Continuity plugin is to capture the important aspects of your visitor's overall user experience during page load and beyond. For example, the plugin measures when the site appeared Visually Ready, and when it was Interactive.

In addition, the Continuity plugin captures in-page interactions (such as keys, clicks and scrolls), and monitors how the site performed when responding to these inputs.

Finally, the Continuity plugin is utilizing cutting-edge browser performance APIs like LongTasks to get important insights into how the browser is performing.

Here are some of the metrics that the Continuity plugin captures:

  • Timers:
    • Time to Visually Ready: When did the user feel like they could interact with the site? When did it look ready? (see below for details)
    • Time to Interactive: After the page was Visually Ready, when was the first time the user could have interacted with the site, and had a good (performant) experience? (see below for details)
    • Time to First Interaction: When was the first time the user tried to interact (key, click or scroll) with the site?
    • First Input Delay: For the first interaction on the page, how responsive was it?
  • Interaction metrics:
    • Interactions: Keys, mouse movements, clicks, and scrolls (counts and an event log)
    • Delayed Interactions: How often was the user's interaction delayed more than 50ms?
    • Rage Clicks: Did the user repeatedly clicked on the same element/region?
  • Page performance metrics:
    • Frame Rate data: FPS during page load, minimum FPS, number of long frames
    • Long Task data: Number of Long Tasks, how much time they took, attribution to what caused them
    • Page Busy: Measurement of the page's busyness

This data is captured during the page load, as well as when the user later interacts with the site (if configured via afterOnload). These metrics are reported at regular intervals, so you can see how they change over time.

If configured, the Continuity plugin can send additional beacons after a page interaction happens (via monitorInteractions).


The Continuity plugin has a variety of options to configure what it does (and what it doesn't do):

Monitoring Long Tasks

If monitorLongTasks is turned on, the Continuity plugin will monitor Long Tasks (if the browser supports it).

Long Tasks represent work being done on the browser's UI thread that monopolize the UI thread and block other critical tasks from being executed (such as reacting to user input). Long Tasks can be caused by anything from JavaScript execution, to parsing, to layout. The browser fires LongTask events (via the PerformanceObserver) when a task takes over 50 milliseconds to execute.

Long Tasks are important to measure as a Long Task will block all other user input (e.g. clicks, keys and scrolls).

Long Tasks are powerful because they can give attribution about what component caused the task, i.e. the source JavaScript file.

If monitorLongTasks is enabled:

  • A PerformanceObserver will be turned on to capture all Long Tasks that happen on the page.
  • Long Tasks will be used to calculate Time to Interactive
  • A log (, timeline ( and other Long Task metrics (*) will be added to the beacon (see Beacon Parameters details below)

The log is a JSON (or JSURL) object of compressed LongTask data. See the source code for what each attribute maps to.

Long Tasks are currently a cutting-edge browser feature and will not be available in older browsers.

Enabling Long Tasks should not have a performance impact on the page load experience, as collecting of the tasks are via the lightweight PerformanceObserver interface.

Monitoring Page Busy

If monitorPageBusy is turned on, the Continuity plugin will measure Page Busy.

Page Busy is a way of measuring how much work was being done on the page (how "busy" it was). Page Busy is calculated via setInterval() polling: a timeout is scheduled on the page at a regular interval, and busyness is detected if that timeout does not fire at the time it was expected to.

Page Busy is a percentage -- 100% means that the browser was entirely busy doing other things, while 0% means the browser was idle.

Page Busy is just an estimate, as it uses sampling. As an example, if you have a high number of small tasks that execute frequently, Page Busy might run at a frequency that it either detects 100% (busy) or 0% (idle).

Page Busy is not the most efficient way of measuring what the browser is doing, but since it is calculated via setInterval(), it is supported in all browsers. The Continuity plugin currently measures Page Busy by polling every 32 milliseconds.

Page Busy can be an indicator of how likely the user will have a good experience when they interact with it. If Page Busy is 100%, the user may see the page lag behind their input.

If monitorPageBusy is enabled:

  • The Page Busy monitor will be active (polling every 32 milliseconds) (unless Long Tasks is supported and enabled)
  • Page Busy will be used to calculate Time to Interactive
  • A timeline (c.t.busy) and the overall Page Busy % (c.b) will be added to the beacon (see Beacon Parameters details below)

Enabling Page Busy monitoring should not have a noticable effect on the page load experience. The 32-millisecond polling is lightweight and should barely register on JavaScript CPU profiles.

Monitoring Frame Rate

If monitorFrameRate is turned on, the Continuity plugin will measure the Frame Rate of the page via requestAnimationFrame.

requestAnimationFrame is a browser API that can be used to schedule animations that run at the device's refresh rate. It can also be used to measure how many frames were actually delivered to the screen, which can be an indicator of how good the user's experience is.

requestAnimationFrame is available in all modern browsers.

If monitorFrameRate is enabled:

  • requestAnimationFrame will be used to measure Frame Rate
  • Frame Rate will be used to calculate Time to Interactive
  • A timeline (c.t.fps) and many Frame Rate metrics (c.f.*) will be added to the beacon (see Beacon Parameters details below)

Enabling Frame Rate monitoring should not have a noticable effect on the page load experience. The frame callback may happen up to the device's refresh rate (which is often 60 FPS), and the work done in the callback should be barely visible in JavaScript CPU profiles (often less than 5ms over a page load).

Monitoring Interactions

If monitorInteractions is turned on, the Continuity plugin will measure user interactions during the page load and beyond.

Interactions include:

  • Mouse Clicks: Where the user clicked on the screen
    • Rage Clicks: Clicks to the same area repeatedly
  • Mouse Movement: Rough mouse movement will be tracked, but these interactions will not send a beacon on their own, nor be used for Time to First Interaction calculations.
  • Keyboard Presses: Individual key codes are not captured
  • Scrolls: How frequently and far the user scrolled
    • Distinct Scrolls: Scrolls that happened over 2 seconds since the last scroll
  • Page Visibility changes
  • Orientation changes

These interactions are monitored and instrumented throughout the page load. By using the event's timeStamp, we can detect how long it took for the physical event (e.g. mouse click) to execute the JavaScript listening handler (in the Continuity plugin). If there is a delay, this is tracked as an Interaction Delay. Interaction Delays can be an indicator that the user is having a degraded experience.

The very first interaction delay will be added to the beacon as the First Input Delay - this is tracked as the user's first experience with your site is important.

In addition, if afterOnLoad is enabled, these interactions (except Mouse Movements) can also trigger an interaction beacon after the Page Load. afterOnLoadMaxLength can be used to control how many milliseconds after Page Load interactions will be measured for.

After a post-Load interaction occurs, the plugin will wait for afterOnLoadMinWait milliseconds before sending the interaction beacon. If another interaction happens within that timeframe, the plugin will wait another afterOnLoadMinWait milliseconds. This is to ensure that groups of interactions will be batched together. The plugin will wait up to 60 seconds to batch groups of interactions together, at which point a beacon will be sent immediately.

If monitorInteractions is enabled:

  • Passive event handlers will be added to monitor clicks, keys, etc.
  • A log and many interaction metrics (c.f.*) will be added to the beacon (see Beacon Parameters details below)

For interaction beacons, the following will be set:

  • rt.tstart will be the timestamp of the first interaction
  • rt.end will be the timestamp of the last interaction
  • rt.start = 'manual'
  • http.initiator = 'interaction'

Enabling interaction monitoring will add lightweight passive event handlers to scroll, click, mousemove and keydown events. These event handlers should not delay the user's interaction, and are used to measure delays and keep a log of interaction events.

Monitoring Page Statistics

If monitorStats is turned on, the Continuity plugin will measure statistics about the page and browser over time.

These statistics include:

  • Memory Usage: usedJSHeapSize (Chrome-only)
  • Battery Level
  • DOM Size: Number of bytes of HTML in the root frame
  • DOM Length: Number of DOM nodes in the root frame
  • Mutations: How often and how much the page is changing

If monitorStats is enabled:

  • Events and polls will be setup to monitor the above statistics
  • A timeline (c.t.*) of these statistics will be added to the beacon (see details below)

Enabling Page Statistic monitoring adds a poll to the page every second, gathering the above statistics. These statistics should take less than 5ms JavaScript CPU on a desktop browser each poll, but this monitoring is probably the most expensive of the Continuity plugin monitors.

New Timers

There are 4 new timers from the Continuity plugin that center around user interactions:

  • Time to Visually Ready (VR)
  • Time to Interactive (TTI)
  • Time to First Interaction (TTFI)
  • First Input Delay (FID)

Time to Interactive (TTI), at it's core, is a measurement (timestamp) of when the page was interact-able. In other words, at what point does the user both believe the page could be interacted with, and if they happened to try to interact with it then, would they have a good experience?

To calculate Time to Interactive, we need to figure out two things:

  • Does the page appear to the visitor to be interactable?
    • We'll use one or more Visually Ready Signals to determine this
  • If so, what's the first time a user could interact with the page and have a good experience?
    • We'll use several Time to Interactive Signals to determine this

Visually Ready

For the first question, "does the page appear to be interactable?", we need to determine when the page would look to the user like they could interact with it.

It's only after this point that TTI could happen. Think of Visually Ready (VR) as the anchor point of TTI -- it's the earliest possible timestamp in the page's lifecycle that TTI could happen.

We have a few signals that might be appropriate to use as Visually Ready:

  • First Paint (if available)
    • We should wait at least for the first paint on the page
    • i.e. IE's msFirstPaint or Chrome's firstPaintTime
    • These might just be paints of white, so they're not the only signal we should use
  • First Contentful Paint (if available)
  • domContentLoadedEventEnd
    • "The DOMContentLoaded event is fired when the initial HTML document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading"
    • This happens after domInteractive
    • Available in NavigationTiming browsers via a timestamp and all other browser if we're on the page in time to listen for readyState change events
  • Hero Images (if defined)
    • Instead of tracking all Above-the-Fold images, it could be useful to know which specific images are important to the site owner
    • Defined via a simple CSS selector (e.g. .hero-images)
    • Can be measured via ResourceTiming
    • Will add Hero Images Ready c.tti.hi to the beacon
  • "My Framework is Ready" (if defined)
    • A catch-all for other things that we can't automatically track
    • This would be an event or callback from the page author saying their page is ready
    • They could fire this for whatever is important to them, i.e. when their page's click handlers have all registered
    • Will add Framework Ready to the beacon

Once the last of all of the above have happened, Visually Ready has occurred.

Visually Ready will add c.tti.vr to the beacon.

Controlling Visually Ready via Framework Ready

There are two additional options for controlling when Visually Ready happens: via Framework Ready or Hero Images.

If you want to wait for your framework to be ready (e.g. your SPA has loaded or a button has a click handler registered), you can add an option ttiWaitForFrameworkReady.

Once enabled, TTI won’t be calculated until the following is called:

// my framework is ready
if (BOOMR && BOOMR.plugins && BOOMR.plugins.Continuity) {

Controlling Visually Ready via Hero Images

If you want to wait for your hero/main images to be loaded before Visually Ready is measured, you can give the plugin a CSS selector via ttiWaitForHeroImages. If set, Visually Ready will be delayed until all IMGs that match that selector have loaded, e.g.:

window.BOOMR_config = {
  Continuity: {
    enabled: true,
    ttiWaitForHeroImages: ".hero-image"

Note this only works in ResourceTiming-supported browsers (and won’t be used in older browsers).

If no images match the CSS selector at Page Load, this setting will be ignored (the plugin will not wait for a match).

Time to Interactive

After the page is Visually Ready for the user, if they were to try to interact with the page (click, scroll, type), when would they have a good experience (i.e. the page responded in a satisfactory amount of time)?

We can use some of the signals below, when available:

  • Frame Rate (FPS)
    • Available in all modern browsers: by using requestAnimationFrame we can get a sense of the overall frame rate (FPS)
    • To ensure a "smooth" page load experience, ideally the page should never drop below 20 FPS.
    • 20 FPS gives about 50ms of activity to block the main thread at any one time
  • Long Tasks
    • Via the PerformanceObserver, a Long Tasks fires any time the main thread was blocked by a task that took over 50ms such as JavaScript, layout, etc
    • Great indicator both that the page would not have been interact-able and in some cases, attribution as to why
  • Page Busy via setInterval
    • By measuring how long it takes for a regularly-scheduled callback to fire, we can detect other tasks that got in the way
    • Can give an estimate for Page Busy Percentage (%)
    • Available in every browser
  • Delayed interactions
    • If the user interacted with the page and there was a delay in responding to the input

The waitAfterOnload option will delay the beacon for up to that many milliseconds if Time to Interactive doesn't happen by the browser's load event. You shouldn't set it too high, or the likelihood that the page load beacon will be lost increases (because of the user navigating away first, or closing their browser). If waitAfterOnload is reached and TTI hasn't happened yet, the beacon will be sent immediately (missing the TTI timer).

If you set waitAfterOnload to 0 (or it's not set), Boomerang will send the beacon at the regular page load event. If TTI didn’t yet happen, it won’t be reported.

If you want to set waitAfterOnload, we'd recommend a value between 1000 and 5000 (1 and 5 seconds).

Time to Interaction will add c.tti to the beacon. It will also add c.tti.m, which is the higest-accuracy method available for TTI calculation: lt (Long Tasks), raf (FPS), or b (Page Busy).


Putting these two timers together, here's how we measure Visually Ready and Time to Interactive:

  1. Determine the highest Visually Ready timestamp (VRTS):

    • First Contentful Paint (if available)
    • First Paint (if available)
    • domContentLoadedEventEnd
    • Hero Images are loaded (if configured)
    • Framework Ready (if configured)
  2. After VRTS, calculate Time to Interactive by finding the first period of 500ms where all of the following are true:

    • There were no Long Tasks
    • The FPS was always above 20 (if available)
    • Page Busy was less than 10% (if the above aren't available)

Time to First Interaction

Time to First Interaction (TTFI) is the first time a user interacted with the page. This may happen during or after the page's load event.

Time to First Interaction will add c.ttfi to the beacon.

If the user does not interact with the page by the beacon, there will be no c.ttfi on the beacon.

First Input Delay

If the user interacted with the page by the time the beacon was sent, the Continuity plugin will also measure how long it took for the JavaScript event handler to fire.

This can give you an indication of the page being otherwise busy and unresponsive to the user if the callback is delayed.

This time (measured in milliseconds) is added to the beacon as c.fid.


If sendTimeline is enabled, many of the above options will add bucketed "timelines" to the beacon.

The Continuity plugin keeps track of statistics, interactions and metrics over time by keeping track of these counts at a granularity of 100-millisecond intervals.

As an example, if you are measuring Long Tasks, its timeline will have entries whenever a Long Task occurs.

Not every timeline will have data for every interval. As an example, the click timeline will be sparse except for the periods where there was a click. Statistics like DOM Size are captured only once every second. The Continuity plugin is optimized to use as little memory as possible for these cases.

Compressed Timeline Format

If sendTimeline is enabled, the Continuity plugin will add several timelines as c.t.[name] to the beacon in a compressed format.

An example timeline may look like this:

c.t.fps      = 03*a*657576576566766507575*8*65
c.t.domsz    = 11o3,1o4
c.t.mousepct = 2*5*0053*4*00050718

The format of the compressed timeline is as follows:

[Compression Type - 1 character][Data - everything else]

  • Compression Type is a single character that denotes how each timeline's bucket numbers are compressed:
    • 0 (for smaller numbers):
      • Each number takes a single character, encoded in Base-64
      • If a number is >= 64, the number is converted to Base-36 and wrapped in . characters
    • 1 (for larger numbers)
      • Each number is separated by ,s
      • Each number is encoded in Base-36
    • 2 (for percentages)
      • Each number takes two characters, encoded in Base-10
      • If a number is <= 0, it is 00
      • If a number is >= 100, it is __

In addition, for repeated numbers, the format is as follows:

*[Repeat Count]*[Number]


  • Repeat Count is encoded Base-36
  • Number is encoded per the rules above

From the above example, the data would be decompressed to:

c.t.fps =
    [3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 7, 5, 7, 6, 5, 7, 6, 5, 6, 6, 7, 6,
    6, 5, 0, 7, 5, 7, 5, 6, 6, 6, 6, 6, 6, 6, 6, 5];

c.t.domsz = [2163, 2164];

c.t.mousepct = [0, 0, 0, 0, 0, 53, 0, 5, 7, 18];

The timeline can be decompressed via decompressBucketLog (for debug builds).

The Continuity Epoch (c.e) and Continuity Last Beacon ( are timestamps (Base-36) that indicate what timestamp the first bucket represents. If both are given, the Last Beacon timestamp should be used.

For example:

c.e=j5twmlbv       // 1501611350395      // 1501611351212
c.t.domsz=11o3,1o4 // 2163, 2164 using method 1

In the above example, the first value of 2163 (1o3 Base-36) happened at 1501611351212. The second value of 2164 (1o4 Base-36) happened at 1501611351212 + 100 = 1501611351312.

For all of the available timelines, see the Beacon Parameters list below.


If sendLog is enabled, the Continuity plugin will add a log to the beacon as c.l.

The following events will generate a Log entry with the listed parameters:

  • Scrolls (type 0):
    • y: Y pixels
  • Clicks (type 1):
    • x: X pixels
    • y: Y pixels
  • Mouse Movement (type 2):
    • Data is captured at minimum 10 pixel granularity
    • x: X pixels
    • y: Y pixels
  • Keyboard presses (type 3):
    • (no data is captured)
  • Visibility Changes (type 4):
    • s
      • 0: visible
      • 1: hidden
      • 2: prerender
      • 3: unloaded
  • Orientation Changes (type 5):
    • a: Angle

The log is put on the beacon in a compressed format. Here is an example log:


The format of the compressed timeline is as follows:

[Type][Timestamp],[Param1 type][Param 1 value],[... Param2 ...]|[... Event2 ...]
  • Type is a single character indicating what type of event it is, per above
  • Timestamp (navigationStart epoch in milliseconds) is Base-36 encoded
  • Each parameter follows, separated by commas:
    • The first character indicates the type of parameter
    • The subsequent characters are the value of the parameter, Base-36 encoded

From the above example, the data would be decompressed to:

        "type": "mouse",
        "time": 1474,
        "x": 729,
        "y": 313
        "type": "click",
        "time": 5268,
        "x": 725,
        "y": 319
        "type": "key",
        "time": 5921,

The plugin will keep track of the last logMaxEntries entries in the log (default 100).

The timeline can be decompressed via decompressLog (for debug builds).


When enabled, the Continuity plugin adds new layers of instrumentation to each page load. It also keeps some of this instrumentation enabled after the load event, if configured. By default, these instrumentation "monitors" will be turned on:

  • Long Tasks via PerformanceObserver
  • Frame Rate (FPS) via requestAnimationFrame
  • Page Busy via setInterval polling (if Long Tasks aren't supported)
  • Monitoring of interactions such as mouse clicks, movement, keys, and scrolls
  • Page statistics like DOM size/length, memory usage, and mutations

Each of these monitors is designed to be as lightweight as possible, but enabling instrumentation will always incur non-zero CPU time. Please read the above sections for overhead information on each monitor.

With the Continuity plugin enabled, during page load, you may see the plugin's total CPU usage over the entire length of that page load reach 10-35ms, depending on the hardware and makeup of the host-site. In general, for most modern websites, this means Boomerang should still only account for a few percentage points of overall page CPU usage with the Continuity plugin enabled.

The majority of this CPU usage increase is from Page Statistics reporting and FPS monitoring. You can disable either of these monitors individually if desired (monitorStats and monitorFrameRate).

During idle periods (after page load), the Continuity plugin will continue monitoring the above items if afterOnload is enabled. This may increase Boomerang JavaScript CPU usage as well. Again, the majority of this CPU usage increase is from Page Statistic reporting and Frame Rate monitoring, and can be disabled.

When Long Tasks aren't supported by the browser, Page Busy monitoring via setInterval should only 1-2ms CPU during and after page load.

Beacon Parameters

The following parameters will be added to the beacon:

  • c.e: Continuity Epoch timestamp (when everything started measuring) (Base-36)
  • c.l: Log (compressed)
  • Long Task data (compressed)
  • Number of Long Tasks (Base-10)
  • Total duration of Long Tasks (Base-10)
  • c.b: Page Busy percentage (Base-10)
  • c.t.fps: Frame Rate timeline (compressed)
  • c.t.inter: Interactions timeline (compressed)
  • c.t.interdly: Delayed Interactions timeline (compressed)
  • c.t.key: Keyboard press timeline (compressed)
  • Click timeline (compressed)
  • c.t.mouse: Mouse movements timeline (compressed)
  • c.t.mousepct: Mouse movement percentage (of full screen) timeline (compressed)
  • c.t.mem: Memory usage timeline (compressed)
  • c.t.domsz: DOM Size timeline (compressed)
  • c.t.domln: DOM Length timeline (compressed)
  • c.t.mut: DOM Mutations timeline (compressed)
  • c.tti.vr: Visually Ready (Base-10)
  • c.tti.hi: Hero Images ready (Base-10)
  • Framework Ready (Base-10)
  • c.tti.m: Time to Interactive Method (lt, raf, b)
  • c.tti: Time to Interactive (Base-10)
  • c.f: Average Frame Rate over the Frame Rate Duration (Base-10)
  • c.f.d: Frame Rate duration (how long it has been measuring) (Base-10)
  • c.f.m: Minimum Frame Rate (Base-10)
  • c.f.l: Number of Long Frames (>= 50ms) (Base-10)
  • c.f.s: Frame Rate measurement start time (Base-36)
  • c.k: Keyboard event count (Base-10)
  • c.k.e: Keyboard ESC count (Base-10)
  • c.c: Click count (Base-10)
  • c.c.r: Rage click count (Base-10)
  • c.m.p: Mouse movement percentage (Base-10)
  • c.m.n: Mouse movement pixels (Base-10)
  • c.ttfi: Time to First Interactive (Base-10)
  • c.i.dc: Delayed interaction count (Base-10)
  • c.i.dt: Delayed interaction time (Base-10)
  • c.i.a: Average interaction delay (Base-10)
  • c.fid: First Input Delay (Base-10)
  • Last Beacon timestamp (Base-36)
  • c.s: Scroll count (Base-10)
  • c.s.p: Scroll percentage (Base-10)
  • c.s.y: Scroll y (pixels) (Base-10)
  • c.s.d: Distinct scrolls (scrolls that happen 2 seconds after the last) (Base-10)




Signal that the framework is ready


Initializes the plugin.


Name Type Description
config object


Name Type Argument Default Description
Continuity.monitorLongTasks boolean <optional>

Whether or not to monitor Long Tasks.

Continuity.monitorPageBusy boolean <optional>

Whether or not to monitor Page Busy.

Continuity.monitorFrameRate boolean <optional>

Whether or not to monitor Frame Rate.

Continuity.monitorInteractions boolean <optional>

Whether or not to monitor Interactions.

Continuity.monitorStats boolean <optional>

Whether or not to monitor Page Statistics.

Continuity.afterOnload boolean <optional>

Whether or not to monitor Long Tasks, Page Busy, Frame Rate, interactions and Page Statistics after onload (up to afterOnloadMaxLength).

Continuity.afterOnloadMaxLength number <optional>

Maximum time (milliseconds) after onload to monitor.

Continuity.afterOnloadMinWait boolean <optional>

Minimum time after an interaction to wait for more interactions before batching the interactions into a beacon.

Continuity.waitAfterOnload boolean | number <optional>

If set to a number, how long after onload to wait for Time to Interactive to happen before sending a beacon (without TTI).

Continuity.ttiWaitForFrameworkReady boolean <optional>

Whether or not to wait for BOOMR.plugins.Continuity.frameworkReady before Visually Ready (and thus Time to Interactive) can happen.

Continuity.ttiWaitForHeroImages boolean | string <optional>

If set to a string, the CSS selector will wait until the specified images have been loaded before Visually Ready (and thus Time to Interactive) can happen.

Continuity.sendLog boolean <optional>

Whether or not to send the event log with each beacon.

Continuity.logMaxEntries boolean <optional>

How many log entries to keep.

Continuity.sendTimeline boolean <optional>

Whether or not to send the timeline with each beacon.


BOOMR.plugins.Continuity The Continuity plugin for chaining


Whether or not this plugin is complete


Type: boolean

true if the plugin is complete