Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions docs/platforms/javascript/common/troubleshooting/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -691,4 +691,75 @@ shamefully-hoist=true
</Expandable>
</PlatformSection>

<PlatformSection supported={['javascript.cloudflare']}>
<Expandable permalink title="Spans from waitUntil() or other work after the response are missing">
Cloudflare's [`waitUntil()`](https://developers.cloudflare.com/workers/runtime-apis/handlers/fetch/#contextwaituntil) lets work continue after the Worker returns a response. Whether those spans arrive depends on your trace lifecycle.

On the static lifecycle, which is the default, the SDK snapshots the request transaction when the response is returned, so anything finishing later is dropped. Streaming sends each sampled span as it finishes instead, which captures deferred work.

Set `traceLifecycle: "stream"`, which needs `@sentry/cloudflare` version `10.49.0` or newer:

```javascript {filename:index.js}
export default Sentry.withSentry(
(env) => ({
dsn: env.SENTRY_DSN,
tracesSampleRate: 1.0,
traceLifecycle: "stream",
}),
worker
);
```

If you need to keep the static lifecycle, wrap the background work in its own span with `forceTransaction: true`, which records it as a separate transaction. `forceTransaction` isn't available in stream mode.

```javascript {filename:index.js}
ctx.waitUntil(
Sentry.startSpan(
{ name: "background.task", op: "task", forceTransaction: true },
() => updateCacheAndDatabase()
)
);
```

See <PlatformLink to="/tracing/streamed-spans/">Streamed Spans</PlatformLink> for how streaming changes filtering with `beforeSendSpan` and `ignoreSpans`.

</Expandable>

<Expandable permalink title="My events have no release, or the wrong one">
The SDK resolves the release from the `release` option you pass, then the `SENTRY_RELEASE` environment variable, then the `CF_VERSION_METADATA.id` binding. The first one that is set wins. Reading the binding automatically needs `@sentry/cloudflare` version `10.35.0` or newer; on earlier versions, pass it as the `release` option yourself, as shown at the end of this entry.

If your events carry no release, check that the binding is declared in your wrangler config:

```jsonc {tabTitle:JSON} {filename:wrangler.jsonc}
{
"version_metadata": {
"binding": "CF_VERSION_METADATA"
}
}
```

```toml {tabTitle:Toml} {filename:wrangler.toml}
[version_metadata]
binding = "CF_VERSION_METADATA"
```

The binding only carries a meaningful version ID on a deployed Worker. In local development the value is [not applicable or accurate](https://developers.cloudflare.com/workers/local-development/), so events from `wrangler dev` or `vite dev` won't match a release in Sentry.

If your events carry a release you didn't expect, something further up the list is set. A `SENTRY_RELEASE` variable left over in your Worker's environment overrides the binding, and an explicit `release` option overrides both.

To pin the release to the Cloudflare version ID no matter what else is set, pass it yourself:

```javascript
Sentry.withSentry(
(env) => ({
dsn: "___PUBLIC_DSN___",
release: env.CF_VERSION_METADATA?.id,
})
// ...
);
```

</Expandable>
</PlatformSection>

If you need additional help, you can [ask on GitHub](https://github.com/getsentry/sentry-javascript/issues/new/choose). Customers on a paid plan may also contact support.
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const MyAgent = Sentry.instrumentAgentWithSentry(

The Worker that calls the agent names its binding in `rpcTracePropagationBindings`. See <PlatformLink to="/tracing/distributed-tracing/#rpc-trace-propagation">RPC Trace Propagation</PlatformLink>.

`instrumentAgentWithSentry` works with `Agent` from `agents`, `AIChatAgent` from `@cloudflare/ai-chat`, and `McpAgent` from `agents/mcp`. When you build with the <PlatformLink to="/features/vite-plugin/">Sentry Cloudflare Vite plugin</PlatformLink>'s `autoInstrumentation`, the plugin detects and wraps Agent classes automatically.
`instrumentAgentWithSentry` works with `Agent` from `agents`, `AIChatAgent` from `@cloudflare/ai-chat`, and `McpAgent` from `agents/mcp`. When you build with the <PlatformLink to="/install/vite-plugin/">Sentry Cloudflare Vite plugin</PlatformLink>'s `autoInstrumentation`, the plugin detects and wraps Agent classes automatically.

## Conversation IDs

Expand Down Expand Up @@ -93,7 +93,7 @@ Populate the Conversations **User** column with `Sentry.setUser` on every reques

- <PlatformLink to="/agent-tracing/workers-ai/">Workers AI</PlatformLink>
- <PlatformLink to="/features/durableobject/">Durable Objects</PlatformLink>
- <PlatformLink to="/features/vite-plugin/">Vite Plugin</PlatformLink>
- <PlatformLink to="/install/vite-plugin/">Vite Plugin</PlatformLink>
- <PlatformLink to="/agent-tracing/#tracking-conversations">
Tracking Conversations
</PlatformLink>
Expand Down
150 changes: 150 additions & 0 deletions docs/platforms/javascript/guides/cloudflare/features/pages.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
---
title: Cloudflare Pages
description: "Learn how to instrument a Cloudflare Pages application with Sentry using the sentryPagesPlugin middleware."
---

<Alert>

Cloudflare recommends [migrating to Workers with static assets](https://developers.cloudflare.com/workers/static-assets/migration-guides/migrate-from-pages/). Workers covers most Pages use cases with a broader feature set, and it's where new Cloudflare features land. Pages keeps working, so this page stays accurate, but start new projects on Workers and follow the <PlatformLink to="/">Cloudflare guide</PlatformLink> instead.

After migrating, you replace `sentryPagesPlugin` with the Vite plugin or `withSentry`, depending on how you build.

</Alert>

Cloudflare Pages applications are instrumented with the `sentryPagesPlugin` middleware instead of the `withSentry` wrapper that Workers use. The rest of the SDK behaves the same, so the <PlatformLink to="/">Cloudflare guide</PlatformLink> still applies for installation, Wrangler configuration, source maps, and the options reference.

## Install

<PlatformContent includePath="getting-started-install" />

## Configure

### Wrangler Configuration

<PlatformContent
includePath="getting-started-config"
platform="javascript.cloudflare"
/>

### Add the Middleware

<SplitLayout>
<SplitSection>
<SplitSectionText>

To use the Sentry SDK, add the `sentryPagesPlugin` as [middleware to your Cloudflare Pages application](https://developers.cloudflare.com/pages/functions/middleware/).

<Include name="cloudflare-pages-middleware-intro.mdx" />

</SplitSectionText>
<SplitSectionCode>

```javascript {filename:functions/_middleware.js}
import * as Sentry from "@sentry/cloudflare";

export const onRequest = [
// Make sure Sentry is the first middleware
Sentry.sentryPagesPlugin((context) => ({
dsn: "___PUBLIC_DSN___",

dataCollection: {
// Any dataCollection object (including {}) uses permissive defaults:
// userInfo, cookies, HTTP bodies, genAI prompts/responses, and more.
// Uncomment to tighten. Details:
// https://docs.sentry.io/platforms/javascript/guides/cloudflare/configuration/options/#dataCollection
// userInfo: false,
// httpBodies: [],
// genAI: { inputs: false, outputs: false },
},

// Set tracesSampleRate to 1.0 to capture 100% of spans for tracing.
// Learn more at
// https://docs.sentry.io/platforms/javascript/guides/cloudflare/configuration/options/#tracesSampleRate
tracesSampleRate: 1.0,
})),
// Add more middlewares here
];
```

</SplitSectionCode>
</SplitSection>
</SplitLayout>

<Expandable title="Don't have access to onRequest?">
<SplitLayout>
<SplitSection>
<SplitSectionText>

If you don't have access to the `onRequest` middleware API, you can use the `wrapRequestHandler` API instead. For example:

</SplitSectionText>
<SplitSectionCode>

```javascript
// hooks.server.js
import * as Sentry from "@sentry/cloudflare";

export const handle = ({ event, resolve }) => {
const requestHandlerOptions = {
options: {
dsn: event.platform.env.SENTRY_DSN,
tracesSampleRate: 1.0,
},
request: event.request,
context: event.platform.ctx,
};
return Sentry.wrapRequestHandler(requestHandlerOptions, () => resolve(event));
};
```

</SplitSectionCode>
</SplitSection>
</SplitLayout>

</Expandable>

## Verify Your Setup

<SplitLayout>
<SplitSection>
<SplitSectionText>

Create a new route that throws an error when called by adding the following code snippet to a file in your `functions` directory, such as `functions/debug-sentry.js`:

</SplitSectionText>
<SplitSectionCode>

```javascript {filename:debug-sentry.js}
export async function onRequest(context) {
throw new Error("My first Sentry error!");
}
```

</SplitSectionCode>
</SplitSection>
</SplitLayout>

To test your tracing configuration, start a span around the failing code:

```javascript {filename:debug-sentry.js}
import * as Sentry from "@sentry/cloudflare";

export async function onRequest(context) {
await Sentry.startSpan(
{
op: "test",
name: "My First Test Span",
},
async () => {
await new Promise((resolve) => setTimeout(resolve, 100)); // Wait for 100ms
throw new Error("My first Sentry error!");
}
);
}
```

Then head over to your project on [Sentry.io](https://sentry.io) to view the collected data (it takes a couple of moments for the data to appear).

## Known Limitations

The <PlatformLink to="/#known-limitations">limitations of the Cloudflare Workers runtime</PlatformLink> apply to Pages Functions as well, including zero-duration spans for CPU-bound work.
Loading
Loading