---
title: "Astro integration"
url: "https://bicho.fyi/docs/astro"
description: "Add Bicho error reporting to Astro static and SSR sites. Configure separate browser and server projects, review capture limits, and protect credentials."
---

[`@bicho-fyi/astro`](https://www.npmjs.com/package/@bicho-fyi/astro) connects Astro to your own Bicho instance using the JavaScript SDK. Enable automatic browser capture on static or SSR sites, server request-exception reporting on SSR sites, or both. Each mode is opt-in and has independent configuration.

## Install

```
npm install @bicho-fyi/astro
```

The published 1.0.0 package requires Node 24+ and declares Astro `^6.0.0 || ^7.4.0`. Use an SSR adapter compatible with your Astro version for server reporting; browser capture also works with static output.

[Deploy Bicho and create projects](/docs/) first. Use separate projects for browser and server errors when you want to investigate them independently. Both must use `secret: false`: this integration sends public ingest keys only, including on the server.

## Configure Astro

Add the integration to your existing `astro.config.mjs`:

```
import { defineConfig } from 'astro/config';
import bicho from '@bicho-fyi/astro';

export default defineConfig({
  integrations: [bicho({
    browser: {
      endpoint: 'https://your-bicho-worker.example/v1/logs',
      key: 'BROWSER_PUBLIC_KEY',
      serviceName: 'my-app/browser',
      environment: 'production',
    },
    server: {
      endpoint: 'https://your-bicho-worker.example/v1/logs',
      key: 'SERVER_PUBLIC_KEY',
      serviceName: 'my-app/server',
      environment: 'production',
      closeTimeout: 2000,
    },
  })],
});
```

Keep your existing adapter and `output` settings for SSR. Static sites only need `browser`. Omit either mode or set it to `false` to disable it. Endpoints and public keys can point to different projects or collectors. Use the generated `otlp.endpoint` and `otlp.headers['X-Bicho-Key']`; neither a project ID nor an admin token belongs in these settings.

Browser configuration is public. Never put ingest secrets or admin credentials in it. Server configuration stays in server modules, but the server transport still requires a public-key-only project. HTTPS is required except on loopback. If you use a Content Security Policy, allow the collector in `connect-src`.

## Options

| Option | Applies to | Default | Purpose |
| --- | --- | --- | --- |
| endpoint | Both | Required | Full OTLP endpoint ending in /v1/logs |
| key | Both | Required | Public ingest key for the selected project |
| serviceName | Both | SDK default | Service label attached to reports |
| environment | Both | Unset | Application environment |
| release | Both | Unset | Application release |
| autoCapture | Browser | true | Capture uncaught errors and unhandled promise rejections |
| closeTimeout | Server | 2000 | Delivery deadline in milliseconds, from 0 to 10000 |

The integration serializes only these options. JavaScript SDK hooks, tags, and custom contexts are not integration settings.

## Browser capture

Astro bundles a page module that initializes the JavaScript SDK. Once initialized, it listens for uncaught JavaScript exceptions and unhandled promise rejections. It does not capture earlier failures, caught exceptions, `console.error()`, explicit HTTP error responses, or resource failures without JavaScript error data.

Do not initialize another Bicho browser client alongside this integration or you can report the same failure twice. For consent-controlled initialization, custom filtering hooks, or manual browser reporting, omit `browser` and use the [JavaScript SDK](/docs/javascript/) in your own client entry instead. Setting `autoCapture: false` disables the listeners; the integration does not expose a global client for manual calls.

Browser delivery is best effort, particularly during navigation and shutdown. Messages and stack traces can still contain private application data.

## Server capture and limits

The integration adds pre middleware. If the downstream request handler throws, the middleware reports the original exception through a fresh SDK client, waits for bounded delivery, and rethrows the same value. Reporting failures do not replace the application’s original error. Successful responses and explicit 500/503 responses pass through unchanged.

Prerendered routes skip server reporting, including failed prerenders. The middleware installs no process handlers and does not capture build errors or failures outside its request chain.

| Failure | Automatic server reporting |
| --- | --- |
| Page frontmatter throws through next() | Original exception |
| Endpoint or downstream middleware throws through next() | Original exception |
| Handler returns a 500/503 response | None |
| Nested component fails after streaming has started | None |
| Static prerender or build fails | None |

A streamed component error can happen after `next()` has returned a response. The integration does not buffer the response stream to catch it. Node may terminate a response after sending status 200; local Cloudflare preview may return an empty 200 body. Neither result means the middleware captured the error. Other adapters can expose different boundaries.

Server reporting can delay a failed request by up to `closeTimeout` plus local processing time. It does not wait on healthy requests. A timeout or collector failure can lose an event.

## Explicit server reporting

For a boundary the middleware cannot observe, report the original error at its source:

```
import { reportError } from '@bicho-fyi/astro/server';

const delivered = await reportError(error, {
  endpoint: 'https://your-bicho-worker.example/v1/logs',
  key: 'SERVER_PUBLIC_KEY',
  closeTimeout: 2000,
});
```

`reportError()` creates and closes an isolated client. It returns a delivery boolean and does not throw on reporting failure. Keep the application’s existing error handling.

An existing dynamic `500.astro` can report `Astro.props.error` with prerender and error-presence guards. Use it instead of middleware reporting for the same failure, not in addition, to avoid duplicates. A 500 page cannot recover a stream that already started, and the integration does not create or replace your error page.

## Check delivery

Use dedicated test projects. Trigger an uncaught error in a browser page after initialization and a throwing request handler on your SSR site. These create real error reports; a build-time exception is not a server capture test.

Search each project through your instance’s [MCP](/docs/mcp/) or [HTTP API](/docs/api/), then read the stored event and check its message, service, environment, and project. A returned UID or delivery boolean is not a substitute for reading the evidence back. See [operations](/docs/operations/) if a report is missing.

The integration adds no automatic request URL, headers, cookies, or body collection. Review [Astro privacy and credentials](/docs/privacy/#astro) before enabling it. It does not upload source maps or provide tracing, replay, or crash recovery.

-   [Astro integration source and full reference](https://github.com/bicho-fyi/bicho-astro)
-   [Astro package on npm](https://www.npmjs.com/package/@bicho-fyi/astro)