Flare by Spatie
    • Error Tracking
    • Performance Monitoring
    • Logs
  • Pricing
  • Docs
  • Insights
  • Changelog
  • Back to Flare ⌘↵ Shortcut: Command or Control Enter
  • Sign in
  • Try Flare for free
  • Error Tracking
  • Performance Monitoring
  • Logs
  • Pricing
  • Docs
  • Insights
  • Changelog
    • Back to Flare ⌘↵ Shortcut: Command or Control Enter
    • Try Flare for free
    • Sign in
Flare Flare PHP PHP JavaScript JavaScript Protocol Protocol
JavaScript
  • PHP
  • JavaScript
  • General
  • Introduction
  • Sending data
  • Events
  • Errors
  • Attributes
  • Sourcemaps
  • Traces
  • Lifecycle
  • Web vitals
  • Aggregations
  • Shared by all clients
  • Entry points
  • Resources
  • Attribute formats
  • Errors payload
  • Traces payload
  • Logs payload

Events

View as Markdown

Event is the umbrella term for two things. A span is an operation with a duration, like a page load or a fetch call. A span event is something that happened at a single moment inside a span.

This page lists the span types a browser client sends. For the payload they go in, see the traces payload and the errors payload. For the types a PHP client sends, see Events in the PHP protocol docs.

You set the type with the flare.span_type attribute on the span. Flare removes that attribute before it shows the span, so it never appears in the interface.

Page spans

browser_pageload and browser_navigation are container spans. Every other browser span points back at one of them through its parentSpanId chain.

The two carry the same attributes. A browser_pageload is the browser loading a document. A browser_navigation is your router swapping the view without loading a new document.

browser_pageload

The initial page load.

Backdate the start of this span to the browser's navigation start rather than to the moment your script ran. The Navigation Timing entry gives you that. Otherwise the span misses everything that happened before your bundle loaded, which is usually the slow part.

Since it is the root of the trace, it carries the entry point attributes. For a browser page that means flare.entry_point.type is web, flare.entry_point.handler.type is browser, flare.entry_point.value is the full URL, and flare.entry_point.handler.identifier is the route. On top of those:

Attribute Type Description
http.route string The route, the same value as flare.entry_point.handler.identifier
flare.route.source string route if a router gave you the pattern, url if you fell back to the path
url.full string Full page URL, redacted
user_agent.original string User agent string
http.request.referrer string Referrer URL, redacted
document.ready_state string Document ready state when the span opened

It can also carry browser.web_vital.* attributes for any vital that was final before the span closed. See Web vitals.

Flare groups page performance on http.route. Leave it out and the trace still works, but the page will not show up in the Browser Pages numbers.

flare.entry_point.handler.identifier is what Flare shows as the label of the span in a trace.

Getting the route right

The route should be the route pattern, not the URL the user landed on. Send /products/{id}, not /products/9f2c. If you send the concrete path, every product page becomes its own aggregation and the numbers are useless.

Set flare.route.source to route when a router gave you the pattern and url when you had to fall back to location.pathname. Flare shows this so people know whether they are looking at real route grouping or raw paths.

Routers often know where they are going before the address bar changes. If you open the span against that destination and the URL then changes, because of a redirect or because a newer navigation replaced it, update url.full and flare.entry_point.value on the open span. Leave the two route attributes alone. Deriving them again from the new URL turns your pattern back into a concrete path.

browser_navigation

A client-side route change. Same attributes as browser_pageload.

Vitals never belong here. They measure the document, and a client-side route change does not load a new one.

Request spans

browser_fetch

A request made with fetch.

Attribute Type Description
url.full string Request URL, redacted
http.request.method string HTTP method
server.address string Request host, when the URL resolved against the page origin
http.response.status_code int Response status code

Flare needs both url.full and http.request.method to group the request. It reads the host and path out of url.full, so sending server.address on its own is not enough.

browser_xhr

A request made with XMLHttpRequest. Same attributes as browser_fetch.

Keep the two types separate even though they end up in the same aggregation. Most application code uses fetch these days, so an XMLHttpRequest usually points at a library rather than at something you wrote.

Component spans

browser_component

A component mount.

Attribute Type Description
flare.component.name string Component name. Flare uses the span name when this is missing

Three rules make a component tree come out right.

Point at the nearest profiled ancestor. Set parentSpanId to the span of the closest profiled component above this one, and to the container when there is none. Spans travel as a flat list, so parentSpanId is the only record of which component sat inside which. Point them all at the container and the tree flattens to one level. The lifecycle page shows a flat list and the tree Flare builds from it side by side.

Skip the components you are not profiling. Profiling is usually opt-in per component, so the nearest profiled ancestor is often not the direct parent in your component tree. An unprofiled component in between is passed over, and its children attach to the closest profiled component above it.

Reserve the parent's id early. Components finish mounting from the inside out, so a child's span normally ends before its parent's. You therefore need the parent's spanId before the parent's span exists. Generate that id when the component starts mounting, not when it finishes.

A child may then appear earlier in the spans array than its parent. That is fine. Flare reads the whole payload before it resolves parents, so the order inside the array carries no meaning.

Flare works out which framework a component belongs to from the flare.framework.name resource attribute, not from the span. That value is lowercase, for example react, vue, svelte or sveltekit.

Web vital spans

browser_web_vital

A zero duration span carrying the vitals that were not ready in time to be added to the page span. Its timestamps and its parent reference both behave differently from every other span, so it has its own page: Web vitals.

Span event types

A browser client sends one span event type. Everything else in a browser trace is a span.

php_glow

A short note the developer left behind for debugging context. It goes in the events array of an error report, not in a trace.

Attribute Type Description
glow.name string Glow name
glow.level string Glow level
glow.context object Glow context data

The php_ prefix is a leftover. The browser client sends the same type string the PHP client does, so the value included in the payload really is php_glow. Since span events are something getting deprecated in the OTel spec, we did not want to introduce a new glow type just for JavaScript.

Example

A page load that fetched some data and mounted two components:

{
    "resourceSpans": [
        {
            "resource": {
                "attributes": [
                    { "key": "service.name", "value": { "stringValue": "Acme Storefront" } },
                    { "key": "telemetry.sdk.language", "value": { "stringValue": "javascript" } },
                    { "key": "telemetry.sdk.name", "value": { "stringValue": "@flareapp/js" } },
                    { "key": "telemetry.sdk.version", "value": { "stringValue": "2.6.0" } },
                    { "key": "flare.language.name", "value": { "stringValue": "javascript" } },
                    { "key": "flare.framework.name", "value": { "stringValue": "react" } }
                ],
                "droppedAttributesCount": 0
            },
            "scopeSpans": [
                {
                    "scope": { "name": "@flareapp/js", "version": "2.6.0" },
                    "spans": [
                        {
                            "traceId": "8d4f1a2b3c5e607988d4f1a2b3c5e079",
                            "spanId": "1a2b3c4d5e6f7081",
                            "parentSpanId": null,
                            "name": "/products/{id}",
                            "startTimeUnixNano": 1710252000000000000,
                            "endTimeUnixNano": 1710252001240000000,
                            "status": { "code": 0 },
                            "attributes": [
                                { "key": "flare.span_type", "value": { "stringValue": "browser_pageload" } },
                                { "key": "flare.entry_point.type", "value": { "stringValue": "web" } },
                                { "key": "flare.entry_point.value", "value": { "stringValue": "https://acme.test/products/9f2c" } },
                                { "key": "flare.entry_point.handler.type", "value": { "stringValue": "browser" } },
                                { "key": "flare.entry_point.handler.identifier", "value": { "stringValue": "/products/{id}" } },
                                { "key": "http.route", "value": { "stringValue": "/products/{id}" } },
                                { "key": "flare.route.source", "value": { "stringValue": "route" } },
                                { "key": "url.full", "value": { "stringValue": "https://acme.test/products/9f2c" } },
                                { "key": "document.ready_state", "value": { "stringValue": "loading" } },
                                { "key": "browser.web_vital.ttfb", "value": { "doubleValue": 148 } },
                                { "key": "browser.web_vital.fcp", "value": { "doubleValue": 612 } }
                            ],
                            "droppedAttributesCount": 0,
                            "events": [],
                            "droppedEventsCount": 0
                        },
                        {
                            "traceId": "8d4f1a2b3c5e607988d4f1a2b3c5e079",
                            "spanId": "2b3c4d5e6f708192",
                            "parentSpanId": "1a2b3c4d5e6f7081",
                            "name": "GET /api/products/9f2c",
                            "startTimeUnixNano": 1710252000310000000,
                            "endTimeUnixNano": 1710252000602000000,
                            "status": { "code": 0 },
                            "attributes": [
                                { "key": "flare.span_type", "value": { "stringValue": "browser_fetch" } },
                                { "key": "http.request.method", "value": { "stringValue": "GET" } },
                                { "key": "url.full", "value": { "stringValue": "https://acme.test/api/products/9f2c" } },
                                { "key": "server.address", "value": { "stringValue": "acme.test" } },
                                { "key": "http.response.status_code", "value": { "intValue": 200 } }
                            ],
                            "droppedAttributesCount": 0,
                            "events": [],
                            "droppedEventsCount": 0
                        },
                        {
                            "traceId": "8d4f1a2b3c5e607988d4f1a2b3c5e079",
                            "spanId": "3c4d5e6f708192a3",
                            "parentSpanId": "1a2b3c4d5e6f7081",
                            "name": "ProductPage",
                            "startTimeUnixNano": 1710252000640000000,
                            "endTimeUnixNano": 1710252000905000000,
                            "status": { "code": 0 },
                            "attributes": [
                                { "key": "flare.span_type", "value": { "stringValue": "browser_component" } },
                                { "key": "flare.component.name", "value": { "stringValue": "ProductPage" } }
                            ],
                            "droppedAttributesCount": 0,
                            "events": [],
                            "droppedEventsCount": 0
                        },
                        {
                            "traceId": "8d4f1a2b3c5e607988d4f1a2b3c5e079",
                            "spanId": "4d5e6f708192a3b4",
                            "parentSpanId": "3c4d5e6f708192a3",
                            "name": "PriceTag",
                            "startTimeUnixNano": 1710252000701000000,
                            "endTimeUnixNano": 1710252000748000000,
                            "status": { "code": 0 },
                            "attributes": [
                                { "key": "flare.span_type", "value": { "stringValue": "browser_component" } },
                                { "key": "flare.component.name", "value": { "stringValue": "PriceTag" } }
                            ],
                            "droppedAttributesCount": 0,
                            "events": [],
                            "droppedEventsCount": 0
                        }
                    ]
                }
            ]
        }
    ]
}

PriceTag points at ProductPage, not at the page load, because it mounted inside it.

The spans are listed parent first here so the example reads well. A real client sends them in completion order, so children come before parents. Either is fine, since Flare reads the whole payload before resolving parents. See Lifecycle.

Two vitals are added to the page span because they were measured before the pageload span closed. The other three vitals arrive later, in a second request, on a browser_web_vital span.

Every timestamp is a JSON integer. Sending one as a string is a validation error, and so is a value with a fraction left over from converting milliseconds. See Sending data.

Sending data Attributes

On this page

  • Page spans
  • Request spans
  • Component spans
  • Web vital spans
  • Span event types
  • Example

Catch errors and fix slowdowns with Flare, the full-stack application monitoring platform for Laravel, PHP & JavaScript.

  • Platform
  • Error Tracking
  • Performance Monitoring
  • Pricing
  • Support
  • Resources
  • Insights
  • Newsletter
  • Changelog
  • Documentation
  • Affiliate program
  • uptime status badge Service status
  • Terms of use
  • DPA
  • Privacy & cookie Policy
Made in by Spatie logo
Flare