Build a request analytics pipeline with Wrangler.
Record requests to a Cloudflare Worker with Basin Pipelines, store them as an Apache Iceberg table in Basin Catalog, and count requests by path with Basin SQL.
Worker → Basin Pipelines → Basin Catalog → Basin SQL
- A Cloudflare account with Workers Paid and R2 enabled. Refer to Basin Pipelines pricing and Basin SQL pricing for availability and usage details.
- Node.js and npm ↗︎. The Worker starter installs Wrangler for you.
- An R2 Account API token with Admin Read & Write permission. Create it from R2 object storage > Overview > Manage API tokens. Keep the token private. The setup command requests it, and Basin SQL uses the same token.
-
Create a JavaScript Hello World Worker with C3 ↗︎:
npm create cloudflare@latest -- hello-world-pipeline --type=hello-world --lang=js --no-deploy --no-git --accept-defaultsyarn create cloudflare hello-world-pipeline --type=hello-world --lang=js --no-deploy --no-git --accept-defaultspnpm create cloudflare@latest hello-world-pipeline --type=hello-world --lang=js --no-deploy --no-git --accept-defaultsGo to the project directory:
cd hello-world-pipelineThe starter creates
src/index.jsandwrangler.jsonc. If Wrangler requests authentication during the next step, log in:npx wrangler loginyarn wrangler loginpnpm wrangler login -
Create a stream, sink, and pipeline with the interactive setup:
npx wrangler basin pipelines setup --name request_eventsyarn wrangler basin pipelines setup --name request_eventspnpm wrangler basin pipelines setup --name request_eventsIn the setup prompts:
- Turn off the HTTP endpoint. This Worker sends events through a binding.
- Build the schema interactively with one required
stringfield namedpath. - Select Data Catalog (Iceberg) and Advanced. Enter a unique R2 bucket name, such as
request-events-<UNIQUE_SUFFIX>. Use namespacedefaultand tablerequest_events. - Enter your R2 Account API token. Accept the default compression and 100 MB file size, then set the roll interval to 60 seconds.
- Confirm resource creation and select Simple ingestion for the pipeline SQL.
Save the bucket name and the stream ID shown in the setup output. The Worker binding uses the stream ID, not the pipeline ID. If you missed it, list the streams and find
request_events_stream:npx wrangler basin pipelines streams listyarn wrangler basin pipelines streams listpnpm wrangler basin pipelines streams list -
Add a
pipelinesproperty inside the root object ofwrangler.jsonc. Replace<STREAM_ID>with the stream ID from setup, and keep the other generated properties:{ "pipelines": [ { "binding": "EVENTS", "stream": "<STREAM_ID>" } ] }[[pipelines]] binding = "EVENTS" stream = "<STREAM_ID>"In
src/index.js, add one line before the existing response. The Worker still returnsHello World!:src/index.jsjs export default { async fetch(request, env, ctx) { await env.EVENTS.send([{ path: new URL(request.url).pathname }]); return new Response("Hello World!"); }, };src/index.tsts export default { async fetch(request, env, ctx) { await env.EVENTS.send([{ path: new URL(request.url).pathname }]); return new Response("Hello World!"); }, };The binding handles ingestion authentication. Do not add your R2 API token to the Worker or
wrangler.jsonc. -
Deploy the Worker:
npx wrangler deployyarn wrangler deploypnpm wrangler deployOpen the URL printed by Wrangler at
/and/example. Both paths displayHello World!, and each request records its path. Refresh/to record another request. -
Get the warehouse name associated with your R2 bucket:
npx wrangler basin catalog get <YOUR_BUCKET>yarn wrangler basin catalog get <YOUR_BUCKET>pnpm wrangler basin catalog get <YOUR_BUCKET>Set the token in your terminal session, then count requests by path:
export WRANGLER_BASIN_SQL_AUTH_TOKEN="<YOUR_R2_ACCOUNT_API_TOKEN>"npx wrangler basin sql query "<WAREHOUSE_NAME>" "SELECT path, COUNT(*) AS requests FROM default.request_events GROUP BY path ORDER BY requests DESC"yarn wrangler basin sql query "<WAREHOUSE_NAME>" "SELECT path, COUNT(*) AS requests FROM default.request_events GROUP BY path ORDER BY requests DESC"pnpm wrangler basin sql query "<WAREHOUSE_NAME>" "SELECT path, COUNT(*) AS requests FROM default.request_events GROUP BY path ORDER BY requests DESC"Replace
<WAREHOUSE_NAME>with the value from the catalog command. The results should include/and/examplewith request counts. Other paths, such as/favicon.ico, may also appear. If the table is not found or returns no rows, wait a few minutes for the first file to be written, then run the query again.
Add a timestamp, request method, or country to the events after your first query works. For more detail, refer to Basin Pipelines getting started, Basin Catalog getting started, Basin SQL getting started, and Workers bindings.