# AppSignal vs Honeybadger: A Hands-On Error Tracking Comparison for 2026

On annual billing, AppSignal's first paid tier costs $279 a year and Honeybadger Team costs $286. A seven-dollar gap won't make the decision for you, so what matters is which half of monitoring each one covers well.

My test made that split plain. Honeybadger reported every failure I planted, including a promise rejection nobody handled. AppSignal missed that one, but it timed every request and showed checkout going from 2 ms to 4.59 s on a bad release, a slowdown Honeybadger had no way to measure.

**AppSignal is an application performance monitor that includes error tracking,** with traces, slow-query rankings, logs, host metrics, anomaly triggers and heartbeat monitors in the same app. It bills by request volume.

[ad-logs]

Honeybadger starts from the error. It's an error tracker with Insights, an event store you query with its own language, BadgerQL, plus uptime checks and a status page on every plan, and check-ins for scheduled jobs. It bills by error count and has no tracing.

I ran both against the same deliberately broken Node.js bookstore in late October 2026. You'll find them weighed on getting started, what each catches, debugging, grouping, browser monitoring, regressions, request performance, logs, uptime and alerting, AI help and cost.

## AppSignal vs Honeybadger: Results at a glance

These verdicts reflect an Express and Vite app written as ES modules. A CommonJS app, or alert channels wired into either tool, could move a couple of them.

| Area | Better in my test | Why |
|---|---|---|
| Setup | **Honeybadger** | One package and one key for server and browser; AppSignal's wizard has no ESM path |
| Error capture | **Honeybadger** | Reported a stray promise rejection AppSignal let through |
| Debugging an error | **Honeybadger**, narrowly | Request-scoped server breadcrumbs with timings; neither showed backend source |
| Error grouping | **AppSignal**, narrowly | Kept failures on different routes apart; Honeybadger merged them |
| Real user monitoring | **AppSignal**, narrowly | Collects Core Web Vitals; Honeybadger has no RUM; neither records sessions |
| Releases and regressions | Mixed | AppSignal shows what a release changed; Honeybadger handles a returning bug better |
| Performance | **AppSignal** | Per-release timing, traces and slow queries; Honeybadger records no request timing |
| Logs and events | Mixed | AppSignal links logs to incidents; Honeybadger's BadgerQL is the faster way to query them |
| Monitoring and alerts | Not compared | I wired no alert channel; only AppSignal's monitors were exercised |
| AI-assisted debugging | Not compared | Neither has an in-app assistant I could test |
| Price | **AppSignal**, narrowly | Nearly the same price, with performance monitoring included |

## How I tested AppSignal and Honeybadger

My test subject is a bookstore built to misbehave. Its Express backend stores the catalogue and orders in SQLite, its Vite front end switches pages by hash, a mock pricing service answers on the side, and a timed job compiles sales figures. Headless browser sessions played the shoppers, so both tools saw the same failures from the same code.

The failures I planted:

- **Storefront crashes:** a wishlist button that reads a null object, plus API failures the storefront reports itself.
- **API crashes:** an unknown coupon at checkout, a lookup for a book that doesn't exist, and an empty stock shelf.
- **An unreliable upstream:** the price service sometimes answers 503.
- **Async failures:** an unhandled rejection in the recommendations code, and a crashing report job.
- **Late additions:** a slow query plus a payment bug, switched on only in the third version.

### Three versions of the app

| Version | Purpose |
|---|---|
| 1.0.0 | Installing each tool and reading its first error pages |
| 1.1.0 | A regression check, with the coupon bug closed and then shipped untouched |
| 1.2.0 | A faulty deploy, with a slower book query on checkout and a card charge failing one time in five |

Version 1.2.0 is where the tools pulled apart. It put a slowdown and a new error on the same checkout request, so it tested whether a tool could explain a bad deploy as well as flag it.

### SDKs and test limitations

| Platform | AppSignal | Honeybadger |
|---|---|---|
| Server | `@appsignal/nodejs` 3.9.4, built on OpenTelemetry | `@honeybadger-io/js` 6.17.0 |
| Browser | `@appsignal/browser` 1.0.0-beta.9, a Labs release | `@honeybadger-io/js` 6.17.0, browser build |
| Account | Hosted | 30-day trial |

- **Counts:** the two tools received separate runs of shopper traffic, so treat their totals as rough.
- **ES modules:** the app uses ES modules, which affected setup and stack frames in AppSignal.
- **Host metrics:** AppSignal's agent collects these on Linux only, which meant a second 1.2.0 run from my Ubuntu box.
- **My own code:** I corrected a bug in my AppSignal integration after its first run, which had left custom spans and handled errors detached from their requests. Unhandled rejections were left to each SDK.
- **Alerting:** neither tool had a notifier attached, and their uptime checkers can't see a laptop.

### Terms in each tool

The two tools often use different names for the same thing:

| Concept | AppSignal | Honeybadger |
|---|---|---|
| A release | Revision | Deploy |
| A fixed error | Closed | Resolved |
| Issue history | Logbook | History |
| Release list | Deploys page | Deployments list |
| Event and log store | Logging | Insights |
| Scheduled job monitoring | Process monitoring | Check-ins |

## Setup and onboarding

AppSignal runs a native agent and walks you through a wizard per language and framework. Honeybadger ships one JavaScript package for both the server and the browser, with one API key for the whole project. Both were reporting errors within the hour, and each had one thing worth knowing before you start.

### AppSignal: A guided wizard that assumes CommonJS

The wizard starts by telling you how much each language gets:

![AppSignal language picker with Node.js as Full APM and JavaScript as Errors only](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/e4019e83-a8b8-49b8-3575-72ca38a13800/lg2x =1512x802)

"Full APM" for Node.js and "Errors only" for browser JavaScript is a fair summary of the product. The next steps cover the npm package, your framework, the Express error handler and a config file:

![AppSignal wizard step for the appsignal.cjs config file](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/88971dd6-b46a-4dfd-e107-926cf8458e00/md1x =1512x802)

The file is `appsignal.cjs`, loaded with `node --require`. Every step assumes CommonJS, so for an ES module app I registered AppSignal's import hook myself, or Express wouldn't have been traced. The wizard doesn't mention that case.

Once the key was right, data arrived in about a minute, and the `revision` value in the config created the first deploy with no extra call.

### Honeybadger: One package, one key

Honeybadger's Node.js setup is a single `configure` call plus two Express middlewares:

```javascript
[label src/monitoring/honeybadger.js]
Honeybadger.configure({
  apiKey: process.env.HONEYBADGER_API_KEY,
  environment: config.environment,
  revision: config.appVersion,
  projectRoot: process.cwd(),
[highlight]
  reportData: true,
[/highlight]
  enableUncaught: true,
  enableUnhandledRejection: true,
  insights: { enabled: true, console: true, http: true },
});
```

The highlighted line matters on a laptop. Honeybadger ignores the "development" environment unless you set `reportData`, and its setup page says so. The browser uses the same package and the same key, so both sides land in one project.

Source map uploads and deploy reports both worked with the project's API key on the trial, through Honeybadger's REST API. There's no separate token to create.

<details>
<summary>A side effect of the Express request handler</summary>

Honeybadger's request handler passes an unhandled promise rejection into Express after the response has already been sent. An `ERR_HTTP_HEADERS_SENT` warning followed from my last error middleware. Nothing crashed, and Honeybadger still filed the rejection, so this is noise in your logs more than a fault.

</details>

> **Worth turning on in Honeybadger:** set `reportData: true` in any environment named "development" that you want reported, or your first test errors won't show up.

### Setup comparison

| Capability | AppSignal | Honeybadger |
|---|---|---|
| Install path | Wizard per language and framework | `configure` plus Express middleware |
| Server and browser | Two SDKs, one app | ✔: one package, one key, one project |
| ES modules | ✘: wizard covers CommonJS only | ✔: worked as documented |
| Development environment | ✔: reported by default | ✘: skipped unless `reportData` is set |
| Releases | ✔: from `revision` in config | ✔: deploy API call |
| Source maps | Uploaded per release | ✔: API upload with the project key |

**Verdict: Honeybadger.** One package covering both sides, with a project key that works for everything, is the simpler start. AppSignal's wizard is friendlier until your app uses ES modules. Honeybadger suits a team that wants errors in an afternoon, and AppSignal suits a CommonJS app that wants performance data from day one.

## Error capture

Both tools hook into the same Node.js and browser events, but they don't count the same failures. The difference showed up on the one failure that no code reported on purpose.

### AppSignal: Everything except the unhandled rejection

AppSignal's first run produced 11 issues:

![AppSignal error list after the first run](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/4011f775-169a-4f07-1df2-68fb25c66400/orig =1512x802)

The API crashes, the 503s, the failing job and the wishlist crash are all listed. The Browser SDK also files a failed fetch as an `HTTPError` next to the storefront's own `ApiError`, so one failed call can appear twice.

One planted failure is missing. The recommendations route reads 0% errors, and the rejection exists only in a log line from my own code:

![AppSignal log detail for the unhandled rejection](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/c68188d0-1800-416d-5459-107378472700/lg2x =1512x802)

"Recommendation engine timed out" is in the log attributes, tagged with the release. An app that doesn't log its rejections would have no trace of them.

### Honeybadger: Every failure, including the quiet one

Honeybadger's list held 8 groups after the same traffic:

![Honeybadger errors list with backend and browser errors in one project](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/ea777019-95d1-4ae9-2231-99bf0ab08200/public =1512x744)

The unhandled rejection is there with its own group, next to the server crashes, the report job and the browser errors. Each row shows its environment, so browser rows say "production" from the Vite build and server rows say "development".

### Capture comparison

| Capability | AppSignal | Honeybadger |
|---|---|---|
| Server crashes | ✔: caught | ✔: caught |
| Browser crashes | ✔: caught | ✔: caught |
| Unhandled rejection | ✘: logged only | ✔: own group |
| Background job | ✔: caught | ✔: caught |
| Failed fetches | ✔: reported automatically, can double count | Through the app's own reports |
| Server and browser in one list | ✔: by namespace | ✔: by environment tag |

**Verdict: Honeybadger.** It reported every failure I planted. AppSignal let an unhandled rejection pass as a successful request, which is exactly the failure a Node.js team is least likely to catch on its own.

## Debugging an error

A good error page gets you to the bad line and shows what happened just before it. Neither tool showed backend source code in my app. They differ in what they give you instead.

### AppSignal: Clear browser context, unreadable server frames

On server errors, AppSignal flagged my app's own frame with a warning icon:

![AppSignal backtrace with a warning icon on the app frame](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/ca3d0cc7-7caa-4b6f-fb6f-dad3e5600a00/md1x =1512x802)

The frames around it are Express and OpenTelemetry internals, with no toggle to hide them. Hovering the icon explains why no code appears:

![Close-up of AppSignal's parse warning on an ES module stack frame](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/97275968-1eac-4be5-1b66-27228c19dd00/orig =1700x188)

AppSignal couldn't read the `file://` frame format that ES modules produce, so every backend error showed a file and line number with nothing under it.

The browser side was much better. Source maps resolved the wishlist crash to the original file:

![AppSignal browser error mapped to src/pages.js](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/5fe680f1-07c2-4ff6-bd4e-50125d063800/orig =1512x802)

AppSignal opens the original source and marks line 122, where the wishlist push fails. The breadcrumbs above it read like a replay in text:

![AppSignal browser breadcrumbs ending in the click and the crash](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/9cba6d82-975f-4c93-0961-aeb751111200/md2x =1512x802)

The click row names the button and where it was on screen, followed by the app's own note and the crash. On the server, AppSignal's Node.js SDK has no breadcrumbs API, so mine went into custom data as raw JSON.

### Honeybadger: Server breadcrumbs with a clock on them

Honeybadger's backend error page showed the file and line, but no code either:

![Honeybadger backend error with the file, line and linked deploy](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/cb0387ec-94d8-48ae-f5f1-e0a6cf133000/md2x =1512x744)

The backtrace reads `server.js:150:45` under a `[PROJECT_ROOT]` prefix. The **Location** row names the deploy the error happened after, which becomes useful once you ship more releases.

Browser source maps worked through the API upload:

![Honeybadger browser backtrace mapped to src/api.js](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/023fd178-09cb-44cf-2f10-3b96062e9c00/public =1512x744)

The original `src/api.js` lines appear with the `throw` highlighted. Server errors carry the request and the user:

![Honeybadger Context and Params tabs on a server error](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/6f78c559-79b4-46ec-9dab-0e02089d1700/md1x =1512x744)

**Params** shows the request body, and **Context** shows the user with an **Email user** button. Server breadcrumbs stay scoped to the request:

![Honeybadger request-scoped breadcrumbs on a server error](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/0a99484a-de54-46b3-9d5e-c30c54c6bb00/public =1512x744)

"checkout started" and "book found" are the only entries, and each one is timed relative to the error. That timing pays off in the performance section. One later payment error did carry a stray notice breadcrumb from 51 seconds earlier, so the isolation isn't perfect.

### Debugging comparison

| Capability | AppSignal | Honeybadger |
|---|---|---|
| Server source lines | ✘: ESM frames not parsed | ✘: file and line only |
| Browser source maps | ✔: mapped to `pages.js` | ✔: mapped to `api.js` |
| Browser breadcrumbs | ✔: click targets and request durations | ✔: clicks, navigation and requests |
| Server breadcrumbs | ✘: custom data only | ✔: per request, with relative times |
| Request body | ✔: JSON payload | ✔: Params tab |
| User on errors | Tags | ✔: Context, with Email user |
| Trace from the error | ✔: one span | ✘: no tracing |

**Verdict: Honeybadger, narrowly.** Its server errors carried a timed trail of what the request did, where AppSignal had raw JSON. AppSignal's browser trail was the more detailed of the two, so a front-end-heavy team may see it the other way.

[summary]
<iframe width="100%" class="aspect-video h-auto" src="https://www.youtube.com/embed/-26mmryojE4" title="Error tracking | Better Stack" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

Neither tool showed a single line of backend code in my ES module app: AppSignal couldn't parse the frames, and Honeybadger listed only the file and line. I also tested the same release in Better Stack, where the payment error opened on the source around `server.js:173`:

![Better Stack payment error with the source around server.js:173](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/e5e5a3b3-9db0-4323-aa84-fa0088103900/lg2x =1512x744)

The planted-bug comment is right there in the code view, and all 10 exceptions sit in one group despite different amounts in each message. The bug is readable on the error page, with no trip to your editor.

**[See the code behind every exception](https://betterstack.com/error-tracking)**
[/summary]

## Error grouping

A good grouping rule gives each bug exactly one row. AppSignal combines the exception class with the route. Honeybadger combines the class with the first frame of the stack, and that choice bites when failures share a helper function.

### AppSignal: One issue per bug and route

After my integration fix, each bug in AppSignal had one row per route:

![AppSignal error list grouped by error class and route](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/391e5dd7-7b4f-4542-0595-6df4ffbd3900/lg1x =1512x802)

The storefront's `ApiError` splits into `/orders`, `/books/:id` and `/checkout`, so a broken tracking call and a broken checkout stay separate. The out-of-stock error groups under `POST /checkout`.

On 1.2.0, the payment error arrived as one issue, even though each message held a different amount:

![AppSignal payment gateway error as a single issue](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/7fefede7-42bd-4010-5fbe-974abe97e000/orig =1512x802)

That's the result you want from a new bug on a busy path.

### Honeybadger: One group per throw site

Honeybadger's grouping held the payment error together too, with every amount in one group:

![Honeybadger payment gateway error as one group of 7 notices](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/a55c2d52-bd38-4b25-822a-97878035eb00/lg1x =1512x800)

The trouble came earlier, with the storefront's `ApiError`. Every failed call goes through the same helper, so they all share a top frame:

![Honeybadger ApiError group holding several different failures](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/3603fef7-692a-4050-2791-1ff130038000/public =1512x744)

The tracking 404, the checkout 500, the book 500 and the price 502 all sit in this one group, and its title changes to whichever came last. A real outage on one endpoint would hide among the others.

### Grouping comparison

| Capability | AppSignal | Honeybadger |
|---|---|---|
| Grouping key | Error class plus route | Error class plus top backtrace line |
| New payment bug | ✔: 1 issue | ✔: 1 group |
| Same error on different endpoints | ✔: split by route | ✘: merged into one group |
| Group title | Fixed | Changes to the latest message |
| One failure counted twice | ✘: `HTTPError` beside `ApiError` | Not observed |
| Merge by hand | Not observed | ✔: Merge action, not tested |

**Verdict: AppSignal, narrowly.** It kept different failures apart without splitting a bug by its values. Honeybadger's grouping works well for errors thrown in one place, and it suits apps that don't funnel every failure through a shared helper.

## Real user monitoring and session replay

Real user monitoring tracks page performance for actual visitors, and replay shows what one visitor saw. Neither tool records sessions, so this comes down to the browser data each keeps beyond errors.

### AppSignal: Web vitals as metrics

AppSignal's Browser SDK sends Core Web Vitals, but there's no page for them. They show up as metrics when you build a dashboard chart:

![AppSignal metric picker listing the web vital metrics](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/ee9f968a-5212-46c0-d56a-620df1305700/public =1512x802)

CLS, FCP, INP, LCP and TTFB are all there. A chart can split one by page and release:

![AppSignal LCP chart preview with percentiles](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/4e3a556e-691a-4d50-93fd-c7708a473900/md1x =1512x802)

Because each sample carries its page and version as tags, you can line up a page's load times across versions. The peaks near 6,000 ms come from headless Chromium and my app's planted delays.

### Honeybadger: Errors only in the browser

Honeybadger reports browser errors with breadcrumbs and source maps, and I found no performance or RUM product in its navigation.

### RUM comparison

| Capability | AppSignal | Honeybadger |
|---|---|---|
| Session replay | ✘: not offered | ✘: not offered |
| Core Web Vitals | ✔: chart them yourself | ✘: not observed |
| Load times per version | ✔: split by version tag | ✘: not observed |
| Browser errors | ✔: with breadcrumbs | ✔: with breadcrumbs |

**Verdict: AppSignal, narrowly.** It keeps page performance numbers, even if you build the chart yourself. If you need replay, you'll be adding a third tool to either one.

## Release tracking and regressions

Release tracking answers the first question after every deploy: what did this release break, and did a fixed bug come back? AppSignal reads the release from your app's config and ties every error to it. Honeybadger waits for you to report each deploy, then uses it to label and clean up errors.

Neither has a "regressed" state, so in both a returning bug looks like any other open error:

![Diagram of the error states in AppSignal and Honeybadger and what moves an error between them](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/c51a38ab-ac01-46f4-5e27-5f39d88e8d00/lg2x =1512x615)

The red arrows are the difference. AppSignal reopens a closed error only when its alerting setting would fire. Honeybadger reopens a resolved error on its next occurrence and records the deploy it followed.

### AppSignal: Releases from config, reopens through alerting

AppSignal creates a deploy whenever the `revision` value it starts with changes:

```javascript
[label src/monitoring/appsignal.js]
client = new Appsignal({
  active: true,
  name: 'monitoring-lab',
  pushApiKey: process.env.APPSIGNAL_PUSH_API_KEY,
  environment: config.environment,
[highlight]
  revision: config.appVersion,
[/highlight]
});
```

There's no API call or CI step. Every error then carries its release, and the **Deploys** page compares releases by error rate:

![AppSignal Deploys page with errors per hour for each release](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/533911bb-629f-45dc-a57a-833bf20cdf00/public =1512x802)

**Errors per hour** is the useful column. The release with my returning bug ran at 876.4 an hour against 273.33 for the one before. The rows don't open, so you still go to the error list to see which errors caused the jump.

That list is AppSignal's best release view. Its default **Most recent revisions** filter keeps only errors seen in the latest release:

![AppSignal error list filtered to the most recent revision](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/0ef94b09-006a-4756-3354-4ddeb1502700/orig =1512x802)

**In selection** counts events from the new release and **Total** counts all time, so 5 of 30 means an old error is active again. A new error shows the same number in both columns, which is the only sign it's new.

Closing is the weak spot. AppSignal has no "fixed until the next release" option, only **Closed**, and its **Logbook** didn't record the reopen, only the person who closed it.

### Honeybadger: Releases from deploys, a fresh list on each one

Honeybadger learns about a release when you report a deploy, usually from CI:

```command
curl -s https://api.honeybadger.io/v1/deploys \
  -d "api_key=<your_honeybadger_api_key>" \
  -d "deploy[environment]=production" \
  -d "deploy[revision]=<your_release_version>"
```

Each call adds a row to the **Deployments** list:

![Honeybadger Deployments list with the revision and a Compare link](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/9bb30a83-9855-444f-3632-d967efee7800/lg1x =1512x744)

The **Compare** link opens a GitHub comparison with the previous revision, which only works if your repository has matching tags. The list doesn't count errors per release.

Deploys pay off in the error list. A resolved error that happens again reopens at once, and its page names the deploy it came back after.

#### Resolve errors on deploy

The project setting **Resolve errors on deploy** marks every open error as resolved each time you report a deploy. After a release, the list holds only errors that have happened since:

![Honeybadger errors list after a deploy resolved the server errors](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/80b2533c-8a59-4934-94bc-7449daa6e600/orig =1512x800)

Only the two browser errors are left here, because the deploy I sent named the server's environment. AppSignal has nothing equivalent.

<details>
<summary>Report one deploy per environment</summary>

The setting resolves errors only in the environment named in the deploy call. My browser code reported "production" and my API reported "development", so one release needed two calls before the whole list was cleared.

</details>

### The reopened error in both tools

Here's the same returning bug on each tool's error page, cropped to the fields that tell you it's back:

![The reopened error in AppSignal and Honeybadger with numbered markers](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/cac37b96-231c-4b2a-b368-edf50d2c1600/public =1512x523)

In AppSignal, the state is back to **Open** at ①, and **First in deploy** at ② is the alerting setting that reopened it. Nothing names the release it returned in. In Honeybadger, the status is **Unresolved** at ①, and the location at ② ends in "after deploy 1.1.0", so you know which release to look at.

> **Worth turning on in AppSignal:** keep **Alerting** on **First in deploy** for errors you close, because a closed error reopens only when an alert would fire.
>
> **Worth turning on in Honeybadger:** enable **Resolve errors on deploy** and report a deploy from CI for every environment, so the list starts fresh with each release.

### Release comparison

| Capability | AppSignal | Honeybadger |
|---|---|---|
| How releases are recorded | ✔: `revision` in config | ✔: deploy API call |
| Errors per release | ✔: revision filter and Deploys page | ✘: no counts on the Deployments list |
| Fixed until the next release | ✘: Closed only | ✔: Resolve errors on deploy |
| What reopens an error | The alerting setting | Any new occurrence |
| Release named on a reopened error | ✘: not shown | ✔: "after deploy" |
| Regressed label | ✘: none | ✘: none |
| Reopen in the history | ✘: not recorded | ✘: not recorded |

**Verdict: Mixed.** AppSignal is better at showing what a release changed, with no setup. Honeybadger is better at handling a returning bug, because it reopens on any occurrence and names the deploy. AppSignal fits teams that don't want another CI step, and Honeybadger fits teams that already report deploys.

[summary]
<iframe width="100%" class="aspect-video h-auto" src="https://www.youtube.com/embed/E8JQPRVR20E" title="On-call Overview | Better Stack" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

Both tools reopened the returning bug and then left it looking like every other row, with no trace of the reopen in either history. Better Stack got the identical 1.1.0 traffic in my test, and its list flagged the coupon error in red as "Reoccurred":

![Better Stack error list with the Reoccurred status](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/ff9ed40b-81f9-4dea-bca1-9d2fdeccd200/lg1x =1512x744)

Only the returning error changed, and its activity feed logs the reopen beside the resolve. You won't find a deploy API or automatic resolving there, yet the regression jumps out of the list itself.

**[Spot regressions in the error list](https://betterstack.com/error-tracking)**
[/summary]

## Performance monitoring

A bad deploy often slows a request long before it throws. AppSignal times every request and traces a sample of them. Honeybadger doesn't record request timing, so it can only see a slowdown through what your app tells it.

### AppSignal: The slowdown, release by release

Each action page in AppSignal has a **Performance in the last deploys** table. Here it is for checkout:

![AppSignal performance in the last deploys for POST /checkout](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/ad71c436-657c-4494-63b8-dff9a771b400/lg2x =1512x802)

The mean held at 2 ms through 1.0.0 and 1.1.0, then reached 4.59 s on 1.2.0. You can see the bad release without writing a query.

Opening one slow checkout from 1.2.0 explains the number:

![AppSignal checkout trace on 1.2.0 with the slow query and payment spans](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/d4d05f99-9ded-481f-c91b-7746746c5900/md2x =1512x802)

Its spans give 3.06 s to the book query and 3.3 s to charging the card, a failure and retry included. The breakdown puts 4.39 s of the request in SQLite.

The trace on a checkout that failed is less helpful:

![AppSignal trace for a failed checkout showing only the root span](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/072884f4-ac02-439c-d6a6-c546c3ce2400/md2x =1512x802)

It kept only the root span, so all 3.34 s show as **Other**. To see why the payment error was slow, you have to open a slow request that succeeded.

### Honeybadger: Breadcrumb timings and logged warnings

Honeybadger has no traces, but its breadcrumbs record how long before the error each step happened:

![Honeybadger breadcrumbs on the payment error with relative timings](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/7468d244-0574-4184-1719-79dc03794c00/md1x =1512x800)

"checkout started" is at -2.96 s and "book found" at -0.55 s, so the lookup took about 2.4 s. It's a useful hint, as long as the app writes breadcrumbs around its slow parts.

To tie the slowdown to a release, you query Insights. This BadgerQL query counts warning logs by message and revision:

```text
filter level::str == "warn" | stats count() as count by message::str, revision::str
```

![Honeybadger Insights counting warning logs by revision](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/2867bfb1-72e7-4dea-317e-00ae9f209f00/lg1x =1512x800)

"slow query: SELECT book for checkout" appears 44 times, all on 1.2.0. Honeybadger found the cause because my app logs that warning. It recorded no request durations of its own.

### The bad release in both tools

Here's the same release as each tool recorded it:

![Bar charts of AppSignal's checkout time and Honeybadger's slow-query warnings for each release](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/fd77fb23-a941-4219-62d0-351d231d6500/lg1x =1512x744)

AppSignal measured the jump itself. Honeybadger's bar exists only because of a log line, so a slowdown your code doesn't warn about wouldn't show up at all.

> **Worth turning on in Honeybadger:** log a warning whenever a query or an outgoing call crosses a time limit you choose. Those lines are what Insights can count when a release gets slow.

### Performance comparison

| Capability | AppSignal | Honeybadger |
|---|---|---|
| Request timing | ✔: per action, automatic | ✘: not recorded |
| Comparison by release | ✔: **Performance in the last deploys** | Through a BadgerQL query on logs |
| Traces with spans | ✔: sampled traces | ✘: not offered |
| Failed requests | ✘: child spans dropped | ✘: no traces |
| Query ranking | ✔: by share of time | ✘: not offered |
| Timing hints on errors | Custom data only | ✔: relative breadcrumb times |

**Verdict: AppSignal.** It found the slowdown, its cause and its release with no extra work. Honeybadger got there only because the app logged a warning, so your own logging decides whether it sees a slow release at all.

[summary]
<iframe width="100%" class="aspect-video h-auto" src="https://www.youtube.com/embed/7tQ7haFmSXI" title="Explore Traces | Better Stack" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

AppSignal's trace for the failed checkout lost its child spans, and Honeybadger had no trace to open. When I sent that failing checkout to Better Stack, its payment error linked straight to a complete set of spans:

![Better Stack spans for a failing 1.2.0 checkout](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/65353da5-9fc2-4deb-6b1a-26ad95621f00/lg1x =1512x744)

Of 2.19 s in total, 1.53 s belongs to the book query and 660 ms to the charge, on the very request that failed. The error and its cause sit on one screen, so there's no hunting for a slow request that happened to succeed.

**[Open the spans behind any exception](https://betterstack.com/tracing)**
[/summary]

## Logs and events

Logs catch what errors and traces miss. AppSignal treats logs as one more view of the app, linked to errors and incidents. Honeybadger sends logs, metrics and its own events into Insights and expects you to query them.

### AppSignal: Logs tied to the rest of the app

Calling `Appsignal.logger()` was all it took:

![AppSignal Logging view with severity and live tail](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/c0ef2347-8fbe-48e0-bdd0-ef646a5a6100/md2x =1512x802)

Rows carry a level, the host and a group, and a tail mode streams them live. Clicking a row reveals its attributes, along with jumps into its surrounding lines, a metric builder and Time Detective.

Time Detective earns its name in an outage. Pick a minute, and it lays out that minute's errors, timings and log volume together:

![AppSignal Time Detective at the height of the bad deploy](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/98716ce9-f6b5-4e21-dea0-6fe5a7079800/lg1x =1512x802)

In the worst minute of 1.2.0, checkout averaged 4.76 s with a p90 of 7.23 s, while a book page took 1 ms. Arrow buttons move the snapshot back or forward.

### Honeybadger: One event store with a query language

Insights is a single stream holding logs, notices, console output, uptime results and check-ins:

![Honeybadger Insights event stream](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/73af3744-c297-44b1-43df-9eff9c4b5600/md1x =1512x744)

I sent log events from my code while the SDK also captured the console, so each message arrived twice. Disable one source. Where Insights shines is querying. This one totals my custom metrics:

```text
filter event_type::str == "metric" | stats count() as events, sum(value::float) as total by metric::str
```

![Honeybadger BadgerQL query totalling custom metrics](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/32fad8d5-bd7a-4360-404d-7d715128b300/md2x =1512x744)

It returned 55 orders and 1,026.76 in revenue with one typed query. In AppSignal, the same numbers took about 10 clicks per chart on a custom dashboard. The query editor auto-closes brackets and quotes, which made typing awkward.

### Logs comparison

| Capability | AppSignal | Honeybadger |
|---|---|---|
| Log ingestion | ✔: `Appsignal.logger` | ✔: Insights events |
| Query language | ✘: search and filters | ✔: BadgerQL |
| Custom metrics | ✔: through dashboard charts | ✔: through BadgerQL |
| Live tail | ✔: built in | Not tested |
| Incident snapshot | ✔: Time Detective | ✘: not offered |
| Console capture | Not observed | ✔: automatic, can double your logs |

**Verdict: Mixed.** AppSignal is better when you're in an incident and need context, and Honeybadger is better when you know the question and want to type it. Teams that live in queries will prefer BadgerQL, and teams that browse will prefer AppSignal.

[summary]
<iframe width="100%" class="aspect-video h-auto" src="https://www.youtube.com/embed/XJv7ON314k4" title="Live Tail Overview | Better Stack" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

AppSignal only links logs to an error once they share a trace, and Honeybadger makes you write that join yourself. Better Stack received the same failed checkout in my test, and one click from the exception filtered Live tail down to its trace:

![Better Stack Live tail filtered to one failing checkout](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/0bd2859e-1627-424b-5fcb-b7bb7027c200/public =1512x744)

Next to the error line is the request's own slow-query warning, which names the cause before you've typed anything.

**[Jump from any error to its logs](https://betterstack.com/log-management)**
[/summary]

## Uptime, monitoring and alerts

Beyond requests, you also want eyes on servers, cron work and on-call alerts. AppSignal runs host metrics, anomaly triggers and heartbeat monitors. Honeybadger includes uptime checks, check-ins, status pages and Insights alarms, none of which I could test on a localhost app.

### AppSignal: Host metrics and heartbeats, and a trigger that stayed quiet

I created a **Slow actions** trigger with a one-second mean threshold ahead of 1.2.0:

![AppSignal Slow actions trigger form](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/b4285b24-9f99-4120-74d6-4aeb32da0100/lg2x =1512x802)

It applies to a whole namespace such as `web`, never a single route. Checkout hit 4.59 s, and the anomaly list stayed empty:

![AppSignal Anomalies list with no data](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/c91ab7b4-6000-4f5a-255b-b745734ba100/lg2x =1512x802)

Plenty of quick GET requests dragged the namespace average below one second. A lower one would also have fired on the first release's planted spikes, so the limit is the namespace-wide trigger more than my number.

On Linux, server stats need no configuration. My Ubuntu machine showed up as soon as the app started there:

![AppSignal host metrics for the Ubuntu server](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/41bd94a5-8509-4fae-58c3-a37638fd2a00/orig =1512x802)

The agent itself reports load, memory and disk. For job monitoring, I wrapped the app in `appsignal-run`, gave it a two-minute heartbeat, and killed it:

![AppSignal heartbeat monitor marked Missed](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/25a904cf-4d27-4ebc-5e4b-62ec6a71b300/md2x =1512x802)

It flipped to **Missed** within roughly three minutes. Create the monitor in the UI first, because beats sent to a missing monitor are dropped without a warning.

### Honeybadger: Uptime, check-ins and status pages, untested

Honeybadger's plans include uptime monitors, a status page and check-ins for scheduled jobs, and Insights adds alarms on queries. My report job was a natural fit for a check-in, but I didn't set one up, and uptime checks couldn't reach localhost.

### Monitoring comparison

| Capability | AppSignal | Honeybadger |
|---|---|---|
| Uptime checks | Included, not tested | Included, not tested |
| Status pages | Not observed | Included, not tested |
| Job monitoring | ✔: heartbeats, Missed detected | Check-ins, not tested |
| Host metrics | ✔: automatic on Linux | Not observed |
| Anomaly or query alerts | ✔: per namespace, did not fire | Insights alarms, not tested |
| Alert reached a person | Not tested | Not tested |

**Verdict: Not compared.** No alert left either tool during my test. AppSignal's server and job monitors proved themselves, while Honeybadger's extras stayed on the plan sheet.

## AI-assisted debugging

There's no built-in AI chat in either product. Each one exports context to an assistant you bring, and since I tried neither export, read this part as a description only.

### AppSignal: MCP access for outside assistants

The AppSignal UI had no AI features when I used it. Its docs list a beta MCP server for coding assistants, covering incidents, traces and metrics.

### Honeybadger: Copy for LLM and an MCP server

Every Honeybadger error has a **Copy for LLM** button in its action bar, which you can see on the grouping screenshot. Honeybadger also offers an MCP server that lets assistants search errors and run BadgerQL.

### AI comparison

| Capability | AppSignal | Honeybadger |
|---|---|---|
| Assistant in the product | ✘: not observed | ✘: not offered |
| MCP server | Beta, not tested | Available, not tested |
| Copy an error for a chat | JSON and Markdown export | Copy for LLM, not tested |

**Verdict: Not compared.** Both leave the diagnosis to an outside assistant, and I didn't test either path.

[summary]
<iframe width="100%" class="aspect-video h-auto" src="https://www.youtube.com/embed/n6TtDk8ITgc" title="AI SRE Demo | Better Stack" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

Neither tool will investigate a bad release for you, so the diagnosis falls to whoever is on call. So I asked Better Stack's AI SRE to compare 1.2.0 against 1.1.0 and explain the damage. It read releases, exceptions, spans and logs, with no code access:

![Better Stack AI SRE comparing 1.2.0 with 1.1.0](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/9c18a3bf-a83b-4e4c-2b40-adaf417dfc00/md2x =1512x744)

It found one slow statement among many fast ones and cleared the database host. It then split off the card failures as their own cause: 10 failed charges out of 48, none before 1.2.0. That took around four minutes and cost $0.49, and both root causes were right.

**[Let AI SRE explain your next bad deploy](https://betterstack.com/ai-sre)**
[/summary]

## Pricing

AppSignal prices plans by monthly requests and never bills overages. Honeybadger charges by error count, with optional overage billing and Insights quotas measured per day.

I read AppSignal's pricing page on November 4, 2026 and Honeybadger's on November 5, 2026. Treat these as a snapshot and recheck them before buying.

### Free plans and trials

| Item | AppSignal Free | Honeybadger Developer |
|---|---|---|
| Price | $0 | $0 |
| Users | Not stated | 1 |
| Volume | 30,000 requests a month | 5,000 errors a month |
| Logs | 1 GB | Insights: 50 MB a day, kept 7 days |
| Retention | 5 days | 15 days for errors |
| Uptime | Not stated for Free | 1 monitor, every 5 minutes |
| Status pages | Not stated | 1 |
| Paid-plan trial | 30 days, no card | 30 days, no card |

### Entry-level paid plans

| Item | AppSignal entry plan | Honeybadger Team |
|---|---|---|
| Yearly | $279, roughly $23.25 monthly | $286, roughly $23.83 monthly |
| Monthly billing | Price not listed | $26 a month |
| Users | Not stated | Unlimited |
| Volume | 250,000 requests a month | 50,000 errors a month |
| Logs | 1 GB a month | Insights: 100 MB a day, kept 7 days |
| Error retention | Not stated on the pricing page | 90 days |
| Uptime | Not stated | 5 monitors, every 2 minutes |
| Tracing | ✔: included | ✘: not offered |

Honeybadger Business costs $80 a month, or $880 a year, with 180-day error retention and one-minute uptime checks.

### What costs extra

| Need | AppSignal | Honeybadger |
|---|---|---|
| More volume | Moved up a tier if a 30-day review shows sustained overuse | Optional overage, $0.0003 per notification on Team |
| Over the quota | No overage charges | Up to 125% processed, then paused until month end |
| Long-term logs | $89 a month | Insights add-on, price not listed |
| More uptime monitors | Not listed | Add-on, price not listed |

### Comparing the actual cost

The entry plans cost within a dollar a month of each other on annual billing. What differs is the unit, and what the money covers.

AppSignal's plan includes the traces, slow queries, logs and host metrics that carried it through the performance section. To get request timing next to Honeybadger, you'd add a tracing product, and our [Raygun vs Honeybadger comparison](https://betterstack.com/community/comparisons/raygun-vs-honeybadger/) looks at one way teams fill that gap.

Honeybadger's plan covers errors, Insights, uptime and a status page, and it counts errors, so a busy API with few failures stays cheap. AppSignal counts requests, so the same API pays for its traffic. Teams wanting incidents and on-call under one invoice can read our [comparison for AppSignal](https://betterstack.com/community/comparisons/better-stack-vs-appsignal/).

**Verdict: AppSignal, narrowly.** At almost the same price, it includes performance monitoring that Honeybadger doesn't sell. Honeybadger is the better buy for high-traffic apps that rarely fail, or for teams that want a status page in the bundle.

## Full feature comparison

| Feature | AppSignal | Honeybadger |
|---|---|---|
| SDKs | Native Node.js agent and Browser SDK | One JavaScript package for both |
| ES module apps | ✔: after registering the hook | ✔: out of the box |
| Unhandled rejections | ✘: not reported | ✔: reported |
| Backend code view | ✘: frames unreadable | ✘: location only |
| Browser source maps | ✔: works | ✔: API upload |
| Server breadcrumbs | ✘: custom data only | ✔: per request, timed |
| Grouping | Error class plus route | Error class plus top frame |
| Session replay | ✘: not offered | ✘: not offered |
| Web vitals | ✔: as metrics | ✘: not observed |
| Releases | ✔: from config | ✔: deploy API |
| Resolve on deploy | ✘: not offered | ✔: per environment |
| Regressed label | ✘: none | ✘: none |
| Tracing | ✔: sampled traces | ✘: not offered |
| Slow queries | ✔: ranked by impact | ✘: not offered |
| Logs | ✔: live tail and Time Detective | ✔: Insights with BadgerQL |
| Host metrics | ✔: on Linux | Not observed |
| Job monitoring | ✔: heartbeats | Check-ins, not tested |
| Uptime and status pages | Uptime included, not tested | Both included, not tested |
| AI | Beta MCP server, untried | Copy for LLM plus MCP, untried |
| Free plan | ✔: 30,000 requests | ✔: 5,000 errors |

## Which should you choose?

Start with what usually goes wrong in your app: requests that get slow, or exceptions nobody catches.

### Choose AppSignal if slow releases are your bigger risk

AppSignal showed the bad deploy release by release, traced it to the slow query and ranked that query by impact. Its logs, Time Detective, host metrics and heartbeats round it out, and the bill never grows with overages.

The trade-offs are in error handling. It missed an unhandled rejection, showed no backend code for ES modules, and kept no record when a closed error reopened. Its trigger also stayed quiet through the slowdown. To see it against a heavier error tracker, read our [Sentry vs AppSignal comparison](https://betterstack.com/community/comparisons/sentry-vs-appsignal/).

### Choose Honeybadger if you want every exception caught and a fresh list on each deploy

Honeybadger caught every failure, kept server breadcrumbs per request with timings, and named the deploy a returning bug came back after. One package covers server and browser, BadgerQL answers custom questions in a line, and uptime and a status page come with the plan.

Its limits are timing and grouping. It records no request durations, so a slowdown is invisible unless your code logs it, and errors that share a helper merge into one group. Where tracing is a must, look at our [Sentry vs Honeybadger comparison](https://betterstack.com/community/comparisons/sentry-vs-honeybadger/).

## FAQ

### Does Honeybadger have performance monitoring?

Not request timing or tracing, in my test. Breadcrumb timings and warning logs in Insights can hint at a slowdown, but only if your app writes them.

### Will AppSignal report an unhandled promise rejection?

Not in my Node.js app. That route counted as error-free, and the failure surfaced only because my code logged it.

### Can both tools resolve errors when you deploy?

Only Honeybadger. Its **Resolve errors on deploy** setting resolves open errors in the environment you name in each deploy call. AppSignal has a **Closed** state, and a closed error reopens when its alerting setting fires.

### Which is cheaper?

They're nearly the same on annual billing: about $23.25 a month for AppSignal's first paid tier and $23.83 for Honeybadger Team. AppSignal counts requests and Honeybadger counts errors, so your traffic decides which bill is smaller.

## Final thoughts

The real choice is which blind spot you'd rather manage. AppSignal measures everything about a request and still let an unhandled rejection pass as a success. Honeybadger catches every exception and can't tell you a request got slower unless your code says so.

You can patch either gap. Add a rejection handler for AppSignal, or slow-query warnings for Honeybadger. Pick the one whose missing half **you'd actually remember to patch**.