sign up

How to optimize your debugging workflow with BugReplay

BugReplay HQ

We created BugReplay to save you time. Indeed, some of our customers have reduced the amount of time they spend on bug resolution by over 75%– that includes the amount of time it takes to report a bug, diagnose a bug, fix a bug, and test the fix.


The “bug report” has made great strides over the last few years. Gone are the days when you would wake up to this: “That thing on the site is broken. Please fix it ASAP.”


Today’s post examine's the elements of a good bug report, and how BugReplay can help you at every step. Dare I say- bug reporting can be fun for everyone! Here’s a sample BugReplay bug report so you can see what we're talking about.


The elements of a proper bug report include:


1.    Title and description. It seems self-evident, but providing your bug report with a suitable title makes your entire team happy. You can keep track of the bugs better, your developers know exactly what they’re getting into without having to open the report, and your project managers can manage the tickets more efficiently. A good title and description help prevent the ticket from getting lost in the shuffle. What’s the problem? And where is it? Keep it short and simple. With BugReplay, you can add a title and description at several points in the process, and edit them later- when you first create the report in the browser extension or later from your dashboard.


2.    Steps to Reproduce. What’s the expected behavior? What’s the actual behavior? Start from there. It’s always best to include a note on how to reproduce the bug in question. Include all the relevant URLs! (I don’t want to spoil the fun, butBugReplay captures the URLs– and a LOT of other data– automatically, so you don’t have to. You also don’t have to write out all the steps to reproduce. WithBugReplay, the screen recording captures exactly what happened, and when it happened, allowing the developers to see the bug for themselves.


3.    Add some environmental details. Where did you encounter this bug? What operating system? What browser? Was the browser version up to date? Were cookies enabled? Okay, enough questions. None of that matters. Why? Because BugReplay captures all that information automatically.


4.    Add the logs.  Developers often want to see your console logs so that they can see what happened. Sometimes they ask for something that you don’t even understand. That often creates friction among technical and non-technical members of the team, or between QA and development generally.BugReplay automatically collects all the frontend data like JavaScript logs, network traffic, and resource timing information, as well as the backend data such as server logs and exceptions. Basically, all the data that you could ever want! And what’s more, all this data is automatically synched with the video, so you can pinpoint what’s happening at a precise moment. You can read more about our full-stack feature set on our Zendesk page. The technical documentation is also on GitHub.

5.    Provide evidence of the bug. If you can capture a screenshot or a video of the bug, then it’ll make it much easier for everyone to get on the same page. Well, the cat’s out of the bag on this one. That’s our core product: all you have to do with BugReplay is open the site, click record, and you’re done. You can also take unlimited screenshots. Here’s the sample bug report again, so you can see exactly what you’d be getting!


6.    Send the bug report to the right place. This one is important too. Don’t just send a bug report to the back of the queue. Instead, add the right tags (indicating severity of the bug report) and statuses (frontend or backend, web or mobile, is it design or development, is it in Project X or Project Y, etc.). BugReplay makes all that easy- you can assign the ticket, add tags and status, you can even write some comments in the ticket, or attach additional documents. You can keep the report private or share the report outside your team with a publicURL.


7.    Integrate with your existing workflow. To make your life as easy as possible, we’ve also built some integrations, so that you can always make sure the bug report is easy-to-find and given its proper due. We have integrations with Jira, Slack,Trello, Zendesk, GitHub, GitLab, Asana, Basecamp, and Zapier. To sync the server-side data with your BugReplay video bug reports, we have all the documentation you need to set up with our APIs. We also have integrations withSentry and Papertrail, making it easy to incorporate data from third-party vendors. Our Bugsnag integration is in progress.

Speaking of integrations, there’s one more feature we’re excited to write about: automated testing. BugReplay began as a manual, interactive debugging tool. But we’ve now integrated with popular end-to-end automation frameworks to automate the entire BugReplay reporting process. If you’re an automation QA engineer or test engineer or other such position, we have integrations with, Nightwatch.js, Cypress, and TestCafe. Check out more on our GitHub page. Or watch some tutorials on our YouTube page.

Happy (bug) hunting!

New Add-On: Server Logs and Exception Tracking

BugReplay HQ

Today we’re announcing the release of our Full Stack add-on product, which synchronizes your server logs and exceptions with your BugReplay video bug reports and all the frontend data you’re already collecting.

With the full stack add-on, you can track exceptions whenever you record a bug on your own web application. All network calls towards your backend will automatically receive a special key in the header that your developers can intercept and send back to our API to log whatever is most useful for analyzing bugs.

While you can use our APIs to sync your server-side data, you can also integrate with your existing vendor. We currently offer integrations with Sentry and Papertrail.

You can learn more on our help desk. The technical documentation is also available on our GitHub page. Video tutorials are coming soon!

Converting Create React Apps to esbuild

Brooks Lybrand

As a product developer and not a JavaScript tools expert, I rely heavily on frameworks and packaged tools such as Create React App (CRA) and Next.js to handle the “build” side of my applications. When I leverage these tools to more quickly and efficiently compile and bundle my applications, I rely on someone else having already done the heavy lifting of configuring Babel and webpack.

However, sometimes I want a little more control and speed in my bundling process. That is why I decided to test a new and exciting bundler called esbuild. To do this, I convert a project I’d built with CRA to a custom version that uses esbuild. As an introduction to esbuild, CRA users may find this particularly useful.

What is esbuild?

Esbuild advertises itself as “an extremely fast JavaScript bundler”, which succinctly highlights what this simple, yet powerful tool is all about.

JavaScript bundler

We’ve had JavaScript bundlers for years, long before I became a web developer. You use bundlers to break up your project into multiple files for an easier development experience, while still bundling all of your code together for browsers to run.


Esbuild’s claim to fame is that it’s fast. This is the driving force behind using it, though there are lots of other cool things it can do (see the “major features” on the first page of the docs).

Why is esbuild so fast? It’s fast because it’s built in Go instead of JavaScript, which is a much faster language. Go also handles concurrent processes really well, making for a speedy bundling experience.

Why use esbuild?

So you can build faster! There are roughly two sides to building an app, development and production.

During development, esbuild uses incremental builds, which make it very easy to change your code, save, and see your updated app. This means you don’t have to rebuild your entire application every time you make a change during development.

Second, there is the production side to building a website. Bundling for production is often different from bundling for development, because you’ll usually want to do things like minify your source code, tree shake your app, and create source maps. You don’t really need to do these things during development, as these features add more time to building your bundle. For small projects that aren’t rebuilt often, the time it takes to build the bundle isn’t that big of a deal. 

However, for larger projects you typically require CI/CD pipelines to catch errors before pushing to production, as well as preview deployments created on every commit. Because of features like these, your production build is generated more often than you’d expect. 

To speed up this process, developers need to get feedback on whether their build passes the test suite, so they can share preview deployments with reviewers more quickly. With it’s incredible speed, esbuild tightens the feedback loop for developers, leading to faster insights and thus new features getting shipped more quickly.

Converting a CRA app to esbuild

To learn how esbuild works, we will convert a simple app which implements John Conway’s Game of Life in React. You can check out a live version of the app, or look at the source code. Note, the application runs pretty smoothly for me on every browser I’ve tried except for Chrome.

Currently this application uses Create React App. We are going to replace CRA with esbuild.

Installing esbuild

We begin the process by installing esbuild and uninstalling react-scripts.

Next we need to update our public/index.html file to fix how CRA handled some images. Since esbuild does not bundle css the same way as CRA, we also need to import all our styles generated by Tailwind CSS in this file. If you’re not familiar with Tailwind, don’t worry about it, just know that it’s been set up to automatically generate build/index.css which has all of the styles we use.

Bundling an application with esbuild

Now we’re ready to bundle our application with esbuild. If we run the following command in the terminal, it will create the production build almost instantly:

npx esbuild src/index.tsx --bundle --minify --outdir=public/build

While we could add this as a script in our package.json file, it is better in the long run to create a JavaScript file to handle the build script. To do this, we create the file scripts/build.js.

We use an IIFE (Immediately Invoked Function Expression) to call esbuild directly, passing in many of the same commands as we passed to the CLI. There is much more you can do with esbuild, but this is a nice start.

Let’s go ahead and update the scripts section in package.json.

Now we run npm run build to make Tailwind create the production stylesheet and esbuild generate the production bundle. If we run npx serve -s public, we can start hosting a local version of the application.

Comparing esbuild and CRA build speeds

If you ran the CRA build before, you’ll notice that esbuild is significantly faster.

I compared running the two side by side and the build time was reduced by 70% using esbuild. The majority of the esbuild version’s runtime is running Tailwind CSS/PostCSS, so the actual work esbuildis doing takes almost no time. This is a really small app, so your mileage will vary, but as your application gets larger, esbuild will scale really well.

Implementing live reloading

We’ve gained some speed, but we’ve lost a big feature, the development version of our application. As a modern web developer, I want to see the changes I make in my code reflect nearly instantly in the browser, which is something CRA gave us for free.\

To get live-reloading setup in esbuild, we’re going to need to do a little bit of work. First, let’s start by installing 2 helpful tools, chokidar and live-server:

Next, we’ll add a start.js file in the scripts directory we created earlier:

There’s a little more going on here, but hopefully the code is pretty easy to follow. Basically we’re using chokidar to watch if we make any changes inside of the src directory, and if we do it will rebuild the application. For more details, take a look at the more fleshed out example from which I derived my script. Now we can run npm start and have our application automatically reload when we make changes to our codebase. Take a look at the code changes we made. It really didn’t take a whole lot to replace CRA with esbuild (especially if you ignore the package-lock.json changes 😉).

What we gained


I can’t stress speed enough, this is esbuild’s biggest draw. It’s freaking fast!

We also gained a lot of control. Don’t get me wrong, abstracting things away and using pre-existing frameworks and tools to get your apps up and running can be incredibly valuable. But sometimes it’s nice, and even necessary, to look under the hood and be able to hook things up for yourself.

What we lost

We did unfortunately lose a few things. Currently esbuild doesn’t support hot module replacement, so it’s up to you to set up some sort of live reload as we did above. Given esbuild’s incremental builds, this is still very fast.  But we lost some nice developer experience benefits.

Additionally, esbuild does not have a 1.0 version yet. People can and certainly have used esbuild in production settings, however it is still under very active development, so approach with caution when deciding if it’s the right tool for your next project.

Other resources

There are a number of community plugins available which handle things like converting markdown, implementing various css flavors, compiling Svelte or Vue components, and much more. You can create your own plugins if you need, but it’s definitely worth checking out the community plugins first.

Besides the esbuild docs, I found the blog “What is esbuild?” to be a very helpful survey.

If this blog has made you excited about the potential that esbuild unlocks for frontend development, definitely check out Snowpack (a frontend build tool) or Remix (a React framework) which are both amazing and use esbuild. For further inspiration, checkout the thousands of open source projects using esbuild.

Communicating with Developers

Brooks Lybrand

A unique communication challenge

While communication can be difficult in any work arena, communication between developers has unique challenges.

These challenges often center around the nature of the work we’re doing, resulting in asynchronous communication, and issues around how "it works on my machine".

Asynchronous communication

Communication between members of partially or completely remote development teams tends to be asynchronous. Developers communicate with each other across the globe, using a variety of platforms like slack, discord, and email. Frustrations can arise, for example, as developers try to communicate across time zones and potentially even language barriers to resolve development issues with colleagues who aren’t even awake.

“It works on my machine”

Then there is the pesky "it works on my machine" issue. When a developer creates a new feature, it doesn’t always work on a colleague’s - or worse, a customer's - device. This often occurs due to missing or incorrect environment variables such as databases credentials, or differing operating systems and/or browsers.

Trying to discover why someone else's code is not working on your machine can be tough, because you don't know how they got it to work, and what information they need about your machine to debug. Finding a solution in these scenarios requires ongoing back-and-forth communication that potentially becomes very frustrating.

The communication formula

No tool magically fixes communication challenges. Good results come when we cultivate empathy and develop processes to reduce friction. For good developer communication, here’s a simple formula:

  • Assume the best about the other person
  • First understand, then be understood
  • Show your work

Assume the best about the other person

Most people are just trying to do their best and developers really want their code to work for others. Yet it can be easy to become angry when you assume, for example, that another developer is being intentionally vague when your attempt to communicate with them to fix a problem isn’t working.

When communication is difficult, it’s best to take a step back and give the other person the benefit of the doubt. Ask yourself if it is possible that you’re the one not communicating clearly? Perhaps you can fix something too. In any event, choose to believe that others are doing their best to communicate effectively with you.

First understand, then be understood

When reviewing another developer’s work or trying to run their program, ask yourself these questions:

Did you read their instructions carefully? Did you follow each step? Did they leave any comments in their code, or anywhere else that might be useful?

In the best case scenario, you can solve the communication on your own by making sure you've understood and tried the other developer’s instructions. Alternatively, you may still have issues, but your next conversation with the developer builds on what you discovered on your own. When you do everything you can to understand, you show the other developer that you're not being lazy or difficult, but are working towards clear communication.

Show your work

If you are sharing your development work, have you written your steps out? Do you have an updated README? Have you added comments to your code/PR?

If you're reviewing someone’s code, have a question, or have spotted a bug, have you explained the steps it took to produce the issues you see? Can you share a screenshot or recording?

There are tools and processes you can use to show your work, and make it easier to communicate with other developers. As a best practice to enhance communication efforts between developers, your team or company should acquire the appropriate tool and write down a process to help developers show their work. For example, if your company uses BugReplay, you can capture screenshots coupled with console and network logs to show your outcomes to another developer.

Apply the communication formula

Let’s walk through a couple of “It works on my machine” communication scenarios, where two developers learn to use the formula above to communicate clearly and effectively with each other.

Example 1: Testing Authentication Workflow

In this scenario, Sally is a developer working on the authentication workflow for a new website, where users are authenticated via their Google accounts. She’s asked Bill to review her work. Feel free to check out the source code, or take a look at the live demo.

Sally just completed programming the ability to authenticate users with their Google accounts. She asks Bill to pull her code base and test whether he can log in. She sends him a link to the repository, provides the environment variables he needs to put in his .env file, and tells him the instructions are in the file.

Bill clones Sally’s repo, installs all the packages, and sets up the variables correctly, but once he clicks the "Continue with Google" button, something goes wrong! He's not sure why things aren't working – he checks his .env file to make sure the setup is correct, then runs through the installation steps again.

He still gets the same error. Bill figures the best way to share what seems like a bug is to send Sally a screencast of the issue. You can see for yourself his recording in BugReplay, which captures helpful network logs and other information about the environment in which the failure occurred.

When she reviews the logs, Sally sees that Bill ran the code on the port https://localhost:8000. However, the Google authentication is set up so that it redirects to https://localhost:3000. When she contacts Bill to ask why he ran the code on port 8000, he tells her he was told to do so in a previous project, and assumed he should do so again.

Sally explains that Google requires allowed domains to be explicitly set up, and the developer domain they are using is https://localhost:3000. Bill reruns the installation, this time without overriding the default port 3000, and it works like a charm! Sally updates the README to make the domain requirement more explicit so others won’t experience Bill’s issue.

Now let’s review how Sally and Bill applied the communication formula to their situation:

  • Assume the best about the other person
    We don't know what went on in Bill or Sally's minds during this whole exchange, but they both acted respectfully in giving and receiving feedback, even when things weren't working.
  • First understand, then be understood
    Bill probably could have done a better job here. He did attempt to run through the setup several times, but when it came to starting the server, he added the --port 8000 command in order to run it on a different port than the default, which was an extra step Sally didn’t ask him to do. People often get used to doing something one way, and don’t realize that their actions might break things in a different project.
  • Show your work
    As soon as Bill realized he had an issue he didn't know how to resolve, he documented exactly what was happening. BugReplay made it exceptionally easy to hit record, get all the relevant information, and send it to Sally. From there, Sally quickly figured out what was going on and was able to take the feedback to improve the documentation.

In the end, this was a communication win for everyone!

Example 2:  Previewing a Deployment

In this scenario, Sally implements a new passwordless authentication method using 🪄magic🪄 links. Unlike Google authentication, magic links can be used for preview deployments.

As a result, when Sally asks Bill to test her new authentication method, he won’t have to pull all of Sally's code, install the dependencies, and run everything locally on his machine. Sally uses the platform vercel so that each pull request automatically deploys its own unique URL for every commit which anyone can view.

Sally sends Bill a link to her pull request, which directs him to this preview deployment.

Bill is happy to review Sally's work, but again runs into trouble. As before, he documents his attempt to test Sally’s authentication method and sends the recording to Sally.

In the recording, as shown in the video below, Bill repeatedly clicks the Continue with Email button, but nothing happens:

From the network logs Bill sends her, Sally sees that Bill gets a 500 HTTP response code, which indicates a problem on the server. She tests the preview link herself and gets exactly the same result.

After some additional investigation, Sally realizes that she forgot to add the necessary environment variables to production 🤦. She adds the variables and sends Bill the deployment preview again. This time Bill reviews and approves!

Sally and Bill have certainly become better at applying the communication formula, as you see here:

  • Assume the best about the other person
    Bill and Sally were both respectful towards each other. The preview deployment provides an ‘’objective source of truth”, because nothing has to be set up locally to view the new feature, and both of them can view the same site through the same link. This made it easy to verify that Bill tested the deployment correctly.  
  • First understand, then be understood
    Bill clearly understood what he was testing and correctly followed the instructions Sally provided. Sally made sure to figure out what bug Bill discovered. Sally could have done a better job verifying her own work before sending it to Bill. While she did test the magic links locally, she never checked if they worked in the preview link.
  • Show your work
    Bill was able to leverage some useful software to share a screencast and the network logs with Sally. He wasn't able to show what happened on the server, but he gave Sally enough information to direct her to the solution.


Just as we have to learn how to code, we also need to grow our communication skills.

Acquiring communication skills isn’t hard when we follow the communication formula to become more empathetic, aware, and diligent.

In the end, while understanding linked-lists can help you get a job, effective communication allows you to excel on the job.

What is Automated Testing

Brooks Lybrand

The words “automated testing” elicit many kinds of emotion.

For some it evokes painful memories of blindly chasing the elusive “100% test coverage,” spending more time writing test code than application code. For others it inspires confidence, a reminder of how automated tests saved them from shipping detrimental bugs. For others still, “automated testing” inspires guilt, because you know you should make the investment, but haven’t quite found the time.

If you are in the latter group, don’t worry—we’re going to dive into automated testing, why you should care about it, and how you can get started.

Everybody’s doing it

First, let’s focus on testing. The truth is, everyone tests their software. From developers to customers, everyone plays a part in testing your application. At the most fundamental level, testing software is about providing some input(s), getting some output(s), and then judging whether you get the result you expect.

Every time a programmer runs their code, they’re testing whether it runs without crashing, looks right visually, and calls all the calculations/functions correctly. When a quality assurance (QA) engineer tests code they might be manually walking through a user story, such as registering a new account, and checking that the behavior is correct at every step.

Ultimately, whether they know it or not, your end users test your software too, every time they use it. And you can tell that users are testing your code because, when things go wrong, most people are not afraid to let you know.

So there’s no avoiding it, everyone everywhere is always testing software. But as developers and as a company, you get to choose how you want to test your applications.

Automate it!

What are computers good at? A quick search on the internet will reveal that computers are really good at running repetitive, boring tasks. What is a test if not a set of boring repetitive tasks? Like: open this url, click in the email field, type “, click in the password field, type “password1234”, click the “login” button

What are humans better at than computers? Making mistakes, of course! That includes making mistakes doing repetitive tasks. Humans may correctly complete the checklist of a formalized test once or twice, but with continued repetition, chances are that they’ll stumble along the way and ruin the test.

Computers are actually very bad at making mistakes, as long as they receive crystal clear instructions. So, if computers are good at repetitive tasks, and bad at making mistakes, they make the perfect candidates to be your primary testers!

An automated test uses code to tell a computer how to run different functionality, check the results, and let you know whether or not everything went as expected.

There are many different types of tests, all serving different purposes. One of the most advanced and powerful types of tests is an end-to-end (e2e) test, where you run your code in the same environment as your users, simulating their actions as closely as possible. In the world of web development this means running your site in an actual browser, while the computer clicks around and types things to see how everything behaves. More on this later.

Why doesn’t everyone have automated testing?

At this point automated testing seems pretty attractive. So why isn’t everyone doing it?

There are several reasons a software engineer or team might not be using automated testing. For example, setting up the testing takes time, and sometimes the budget/scope of the project doesn’t allow for it. Testing can also take a lot of work to set up if you’ve never done it before: there are libraries to think about, environments to configure, and competing testing philosophies to consider. Additionally, if you’re dealing with databases or APIs, you typically have to mock them, or create a test database so you don’t accidentally erase all of your users’ data, or blow the roof off your server bill.

So is automated testing worth it?

Here’s everyone’s least favorite answer: “It depends.”

Are you working on a side project just for yourself? Then probably no. Are you building financial software that is handling super sensitive information for paying customers? Then yes, you’d likely want to use automated testing.

There’s a broad spectrum of testing needs, and all sorts of situations in which automated testing may or may not be a good investment. Overall you and your team should take the time to really consider if it’s worth it for you.

One thing that can make your decision easier is realizing that testing is not an all-or-nothing proposition. You don’t have to have 100% test coverage, especially not at the beginning. Since ultimately, given enough time and enough customers, all of your code does get tested, ask yourself: “Would I rather have a computer test this first, or my customer?”.

So, it’s probably a good idea to have at least some automated tests in your application, which leads to the question…

Where should I start?

There’s no perfect answer to this question, but there are several good options

Start with something easy

It will probably take longer to write your first test than the second one. For the first test, you have to acquire all the tools, configure the environment, read the documentation, and so on.

It can be really helpful to start with something simple to get that first win. Test your `addTwoNumbers` function first: you’ll actually feel great getting a test suite to run your code and tell you whether or not you remember elementary math.

The actual test can be something as simple as:

test('adds 2 numbers together correctly', () => {   const result = addTwoNumbers(2, 2);   const expected = 4;   expect(result).toBe(expected); });

Start with the most important piece

What part of your application would cause the most stress if it failed? This could be your checkout flow, your authentication, or your automated email system. Having confidence that this mission-critical piece of code won’t break without you knowing first can be enough motivation to get you going.

Start with the thing that always breaks

Do you have a piece of code which just falls apart any time someone touches it? That one function, first written four years ago by the developer who’s long gone, which has been patched over more times than your git history can tell you? That can be an excellent place to start. You’ll feel great knowing that your test identified the issues with this problem code and that when you next update it, you’ll quickly know which changes might cause it to fail. As an added bonus, you might actually understand the code a little better by thinking about how to test its behavior.

Start with new features

Sometimes the easiest way to implement a test is to do it when first adding the feature. In the next standup meeting or the next time you get a request for a new feature, try to carve out some time in the schedule to add a few automated tests.

When should my tests run?

Automated tests serve a major purpose: they let developers know they made a mistake before they share that mistake with their users. So at the most fundamental level, tests should run before the code gets to your user. Here are some ways to run your tests strategically between the time you write code and when you ship it:

While you’re developing

Run test suites in “watch” mode, which means any time you make a change to your code, the appropriate tests run automatically and give you near-instant feedback. Some developers go so far as to write their test first, and then code the feature until the test starts passing. This is known as Test-Driven Development (TDD) or “red/green/refactor”.

Before you commit your code

Run all the tests that depend on the files you changed right before you commit your code. You can automate this step easily with git hooks and, if you’re using JS, you can leverage great tools like husky to set up your hooks.


Running your test in CI (Continuous Integration) and/or CD (Continuous Delivery) typically means running it somewhere in the cloud, off of your computer, in a special environment that is very similar to your production environment. This can take a bit more work to set up, but it has the benefit of not interrupting your workflow while ensuring that erroneous code doesn’t slip into production.

If you want to read more about CI/CD, here is a great introductory article.

What tools should I use

There are many excellent tools available for pretty much every language. If you are in the JavaScript or web development world, you can use the classic Mocha and more modern Jest testing framework. If you want to run your test in a browser as a typical user would, there are lots of great e2e testing suites available. Selenium is one of the oldest of these tools, and there are many newer options like Nightwatch or Cypress.

BugReplay is another great tool. BugReplay started as a tool for manual testing where QA teams could record videos of bugs with time-synced Javascript console and Network traffic logs. BugReplay now has some amazing integrations with several modern e2e test suites. Whenever an automated test fails, BugReplay automatically generates a bug report, and the developer or QA team can simply watch the video and view the JS console and network traffic logs to see what broke and how to fix it.

Reviewing multiple automated tests in BugReplay