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
102 changes: 102 additions & 0 deletions src/content/docs/workers/examples/analytics-engine.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
---
summary: Write custom analytics events to Workers Analytics Engine.
tags:
- Analytics
- Observability
pcx_content_type: example
title: Write to Analytics Engine
sidebar:
order: 1001
description: Write custom analytics events to Workers Analytics Engine for high-cardinality, time-series data.
---

import { TypeScriptExample, WranglerConfig } from "~/components";

[Workers Analytics Engine](/analytics/analytics-engine/) provides time-series analytics at scale. Use it to track custom metrics, build usage-based billing, or understand service health on a per-customer basis.

Unlike logs, Analytics Engine is designed for aggregated queries over high-cardinality data. Writes are non-blocking and do not impact request latency.

## Configure the binding

Add an Analytics Engine dataset binding to your Wrangler configuration file. The dataset is created automatically when you first write to it.

<WranglerConfig>

```jsonc
{
"analytics_engine_datasets": [
{
"binding": "ANALYTICS",
"dataset": "my_dataset",
},
],
}
```

</WranglerConfig>

## Write data points

<TypeScriptExample>

```ts
interface Env {
ANALYTICS: AnalyticsEngineDataset;
}

export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);

// Write a page view event
env.ANALYTICS.writeDataPoint({
blobs: [
url.pathname,
request.headers.get("cf-connecting-country") ?? "unknown",
],
doubles: [1], // Count
indexes: [url.hostname], // Sampling key
});

// Write a response timing event
const start = Date.now();
const response = await fetch(request);
const duration = Date.now() - start;

env.ANALYTICS.writeDataPoint({
blobs: [url.pathname, response.status.toString()],
doubles: [duration],
indexes: [url.hostname],
});

// Writes are non-blocking - no need to await or use waitUntil()
return response;
},
};
```

</TypeScriptExample>

## Data point structure

Each data point consists of:

- **blobs** (strings) - Dimensions for grouping and filtering. Use for paths, regions, status codes, or customer IDs.
- **doubles** (numbers) - Numeric values to record, such as counts, durations, or sizes.
- **indexes** (strings) - A single string used as the [sampling key](/analytics/analytics-engine/sql-api/#sampling). Group related events under the same index.

## Query your data

Query your data using the [SQL API](/analytics/analytics-engine/sql-api/):

```bash
curl "https://api.cloudflare.com/client/v4/accounts/$CLOUDFLARE_ACCOUNT_ID/analytics_engine/sql" \
--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
--data "SELECT blob1 AS path, SUM(_sample_interval) AS views FROM my_dataset WHERE timestamp > NOW() - INTERVAL '1' HOUR GROUP BY path ORDER BY views DESC LIMIT 10"
```

## Related resources

- [Analytics Engine documentation](/analytics/analytics-engine/) - Full reference for Workers Analytics Engine.
- [SQL API reference](/analytics/analytics-engine/sql-api/) - Query syntax and available functions.
- [Grafana integration](/analytics/analytics-engine/grafana/) - Visualize Analytics Engine data in Grafana.
30 changes: 26 additions & 4 deletions src/content/docs/workers/observability/logs/tail-workers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
{
"scriptName": "Example script",
"outcome": "exception",
"eventTimestamp": 1587058642005,

Check warning on line 56 in src/content/docs/workers/observability/logs/tail-workers.mdx

View workflow job for this annotation

GitHub Actions / Semgrep

semgrep.style-guide-potential-date-year

Potential year found. Documentation should strive to represent universal truth, not something time-bound. (add [skip style guide checks] to commit message to skip)
"event": {
"request": {
"url": "https://example.com/some/requested/url",
Expand All @@ -71,21 +71,21 @@
{
"message": ["string passed to console.log()"],
"level": "log",
"timestamp": 1587058642005

Check warning on line 74 in src/content/docs/workers/observability/logs/tail-workers.mdx

View workflow job for this annotation

GitHub Actions / Semgrep

semgrep.style-guide-potential-date-year

Potential year found. Documentation should strive to represent universal truth, not something time-bound. (add [skip style guide checks] to commit message to skip)
}
],
"exceptions": [
{
"name": "Error",
"message": "Threw a sample exception",
"timestamp": 1587058642005

Check warning on line 81 in src/content/docs/workers/observability/logs/tail-workers.mdx

View workflow job for this annotation

GitHub Actions / Semgrep

semgrep.style-guide-potential-date-year

Potential year found. Documentation should strive to represent universal truth, not something time-bound. (add [skip style guide checks] to commit message to skip)
}
],
"diagnosticsChannelEvents": [
{
"channel": "foo",
"message": "The diagnostic channel message",
"timestamp": 1587058642005

Check warning on line 88 in src/content/docs/workers/observability/logs/tail-workers.mdx

View workflow job for this annotation

GitHub Actions / Semgrep

semgrep.style-guide-potential-date-year

Potential year found. Documentation should strive to represent universal truth, not something time-bound. (add [skip style guide checks] to commit message to skip)
}
]
}
Expand All @@ -108,10 +108,32 @@

:::

## Use Analytics Engine for aggregated metrics

If you need aggregated analytics rather than individual log events, consider writing to [Workers Analytics Engine](/analytics/analytics-engine/) from your Tail Worker. Analytics Engine is optimized for high-cardinality, time-series data that you can query with SQL.

For example, you can use a Tail Worker to count errors by endpoint, track response times by customer, or build usage metrics, then write those aggregates to Analytics Engine for querying and visualization.

```js
export default {
async tail(events, env) {
for (const event of events) {
env.ANALYTICS.writeDataPoint({
blobs: [event.scriptName, event.outcome],
doubles: [1],
indexes: [event.event?.request?.cf?.colo ?? "unknown"],
});
}
},
};
```

Refer to the [Analytics Engine documentation](/analytics/analytics-engine/) for more details on writing and querying data.

## Related resources

- [`tail()`](/workers/runtime-apis/handlers/tail/) Handler API docs - Learn how to set up a `tail()` handler in your Worker.

* [Errors and exceptions](/workers/observability/errors/) - Review common Workers errors.
* [Local development and testing](/workers/development-testing/) - Develop and test you Workers locally.
* [Source maps and stack traces](/workers/observability/source-maps) - Learn how to enable source maps and generate stack traces for Workers.
- [Analytics Engine](/analytics/analytics-engine/) - Write custom analytics from your Worker for high-cardinality, time-series queries.
- [Errors and exceptions](/workers/observability/errors/) - Review common Workers errors.
- [Local development and testing](/workers/development-testing/) - Develop and test you Workers locally.
- [Source maps and stack traces](/workers/observability/source-maps) - Learn how to enable source maps and generate stack traces for Workers.
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,18 @@ This chart shows historical data for all Workers on a zone broken down by succes
## GraphQL

Worker metrics are powered by GraphQL. Learn more about querying our data sets in the [Querying Workers Metrics with GraphQL tutorial](/analytics/graphql-api/tutorials/querying-workers-metrics/).

## Custom analytics with Analytics Engine

The metrics described above provide insight into Worker performance and runtime behavior. For custom, application-specific analytics, use [Workers Analytics Engine](/analytics/analytics-engine/).

Analytics Engine is useful for:

- **Custom business metrics** - Track events specific to your application, such as signups, purchases, or feature usage.
- **Per-customer analytics** - Record data with high-cardinality dimensions like customer IDs or API keys.
- **Usage-based billing** - Count API calls, compute units, or other billable events per customer.
- **Performance tracking** - Measure response times, cache hit rates, or error rates with custom dimensions.

Writes to Analytics Engine are non-blocking and do not add latency to your Worker. Query your data using SQL through the [Analytics Engine SQL API](/analytics/analytics-engine/sql-api/) or visualize it in [Grafana](/analytics/analytics-engine/grafana/).

Refer to the [Analytics Engine example](/workers/examples/analytics-engine/) to get started.
Loading