Guide to Vercel Log Drains: Features and Best Practices
Vercel Log Drains push your deployment and runtime logs to an HTTP endpoint you control, so you can forward them to your own observability stack instead of reading them in the dashboard. They aren't Vercel webhooks in the event-notification sense; they're a firehose of log records delivered in batches. But the receiving-side concerns are the same as any webhook: verify the sender, acknowledge fast, and handle volume without dropping data.
This guide covers how Log Drains deliver data, how to verify the x-vercel-signature (which is HMAC-SHA1, not SHA-256), the endpoint handshake, the delivery and error behavior, and the best practices for running a drain in production.
What are Vercel Log Drains?
A Log Drain is an HTTP destination that Vercel POSTs batches of log records to as your projects run. Each request carries multiple log entries, encoded as a JSON array or as newline-delimited JSON (NDJSON). You configure which log sources and environments feed the drain, and Vercel streams matching logs to your endpoint over HTTPS.
Log Drains are a Pro/Enterprise feature and are usage-billed. They deliver logs, not discrete business events, so the payload shape and volume are different from a typical webhook, but the verification and reliability patterns carry over directly.
Vercel Log Drains features
| Feature | Details |
|---|---|
| Delivery | HTTPS POST, logs batched per request |
| Encoding | JSON array or NDJSON (syslog no longer offered) |
| Signature header | x-vercel-signature |
| Signature scheme | HMAC-SHA1 hex digest of the raw body, keyed with the drain secret |
| Endpoint handshake | x-vercel-verify response header echoing a verification token |
| Log sources | static, lambda, edge, build, external, firewall |
| Environments | production, preview (per-drain sampling rules) |
| Error handling | Drain flagged errored if >80% of deliveries fail or >50 failures/hour |
| Configuration | Dashboard (Team Settings > Drains) or REST API |
| Options | Optional gzip compression, custom auth headers |
| Plan | Pro/Enterprise, usage-billed |
What's in a delivery
Each POST is a batch of log records. Log sources include static, lambda, edge, build, external, and firewall (a redirect source also appears in delivered payloads). A few field-level details worth knowing: message fields may be truncated above 256 KB, and a statusCode of -1 means the lambda crashed. Because deliveries are batched, your handler must iterate every record in the request rather than assuming one log per POST.
Setting up a Log Drain
Configure drains in the dashboard under Team Settings > Drains with the "Logs" data type, or via the REST API:
curl -X POST "https://api.vercel.com/v1/drains" \
-H "Authorization: Bearer $VERCEL_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"deliveryFormat": "ndjson",
"url": "https://your-app.example.com/drain",
"sources": ["lambda", "build"],
"environments": ["production"],
"secret": "your-drain-secret",
"headers": {"x-custom-auth": "..."}
}'
The legacy /v1/log-drains and /v2/integrations/log-drains endpoints are deprecated in favor of /v1/drains. You can set a drain secret (used to sign deliveries), optional custom headers, gzip compression, and per-drain sampling.
The verify handshake
When a drain is created or tested, Vercel checks that you own the endpoint. Your endpoint returns a 200 with an x-vercel-verify response header echoing the verification token Vercel expects. This initial verification request is not signed, so don't require a valid x-vercel-signature on it; only signed log deliveries carry that header.
Securing Vercel Log Drains
Every log delivery carries an x-vercel-signature header: a hex-encoded HMAC-SHA1 of the raw request body, keyed with your drain signature secret. Note the algorithm carefully. This is SHA-1, not the SHA-256 most webhook providers use, so reusing a generic SHA-256 verifier will fail every delivery.
Compute the HMAC over the exact raw bytes and compare with a constant-time comparison:
import crypto from "crypto";
const SECRET = process.env.VERCEL_DRAIN_SECRET;
export const config = { api: { bodyParser: false } }; // keep the raw body
export default async function handler(req, res) {
if (req.method !== "POST") return res.status(405).end();
const rawBody = await getRawBody(req); // Buffer of the untouched body
// Verify handshake: the setup request is unsigned. Echo the verification
// token in the x-vercel-verify response header and return 200.
if (!req.headers["x-vercel-signature"]) {
res.setHeader("x-vercel-verify", process.env.VERCEL_VERIFY_TOKEN);
return res.status(200).end();
}
const expected = crypto.createHmac("sha1", SECRET).update(rawBody).digest("hex");
const received = req.headers["x-vercel-signature"] || "";
const a = Buffer.from(expected);
const b = Buffer.from(received);
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
return res.status(403).json({ error: "invalid signature" });
}
res.status(200).json({ ok: true }); // acknowledge fast
for (const record of parseRecords(rawBody)) processQueue.add(record);
}
The same HMAC in Python:
import hashlib
import hmac
import os
SECRET = os.environ["VERCEL_DRAIN_SECRET"].encode()
def verify(raw_body: bytes, signature: str) -> bool:
expected = hmac.new(SECRET, raw_body, hashlib.sha1).hexdigest()
return hmac.compare_digest(expected, signature or "")
Vercel Log Drains limitations and pain points
It's SHA-1, and it's easy to get wrong
The Problem: x-vercel-signature is HMAC-SHA1. Most webhook integrations reach for SHA-256 by default, and a SHA-256 verifier silently rejects every legitimate delivery.
Why It Happens: Log Drains predate the SHA-256 conventions many newer providers adopted, and Vercel kept the SHA-1 scheme.
Workarounds:
- Use
sha1explicitly in your HMAC and verify against the raw body. - Compare in constant time rather than with a plain string equality check.
How Hookdeck Can Help: Hookdeck verifies the x-vercel-signature HMAC-SHA1 at the edge, so your service receives pre-verified deliveries and you don't have to special-case the algorithm.
High, bursty volume
The Problem: Drains stream logs, not occasional events. Traffic spikes with your deployments and request volume, and a slow endpoint quickly falls behind or starts failing deliveries.
Why It Happens: Logs are high-cardinality and high-frequency by nature, especially the lambda and edge sources.
Workarounds:
- Acknowledge with a 200 immediately and push records onto a queue or straight into your log store.
- Use per-drain sampling and scope sources/environments so you only receive what you need.
- Prefer NDJSON and stream-parse rather than buffering giant JSON arrays in memory.
How Hookdeck Can Help: Hookdeck absorbs bursts, durably queues deliveries, and forwards to your endpoint at a rate it can handle, so a spike in log volume doesn't turn into failed deliveries or dropped logs.
Errored-drain thresholds, but no per-batch retry schedule
The Problem: Vercel flags a drain as errored (and emails you) if more than 80% of deliveries fail or more than 50 fail in an hour, but there's no documented per-batch retry schedule. Logs that fail delivery aren't guaranteed to be resent.
Why It Happens: Log delivery favors throughput over the strong retry guarantees you'd expect from business-event webhooks.
Workarounds:
- Keep the endpoint healthy and fast so you stay well under the error thresholds.
- Persist every received batch immediately so a downstream failure doesn't lose logs you already accepted.
- Monitor for Vercel's errored-drain emails.
How Hookdeck Can Help: Hookdeck accepts and durably stores each delivery, then retries to your downstream on a schedule you control, giving log delivery the retry and replay guarantees Vercel doesn't provide per batch.
Batched, truncated, and crash-marked records
The Problem: Each POST holds many records, message fields can be truncated above 256 KB, and statusCode: -1 signals a crashed lambda. A handler that assumes one clean record per request will mishandle all three.
Why It Happens: Batching and truncation keep delivery efficient at log scale.
Workarounds:
- Iterate the full batch and handle truncation and
-1status codes explicitly. - Don't treat a truncated message as malformed; treat it as partial.
How Hookdeck Can Help: Hookdeck can split batched deliveries and transform records before they reach your store, so downstream systems get consistent, individual entries.
Best practices
Verify with HMAC-SHA1 against the raw body
Use sha1, compute over the untouched bytes, and compare in constant time. Don't require a signature on the unsigned verify handshake.
Acknowledge fast, persist first
Return 200 as soon as the signature verifies, then write records to a queue or log store. Never do slow processing before responding. See why to process webhooks asynchronously.
Scope sources, environments, and sampling
Only subscribe the sources and environments you actually consume, and use sampling to control volume and cost.
Handle the batch and its edge cases
Iterate every record, handle 256 KB truncation and statusCode: -1, and prefer NDJSON stream parsing for large batches.
Monitor drain health
Watch for errored-drain emails and track your delivery success rate so you stay under the 80%-failure and 50-failures-per-hour thresholds.
Make Vercel Log Drains production-ready
Hookdeck verifies the SHA-1 signature, absorbs bursts, and durably queues every log batch
Conclusion
Vercel Log Drains give you your logs as a real-time HTTP stream, batched as JSON or NDJSON and signed with an HMAC-SHA1 x-vercel-signature you have to verify against the raw body. The catch is that they behave like a firehose, not an event feed: high bursty volume, batched and occasionally truncated records, errored-drain thresholds instead of a per-batch retry schedule, and an unsigned verify handshake to handle separately.
That leaves you owning fast acknowledgement, burst absorption, durable persistence, and the SHA-1 verification detail. Hookdeck verifies the signature, absorbs spikes, durably queues every batch, and retries to your downstream on your terms, so your log pipeline stays reliable no matter how much Vercel sends.
Get started with Hookdeck for free and handle Vercel Log Drains reliably in minutes.