Get started with React

Getting Opbeat set up to get detailed insights about performance from real users and log exceptions in React applications is quick.

Opbeat for React will automatically measure route changes and user interactions in your application and instrument components, AJAX calls, Redux dispatches etc. to give you detailed insights into what kind of experience your users are having. It will also automatically log exceptions to Opbeat.

  Video:
Watch a short screencast about how to get started with Opbeat in your React app.

Note: Opbeat React is currently in BETA. Sign up here.

Installation

Create a new app in your Opbeat organization and select “React”.

Download from npm

Install the module from npm. The package is called opbeat-react.

Run the following command in your project directory:

$ npm install --save opbeat-react babel-plugin-add-react-displayname

This also installs our babel plugin. The plugin will automatically set MyComponent.displayName = 'MyComponent' to ensure that component names survive the minification/uglification process.

Configuration

To enable Opbeat, you need to import the library and then call initOpbeat with some tokens. These tokens are available in the Opbeat web interface.

Make sure to import opbeat-react before anything else in your application.

import initOpbeat from 'opbeat-react'

initOpbeat({
  orgId: '470e8f31bc7b4f4395143091fe752e8c',
  appId: '9aac8591cc',
});

If you use react-router (v2 or v3), use wrapRouter to enable routing instrumentation. See the transactions api for examples without react-router.

import initOpbeat from 'opbeat-react'
import { Router } from 'react-router'

// enable react-router instrumentation
import { wrapRouter } from 'opbeat-react'

const OpbeatRouter = wrapRouter(Router)

initOpbeat({
  orgId: '470e8f31bc7b4f4395143091fe752e8c',
  appId: '9aac8591cc',
});

ReactDom.render(
  <OpbeatRouter>
    <Route path="/home" />
    <Route path="/about" />
  </OpbeatRouter>,
  document.getElementById('react-mount')
);

If you’re using Redux, add the Opbeat middleware as the last middleware in your chain:

// enable redux instrumentation using the middleware
// NOTE: make sure you put the opbeat middleware last!
import { createOpbeatMiddleware } from 'opbeat-react/redux'

const store = createStore(
  reducer,
  applyMiddleware(
    thunk,
    createOpbeatMiddleware(),  // make sure this is the last one
  ),
);

Finally, remember to add the plugin to your .babelrc or your webpack configuration. It’s important that add-react-displayname be the first plugin in the plugin list:

.babelrc:

{
  "presets": [....],
  "plugins": [
    ["add-react-displayname", ...]
  ]
}

webpack.conf:

Look for the query key:

query: {
  presets: [....],
  plugins: ["add-react-displayname", ...]
}

If you have plugins or presets in your module loaders configuration, make sure to add the plugin there instead:

loaders: {
  test: /\.jsx?$/,
  exclude: /node_modules/,
  loader: 'babel?plugins[]=add-react-displayname,presets[]=react,presets[]=es2015,presets[]=stage-0'
}

Staging and local environments

You should create separate apps on Opbeat for production, staging and local environments. You’ll get separate tokens for each app on Opbeat. You can then do something like:

import initOpbeat from 'opbeat-react'

if (process.env.NODE_ENV === 'production') {
  initOpbeat({
    orgId: '470e8f31bc7b4f4395143091fe752e8c',
    appId: '9aac8591cc', // production app id
  });
}else if(process.env.NODE_ENV === 'staging') {
  initOpbeat({
    orgId: '470e8f31bc7b4f4395143091fe752e8c',
    appId: '9aac8591cc', // staging app id
  });
}
// in local environments, don't call initOpbeat

This requires the webpack plugin DefinePlugin to be correctly set up to define process.env.

Set context information

It’s often useful to include additional information in performance data and exceptions logged to Opbeat. You can do this in the following manner:

import { setUserContext, setExtraContext } from 'opbeat-react'

class OfficeStatus extends React.Component {
  componentDidMount() {
    setUserContext({
      id: 19,
      email: 'ron@opbeat.com',
      username: 'roncohen',
    });

    setExtraContext({
      coffeeLevel: 'low',
      milkSolution: 'skim milk',
    });
  }
}

For projects with Redux, Opbeat will automatically include the content of the store as well as the type of the last 10 actions. This can be disabled by setting actionsCount and sendStateOnException to something falsy in the call to initOpbeat.

Manual error logging

If you happen to manually catch an error, you can send it up to Opbeat like so:

import { captureError } from 'opbeat-react'

try {
  throw new Error('Everything is broken')
} catch (err) {
  captureError(err)
}

Filtering data

Sometimes, you want to filter out sensitive information before it’s sent up to our servers. You can do that in the following manner:

import { addFilter } from 'opbeat-react'

addFilter(data => {
  if (data.extra['Store state'].password) {
    delete data.extra['Store state'].password
  }
  return data  // remember to return data
})

Transactions api

In Opbeat, every measurement must be connected to a transaction. Transactions can be route changes, click events etc.

A simple API is exposed to let you set the name of the ongoing transaction and start new transactions. For example, this can be used to let Opbeat know about route changes even if you’re not using a supported router.

  • startTransaction()
    Call this to let Opbeat know a new transaction has started. For example, if you’re not using a supported router, you can use startTransaction to let Opbeat know that a route change has begun.

  • setTransactionName(transactionName, transactionType)
    Set the name of the ongoing transaction to transactionName. For route changes, transactionName should be the abstract or parametrized route path (/coffees/:beanID and not /coffees/99). You must also specify a type. transactionType is an arbitrary string, but transactions of the same type are shown together in the Opbeat UI. For route changes, you should use the string route-change. setTransactionName will automatically call startTransaction if no transaction has been started yet. If a transaction is already ongoing, setTransactionName will override any name and type previously set.

Example:

This is a Redux middleware that will look for actions of type route-change-action and signal Opbeat that a route change is going on. It relies on a magic method myRouter.matchRoute to convert a concrete path into the abstract route that we need.

const reduxTransactionDetector = store => next => action => {
  if (typeof action === 'object' && action.type === 'route-change-action') {
    const abstractRoute = myRouter.matchRoute(action.newLocation)
    setTransactionName(abstractRoute, 'route-change')
  }
  return next(action)
}

Support

opbeat-react works with react-router 2.x and 3.x and react 0.14.x and 15.x

Opbeat will automatically determine if the browser is supported and disable itself if the browser is not supported.

IE9 and below is not supported. But in general, every modern browser is supported.

Setting up CORS

On browsers that support Cross-Origin Resource Sharing (CORS), Opbeat is able to collect much more detailed information about exceptions.

To enable CORS, first set up your server to return the right Access-Control-Allow-Origin headers. enable-cors.org has a comprehensive guide for different server software.

Then, add the crossorigin attribute to <script> tags (only do this to JavaScript you host yourself or have verified that the respective server returns the correct Access-Control-Allow-Origin headers). Here’s an example:

<script src="/static/js/scripts.js" crossorigin></script>

Note: make sure to force browser caches to invalidate.

Because browsers cache resources including the Access-Control-Allow-Origin header, you need to force these caches to invalidate. The right way to invalidate depends a bit on your setup, but the easiest one is to change the URLs of your scripts by appending a query string parameter, e.g.:

<script src="/static/js/scripts.js?v1" crossorigin></script>

Source Maps

We support source maps to reverse JavaScript minification. If your build script generates source maps, and includes the sourceMappingURL in the generated JavaScript, we will try to detect and download the source map.

Read more in the Source Maps for frontend JavaScript article.

Troubleshooting

Component names garbled

If component names are shown as single letters (e, t, f etc.) in the Opbeat interface, you might not have set up babel-plugin-add-react-displayname correctly. Make sure it’s installed and appears in your webpack or babelrc configuration. If you know which component is not appearing with its correct name, try settings .displayName manually on that component. For example, if Provider shows up as e (or similar):

import ReactDOM from 'react-dom'
import React from 'react'
import { Router, Route } from 'react-router'

import { Provider } from 'react-redux'
Provider.displayName = 'Provider';

ReactDOM.render(
  <Provider store={store}>
    <Router history={history}>
      <Route path="/" component={App}>
      </Route>
    </Router>
  </Provider>,
  document.getElementById('mount')
);

Other problems

Please do not hesitate with contacting us if you need help.

Upgrading from 2.x to 3.x

A few things changed for 3.x:

  • Router integration now requires you to manually wrap the router. This is less error prone and easier to understand. Remove any import 'opbeat-react/router' lines you have. Instead, add

      // enable react-router instrumentation
      import { wrapRouter } from 'opbeat-react'
    
      const OpbeatRouter = wrapRouter(Router)
    

    and then make sure you use OpbeatRouter where you’d normally use Router.

  • Hooks into React now require that opbeat-react be loaded before React is loaded. This means if you’re using a vendor bundle, you must make sure opbeat-react is in that vendor bundle and is loaded before React.

  • Configuration parameters redux.actionsCount and redux.sendStateOnException and now plainly called actionsCount and sendStateOnException