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

Sending data

View as Markdown

The three ingestion endpoints are the same for every client. What differs in a browser is how you reach them: which key you may use, why a request can be rejected on its origin, how to write a timestamp in JavaScript, and how to get the last batch out while the page is closing.

For the endpoints themselves, see Errors payload, Traces payload and Logs payload.

Use the public project key

A browser client authenticates with your project's public API key, in the x-api-token header, on all three endpoints.

Never ship the private key. Everything in a bundle can be read by anyone who opens the page, so a private key in front-end code is a leaked private key. The public key is built for this: it can send telemetry and upload sourcemaps, and nothing else.

The sourcemap endpoint also takes the public key, but reads it from a key field in the body instead of from a header.

The origin allowlist

Because a public key travels with your bundle, a project can list the domains it accepts browser traffic from. Flare checks that list at the edge, before anything else happens to your payload.

  • The check reads the Origin header, and falls back to the hostname of Referer when Origin is absent.
  • When neither yields a hostname, or the hostname is not on the list, the request is rejected with 403 and the message Origin is not allowed for this public key.
  • An empty list allows every origin. That is the default, so a new project sends without configuring anything.
  • Requests made with the private key skip the check, so server-side code is never affected by it.

A pattern may contain *, as in *.example.com. A pattern without a * has to equal the hostname, so example.com does not match app.example.com.

Changes to the list need up to about 90 seconds to reach the edge. Someone who corrects their allowlist and immediately retries still gets the 403.

The rejection is a real response, not a CORS failure

Preflight requests always answer with Access-Control-Allow-Origin: *, including for an origin that is not allowed. The rejection then arrives as an ordinary 403 that your client can read, log and report on. Rejecting at preflight instead would surface in the browser as an opaque CORS error, which tells you nothing about what went wrong.

Writing timestamps in JavaScript

The traces endpoint requires JSON integers. startTimeUnixNano, endTimeUnixNano and a span event's timeUnixNano are rejected with a validation error when you send them as strings.

The logs endpoint is looser: timeUnixNano and observedTimeUnixNano accept an integer or a string.

Two things follow from that in JavaScript.

Round before you send. Date.now() and performance.now() both give milliseconds, so you multiply by one million to get nanoseconds. That multiplication can leave a fraction, and a fractional value is not an integer, so the traces endpoint rejects it. Round the result.

Expect the last few digits to move. A nanosecond timestamp is around 1.7e18, well past Number.MAX_SAFE_INTEGER. A JavaScript number still holds a value that size, but only to roughly 256 nanoseconds of resolution. That is far finer than anything a browser clock measures, so no real timing information is lost. It does mean the number is not an exact identifier: never use a timestamp to tell two spans apart, use the span id. Copying a timestamp from one span to another is fine, as web vitals requires, because the same number goes out both times.

Getting the last batch out

Sending one request per span would be wasteful, so spans and log records are collected and sent in batches. The batch that is still buffered when the visitor leaves is the one that needs care.

Start the final flush when the document becomes hidden, through visibilitychange. unload and beforeunload do not fire reliably, in particular on mobile, so a client that waits for them loses the tail of most sessions.

A request started at that moment is cancelled along with the document unless it is marked to outlive it. Use fetch with keepalive, or navigator.sendBeacon. Browsers cap the combined body of all in-flight keepalive requests at roughly 64 KB, and a request over that budget fails outright. On this path, send the newest records that fit and drop the rest, rather than losing the whole batch.

This is also when the second web vitals request goes out. Send it on the first client-side navigation or on page hide, whichever comes first. See Web vitals.

Sampling

Sampling is a decision the client makes, and it leaves no trace in the payload. There is no field that tells Flare a trace stands for five others, so the aggregate numbers count what arrived.

Take the decision once, when the root span of a trace is created, and apply it to every span in that trace. A trace must be sent whole or not at all. Sending some spans and holding others back breaks the parentSpanId chain, and the spans that did arrive get dropped during processing without any signal that it happened. See Lifecycle.

Introduction Events

On this page

  • Use the public project key
  • The origin allowlist
  • Writing timestamps in JavaScript
  • Getting the last batch out
  • Sampling

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