Skip to main content
A drain forwards what Vercel’s platform records (logs, Vercel’s spans, Web Vitals, page views) to an HTTP endpoint as it happens. The Marketplace connector creates drains for every project in one step. This page covers what drains send and how to create them yourself.

When to create drains yourself

  • You want drains for some projects only, or one drain for several projects.
  • You want your own dataset and collection names.
  • You want to route some log sources to their own dataset as well, for example firewall logs to a security team’s dataset.
  • You manage drains in your own scripts or infrastructure code.

Drain types

Use ingestion.us.bronto.io for the US region. Every drain authenticates with the header x-bronto-api-key and an API key with the Ingestion role (see API Keys). Log, Speed Insights and Web Analytics drains also set x-bronto-dataset and x-bronto-collection, which decide where the data lands. Trace drains don’t need them: traces appear in Explore Traces, not in datasets. What each drain contains:
  • Logs: seven sources, in the field source: lambda (functions), edge, static, build, external (external rewrites), firewall and redirect. Each record carries deploymentId; request records add environment, executionRegion and the request’s proxy.* fields, and function logs from traced requests carry traceId and spanId. See Functions, Builds and CDN, routing and firewall.
  • Traces: Vercel’s spans for each request (vercel.edge-network, vercel.serverless-runtime). Spans from your own code reach Bronto directly through OpenTelemetry from code.
  • Speed Insights: Core Web Vitals from real users. Requires Speed Insights Plus. See Speed Insights.
  • Web Analytics: page views and custom events. See Web Analytics.
  • AI Gateway traces: one trace per model request. Vercel’s REST API docs don’t list this schema; create it in the dashboard. See Vercel AI SDK, AI Gateway and agents.

Create a drain yourself

In the dashboard

  1. Open Team Settings → Drains → Add Drain.
  2. Choose the data (logs, traces, Speed Insights or Web Analytics) and the projects.
  3. For logs, choose the sources and environments to send.
  4. Set the endpoint and format from the table above, and add the headers x-bronto-api-key, x-bronto-dataset and x-bronto-collection.
Saving the drain sends three Test log message records. Filter them out if you count events.

With the REST API

A log drain for one project, sent to the dataset vercel-logs in the collection my-app:
A trace drain sends OTLP protobuf, and its endpoint is an object:
For Web Analytics, use "schemas": { "analytics": { "version": "v2" } }; for Speed Insights, "speed_insights": { "version": "v1" }.

Filter what a drain sends

A filter decides which records a drain forwards. Use it to route: a second drain with a filter sends some of the records to another dataset as well, while the main drain sends everything. Set it on create or with PATCH /v1/drains/{id}. version must be "v2". Only production build and firewall logs:
A filter can also be a text expression. This one keeps only firewall logs, from every environment:
When you read a drain with GET /v1/drains/{id}, its filter is returned in the field filterV2. The field filter stays empty, so check filterV2 to see which filter a drain applies.
A filter keeps or drops whole records. Everything a drain does forward reaches Bronto in full.

Formats, batching and delivery time

  • ndjson sends Content-Type: application/x-ndjson, one record per line. json sends application/json, one JSON array per request. The connector and the drains in this guide use NDJSON.
  • compression: "gzip" may not compress. Vercel’s docs say deliveries can be compressed, but on a test log drain over 20 minutes and 1,700 requests (up to 53 KB each) no request carried Content-Encoding and every body was plain JSON. The cost is the same either way (see What drains cost).
  • Batches are small. In a test project with about 225 log records a minute, Vercel sent about 56 requests a minute: a median of 3 records per request, at most 65. The median record was 1.2 KB.
  • Delivery is near real time. Half of the records arrived within 5 seconds of their timestamp, 95% within about a minute, all within about 2 minutes.
  • Changes take minutes to apply. After a PATCH, deliveries kept the old settings for 2 to 4 minutes.

Verify deliveries with a signature

When a drain has a secret, every request carries the header x-vercel-signature: an HMAC-SHA1 of the request body, hex-encoded, keyed with the secret. Drains created through the REST API have no secret until you set one ("delivery": { "secret": "…" } on create or by PATCH). Bronto’s endpoint authenticates drains by API key. The signature matters when a drain goes to your own receiver first, for example a forwarder that enriches records:
Compute it over the raw body as received, before parsing.

When deliveries fail

Vercel doesn’t buffer a failing drain. In a test, the receiving endpoint answered 500 for 15 minutes:
  • Vercel sent each batch twice: the retry came about 0.2 seconds after the first attempt (at most 0.5 seconds), then the batch was dropped.
  • Of 1,803 records created in those 15 minutes, 1,767 (98%) were never delivered. Nothing was resent after the endpoint recovered.
  • Deliveries resumed within a second of recovery.
Vercel reports failing drains: when more than 80% of deliveries fail, or more than 50 in an hour, it sends a notification email and marks the drain as errored on the Drains page. See Errored Drains. So a drain is only as reliable as the endpoint it sends to. If a drain goes to your own receiver first, keep it simple and highly available, and have it queue records rather than fail the request.

What drains cost

Vercel charges **$0.50 per GB** for drains on Pro, measured as the uncompressed JSON of each record, whatever the delivery encoding. AI Gateway trace drains add $0.05 per 1,000 traces. To see what drains cost per project, query Vercel’s billing API, GET /v1/billing/charges. It returns one line per service and day (ServiceName: Drains Volume) with the ProjectId. Bronto keeps everything a drain sends, so send everything, once. The volume that’s worth removing is duplicates: a trace drain also forwards your own spans, so if your code exports them directly as well, every span arrives twice (see OpenTelemetry from code). Use filters to route records, not to drop them.

Known limits

  • Drains need a Pro or Enterprise plan.
  • Changes take minutes to apply. After a PATCH, deliveries keep the old settings for 2 to 4 minutes. A drain’s filter is in filterV2, not in filter.
  • A plain trace drain doesn’t carry AI Gateway traces. They need their own ai_gateway drain.

References