We use cookies or similar technologies to personalize your online experience and tailor marketing to you. Many of our product features require cookies to function properly. Your use of this site and online product constitutes your consent to these personalization technologies. Read our Privacy Policy to find out more.

X

Instrumenting Browser JavaScript Apps

If you send data about your web applications to Honeycomb, you probably already know to “start at the edge” and instrument each request as it reaches your servers. But for some types of applications — especially single-page apps (SPAs) and other JavaScript-intensive cases — you may find that instrumenting server requests isn’t enough to have good visibility into how users interact with your app. For these kinds of apps, you may want to send data directly from the browser to build up a richer view of how your app behaves in production.

Step 1: Add instrumentation JavaScript

To construct events to send to Honeycomb, build flat objects with string keys and values that are strings, numbers, and booleans.

// Example payload of an event to forward to Honeycomb
var someEvent = {
  type: "page-load",
  request_id: 123456,
  user_agent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) SomeBrowser/123.45"
  asset_version: "1.232.90"
  timing_page_load_duration_ms: 2456.45,
  ab_group_touch_ui: true,
  ab_group_multi_team_chat: false,
  canary: false,
  window_height: 900,
  window_width: 1245,
};

// Honeycomb expects a JSON payload:
var payload = JSON.stringify(someEvent);

See our blog post about how we track page loads at Honeycomb for more ideas about what to track, including example code from the Honeycomb source.

If you don’t have pre-existing browser instrumentation, you can start with a RUM instrumentation library like Boomerang. You can configure Boomerang with plugins to collect data about page load timings and other characteristics of the in-browser experience, and URL-decode its payload format (a flat object) to forward directly to Honeycomb.

Step 2: Send events to Honeycomb

The safest way to send browser data to Honeycomb is to proxy it via a server-side web application that already has Honeycomb instrumentation. We recommend adding a dedicated endpoint for forwarding events to Honeycomb.

// HTTP handler for our `/honeycomb_proxy` forwarding endpoint
func (h *InstrumentationHandler) sendToHoneycomb(eventMetadata map[string]interface{}, user *types.User) {
    // Libhoney imported from https://github.com/honeycombio/libhoney-go
    ev := h.Libhoney.NewEvent()
    ev.Add(eventMetadata)      // The JSON event we constructed in the browser

    // Add any relevant fields that are easier to populate server-side
    ev.AddField("user_id", user.ID)
    ev.AddField("user_email", user.Email)

    // Send the event to the Honeycomb API
    ev.Send()
}
# Make a HoneycombController or add to an existing instrumentation controller
def send_to_honeycomb
  honeycomb_event = params[:honeycomb_event]
    # Whitelist keys you expect in your honeycomb events
    .permit(
      :event_type,
      :duration_page_load,
      :duration_first_paint,
      :connection_type,
      :user_agent
      # ... plus probably many more keys!
    )
    .to_h

  # Add any relevant fields that are easier to populate server-side
  honeycomb_event[:user_id] = current_user.id
  honeycomb_event[:user_email] = current_user.email

  # Send the event to the Honeycomb API
  # $honeycomb is a libhoney client instance https://github.com/honeycombio/libhoney-rb
  $honeycomb.send_now(honeycomb_event)
end

This endpoint can augment the event you construct in the browser with any fields that are easier to populate server-side (e.g. user email, team ID, plan type) before forwarding the event to Honeycomb. It also is a convenient place to add calculated fields using libraries that may be too large or complicated to include client-side. For example, you may want to use a geo-IP database to map the client IP address to approximate location, or map the client user agent to operating system, browser, and device fields that you attach to your Honeycomb events.

See our SDK docs for more information on how to send data to Honeycomb in the server-side language of your choice.

Can I send data directly to Honeycomb from the browser?

We currently caution against including your Honeycomb API key directly in your client-side JS. Your API key can be used to create new datasets, so the safest place to keep it is server-side with your backend application code.

However, for some cases—for example, if you maintain a client-only application that does not talk to any backend application servers—you may be willing to accept the risks of including your API key in your JavaScript to avoid maintaining a proxy. In that case, you can send data (as a JSON object) from the browser directly to Honeycomb via a POST request. We recommend creating a separate API key for exclusive use in your client-side JS and granting it only permission to send events.

// Example of sending an event directly from the browser to the Honeycomb API:
var honeycombWriteKey = "YOUR-HONEYCOMB-API-KEY-HERE";
var honeycombDatasetName = "Your App Name";
var someEvent = {
  // ... add fields to your honeycomb event here (see prior section)
};

var xhr = new XMLHttpRequest();
xhr.open("POST",  "https://api.honeycomb.io/1/events/" + encodeURIComponent(honeycombDatasetName), true);
xhr.setRequestHeader("X-Honeycomb-Team", honeycombWriteKey);
xhr.send(JSON.stringify(someEvent));

Browser instrumentation best practices

Any information that’s available in the browser via JavaScript can be added to your events — the hardest part is knowing when to send them. Here are the points when we recommend sending an event to Honeycomb:

For more ideas on what data your instrumentation can send to Honeycomb, see our blog post on Instrumenting browser page loads at Honeycomb.